1 /*
2  * ttkLayout.c --
3  *
4  * Generic layout processing.
5  *
6  * Copyright (c) 2003 Joe English.  Freely redistributable.
7  */
8 
9 #include "tkInt.h"
10 #include "ttkThemeInt.h"
11 
12 #define MAX(a,b) (a > b ? a : b)
13 #define MIN(a,b) (a < b ? a : b)
14 
15 /*------------------------------------------------------------------------
16  * +++ Ttk_Box and Ttk_Padding utilities:
17  */
18 
19 Ttk_Box
Ttk_MakeBox(int x,int y,int width,int height)20 Ttk_MakeBox(int x, int y, int width, int height)
21 {
22     Ttk_Box b;
23     b.x = x; b.y = y; b.width = width; b.height = height;
24     return b;
25 }
26 
27 int
Ttk_BoxContains(Ttk_Box box,int x,int y)28 Ttk_BoxContains(Ttk_Box box, int x, int y)
29 {
30     return box.x <= x && x < box.x + box.width
31 	&& box.y <= y && y < box.y + box.height;
32 }
33 
34 Tcl_Obj *
Ttk_NewBoxObj(Ttk_Box box)35 Ttk_NewBoxObj(Ttk_Box box)
36 {
37     Tcl_Obj *result[4];
38 
39     result[0] = Tcl_NewIntObj(box.x);
40     result[1] = Tcl_NewIntObj(box.y);
41     result[2] = Tcl_NewIntObj(box.width);
42     result[3] = Tcl_NewIntObj(box.height);
43 
44     return Tcl_NewListObj(4, result);
45 }
46 
47 /*
48  * packTop, packBottom, packLeft, packRight --
49  * 	Carve out a parcel of the specified height (resp width)
50  * 	from the specified cavity.
51  *
52  * Returns:
53  * 	The new parcel.
54  *
55  * Side effects:
56  * 	Adjust the cavity.
57  */
58 
packTop(Ttk_Box * cavity,int height)59 static Ttk_Box packTop(Ttk_Box *cavity, int height)
60 {
61     Ttk_Box parcel;
62     height = MIN(height, cavity->height);
63     parcel = Ttk_MakeBox(cavity->x, cavity->y, cavity->width, height);
64     cavity->y += height;
65     cavity->height -= height;
66     return parcel;
67 }
68 
packBottom(Ttk_Box * cavity,int height)69 static Ttk_Box packBottom(Ttk_Box *cavity, int height)
70 {
71     height = MIN(height, cavity->height);
72     cavity->height -= height;
73     return Ttk_MakeBox(
74 	cavity->x, cavity->y + cavity->height,
75 	cavity->width, height);
76 }
77 
packLeft(Ttk_Box * cavity,int width)78 static Ttk_Box packLeft(Ttk_Box *cavity, int width)
79 {
80     Ttk_Box parcel;
81     width = MIN(width, cavity->width);
82     parcel = Ttk_MakeBox(cavity->x, cavity->y, width,cavity->height);
83     cavity->x += width;
84     cavity->width -= width;
85     return parcel;
86 }
87 
packRight(Ttk_Box * cavity,int width)88 static Ttk_Box packRight(Ttk_Box *cavity, int width)
89 {
90     width = MIN(width, cavity->width);
91     cavity->width -= width;
92     return Ttk_MakeBox(cavity->x + cavity->width,
93 	    cavity->y, width, cavity->height);
94 }
95 
96 /*
97  * Ttk_PackBox --
98  * 	Carve out a parcel of the specified size on the specified side
99  * 	in the specified cavity.
100  *
101  * Returns:
102  * 	The new parcel.
103  *
104  * Side effects:
105  * 	Adjust the cavity.
106  */
107 
Ttk_PackBox(Ttk_Box * cavity,int width,int height,Ttk_Side side)108 Ttk_Box Ttk_PackBox(Ttk_Box *cavity, int width, int height, Ttk_Side side)
109 {
110     switch (side) {
111 	default:
112 	case TTK_SIDE_TOP:	return packTop(cavity, height);
113 	case TTK_SIDE_BOTTOM:	return packBottom(cavity, height);
114 	case TTK_SIDE_LEFT:	return packLeft(cavity, width);
115 	case TTK_SIDE_RIGHT:	return packRight(cavity, width);
116     }
117 }
118 
119 /*
120  * Ttk_PadBox --
121  * 	Shrink a box by the specified padding amount.
122  */
Ttk_PadBox(Ttk_Box b,Ttk_Padding p)123 Ttk_Box Ttk_PadBox(Ttk_Box b, Ttk_Padding p)
124 {
125     b.x += p.left;
126     b.y += p.top;
127     b.width -= (p.left + p.right);
128     b.height -= (p.top + p.bottom);
129     if (b.width <= 0) b.width = 1;
130     if (b.height <= 0) b.height = 1;
131     return b;
132 }
133 
134 /*
135  * Ttk_ExpandBox --
136  * 	Grow a box by the specified padding amount.
137  */
Ttk_ExpandBox(Ttk_Box b,Ttk_Padding p)138 Ttk_Box Ttk_ExpandBox(Ttk_Box b, Ttk_Padding p)
139 {
140     b.x -= p.left;
141     b.y -= p.top;
142     b.width += (p.left + p.right);
143     b.height += (p.top + p.bottom);
144     return b;
145 }
146 
147 /*
148  * Ttk_StickBox --
149  * 	Place a box of size w * h in the specified parcel,
150  * 	according to the specified sticky bits.
151  */
Ttk_StickBox(Ttk_Box parcel,int width,int height,unsigned sticky)152 Ttk_Box Ttk_StickBox(Ttk_Box parcel, int width, int height, unsigned sticky)
153 {
154     int dx, dy;
155 
156     if (width > parcel.width) width = parcel.width;
157     if (height > parcel.height) height = parcel.height;
158 
159     dx = parcel.width - width;
160     dy = parcel.height - height;
161 
162     /*
163      * X coordinate adjustment:
164      */
165     switch (sticky & (TTK_STICK_W | TTK_STICK_E))
166     {
167 	case TTK_STICK_W | TTK_STICK_E:
168 	    /* no-op -- use entire parcel width */
169 	    break;
170 	case TTK_STICK_W:
171 	    parcel.width = width;
172 	    break;
173 	case TTK_STICK_E:
174 	    parcel.x += dx;
175 	    parcel.width = width;
176 	    break;
177 	default :
178 	    parcel.x += dx / 2;
179 	    parcel.width = width;
180 	    break;
181     }
182 
183     /*
184      * Y coordinate adjustment:
185      */
186     switch (sticky & (TTK_STICK_N | TTK_STICK_S))
187     {
188 	case TTK_STICK_N | TTK_STICK_S:
189 	    /* use entire parcel height */
190 	    break;
191 	case TTK_STICK_N:
192 	    parcel.height = height;
193 	    break;
194 	case TTK_STICK_S:
195 	    parcel.y += dy;
196 	    parcel.height = height;
197 	    break;
198 	default :
199 	    parcel.y += dy / 2;
200 	    parcel.height = height;
201 	    break;
202     }
203 
204     return parcel;
205 }
206 
207 /*
208  * AnchorToSticky --
209  * 	Convert a Tk_Anchor enum to a TTK_STICKY bitmask.
210  */
AnchorToSticky(Tk_Anchor anchor)211 static Ttk_Sticky AnchorToSticky(Tk_Anchor anchor)
212 {
213     switch (anchor)
214     {
215 	case TK_ANCHOR_N:	return TTK_STICK_N;
216 	case TK_ANCHOR_NE:	return TTK_STICK_N | TTK_STICK_E;
217 	case TK_ANCHOR_E:	return TTK_STICK_E;
218 	case TK_ANCHOR_SE:	return TTK_STICK_S | TTK_STICK_E;
219 	case TK_ANCHOR_S:	return TTK_STICK_S;
220 	case TK_ANCHOR_SW:	return TTK_STICK_S | TTK_STICK_W;
221 	case TK_ANCHOR_W:	return TTK_STICK_W;
222 	case TK_ANCHOR_NW:	return TTK_STICK_N | TTK_STICK_W;
223 	default:
224 	case TK_ANCHOR_CENTER:	return 0;
225     }
226 }
227 
228 /*
229  * Ttk_AnchorBox --
230  * 	Place a box of size w * h in the specified parcel,
231  * 	according to the specified anchor.
232  */
Ttk_AnchorBox(Ttk_Box parcel,int width,int height,Tk_Anchor anchor)233 Ttk_Box Ttk_AnchorBox(Ttk_Box parcel, int width, int height, Tk_Anchor anchor)
234 {
235     return Ttk_StickBox(parcel, width, height, AnchorToSticky(anchor));
236 }
237 
238 /*
239  * Ttk_PlaceBox --
240  * 	Combine Ttk_PackBox() and Ttk_StickBox().
241  */
Ttk_PlaceBox(Ttk_Box * cavity,int width,int height,Ttk_Side side,unsigned sticky)242 Ttk_Box Ttk_PlaceBox(
243     Ttk_Box *cavity, int width, int height, Ttk_Side side, unsigned sticky)
244 {
245     return Ttk_StickBox(
246 	    Ttk_PackBox(cavity, width, height, side), width, height, sticky);
247 }
248 
249 /*
250  * Ttk_PositionBox --
251  * 	Pack and stick a box according to PositionSpec flags.
252  */
253 MODULE_SCOPE Ttk_Box
Ttk_PositionBox(Ttk_Box * cavity,int width,int height,Ttk_PositionSpec flags)254 Ttk_PositionBox(Ttk_Box *cavity, int width, int height, Ttk_PositionSpec flags)
255 {
256     Ttk_Box parcel;
257 
258 	 if (flags & TTK_EXPAND)	parcel = *cavity;
259     else if (flags & TTK_PACK_TOP)	parcel = packTop(cavity, height);
260     else if (flags & TTK_PACK_LEFT)	parcel = packLeft(cavity, width);
261     else if (flags & TTK_PACK_BOTTOM)	parcel = packBottom(cavity, height);
262     else if (flags & TTK_PACK_RIGHT)	parcel = packRight(cavity, width);
263     else				parcel = *cavity;
264 
265     return Ttk_StickBox(parcel, width, height, flags);
266 }
267 
268 /*
269  * TTKInitPadding --
270  * 	Common factor of Ttk_GetPaddingFromObj and Ttk_GetBorderFromObj.
271  * 	Initializes Ttk_Padding record, supplying default values
272  * 	for missing entries.
273  */
TTKInitPadding(int padc,int pixels[4],Ttk_Padding * pad)274 static void TTKInitPadding(int padc, int pixels[4], Ttk_Padding *pad)
275 {
276     switch (padc)
277     {
278 	case 0: pixels[0] = 0; /*FALLTHRU*/
279 	case 1:	pixels[1] = pixels[0]; /*FALLTHRU*/
280 	case 2:	pixels[2] = pixels[0]; /*FALLTHRU*/
281 	case 3:	pixels[3] = pixels[1]; /*FALLTHRU*/
282     }
283 
284     pad->left	= (short)pixels[0];
285     pad->top	= (short)pixels[1];
286     pad->right	= (short)pixels[2];
287     pad->bottom	= (short)pixels[3];
288 }
289 
290 /*
291  * Ttk_GetPaddingFromObj --
292  *
293  * 	Extract a padding specification from a Tcl_Obj * scaled
294  * 	to work with a particular Tk_Window.
295  *
296  * 	The string representation of a Ttk_Padding is a list
297  * 	of one to four Tk_Pixel specifications, corresponding
298  * 	to the left, top, right, and bottom padding.
299  *
300  * 	If the 'bottom' (fourth) element is missing, it defaults to 'top'.
301  * 	If the 'right' (third) element is missing, it defaults to 'left'.
302  * 	If the 'top' (second) element is missing, it defaults to 'left'.
303  *
304  * 	The internal representation is a Tcl_ListObj containing
305  * 	one to four Tk_PixelObj objects.
306  *
307  * Returns:
308  * 	TCL_OK or TCL_ERROR.  In the latter case an error message is
309  * 	left in 'interp' and '*paddingPtr' is set to all-zeros.
310  * 	Otherwise, *paddingPtr is filled in with the padding specification.
311  *
312  */
Ttk_GetPaddingFromObj(Tcl_Interp * interp,Tk_Window tkwin,Tcl_Obj * objPtr,Ttk_Padding * pad)313 int Ttk_GetPaddingFromObj(
314     Tcl_Interp *interp,
315     Tk_Window tkwin,
316     Tcl_Obj *objPtr,
317     Ttk_Padding *pad)
318 {
319     Tcl_Obj **padv;
320     int i, padc, pixels[4];
321 
322     if (TCL_OK != Tcl_ListObjGetElements(interp, objPtr, &padc, &padv)) {
323 	goto error;
324     }
325 
326     if (padc > 4) {
327 	if (interp) {
328 	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
329 		    "Wrong #elements in padding spec", -1));
330 	    Tcl_SetErrorCode(interp, "TTK", "VALUE", "PADDING", NULL);
331 	}
332 	goto error;
333     }
334 
335     for (i=0; i < padc; ++i) {
336 	if (Tk_GetPixelsFromObj(interp, tkwin, padv[i], &pixels[i]) != TCL_OK) {
337 	    goto error;
338 	}
339     }
340 
341     TTKInitPadding(padc, pixels, pad);
342     return TCL_OK;
343 
344 error:
345     pad->left = pad->top = pad->right = pad->bottom = 0;
346     return TCL_ERROR;
347 }
348 
349 /* Ttk_GetBorderFromObj --
350  * 	Same as Ttk_GetPaddingFromObj, except padding is a list of integers
351  * 	instead of Tk_Pixel specifications.  Does not require a Tk_Window
352  * 	parameter.
353  *
354  */
Ttk_GetBorderFromObj(Tcl_Interp * interp,Tcl_Obj * objPtr,Ttk_Padding * pad)355 int Ttk_GetBorderFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Ttk_Padding *pad)
356 {
357     Tcl_Obj **padv;
358     int i, padc, pixels[4];
359 
360     if (TCL_OK != Tcl_ListObjGetElements(interp, objPtr, &padc, &padv)) {
361 	goto error;
362     }
363 
364     if (padc > 4) {
365 	if (interp) {
366 	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
367 		    "Wrong #elements in padding spec", -1));
368 	    Tcl_SetErrorCode(interp, "TTK", "VALUE", "BORDER", NULL);
369 	}
370 	goto error;
371     }
372 
373     for (i=0; i < padc; ++i) {
374 	if (Tcl_GetIntFromObj(interp, padv[i], &pixels[i]) != TCL_OK) {
375 	    goto error;
376 	}
377     }
378 
379     TTKInitPadding(padc, pixels, pad);
380     return TCL_OK;
381 
382 error:
383     pad->left = pad->top = pad->right = pad->bottom = 0;
384     return TCL_ERROR;
385 }
386 
387 /*
388  * Ttk_MakePadding --
389  *	Return an initialized Ttk_Padding structure.
390  */
Ttk_MakePadding(short left,short top,short right,short bottom)391 Ttk_Padding Ttk_MakePadding(short left, short top, short right, short bottom)
392 {
393     Ttk_Padding pad;
394     pad.left = left;
395     pad.top = top;
396     pad.right = right;
397     pad.bottom = bottom;
398     return pad;
399 }
400 
401 /*
402  * Ttk_UniformPadding --
403  * 	Returns a uniform Ttk_Padding structure, with the same
404  * 	border width on all sides.
405  */
Ttk_UniformPadding(short borderWidth)406 Ttk_Padding Ttk_UniformPadding(short borderWidth)
407 {
408     Ttk_Padding pad;
409     pad.left = pad.top = pad.right = pad.bottom = borderWidth;
410     return pad;
411 }
412 
413 /*
414  * Ttk_AddPadding --
415  *	Combine two padding records.
416  */
Ttk_AddPadding(Ttk_Padding p1,Ttk_Padding p2)417 Ttk_Padding Ttk_AddPadding(Ttk_Padding p1, Ttk_Padding p2)
418 {
419     p1.left += p2.left;
420     p1.top += p2.top;
421     p1.right += p2.right;
422     p1.bottom += p2.bottom;
423     return p1;
424 }
425 
426 /* Ttk_RelievePadding --
427  * 	Add an extra n pixels of padding according to specified relief.
428  * 	This may be used in element geometry procedures to simulate
429  * 	a "pressed-in" look for pushbuttons.
430  */
Ttk_RelievePadding(Ttk_Padding padding,int relief,int n)431 Ttk_Padding Ttk_RelievePadding(Ttk_Padding padding, int relief, int n)
432 {
433     switch (relief)
434     {
435 	case TK_RELIEF_RAISED:
436 	    padding.right += n;
437 	    padding.bottom += n;
438 	    break;
439 	case TK_RELIEF_SUNKEN:	/* shift */
440 	    padding.left += n;
441 	    padding.top += n;
442 	    break;
443 	default:
444 	{
445 	    int h1 = n/2, h2 = h1 + n % 2;
446 	    padding.left += h1;
447 	    padding.top += h1;
448 	    padding.right += h2;
449 	    padding.bottom += h2;
450 	    break;
451 	}
452     }
453     return padding;
454 }
455 
456 /*
457  * Ttk_GetStickyFromObj --
458  * 	Returns a stickiness specification from the specified Tcl_Obj*,
459  * 	consisting of any combination of n, s, e, and w.
460  *
461  * Returns: TCL_OK if objPtr holds a valid stickiness specification,
462  *	otherwise TCL_ERROR.  interp is used for error reporting if non-NULL.
463  *
464  */
Ttk_GetStickyFromObj(Tcl_Interp * interp,Tcl_Obj * objPtr,Ttk_Sticky * result)465 int Ttk_GetStickyFromObj(
466     Tcl_Interp *interp, Tcl_Obj *objPtr, Ttk_Sticky *result)
467 {
468     const char *string = Tcl_GetString(objPtr);
469     Ttk_Sticky sticky = 0;
470     char c;
471 
472     while ((c = *string++) != '\0') {
473 	switch (c) {
474 	    case 'w': case 'W': sticky |= TTK_STICK_W; break;
475 	    case 'e': case 'E': sticky |= TTK_STICK_E; break;
476 	    case 'n': case 'N': sticky |= TTK_STICK_N; break;
477 	    case 's': case 'S': sticky |= TTK_STICK_S; break;
478 	    default:
479 	    	if (interp) {
480 		    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
481 			"Bad -sticky specification %s",
482 			Tcl_GetString(objPtr)));
483 		    Tcl_SetErrorCode(interp, "TTK", "VALUE", "STICKY", NULL);
484 		}
485 		return TCL_ERROR;
486 	}
487     }
488 
489     *result = sticky;
490     return TCL_OK;
491 }
492 
493 /* Ttk_NewStickyObj --
494  * 	Construct a new Tcl_Obj * containing a stickiness specification.
495  */
Ttk_NewStickyObj(Ttk_Sticky sticky)496 Tcl_Obj *Ttk_NewStickyObj(Ttk_Sticky sticky)
497 {
498     char buf[5];
499     char *p = buf;
500 
501     if (sticky & TTK_STICK_N)	*p++ = 'n';
502     if (sticky & TTK_STICK_S)	*p++ = 's';
503     if (sticky & TTK_STICK_W)	*p++ = 'w';
504     if (sticky & TTK_STICK_E)	*p++ = 'e';
505 
506     *p = '\0';
507     return Tcl_NewStringObj(buf, p - buf);
508 }
509 
510 /*------------------------------------------------------------------------
511  * +++ Layout nodes.
512  */
513 
514 typedef struct Ttk_LayoutNode_ Ttk_LayoutNode;
515 struct Ttk_LayoutNode_
516 {
517     unsigned		flags;		/* Packing and sticky flags */
518     Ttk_ElementClass 	*eclass;	/* Class record */
519     Ttk_State 	 	state;		/* Current state */
520     Ttk_Box 		parcel;		/* allocated parcel */
521     Ttk_LayoutNode	*next, *child;
522 };
523 
Ttk_NewLayoutNode(unsigned flags,Ttk_ElementClass * elementClass)524 static Ttk_LayoutNode *Ttk_NewLayoutNode(
525     unsigned flags, Ttk_ElementClass *elementClass)
526 {
527     Ttk_LayoutNode *node = ckalloc(sizeof(*node));
528 
529     node->flags = flags;
530     node->eclass = elementClass;
531     node->state = 0u;
532     node->next = node->child = 0;
533     node->parcel = Ttk_MakeBox(0,0,0,0);
534 
535     return node;
536 }
537 
Ttk_FreeLayoutNode(Ttk_LayoutNode * node)538 static void Ttk_FreeLayoutNode(Ttk_LayoutNode *node)
539 {
540     while (node) {
541 	Ttk_LayoutNode *next = node->next;
542 	Ttk_FreeLayoutNode(node->child);
543 	ckfree(node);
544 	node = next;
545     }
546 }
547 
548 /*------------------------------------------------------------------------
549  * +++ Layout templates.
550  */
551 
552 struct Ttk_TemplateNode_ {
553     char *name;
554     unsigned flags;
555     struct Ttk_TemplateNode_ *next, *child;
556 };
557 
Ttk_NewTemplateNode(const char * name,unsigned flags)558 static Ttk_TemplateNode *Ttk_NewTemplateNode(const char *name, unsigned flags)
559 {
560     Ttk_TemplateNode *op = ckalloc(sizeof(*op));
561     op->name = ckalloc(strlen(name) + 1); strcpy(op->name, name);
562     op->flags = flags;
563     op->next = op->child = 0;
564     return op;
565 }
566 
Ttk_FreeLayoutTemplate(Ttk_LayoutTemplate op)567 void Ttk_FreeLayoutTemplate(Ttk_LayoutTemplate op)
568 {
569     while (op) {
570 	Ttk_LayoutTemplate next = op->next;
571 	Ttk_FreeLayoutTemplate(op->child);
572 	ckfree(op->name);
573 	ckfree(op);
574 	op = next;
575     }
576 }
577 
578 /* InstantiateLayout --
579  *	Create a layout tree from a template.
580  */
581 static Ttk_LayoutNode *
Ttk_InstantiateLayout(Ttk_Theme theme,Ttk_TemplateNode * op)582 Ttk_InstantiateLayout(Ttk_Theme theme, Ttk_TemplateNode *op)
583 {
584     Ttk_ElementClass *elementClass = Ttk_GetElement(theme, op->name);
585     Ttk_LayoutNode *node = Ttk_NewLayoutNode(op->flags, elementClass);
586 
587     if (op->next) {
588 	node->next = Ttk_InstantiateLayout(theme,op->next);
589     }
590     if (op->child) {
591 	node->child = Ttk_InstantiateLayout(theme,op->child);
592     }
593 
594     return node;
595 }
596 
597 /*
598  * Ttk_ParseLayoutTemplate --
599  *	Convert a Tcl list into a layout template.
600  *
601  * Syntax:
602  * 	layoutSpec ::= { elementName ?-option value ...? }+
603  */
604 
605 /* NB: This must match bit definitions TTK_PACK_LEFT etc. */
606 static const char *packSideStrings[] =
607     { "left", "right", "top", "bottom", NULL };
608 
Ttk_ParseLayoutTemplate(Tcl_Interp * interp,Tcl_Obj * objPtr)609 Ttk_LayoutTemplate Ttk_ParseLayoutTemplate(Tcl_Interp *interp, Tcl_Obj *objPtr)
610 {
611     enum {  OP_SIDE, OP_STICKY, OP_EXPAND, OP_BORDER, OP_UNIT, OP_CHILDREN };
612     static const char *optStrings[] = {
613 	"-side", "-sticky", "-expand", "-border", "-unit", "-children", 0 };
614 
615     int i = 0, objc;
616     Tcl_Obj **objv;
617     Ttk_TemplateNode *head = 0, *tail = 0;
618 
619     if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK)
620 	return 0;
621 
622     while (i < objc) {
623 	const char *elementName = Tcl_GetString(objv[i]);
624 	unsigned flags = 0x0, sticky = TTK_FILL_BOTH;
625 	Tcl_Obj *childSpec = 0;
626 
627 	/*
628 	 * Parse options:
629 	 */
630 	++i;
631 	while (i < objc) {
632 	    const char *optName = Tcl_GetString(objv[i]);
633 	    int option, value;
634 
635 	    if (optName[0] != '-')
636 		break;
637 
638 	    if (Tcl_GetIndexFromObjStruct(interp, objv[i], optStrings,
639 		    sizeof(char *), "option", 0, &option)
640 		!= TCL_OK)
641 	    {
642 		goto error;
643 	    }
644 
645 	    if (++i >= objc) {
646 		Tcl_SetObjResult(interp, Tcl_ObjPrintf(
647 			"Missing value for option %s",
648 			Tcl_GetString(objv[i-1])));
649 		Tcl_SetErrorCode(interp, "TTK", "VALUE", "LAYOUT", NULL);
650 		goto error;
651 	    }
652 
653 	    switch (option) {
654 		case OP_SIDE:	/* <<NOTE-PACKSIDE>> */
655 		    if (Tcl_GetIndexFromObjStruct(interp, objv[i], packSideStrings,
656 				sizeof(char *), "side", 0, &value) != TCL_OK)
657 		    {
658 			goto error;
659 		    }
660 		    flags |= (TTK_PACK_LEFT << value);
661 
662 		    break;
663 		case OP_STICKY:
664 		    if (Ttk_GetStickyFromObj(interp,objv[i],&sticky) != TCL_OK)
665 			goto error;
666 		    break;
667 		case OP_EXPAND:
668 		    if (Tcl_GetBooleanFromObj(interp,objv[i],&value) != TCL_OK)
669 			goto error;
670 		    if (value)
671 			flags |= TTK_EXPAND;
672 		    break;
673 		case OP_BORDER:
674 		    if (Tcl_GetBooleanFromObj(interp,objv[i],&value) != TCL_OK)
675 			goto error;
676 		    if (value)
677 			flags |= TTK_BORDER;
678 		    break;
679 		case OP_UNIT:
680 		    if (Tcl_GetBooleanFromObj(interp,objv[i],&value) != TCL_OK)
681 			goto error;
682 		    if (value)
683 			flags |= TTK_UNIT;
684 		    break;
685 		case OP_CHILDREN:
686 		    childSpec = objv[i];
687 		    break;
688 	    }
689 	    ++i;
690 	}
691 
692 	/*
693 	 * Build new node:
694 	 */
695 	if (tail) {
696 	    tail->next = Ttk_NewTemplateNode(elementName, flags | sticky);
697 	    tail = tail->next;
698 	} else {
699 	    head = tail = Ttk_NewTemplateNode(elementName, flags | sticky);
700 	}
701 	if (childSpec) {
702 	    tail->child = Ttk_ParseLayoutTemplate(interp, childSpec);
703 	    if (!tail->child) {
704                 Tcl_SetObjResult(interp, Tcl_ObjPrintf("Invalid -children value"));
705                 Tcl_SetErrorCode(interp, "TTK", "VALUE", "CHILDREN", NULL);
706 		goto error;
707 	    }
708 	}
709     }
710 
711     return head;
712 
713 error:
714     Ttk_FreeLayoutTemplate(head);
715     return 0;
716 }
717 
718 /* Ttk_BuildLayoutTemplate --
719  * 	Build a layout template tree from a statically defined
720  * 	Ttk_LayoutSpec array.
721  */
Ttk_BuildLayoutTemplate(Ttk_LayoutSpec spec)722 Ttk_LayoutTemplate Ttk_BuildLayoutTemplate(Ttk_LayoutSpec spec)
723 {
724     Ttk_TemplateNode *first = 0, *last = 0;
725 
726     for ( ; !(spec->opcode & _TTK_LAYOUT_END) ; ++spec) {
727 	if (spec->elementName) {
728 	    Ttk_TemplateNode *node =
729 		Ttk_NewTemplateNode(spec->elementName, spec->opcode);
730 
731 	    if (last) {
732 		last->next = node;
733 	    } else {
734 		first = node;
735 	    }
736 	    last = node;
737 	}
738 
739 	if (spec->opcode & _TTK_CHILDREN && last) {
740 	    int depth = 1;
741 	    last->child = Ttk_BuildLayoutTemplate(spec+1);
742 
743 	    /* Skip to end of group:
744 	     */
745 	    while (depth) {
746 		++spec;
747 		if (spec->opcode & _TTK_CHILDREN) {
748 		    ++depth;
749 		}
750 		if (spec->opcode & _TTK_LAYOUT_END) {
751 		    --depth;
752 		}
753 	    }
754 	}
755 
756     } /* for */
757 
758     return first;
759 }
760 
Ttk_RegisterLayouts(Ttk_Theme theme,Ttk_LayoutSpec spec)761 void Ttk_RegisterLayouts(Ttk_Theme theme, Ttk_LayoutSpec spec)
762 {
763     while (!(spec->opcode & _TTK_LAYOUT_END)) {
764 	Ttk_LayoutTemplate layoutTemplate = Ttk_BuildLayoutTemplate(spec+1);
765 	Ttk_RegisterLayoutTemplate(theme, spec->elementName, layoutTemplate);
766 	do {
767 	    ++spec;
768 	} while (!(spec->opcode & _TTK_LAYOUT));
769     }
770 }
771 
Ttk_UnparseLayoutTemplate(Ttk_TemplateNode * node)772 Tcl_Obj *Ttk_UnparseLayoutTemplate(Ttk_TemplateNode *node)
773 {
774     Tcl_Obj *result = Tcl_NewListObj(0,0);
775 
776 #   define APPENDOBJ(obj) Tcl_ListObjAppendElement(NULL, result, obj)
777 #   define APPENDSTR(str) APPENDOBJ(Tcl_NewStringObj(str,-1))
778 
779     while (node) {
780 	unsigned flags = node->flags;
781 
782 	APPENDSTR(node->name);
783 
784 	/* Back-compute -side.  <<NOTE-PACKSIDE>>
785 	 * @@@ NOTES: Ick.
786 	 */
787 	if (flags & TTK_EXPAND) {
788 	    APPENDSTR("-expand");
789 	    APPENDSTR("1");
790 	} else {
791 	    if (flags & _TTK_MASK_PACK) {
792 		int side = 0;
793 		unsigned sideFlags = flags & _TTK_MASK_PACK;
794 
795 		while (!(sideFlags & TTK_PACK_LEFT)) {
796 		    ++side;
797 		    sideFlags >>= 1;
798 		}
799 		APPENDSTR("-side");
800 		APPENDSTR(packSideStrings[side]);
801 	    }
802 	}
803 
804 	/*
805 	 * In Ttk_ParseLayoutTemplate, default -sticky is "nsew", so always
806 	 * include this even if no sticky bits are set.
807 	 */
808 
809 	APPENDSTR("-sticky");
810 	APPENDOBJ(Ttk_NewStickyObj(flags & _TTK_MASK_STICK));
811 
812 	/* @@@ Check again: are these necessary? Can't see any effect! */
813 	if (flags & TTK_BORDER)	{ APPENDSTR("-border"); APPENDSTR("1"); }
814 	if (flags & TTK_UNIT) 	{ APPENDSTR("-unit"); APPENDSTR("1"); }
815 
816 	if (node->child) {
817 	    APPENDSTR("-children");
818 	    APPENDOBJ(Ttk_UnparseLayoutTemplate(node->child));
819 	}
820 	node = node->next;
821     }
822 
823 #   undef APPENDOBJ
824 #   undef APPENDSTR
825 
826     return result;
827 }
828 
829 /*------------------------------------------------------------------------
830  * +++ Layouts.
831  */
832 struct Ttk_Layout_
833 {
834     Ttk_Style	 	style;
835     void 		*recordPtr;
836     Tk_OptionTable	optionTable;
837     Tk_Window		tkwin;
838     Ttk_LayoutNode	*root;
839 };
840 
TTKNewLayout(Ttk_Style style,void * recordPtr,Tk_OptionTable optionTable,Tk_Window tkwin,Ttk_LayoutNode * root)841 static Ttk_Layout TTKNewLayout(
842     Ttk_Style style,
843     void *recordPtr,Tk_OptionTable optionTable, Tk_Window tkwin,
844     Ttk_LayoutNode *root)
845 {
846     Ttk_Layout layout = ckalloc(sizeof(*layout));
847     layout->style = style;
848     layout->recordPtr = recordPtr;
849     layout->optionTable = optionTable;
850     layout->tkwin = tkwin;
851     layout->root = root;
852     return layout;
853 }
854 
Ttk_FreeLayout(Ttk_Layout layout)855 void Ttk_FreeLayout(Ttk_Layout layout)
856 {
857     Ttk_FreeLayoutNode(layout->root);
858     ckfree(layout);
859 }
860 
861 /*
862  * Ttk_CreateLayout --
863  *	Create a layout from the specified theme and style name.
864  *	Returns: New layout, 0 on error.
865  *	Leaves an error message in interp's result if there is an error.
866  */
Ttk_CreateLayout(Tcl_Interp * interp,Ttk_Theme themePtr,const char * styleName,void * recordPtr,Tk_OptionTable optionTable,Tk_Window tkwin)867 Ttk_Layout Ttk_CreateLayout(
868     Tcl_Interp *interp,		/* where to leave error messages */
869     Ttk_Theme themePtr,
870     const char *styleName,
871     void *recordPtr,
872     Tk_OptionTable optionTable,
873     Tk_Window tkwin)
874 {
875     Ttk_Style style = Ttk_GetStyle(themePtr, styleName);
876     Ttk_LayoutTemplate layoutTemplate =
877 	Ttk_FindLayoutTemplate(themePtr,styleName);
878     Ttk_ElementClass *bgelement = Ttk_GetElement(themePtr, "background");
879     Ttk_LayoutNode *bgnode;
880 
881     if (!layoutTemplate) {
882 	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
883 		"Layout %s not found", styleName));
884 	Tcl_SetErrorCode(interp, "TTK", "LOOKUP", "LAYOUT", styleName, NULL);
885 	return 0;
886     }
887 
888     bgnode = Ttk_NewLayoutNode(TTK_FILL_BOTH, bgelement);
889     bgnode->next = Ttk_InstantiateLayout(themePtr, layoutTemplate);
890 
891     return TTKNewLayout(style, recordPtr, optionTable, tkwin, bgnode);
892 }
893 
894 /* Ttk_CreateSublayout --
895  * 	Creates a new sublayout.
896  *
897  * 	Sublayouts are used to draw subparts of a compound widget.
898  *	They use the same Tk_Window, but a different option table
899  *	and data record.
900  */
901 Ttk_Layout
Ttk_CreateSublayout(Tcl_Interp * interp,Ttk_Theme themePtr,Ttk_Layout parentLayout,const char * baseName,Tk_OptionTable optionTable)902 Ttk_CreateSublayout(
903     Tcl_Interp *interp,
904     Ttk_Theme themePtr,
905     Ttk_Layout parentLayout,
906     const char *baseName,
907     Tk_OptionTable optionTable)
908 {
909     Tcl_DString buf;
910     const char *styleName;
911     Ttk_Style style;
912     Ttk_LayoutTemplate layoutTemplate;
913 
914     Tcl_DStringInit(&buf);
915     Tcl_DStringAppend(&buf, Ttk_StyleName(parentLayout->style), -1);
916     Tcl_DStringAppend(&buf, baseName, -1);
917     styleName = Tcl_DStringValue(&buf);
918 
919     style = Ttk_GetStyle(themePtr, styleName);
920     layoutTemplate = Ttk_FindLayoutTemplate(themePtr, styleName);
921 
922     if (!layoutTemplate) {
923 	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
924 		"Layout %s not found", styleName));
925 	Tcl_SetErrorCode(interp, "TTK", "LOOKUP", "LAYOUT", styleName, NULL);
926 	return 0;
927     }
928 
929     Tcl_DStringFree(&buf);
930 
931     return TTKNewLayout(
932 	    style, 0, optionTable, parentLayout->tkwin,
933 	    Ttk_InstantiateLayout(themePtr, layoutTemplate));
934 }
935 
936 /* Ttk_RebindSublayout --
937  * 	Bind sublayout to new data source.
938  */
Ttk_RebindSublayout(Ttk_Layout layout,void * recordPtr)939 void Ttk_RebindSublayout(Ttk_Layout layout, void *recordPtr)
940 {
941     layout->recordPtr = recordPtr;
942 }
943 
944 /*
945  * Ttk_QueryOption --
946  * 	Look up an option from a layout's associated option.
947  */
Ttk_QueryOption(Ttk_Layout layout,const char * optionName,Ttk_State state)948 Tcl_Obj *Ttk_QueryOption(
949     Ttk_Layout layout, const char *optionName, Ttk_State state)
950 {
951     return Ttk_QueryStyle(
952 	layout->style,layout->recordPtr,layout->optionTable,optionName,state);
953 }
954 
955 /*
956  * Ttk_LayoutStyle --
957  * 	Extract Ttk_Style from Ttk_Layout.
958  */
Ttk_LayoutStyle(Ttk_Layout layout)959 Ttk_Style Ttk_LayoutStyle(Ttk_Layout layout)
960 {
961     return layout->style;
962 }
963 
964 /*------------------------------------------------------------------------
965  * +++ Size computation.
966  */
967 static void Ttk_NodeListSize(
968     Ttk_Layout layout, Ttk_LayoutNode *node,
969     Ttk_State state, int *widthPtr, int *heightPtr); /* Forward */
970 
Ttk_NodeSize(Ttk_Layout layout,Ttk_LayoutNode * node,Ttk_State state,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)971 static void Ttk_NodeSize(
972     Ttk_Layout layout, Ttk_LayoutNode *node, Ttk_State state,
973     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
974 {
975     int elementWidth, elementHeight, subWidth, subHeight;
976     Ttk_Padding elementPadding;
977 
978     Ttk_ElementSize(node->eclass,
979 	layout->style, layout->recordPtr,layout->optionTable, layout->tkwin,
980 	state|node->state,
981 	&elementWidth, &elementHeight, &elementPadding);
982 
983     Ttk_NodeListSize(layout,node->child,state,&subWidth,&subHeight);
984     subWidth += Ttk_PaddingWidth(elementPadding);
985     subHeight += Ttk_PaddingHeight(elementPadding);
986 
987     *widthPtr = MAX(elementWidth, subWidth);
988     *heightPtr = MAX(elementHeight, subHeight);
989     *paddingPtr = elementPadding;
990 }
991 
Ttk_NodeListSize(Ttk_Layout layout,Ttk_LayoutNode * node,Ttk_State state,int * widthPtr,int * heightPtr)992 static void Ttk_NodeListSize(
993     Ttk_Layout layout, Ttk_LayoutNode *node,
994     Ttk_State state, int *widthPtr, int *heightPtr)
995 {
996     if (!node) {
997 	*widthPtr = *heightPtr = 0;
998     } else {
999 	int width, height, restWidth, restHeight;
1000 	Ttk_Padding unused;
1001 
1002 	Ttk_NodeSize(layout, node, state, &width, &height, &unused);
1003 	Ttk_NodeListSize(layout, node->next, state, &restWidth, &restHeight);
1004 
1005 	if (node->flags & (TTK_PACK_LEFT|TTK_PACK_RIGHT)) {
1006 	    *widthPtr = width + restWidth;
1007 	} else {
1008 	    *widthPtr = MAX(width, restWidth);
1009 	}
1010 
1011 	if (node->flags & (TTK_PACK_TOP|TTK_PACK_BOTTOM)) {
1012 	    *heightPtr = height + restHeight;
1013 	} else {
1014 	    *heightPtr = MAX(height, restHeight);
1015 	}
1016     }
1017 }
1018 
1019 /*
1020  * Ttk_LayoutNodeInternalPadding --
1021  * 	Returns the internal padding of a layout node.
1022  */
Ttk_LayoutNodeInternalPadding(Ttk_Layout layout,Ttk_LayoutNode * node)1023 Ttk_Padding Ttk_LayoutNodeInternalPadding(
1024     Ttk_Layout layout, Ttk_LayoutNode *node)
1025 {
1026     int unused;
1027     Ttk_Padding padding;
1028     Ttk_ElementSize(node->eclass,
1029 	layout->style, layout->recordPtr, layout->optionTable, layout->tkwin,
1030 	0/*state*/, &unused, &unused, &padding);
1031     return padding;
1032 }
1033 
1034 /*
1035  * Ttk_LayoutNodeInternalParcel --
1036  * 	Returns the inner area of a specified layout node,
1037  * 	based on current parcel and element's internal padding.
1038  */
Ttk_LayoutNodeInternalParcel(Ttk_Layout layout,Ttk_LayoutNode * node)1039 Ttk_Box Ttk_LayoutNodeInternalParcel(Ttk_Layout layout, Ttk_LayoutNode *node)
1040 {
1041     Ttk_Padding padding = Ttk_LayoutNodeInternalPadding(layout, node);
1042     return Ttk_PadBox(node->parcel, padding);
1043 }
1044 
1045 /* Ttk_LayoutSize --
1046  * 	Compute requested size of a layout.
1047  */
Ttk_LayoutSize(Ttk_Layout layout,Ttk_State state,int * widthPtr,int * heightPtr)1048 void Ttk_LayoutSize(
1049     Ttk_Layout layout, Ttk_State state, int *widthPtr, int *heightPtr)
1050 {
1051     Ttk_NodeListSize(layout, layout->root, state, widthPtr, heightPtr);
1052 }
1053 
Ttk_LayoutNodeReqSize(Ttk_Layout layout,Ttk_LayoutNode * node,int * widthPtr,int * heightPtr)1054 void Ttk_LayoutNodeReqSize(	/* @@@ Rename this */
1055     Ttk_Layout layout, Ttk_LayoutNode *node, int *widthPtr, int *heightPtr)
1056 {
1057     Ttk_Padding unused;
1058     Ttk_NodeSize(layout, node, 0/*state*/, widthPtr, heightPtr, &unused);
1059 }
1060 
1061 /*------------------------------------------------------------------------
1062  * +++ Layout placement.
1063  */
1064 
1065 /* Ttk_PlaceNodeList --
1066  *	Compute parcel for each node in a layout tree
1067  *	according to position specification and overall size.
1068  */
Ttk_PlaceNodeList(Ttk_Layout layout,Ttk_LayoutNode * node,Ttk_State state,Ttk_Box cavity)1069 static void Ttk_PlaceNodeList(
1070     Ttk_Layout layout, Ttk_LayoutNode *node, Ttk_State state, Ttk_Box cavity)
1071 {
1072     for (; node; node = node->next)
1073     {
1074 	int width, height;
1075 	Ttk_Padding padding;
1076 
1077 	/* Compute node size: (@@@ cache this instead?)
1078 	 */
1079 	Ttk_NodeSize(layout, node, state, &width, &height, &padding);
1080 
1081 	/* Compute parcel:
1082 	 */
1083 	node->parcel = Ttk_PositionBox(&cavity, width, height, node->flags);
1084 
1085 	/* Place child nodes:
1086 	 */
1087 	if (node->child) {
1088 	    Ttk_Box childBox = Ttk_PadBox(node->parcel, padding);
1089 	    Ttk_PlaceNodeList(layout,node->child, state, childBox);
1090 	}
1091     }
1092 }
1093 
Ttk_PlaceLayout(Ttk_Layout layout,Ttk_State state,Ttk_Box b)1094 void Ttk_PlaceLayout(Ttk_Layout layout, Ttk_State state, Ttk_Box b)
1095 {
1096     Ttk_PlaceNodeList(layout, layout->root, state,  b);
1097 }
1098 
1099 /*------------------------------------------------------------------------
1100  * +++ Layout drawing.
1101  */
1102 
1103 /*
1104  * Ttk_DrawLayout --
1105  * 	Draw a layout tree.
1106  */
Ttk_DrawNodeList(Ttk_Layout layout,Ttk_State state,Ttk_LayoutNode * node,Drawable d)1107 static void Ttk_DrawNodeList(
1108     Ttk_Layout layout, Ttk_State state, Ttk_LayoutNode *node, Drawable d)
1109 {
1110     for (; node; node = node->next)
1111     {
1112 	int border = node->flags & TTK_BORDER;
1113 	int substate = state;
1114 
1115 	if (node->flags & TTK_UNIT)
1116 	    substate |= node->state;
1117 
1118 	if (node->child && border)
1119 	    Ttk_DrawNodeList(layout, substate, node->child, d);
1120 
1121 	Ttk_DrawElement(
1122 	    node->eclass,
1123 	    layout->style,layout->recordPtr,layout->optionTable,layout->tkwin,
1124 	    d, node->parcel, state | node->state);
1125 
1126 	if (node->child && !border)
1127 	    Ttk_DrawNodeList(layout, substate, node->child, d);
1128     }
1129 }
1130 
Ttk_DrawLayout(Ttk_Layout layout,Ttk_State state,Drawable d)1131 void Ttk_DrawLayout(Ttk_Layout layout, Ttk_State state, Drawable d)
1132 {
1133     Ttk_DrawNodeList(layout, state, layout->root, d);
1134 }
1135 
1136 /*------------------------------------------------------------------------
1137  * +++ Inquiry and modification.
1138  */
1139 
1140 /*
1141  * Ttk_IdentifyElement --
1142  * 	Find the element at the specified x,y coordinate.
1143  */
IdentifyNode(Ttk_Element node,int x,int y)1144 static Ttk_Element IdentifyNode(Ttk_Element node, int x, int y)
1145 {
1146     Ttk_Element closest = NULL;
1147 
1148     for (; node; node = node->next) {
1149 	if (Ttk_BoxContains(node->parcel, x, y)) {
1150 	    closest = node;
1151 	    if (node->child && !(node->flags & TTK_UNIT)) {
1152 		Ttk_Element childNode = IdentifyNode(node->child, x,y);
1153 		if (childNode) {
1154 		    closest = childNode;
1155 		}
1156 	    }
1157 	}
1158     }
1159     return closest;
1160 }
1161 
Ttk_IdentifyElement(Ttk_Layout layout,int x,int y)1162 Ttk_Element Ttk_IdentifyElement(Ttk_Layout layout, int x, int y)
1163 {
1164     return IdentifyNode(layout->root, x, y);
1165 }
1166 
1167 /*
1168  * tail --
1169  * 	Return the last component of an element name, e.g.,
1170  * 	"Scrollbar.thumb" => "thumb"
1171  */
tail(const char * elementName)1172 static const char *tail(const char *elementName)
1173 {
1174     const char *dot;
1175     while ((dot=strchr(elementName,'.')) != NULL)
1176 	elementName = dot + 1;
1177     return elementName;
1178 }
1179 
1180 /*
1181  * Ttk_FindElement --
1182  * 	Look up an element by name
1183  */
1184 static Ttk_Element
FindNode(Ttk_Element node,const char * nodeName)1185 FindNode(Ttk_Element node, const char *nodeName)
1186 {
1187     for (; node ; node = node->next) {
1188 	if (!strcmp(tail(Ttk_ElementName(node)), nodeName))
1189 	    return node;
1190 
1191 	if (node->child) {
1192 	    Ttk_Element childNode = FindNode(node->child, nodeName);
1193 	    if (childNode)
1194 		return childNode;
1195 	}
1196     }
1197     return 0;
1198 }
1199 
Ttk_FindElement(Ttk_Layout layout,const char * nodeName)1200 Ttk_Element Ttk_FindElement(Ttk_Layout layout, const char *nodeName)
1201 {
1202     return FindNode(layout->root, nodeName);
1203 }
1204 
1205 /*
1206  * Ttk_ClientRegion --
1207  * 	Find the internal parcel of a named element within a given layout.
1208  * 	If the element is not present, use the entire window.
1209  */
Ttk_ClientRegion(Ttk_Layout layout,const char * elementName)1210 Ttk_Box Ttk_ClientRegion(Ttk_Layout layout, const char *elementName)
1211 {
1212     Ttk_Element element = Ttk_FindElement(layout, elementName);
1213     return element
1214 	? Ttk_LayoutNodeInternalParcel(layout, element)
1215 	: Ttk_WinBox(layout->tkwin)
1216 	;
1217 }
1218 
1219 /*
1220  * Ttk_ElementName --
1221  * 	Return the name (class name) of the element.
1222  */
Ttk_ElementName(Ttk_Element node)1223 const char *Ttk_ElementName(Ttk_Element node)
1224 {
1225     return Ttk_ElementClassName(node->eclass);
1226 }
1227 
1228 /*
1229  * Ttk_ElementParcel --
1230  * 	Return the element's current parcel.
1231  */
Ttk_ElementParcel(Ttk_Element node)1232 Ttk_Box Ttk_ElementParcel(Ttk_Element node)
1233 {
1234     return node->parcel;
1235 }
1236 
1237 /*
1238  * Ttk_PlaceElement --
1239  * 	Explicitly specify an element's parcel.
1240  */
Ttk_PlaceElement(Ttk_Layout layout,Ttk_Element node,Ttk_Box b)1241 void Ttk_PlaceElement(Ttk_Layout layout, Ttk_Element node, Ttk_Box b)
1242 {
1243     node->parcel = b;
1244     if (node->child) {
1245 	Ttk_PlaceNodeList(layout, node->child, 0,
1246 	    Ttk_PadBox(b, Ttk_LayoutNodeInternalPadding(layout, node)));
1247     }
1248 }
1249 
1250 /*
1251  * Ttk_ChangeElementState --
1252  */
Ttk_ChangeElementState(Ttk_LayoutNode * node,unsigned set,unsigned clr)1253 void Ttk_ChangeElementState(Ttk_LayoutNode *node,unsigned set,unsigned clr)
1254 {
1255     node->state = (node->state | set) & ~clr;
1256 }
1257 
1258 /*EOF*/
1259