1 /* square.c - Copyright (C) 2004 Pat Thoyts <patthoyts@users.sourceforge.net>
3 * Minimal sample ttk widget.
10 #if defined(TTK_SQUARE_WIDGET) || 1
12 #ifndef DEFAULT_BORDERWIDTH
13 #define DEFAULT_BORDERWIDTH "2"
17 * First, we setup the widget record. The Ttk package provides a structure
18 * that contains standard widget data so it is only necessary to define
19 * a structure that holds the data required for our widget. We do this by
20 * defining a widget part and then specifying the widget record as the
21 * concatenation of the two structures.
29 Tcl_Obj *borderWidthObj;
30 Tcl_Obj *foregroundObj;
44 * This structure is the same as the option specification structure used
45 * for Tk widgets. For each option we provide the type, name and options
46 * database name and class name and the position in the structure and
47 * default values. At the bottom we bring in the standard widget option
48 * defined for all widgets.
51 static Tk_OptionSpec SquareOptionSpecs[] =
53 {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
54 DEFAULT_BORDERWIDTH, Tk_Offset(Square,square.borderWidthObj), -1,
55 0,0,GEOMETRY_CHANGED },
56 {TK_OPTION_BORDER, "-foreground", "foreground", "Foreground",
57 DEFAULT_BACKGROUND, Tk_Offset(Square,square.foregroundObj),
60 {TK_OPTION_PIXELS, "-width", "width", "Width",
61 "50", Tk_Offset(Square,square.widthObj), -1, 0, 0,
63 {TK_OPTION_PIXELS, "-height", "height", "Height",
64 "50", Tk_Offset(Square,square.heightObj), -1, 0, 0,
67 {TK_OPTION_STRING, "-padding", "padding", "Pad", NULL,
68 Tk_Offset(Square,square.paddingObj), -1,
69 TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
71 {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
72 NULL, Tk_Offset(Square,square.reliefObj), -1, TK_OPTION_NULL_OK, 0, 0},
74 {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
75 NULL, Tk_Offset(Square,square.anchorObj), -1, TK_OPTION_NULL_OK, 0, 0},
77 WIDGET_TAKEFOCUS_TRUE,
78 WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
82 * Almost all of the widget functionality is handled by the default Ttk
83 * widget code and the contained element. The one thing that we must handle
84 * is the -anchor option which positions the square element within the parcel
85 * of space available for the widget.
86 * To do this we must find out the layout preferences for the square
87 * element and adjust its position within our region.
89 * Note that if we do not have a "square" elememt then just the default
90 * layout will be done. So if someone places a label element into the
91 * widget layout it will still be handled but the -anchor option will be
92 * passed onto the label element instead of handled here.
96 SquareDoLayout(void *clientData)
98 WidgetCore *corePtr = (WidgetCore *)clientData;
100 Ttk_Element squareNode;
102 squareNode = Ttk_FindElement(corePtr->layout, "square");
103 winBox = Ttk_WinBox(corePtr->tkwin);
104 Ttk_PlaceLayout(corePtr->layout, corePtr->state, winBox);
107 * Adjust the position of the square element within the widget according
108 * to the -anchor option.
112 Square *squarePtr = (Square *)clientData;
113 Tk_Anchor anchor = TK_ANCHOR_CENTER;
116 b = Ttk_ElementParcel(squareNode);
117 if (squarePtr->square.anchorObj != NULL)
118 Tk_GetAnchorFromObj(NULL, squarePtr->square.anchorObj, &anchor);
119 b = Ttk_AnchorBox(winBox, b.width, b.height, anchor);
121 Ttk_PlaceElement(corePtr->layout, squareNode, b);
126 * Widget commands. A widget is impelemented as an ensemble and the
127 * subcommands are listed here. Ttk provides default implementations
128 * that are sufficient for our needs.
131 static const Ttk_Ensemble SquareCommands[] = {
132 { "configure", TtkWidgetConfigureCommand,0 },
133 { "cget", TtkWidgetCgetCommand,0 },
134 { "identify", TtkWidgetIdentifyCommand,0 },
135 { "instate", TtkWidgetInstateCommand,0 },
136 { "state", TtkWidgetStateCommand,0 },
141 * The Widget specification structure holds all the implementation
142 * information about this widget and this is what must be registered
143 * with Tk in the package initialization code (see bottom).
146 static WidgetSpec SquareWidgetSpec =
148 "TSquare", /* className */
149 sizeof(Square), /* recordSize */
150 SquareOptionSpecs, /* optionSpecs */
151 SquareCommands, /* subcommands */
152 TtkNullInitialize, /* initializeProc */
153 TtkNullCleanup, /* cleanupProc */
154 TtkCoreConfigure, /* configureProc */
155 TtkNullPostConfigure, /* postConfigureProc */
156 TtkWidgetGetLayout, /* getLayoutProc */
157 TtkWidgetSize, /* sizeProc */
158 SquareDoLayout, /* layoutProc */
159 TtkWidgetDisplay /* displayProc */
162 /* ----------------------------------------------------------------------
165 * In this section we demonstrate what is required to create a new themed
172 Tcl_Obj *foregroundObj;
173 Tcl_Obj *borderWidthObj;
179 static Ttk_ElementOptionSpec SquareElementOptions[] =
181 { "-background", TK_OPTION_BORDER, Tk_Offset(SquareElement,borderObj),
182 DEFAULT_BACKGROUND },
183 { "-foreground", TK_OPTION_BORDER, Tk_Offset(SquareElement,foregroundObj),
184 DEFAULT_BACKGROUND },
185 { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(SquareElement,borderWidthObj),
186 DEFAULT_BORDERWIDTH },
187 { "-relief", TK_OPTION_RELIEF, Tk_Offset(SquareElement,reliefObj),
189 { "-width", TK_OPTION_PIXELS, Tk_Offset(SquareElement,widthObj), "20"},
190 { "-height", TK_OPTION_PIXELS, Tk_Offset(SquareElement,heightObj), "20"},
191 { NULL, TK_OPTION_BOOLEAN, 0, NULL }
195 * The element geometry function is called when the layout code wishes to
196 * find out how big this element wants to be. We must return our preferred
197 * size and padding information
200 static void SquareElementSize(
201 void *dummy, void *elementRecord, Tk_Window tkwin,
202 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
204 SquareElement *square = (SquareElement *)elementRecord;
208 Tcl_GetIntFromObj(NULL, square->borderWidthObj, &borderWidth);
209 *paddingPtr = Ttk_UniformPadding((short)borderWidth);
210 Tk_GetPixelsFromObj(NULL, tkwin, square->widthObj, widthPtr);
211 Tk_GetPixelsFromObj(NULL, tkwin, square->heightObj, heightPtr);
215 * Draw the element in the box provided.
218 static void SquareElementDraw(
219 void *dummy, void *elementRecord, Tk_Window tkwin,
220 Drawable d, Ttk_Box b, unsigned int state)
222 SquareElement *square = (SquareElement *)elementRecord;
223 Tk_3DBorder foreground = NULL;
224 int borderWidth = 1, relief = TK_RELIEF_FLAT;
228 foreground = Tk_Get3DBorderFromObj(tkwin, square->foregroundObj);
229 Tcl_GetIntFromObj(NULL, square->borderWidthObj, &borderWidth);
230 Tk_GetReliefFromObj(NULL, square->reliefObj, &relief);
232 Tk_Fill3DRectangle(tkwin, d, foreground,
233 b.x, b.y, b.width, b.height, borderWidth, relief);
236 static Ttk_ElementSpec SquareElementSpec =
239 sizeof(SquareElement),
240 SquareElementOptions,
245 /* ----------------------------------------------------------------------
249 * Every widget class needs a layout style that specifies which elements
250 * are part of the widget and how they should be placed. The element layout
251 * engine is similar to the Tk pack geometry manager. Read the documentation
252 * for the details. In this example we just need to have the square element
253 * that has been defined for this widget placed on a background. We will
254 * also need some padding to keep it away from the edges.
257 TTK_BEGIN_LAYOUT(SquareLayout)
258 TTK_NODE("Square.background", TTK_FILL_BOTH)
259 TTK_GROUP("Square.padding", TTK_FILL_BOTH,
260 TTK_NODE("Square.square", 0))
263 /* ----------------------------------------------------------------------
265 * Widget initialization.
267 * This file defines a new element and a new widget. We need to register
268 * the element with the themes that will need it. In this case we will
269 * register with the default theme that is the root of the theme inheritance
270 * tree. This means all themes will find this element.
271 * We then need to register the widget class style. This is the layout
272 * specification. If a different theme requires an alternative layout, we
273 * could register that here. For instance, in some themes the scrollbars have
274 * one uparrow, in other themes there are two uparrow elements.
275 * Finally we register the widget itself. This step creates a tcl command so
276 * that we can actually create an instance of this class. The widget is
277 * linked to a particular style by the widget class name. This is important
278 * to realise as the programmer may change the classname when creating a
279 * new instance. If this is done, a new layout will need to be created (which
280 * can be done at script level). Some widgets may require particular elements
281 * to be present but we try to avoid this where possible. In this widget's C
282 * code, no reference is made to any particular elements. The programmer is
283 * free to specify a new style using completely different elements.
286 /* public */ MODULE_SCOPE int
287 TtkSquareWidget_Init(Tcl_Interp *interp)
289 Ttk_Theme theme = Ttk_GetDefaultTheme(interp);
291 /* register the new elements for this theme engine */
292 Ttk_RegisterElement(interp, theme, "square", &SquareElementSpec, NULL);
294 /* register the layout for this theme */
295 Ttk_RegisterLayout(theme, "TSquare", SquareLayout);
297 /* register the widget */
298 RegisterWidget(interp, "ttk::square", &SquareWidgetSpec);
303 #endif /* TTK_SQUARE_WIDGET */