1 /*
2  * Copyright (c) 2003, Joe English
3  *
4  * Default implementation for themed elements.
5  *
6  */
7 
8 #include "tkInt.h"
9 #include "ttkTheme.h"
10 #include "ttkWidget.h"
11 
12 #define DEFAULT_BORDERWIDTH "2"
13 #define DEFAULT_ARROW_SIZE "15"
14 #define MIN_THUMB_SIZE 10
15 
16 /*----------------------------------------------------------------------
17  * +++ Null element.  Does nothing; used as a stub.
18  * Null element methods, option table and element spec are public,
19  * and may be used in other engines.
20  */
21 
22 /* public */ Ttk_ElementOptionSpec TtkNullElementOptions[] = { { NULL, 0, 0, NULL } };
23 
24 /* public */ void
TtkNullElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)25 TtkNullElementSize(
26     void *clientData, void *elementRecord, Tk_Window tkwin,
27     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
28 {
29 }
30 
31 /* public */ void
TtkNullElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)32 TtkNullElementDraw(
33     void *clientData, void *elementRecord, Tk_Window tkwin,
34     Drawable d, Ttk_Box b, unsigned int state)
35 {
36 }
37 
38 /* public */ Ttk_ElementSpec ttkNullElementSpec = {
39     TK_STYLE_VERSION_2,
40     sizeof(NullElement),
41     TtkNullElementOptions,
42     TtkNullElementSize,
43     TtkNullElementDraw
44 };
45 
46 /*----------------------------------------------------------------------
47  * +++ Background and fill elements.
48  *
49  * The fill element fills its parcel with the background color.
50  * The background element ignores the parcel, and fills the entire window.
51  *
52  * Ttk_GetLayout() automatically includes a background element.
53  */
54 
55 typedef struct {
56     Tcl_Obj	*backgroundObj;
57 } BackgroundElement;
58 
59 static Ttk_ElementOptionSpec BackgroundElementOptions[] = {
60     { "-background", TK_OPTION_BORDER,
61 	    Tk_Offset(BackgroundElement,backgroundObj), DEFAULT_BACKGROUND },
62     { NULL, 0, 0, NULL }
63 };
64 
FillElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)65 static void FillElementDraw(
66     void *clientData, void *elementRecord, Tk_Window tkwin,
67     Drawable d, Ttk_Box b, unsigned int state)
68 {
69     BackgroundElement *bg = elementRecord;
70     Tk_3DBorder backgroundPtr = Tk_Get3DBorderFromObj(tkwin,bg->backgroundObj);
71 
72     XFillRectangle(Tk_Display(tkwin), d,
73 	Tk_3DBorderGC(tkwin, backgroundPtr, TK_3D_FLAT_GC),
74 	b.x, b.y, b.width, b.height);
75 }
76 
BackgroundElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)77 static void BackgroundElementDraw(
78     void *clientData, void *elementRecord, Tk_Window tkwin,
79     Drawable d, Ttk_Box b, unsigned int state)
80 {
81     FillElementDraw(
82 	clientData, elementRecord, tkwin,
83 	d, Ttk_WinBox(tkwin), state);
84 }
85 
86 static Ttk_ElementSpec FillElementSpec = {
87     TK_STYLE_VERSION_2,
88     sizeof(BackgroundElement),
89     BackgroundElementOptions,
90     TtkNullElementSize,
91     FillElementDraw
92 };
93 
94 static Ttk_ElementSpec BackgroundElementSpec = {
95     TK_STYLE_VERSION_2,
96     sizeof(BackgroundElement),
97     BackgroundElementOptions,
98     TtkNullElementSize,
99     BackgroundElementDraw
100 };
101 
102 /*----------------------------------------------------------------------
103  * +++ Border element.
104  */
105 
106 typedef struct {
107     Tcl_Obj	*borderObj;
108     Tcl_Obj	*borderWidthObj;
109     Tcl_Obj	*reliefObj;
110 } BorderElement;
111 
112 static Ttk_ElementOptionSpec BorderElementOptions[] = {
113     { "-background", TK_OPTION_BORDER,
114 	Tk_Offset(BorderElement,borderObj), DEFAULT_BACKGROUND },
115     { "-borderwidth", TK_OPTION_PIXELS,
116 	Tk_Offset(BorderElement,borderWidthObj), DEFAULT_BORDERWIDTH },
117     { "-relief", TK_OPTION_RELIEF,
118 	Tk_Offset(BorderElement,reliefObj), "flat" },
119     { NULL, 0, 0, NULL }
120 };
121 
BorderElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)122 static void BorderElementSize(
123     void *clientData, void *elementRecord, Tk_Window tkwin,
124     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
125 {
126     BorderElement *bd = elementRecord;
127     int borderWidth = 0;
128     Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
129     *paddingPtr = Ttk_UniformPadding((short)borderWidth);
130 }
131 
BorderElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)132 static void BorderElementDraw(
133     void *clientData, void *elementRecord, Tk_Window tkwin,
134     Drawable d, Ttk_Box b, unsigned int state)
135 {
136     BorderElement *bd = elementRecord;
137     Tk_3DBorder border = NULL;
138     int borderWidth = 1, relief = TK_RELIEF_FLAT;
139 
140     border = Tk_Get3DBorderFromObj(tkwin, bd->borderObj);
141     Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
142     Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
143 
144     if (border && borderWidth > 0 && relief != TK_RELIEF_FLAT) {
145 	Tk_Draw3DRectangle(tkwin, d, border,
146 	    b.x, b.y, b.width, b.height, borderWidth,relief);
147     }
148 }
149 
150 static Ttk_ElementSpec BorderElementSpec = {
151     TK_STYLE_VERSION_2,
152     sizeof(BorderElement),
153     BorderElementOptions,
154     BorderElementSize,
155     BorderElementDraw
156 };
157 
158 /*----------------------------------------------------------------------
159  * +++ Field element.
160  * 	Used for editable fields.
161  */
162 typedef struct {
163     Tcl_Obj	*borderObj;
164     Tcl_Obj	*borderWidthObj;
165 } FieldElement;
166 
167 static Ttk_ElementOptionSpec FieldElementOptions[] = {
168     { "-fieldbackground", TK_OPTION_BORDER,
169 	Tk_Offset(FieldElement,borderObj), "white" },
170     { "-borderwidth", TK_OPTION_PIXELS,
171 	Tk_Offset(FieldElement,borderWidthObj), "2" },
172     { NULL, 0, 0, NULL }
173 };
174 
FieldElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)175 static void FieldElementSize(
176     void *clientData, void *elementRecord, Tk_Window tkwin,
177     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
178 {
179     FieldElement *field = elementRecord;
180     int borderWidth = 2;
181     Tk_GetPixelsFromObj(NULL, tkwin, field->borderWidthObj, &borderWidth);
182     *paddingPtr = Ttk_UniformPadding((short)borderWidth);
183 }
184 
FieldElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)185 static void FieldElementDraw(
186     void *clientData, void *elementRecord, Tk_Window tkwin,
187     Drawable d, Ttk_Box b, unsigned int state)
188 {
189     FieldElement *field = elementRecord;
190     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, field->borderObj);
191     int borderWidth = 2;
192 
193     Tk_GetPixelsFromObj(NULL, tkwin, field->borderWidthObj, &borderWidth);
194     Tk_Fill3DRectangle(tkwin, d, border,
195 	    b.x, b.y, b.width, b.height, borderWidth, TK_RELIEF_SUNKEN);
196 }
197 
198 static Ttk_ElementSpec FieldElementSpec = {
199     TK_STYLE_VERSION_2,
200     sizeof(FieldElement),
201     FieldElementOptions,
202     FieldElementSize,
203     FieldElementDraw
204 };
205 
206 /*
207  *----------------------------------------------------------------------
208  * +++ Padding element.
209  *
210  * This element has no visual representation, only geometry.
211  * It adds a (possibly non-uniform) internal border.
212  * In addition, if "-shiftrelief" is specified,
213  * adds additional pixels to shift child elements "in" or "out"
214  * depending on the -relief.
215  */
216 
217 typedef struct {
218     Tcl_Obj	*paddingObj;
219     Tcl_Obj	*reliefObj;
220     Tcl_Obj	*shiftreliefObj;
221 } PaddingElement;
222 
223 static Ttk_ElementOptionSpec PaddingElementOptions[] = {
224     { "-padding", TK_OPTION_STRING,
225 	Tk_Offset(PaddingElement,paddingObj), "0" },
226     { "-relief", TK_OPTION_RELIEF,
227 	Tk_Offset(PaddingElement,reliefObj), "flat" },
228     { "-shiftrelief", TK_OPTION_INT,
229 	Tk_Offset(PaddingElement,shiftreliefObj), "0" },
230     { NULL, 0, 0, NULL }
231 };
232 
PaddingElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)233 static void PaddingElementSize(
234     void *clientData, void *elementRecord, Tk_Window tkwin,
235     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
236 {
237     PaddingElement *padding = elementRecord;
238     int shiftRelief = 0;
239     int relief = TK_RELIEF_FLAT;
240     Ttk_Padding pad;
241 
242     Tk_GetReliefFromObj(NULL, padding->reliefObj, &relief);
243     Tcl_GetIntFromObj(NULL, padding->shiftreliefObj, &shiftRelief);
244     Ttk_GetPaddingFromObj(NULL,tkwin,padding->paddingObj,&pad);
245     *paddingPtr = Ttk_RelievePadding(pad, relief, shiftRelief);
246 }
247 
248 static Ttk_ElementSpec PaddingElementSpec = {
249     TK_STYLE_VERSION_2,
250     sizeof(PaddingElement),
251     PaddingElementOptions,
252     PaddingElementSize,
253     TtkNullElementDraw
254 };
255 
256 /*----------------------------------------------------------------------
257  * +++ Focus ring element.
258  * 	Draws a dashed focus ring, if the widget has keyboard focus.
259  */
260 typedef struct {
261     Tcl_Obj	*focusColorObj;
262     Tcl_Obj	*focusThicknessObj;
263 } FocusElement;
264 
265 /*
266  * DrawFocusRing --
267  * 	Draw a dotted rectangle to indicate focus.
268  */
DrawFocusRing(Tk_Window tkwin,Drawable d,Tcl_Obj * colorObj,Ttk_Box b)269 static void DrawFocusRing(
270     Tk_Window tkwin, Drawable d, Tcl_Obj *colorObj, Ttk_Box b)
271 {
272     XColor *color = Tk_GetColorFromObj(tkwin, colorObj);
273     unsigned long mask = 0UL;
274     XGCValues gcvalues;
275     GC gc;
276 
277     gcvalues.foreground = color->pixel;
278     gcvalues.line_style = LineOnOffDash;
279     gcvalues.line_width = 1;
280     gcvalues.dashes = 1;
281     gcvalues.dash_offset = 1;
282     mask = GCForeground | GCLineStyle | GCDashList | GCDashOffset | GCLineWidth;
283 
284     gc = Tk_GetGC(tkwin, mask, &gcvalues);
285     XDrawRectangle(Tk_Display(tkwin), d, gc, b.x, b.y, b.width-1, b.height-1);
286     Tk_FreeGC(Tk_Display(tkwin), gc);
287 }
288 
289 static Ttk_ElementOptionSpec FocusElementOptions[] = {
290     { "-focuscolor",TK_OPTION_COLOR,
291 	Tk_Offset(FocusElement,focusColorObj), "black" },
292     { "-focusthickness",TK_OPTION_PIXELS,
293 	Tk_Offset(FocusElement,focusThicknessObj), "1" },
294     { NULL, 0, 0, NULL }
295 };
296 
FocusElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)297 static void FocusElementSize(
298     void *clientData, void *elementRecord, Tk_Window tkwin,
299     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
300 {
301     FocusElement *focus = elementRecord;
302     int focusThickness = 0;
303 
304     Tcl_GetIntFromObj(NULL, focus->focusThicknessObj, &focusThickness);
305     *paddingPtr = Ttk_UniformPadding((short)focusThickness);
306 }
307 
FocusElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)308 static void FocusElementDraw(
309     void *clientData, void *elementRecord, Tk_Window tkwin,
310     Drawable d, Ttk_Box b, unsigned int state)
311 {
312     FocusElement *focus = elementRecord;
313     int focusThickness = 0;
314 
315     if (state & TTK_STATE_FOCUS) {
316 	Tcl_GetIntFromObj(NULL,focus->focusThicknessObj,&focusThickness);
317 	DrawFocusRing(tkwin, d, focus->focusColorObj, b);
318     }
319 }
320 
321 static Ttk_ElementSpec FocusElementSpec = {
322     TK_STYLE_VERSION_2,
323     sizeof(FocusElement),
324     FocusElementOptions,
325     FocusElementSize,
326     FocusElementDraw
327 };
328 
329 /*----------------------------------------------------------------------
330  * +++ Separator element.
331  * 	Just draws a horizontal or vertical bar.
332  * 	Three elements are defined: horizontal, vertical, and general;
333  *	the general separator checks the "-orient" option.
334  */
335 
336 typedef struct {
337     Tcl_Obj	*orientObj;
338     Tcl_Obj	*borderObj;
339 } SeparatorElement;
340 
341 static Ttk_ElementOptionSpec SeparatorElementOptions[] = {
342     { "-orient", TK_OPTION_ANY,
343 	Tk_Offset(SeparatorElement, orientObj), "horizontal" },
344     { "-background", TK_OPTION_BORDER,
345 	Tk_Offset(SeparatorElement,borderObj), DEFAULT_BACKGROUND },
346     { NULL, 0, 0, NULL }
347 };
348 
SeparatorElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)349 static void SeparatorElementSize(
350     void *clientData, void *elementRecord, Tk_Window tkwin,
351     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
352 {
353     *widthPtr = *heightPtr = 2;
354 }
355 
HorizontalSeparatorElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)356 static void HorizontalSeparatorElementDraw(
357     void *clientData, void *elementRecord, Tk_Window tkwin,
358     Drawable d, Ttk_Box b, unsigned int state)
359 {
360     SeparatorElement *separator = elementRecord;
361     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, separator->borderObj);
362     GC lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
363     GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
364 
365     XDrawLine(Tk_Display(tkwin), d, darkGC, b.x, b.y, b.x + b.width, b.y);
366     XDrawLine(Tk_Display(tkwin), d, lightGC, b.x, b.y+1, b.x + b.width, b.y+1);
367 }
368 
VerticalSeparatorElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)369 static void VerticalSeparatorElementDraw(
370     void *clientData, void *elementRecord, Tk_Window tkwin,
371     Drawable d, Ttk_Box b, unsigned int state)
372 {
373     SeparatorElement *separator = elementRecord;
374     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, separator->borderObj);
375     GC lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
376     GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
377 
378     XDrawLine(Tk_Display(tkwin), d, darkGC, b.x, b.y, b.x, b.y + b.height);
379     XDrawLine(Tk_Display(tkwin), d, lightGC, b.x+1, b.y, b.x+1, b.y+b.height);
380 }
381 
GeneralSeparatorElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)382 static void GeneralSeparatorElementDraw(
383     void *clientData, void *elementRecord, Tk_Window tkwin,
384     Drawable d, Ttk_Box b, unsigned int state)
385 {
386     SeparatorElement *separator = elementRecord;
387     int orient;
388     Ttk_GetOrientFromObj(NULL, separator->orientObj, &orient);
389     switch (orient) {
390 	case TTK_ORIENT_HORIZONTAL:
391 	    HorizontalSeparatorElementDraw(
392 		clientData, elementRecord, tkwin, d, b, state);
393 	    break;
394 	case TTK_ORIENT_VERTICAL:
395 	    VerticalSeparatorElementDraw(
396 		clientData, elementRecord, tkwin, d, b, state);
397 	    break;
398     }
399 }
400 
401 static Ttk_ElementSpec HorizontalSeparatorElementSpec = {
402     TK_STYLE_VERSION_2,
403     sizeof(SeparatorElement),
404     SeparatorElementOptions,
405     SeparatorElementSize,
406     HorizontalSeparatorElementDraw
407 };
408 
409 static Ttk_ElementSpec VerticalSeparatorElementSpec = {
410     TK_STYLE_VERSION_2,
411     sizeof(SeparatorElement),
412     SeparatorElementOptions,
413     SeparatorElementSize,
414     HorizontalSeparatorElementDraw
415 };
416 
417 static Ttk_ElementSpec SeparatorElementSpec = {
418     TK_STYLE_VERSION_2,
419     sizeof(SeparatorElement),
420     SeparatorElementOptions,
421     SeparatorElementSize,
422     GeneralSeparatorElementDraw
423 };
424 
425 /*----------------------------------------------------------------------
426  * +++ Sizegrip: lower-right corner grip handle for resizing window.
427  */
428 
429 typedef struct {
430     Tcl_Obj	*backgroundObj;
431 } SizegripElement;
432 
433 static Ttk_ElementOptionSpec SizegripOptions[] = {
434     { "-background", TK_OPTION_BORDER,
435 	Tk_Offset(SizegripElement,backgroundObj), DEFAULT_BACKGROUND },
436     {0,0,0,0}
437 };
438 
SizegripSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)439 static void SizegripSize(
440     void *clientData, void *elementRecord, Tk_Window tkwin,
441     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
442 {
443     int gripCount = 3, gripSpace = 2, gripThickness = 3;
444     *widthPtr = *heightPtr = gripCount * (gripSpace + gripThickness);
445 }
446 
SizegripDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,Ttk_State state)447 static void SizegripDraw(
448     void *clientData, void *elementRecord, Tk_Window tkwin,
449     Drawable d, Ttk_Box b, Ttk_State state)
450 {
451     SizegripElement *grip = elementRecord;
452     int gripCount = 3, gripSpace = 2;
453     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, grip->backgroundObj);
454     GC lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
455     GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
456     int x1 = b.x + b.width-1, y1 = b.y + b.height-1, x2 = x1, y2 = y1;
457 
458     while (gripCount--) {
459 	x1 -= gripSpace; y2 -= gripSpace;
460 	XDrawLine(Tk_Display(tkwin), d, darkGC,  x1,y1, x2,y2); --x1; --y2;
461 	XDrawLine(Tk_Display(tkwin), d, darkGC,  x1,y1, x2,y2); --x1; --y2;
462 	XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y1, x2,y2); --x1; --y2;
463     }
464 }
465 
466 static Ttk_ElementSpec SizegripElementSpec = {
467     TK_STYLE_VERSION_2,
468     sizeof(SizegripElement),
469     SizegripOptions,
470     SizegripSize,
471     SizegripDraw
472 };
473 
474 /*----------------------------------------------------------------------
475  * +++ Indicator element.
476  *
477  * Draws the on/off indicator for checkbuttons and radiobuttons.
478  *
479  * Draws a 3-D square (or diamond), raised if off, sunken if on.
480  *
481  * This is actually a regression from Tk 8.5 back to the ugly old Motif
482  * style; use "altTheme" for the newer, nicer version.
483  */
484 
485 typedef struct {
486     Tcl_Obj *backgroundObj;
487     Tcl_Obj *reliefObj;
488     Tcl_Obj *colorObj;
489     Tcl_Obj *diameterObj;
490     Tcl_Obj *marginObj;
491     Tcl_Obj *borderWidthObj;
492 } IndicatorElement;
493 
494 static Ttk_ElementOptionSpec IndicatorElementOptions[] = {
495     { "-background", TK_OPTION_BORDER,
496 	Tk_Offset(IndicatorElement,backgroundObj), DEFAULT_BACKGROUND },
497     { "-indicatorcolor", TK_OPTION_BORDER,
498 	Tk_Offset(IndicatorElement,colorObj), DEFAULT_BACKGROUND },
499     { "-indicatorrelief", TK_OPTION_RELIEF,
500 	Tk_Offset(IndicatorElement,reliefObj), "raised" },
501     { "-indicatordiameter", TK_OPTION_PIXELS,
502 	Tk_Offset(IndicatorElement,diameterObj), "12" },
503     { "-indicatormargin", TK_OPTION_STRING,
504 	Tk_Offset(IndicatorElement,marginObj), "0 2 4 2" },
505     { "-borderwidth", TK_OPTION_PIXELS,
506 	Tk_Offset(IndicatorElement,borderWidthObj), DEFAULT_BORDERWIDTH },
507     { NULL, 0, 0, NULL }
508 };
509 
510 /*
511  * Checkbutton indicators (default): 3-D square.
512  */
SquareIndicatorElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)513 static void SquareIndicatorElementSize(
514     void *clientData, void *elementRecord, Tk_Window tkwin,
515     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
516 {
517     IndicatorElement *indicator = elementRecord;
518     Ttk_Padding margins;
519     int diameter = 0;
520     Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
521     Tk_GetPixelsFromObj(NULL, tkwin, indicator->diameterObj, &diameter);
522     *widthPtr = diameter + Ttk_PaddingWidth(margins);
523     *heightPtr = diameter + Ttk_PaddingHeight(margins);
524 }
525 
SquareIndicatorElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)526 static void SquareIndicatorElementDraw(
527     void *clientData, void *elementRecord, Tk_Window tkwin,
528     Drawable d, Ttk_Box b, unsigned int state)
529 {
530     IndicatorElement *indicator = elementRecord;
531     Tk_3DBorder border = 0, interior = 0;
532     int relief = TK_RELIEF_RAISED;
533     Ttk_Padding padding;
534     int borderWidth = 2;
535     int diameter;
536 
537     interior = Tk_Get3DBorderFromObj(tkwin, indicator->colorObj);
538     border = Tk_Get3DBorderFromObj(tkwin, indicator->backgroundObj);
539     Tcl_GetIntFromObj(NULL,indicator->borderWidthObj,&borderWidth);
540     Tk_GetReliefFromObj(NULL,indicator->reliefObj,&relief);
541     Ttk_GetPaddingFromObj(NULL,tkwin,indicator->marginObj,&padding);
542 
543     b = Ttk_PadBox(b, padding);
544 
545     diameter = b.width < b.height ? b.width : b.height;
546     Tk_Fill3DRectangle(tkwin, d, interior, b.x, b.y,
547 	    diameter, diameter,borderWidth, TK_RELIEF_FLAT);
548     Tk_Draw3DRectangle(tkwin, d, border, b.x, b.y,
549 	    diameter, diameter, borderWidth, relief);
550 }
551 
552 /*
553  * Radiobutton indicators:  3-D diamond.
554  */
DiamondIndicatorElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)555 static void DiamondIndicatorElementSize(
556     void *clientData, void *elementRecord, Tk_Window tkwin,
557     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
558 {
559     IndicatorElement *indicator = elementRecord;
560     Ttk_Padding margins;
561     int diameter = 0;
562     Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
563     Tk_GetPixelsFromObj(NULL, tkwin, indicator->diameterObj, &diameter);
564     *widthPtr = diameter + 3 + Ttk_PaddingWidth(margins);
565     *heightPtr = diameter + 3 + Ttk_PaddingHeight(margins);
566 }
567 
DiamondIndicatorElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)568 static void DiamondIndicatorElementDraw(
569     void *clientData, void *elementRecord, Tk_Window tkwin,
570     Drawable d, Ttk_Box b, unsigned int state)
571 {
572     IndicatorElement *indicator = elementRecord;
573     Tk_3DBorder border = 0, interior = 0;
574     int borderWidth = 2;
575     int relief = TK_RELIEF_RAISED;
576     int diameter, radius;
577     XPoint points[4];
578     Ttk_Padding padding;
579 
580     interior = Tk_Get3DBorderFromObj(tkwin, indicator->colorObj);
581     border = Tk_Get3DBorderFromObj(tkwin, indicator->backgroundObj);
582     Tcl_GetIntFromObj(NULL,indicator->borderWidthObj,&borderWidth);
583     Tk_GetReliefFromObj(NULL,indicator->reliefObj,&relief);
584     Ttk_GetPaddingFromObj(NULL,tkwin,indicator->marginObj,&padding);
585 
586     b = Ttk_PadBox(b, padding);
587 
588     diameter = b.width < b.height ? b.width : b.height;
589     radius = diameter / 2;
590 
591     points[0].x = b.x;
592     points[0].y = b.y + radius;
593     points[1].x = b.x + radius;
594     points[1].y = b.y + 2*radius;
595     points[2].x = b.x + 2*radius;
596     points[2].y = b.y + radius;
597     points[3].x = b.x + radius;
598     points[3].y = b.y;
599 
600     Tk_Fill3DPolygon(tkwin,d,interior,points,4,borderWidth,TK_RELIEF_FLAT);
601     Tk_Draw3DPolygon(tkwin,d,border,points,4,borderWidth,relief);
602 }
603 
604 static Ttk_ElementSpec CheckbuttonIndicatorElementSpec = {
605     TK_STYLE_VERSION_2,
606     sizeof(IndicatorElement),
607     IndicatorElementOptions,
608     SquareIndicatorElementSize,
609     SquareIndicatorElementDraw
610 };
611 
612 static Ttk_ElementSpec RadiobuttonIndicatorElementSpec = {
613     TK_STYLE_VERSION_2,
614     sizeof(IndicatorElement),
615     IndicatorElementOptions,
616     DiamondIndicatorElementSize,
617     DiamondIndicatorElementDraw
618 };
619 
620 /*
621  *----------------------------------------------------------------------
622  * +++ Menubutton indicators.
623  *
624  * These aren't functional like radio/check indicators,
625  * they're just affordability indicators.
626  *
627  * Standard Tk sets the indicator size to 4.0 mm by 1.7 mm.
628  * I have no idea where these numbers came from.
629  */
630 
631 typedef struct {
632     Tcl_Obj *backgroundObj;
633     Tcl_Obj *widthObj;
634     Tcl_Obj *heightObj;
635     Tcl_Obj *borderWidthObj;
636     Tcl_Obj *reliefObj;
637     Tcl_Obj *marginObj;
638 } MenuIndicatorElement;
639 
640 static Ttk_ElementOptionSpec MenuIndicatorElementOptions[] = {
641     { "-background", TK_OPTION_BORDER,
642 	Tk_Offset(MenuIndicatorElement,backgroundObj), DEFAULT_BACKGROUND },
643     { "-indicatorwidth", TK_OPTION_PIXELS,
644 	Tk_Offset(MenuIndicatorElement,widthObj), "4.0m" },
645     { "-indicatorheight", TK_OPTION_PIXELS,
646 	Tk_Offset(MenuIndicatorElement,heightObj), "1.7m" },
647     { "-borderwidth", TK_OPTION_PIXELS,
648 	Tk_Offset(MenuIndicatorElement,borderWidthObj), DEFAULT_BORDERWIDTH },
649     { "-indicatorrelief", TK_OPTION_RELIEF,
650 	Tk_Offset(MenuIndicatorElement,reliefObj),"raised" },
651     { "-indicatormargin", TK_OPTION_STRING,
652 	    Tk_Offset(MenuIndicatorElement,marginObj), "5 0" },
653     { NULL, 0, 0, NULL }
654 };
655 
MenuIndicatorElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)656 static void MenuIndicatorElementSize(
657     void *clientData, void *elementRecord, Tk_Window tkwin,
658     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
659 {
660     MenuIndicatorElement *mi = elementRecord;
661     Ttk_Padding margins;
662     Tk_GetPixelsFromObj(NULL, tkwin, mi->widthObj, widthPtr);
663     Tk_GetPixelsFromObj(NULL, tkwin, mi->heightObj, heightPtr);
664     Ttk_GetPaddingFromObj(NULL,tkwin,mi->marginObj, &margins);
665     *widthPtr += Ttk_PaddingWidth(margins);
666     *heightPtr += Ttk_PaddingHeight(margins);
667 }
668 
MenuIndicatorElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)669 static void MenuIndicatorElementDraw(
670     void *clientData, void *elementRecord, Tk_Window tkwin,
671     Drawable d, Ttk_Box b, unsigned int state)
672 {
673     MenuIndicatorElement *mi = elementRecord;
674     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, mi->backgroundObj);
675     Ttk_Padding margins;
676     int borderWidth = 2;
677 
678     Ttk_GetPaddingFromObj(NULL,tkwin,mi->marginObj,&margins);
679     b = Ttk_PadBox(b, margins);
680     Tk_GetPixelsFromObj(NULL, tkwin, mi->borderWidthObj, &borderWidth);
681     Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height,
682 	    borderWidth, TK_RELIEF_RAISED);
683 }
684 
685 static Ttk_ElementSpec MenuIndicatorElementSpec = {
686     TK_STYLE_VERSION_2,
687     sizeof(MenuIndicatorElement),
688     MenuIndicatorElementOptions,
689     MenuIndicatorElementSize,
690     MenuIndicatorElementDraw
691 };
692 
693 /*----------------------------------------------------------------------
694  * +++ Arrow elements.
695  *
696  * 	Draws a solid triangle inside a box.
697  * 	clientData is an enum ArrowDirection pointer.
698  */
699 
700 static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT };
701 typedef struct {
702     Tcl_Obj *borderObj;
703     Tcl_Obj *borderWidthObj;
704     Tcl_Obj *reliefObj;
705     Tcl_Obj *sizeObj;
706     Tcl_Obj *colorObj;
707 } ArrowElement;
708 
709 static Ttk_ElementOptionSpec ArrowElementOptions[] = {
710     { "-background", TK_OPTION_BORDER,
711 	Tk_Offset(ArrowElement,borderObj), DEFAULT_BACKGROUND },
712     { "-relief",TK_OPTION_RELIEF,
713 	Tk_Offset(ArrowElement,reliefObj),"raised"},
714     { "-borderwidth", TK_OPTION_PIXELS,
715 	Tk_Offset(ArrowElement,borderWidthObj), "1" },
716     { "-arrowcolor",TK_OPTION_COLOR,
717 	Tk_Offset(ArrowElement,colorObj),"black"},
718     { "-arrowsize", TK_OPTION_PIXELS,
719 	Tk_Offset(ArrowElement,sizeObj), "14" },
720     { NULL, 0, 0, NULL }
721 };
722 
723 static Ttk_Padding ArrowMargins = { 3,3,3,3 };
724 
ArrowElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)725 static void ArrowElementSize(
726     void *clientData, void *elementRecord, Tk_Window tkwin,
727     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
728 {
729     ArrowElement *arrow = elementRecord;
730     int direction = *(int *)clientData;
731     int width = 14;
732 
733     Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &width);
734     width -= Ttk_PaddingWidth(ArrowMargins);
735     TtkArrowSize(width/2, direction, widthPtr, heightPtr);
736     *widthPtr += Ttk_PaddingWidth(ArrowMargins);
737     *heightPtr += Ttk_PaddingWidth(ArrowMargins);
738 }
739 
ArrowElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)740 static void ArrowElementDraw(
741     void *clientData, void *elementRecord, Tk_Window tkwin,
742     Drawable d, Ttk_Box b, unsigned int state)
743 {
744     int direction = *(int *)clientData;
745     ArrowElement *arrow = elementRecord;
746     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, arrow->borderObj);
747     XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj);
748     int relief = TK_RELIEF_RAISED;
749     int borderWidth = 1;
750 
751     Tk_GetReliefFromObj(NULL, arrow->reliefObj, &relief);
752 
753     Tk_Fill3DRectangle(
754 	tkwin, d, border, b.x, b.y, b.width, b.height, borderWidth, relief);
755 
756     TtkFillArrow(Tk_Display(tkwin), d, Tk_GCForColor(arrowColor, d),
757 	Ttk_PadBox(b, ArrowMargins), direction);
758 }
759 
760 static Ttk_ElementSpec ArrowElementSpec = {
761     TK_STYLE_VERSION_2,
762     sizeof(ArrowElement),
763     ArrowElementOptions,
764     ArrowElementSize,
765     ArrowElementDraw
766 };
767 
768 /*----------------------------------------------------------------------
769  * +++ Trough element.
770  *
771  * Used in scrollbars and scales in place of "border".
772  */
773 
774 typedef struct {
775     Tcl_Obj *colorObj;
776     Tcl_Obj *borderWidthObj;
777     Tcl_Obj *reliefObj;
778 } TroughElement;
779 
780 static Ttk_ElementOptionSpec TroughElementOptions[] = {
781     { "-borderwidth", TK_OPTION_PIXELS,
782 	Tk_Offset(TroughElement,borderWidthObj), DEFAULT_BORDERWIDTH },
783     { "-troughcolor", TK_OPTION_BORDER,
784 	Tk_Offset(TroughElement,colorObj), DEFAULT_BACKGROUND },
785     { "-troughrelief",TK_OPTION_RELIEF,
786 	Tk_Offset(TroughElement,reliefObj), "sunken" },
787     { NULL, 0, 0, NULL }
788 };
789 
TroughElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)790 static void TroughElementSize(
791     void *clientData, void *elementRecord, Tk_Window tkwin,
792     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
793 {
794     TroughElement *troughPtr = elementRecord;
795     int borderWidth = 2;
796 
797     Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth);
798     *paddingPtr = Ttk_UniformPadding((short)borderWidth);
799 }
800 
TroughElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)801 static void TroughElementDraw(
802     void *clientData, void *elementRecord, Tk_Window tkwin,
803     Drawable d, Ttk_Box b, unsigned int state)
804 {
805     TroughElement *troughPtr = elementRecord;
806     Tk_3DBorder border = NULL;
807     int borderWidth = 2, relief = TK_RELIEF_SUNKEN;
808 
809     border = Tk_Get3DBorderFromObj(tkwin, troughPtr->colorObj);
810     Tk_GetReliefFromObj(NULL, troughPtr->reliefObj, &relief);
811     Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth);
812 
813     Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height,
814 	    borderWidth, relief);
815 }
816 
817 static Ttk_ElementSpec TroughElementSpec = {
818     TK_STYLE_VERSION_2,
819     sizeof(TroughElement),
820     TroughElementOptions,
821     TroughElementSize,
822     TroughElementDraw
823 };
824 
825 /*
826  *----------------------------------------------------------------------
827  * +++ Thumb element.
828  *
829  * Used in scrollbars.
830  */
831 
832 typedef struct {
833     Tcl_Obj *orientObj;
834     Tcl_Obj *thicknessObj;
835     Tcl_Obj *reliefObj;
836     Tcl_Obj *borderObj;
837     Tcl_Obj *borderWidthObj;
838 } ThumbElement;
839 
840 static Ttk_ElementOptionSpec ThumbElementOptions[] = {
841     { "-orient", TK_OPTION_ANY,
842 	Tk_Offset(ThumbElement, orientObj), "horizontal" },
843     { "-width", TK_OPTION_PIXELS,
844 	Tk_Offset(ThumbElement,thicknessObj), DEFAULT_ARROW_SIZE },
845     { "-relief", TK_OPTION_RELIEF,
846 	Tk_Offset(ThumbElement,reliefObj), "raised" },
847     { "-background", TK_OPTION_BORDER,
848 	Tk_Offset(ThumbElement,borderObj), DEFAULT_BACKGROUND },
849     { "-borderwidth", TK_OPTION_PIXELS,
850 	Tk_Offset(ThumbElement,borderWidthObj), DEFAULT_BORDERWIDTH },
851     { NULL, 0, 0, NULL }
852 };
853 
ThumbElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)854 static void ThumbElementSize(
855     void *clientData, void *elementRecord, Tk_Window tkwin,
856     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
857 {
858     ThumbElement *thumb = elementRecord;
859     int orient, thickness;
860 
861     Tk_GetPixelsFromObj(NULL, tkwin, thumb->thicknessObj, &thickness);
862     Ttk_GetOrientFromObj(NULL, thumb->orientObj, &orient);
863 
864     if (orient == TTK_ORIENT_VERTICAL) {
865 	*widthPtr = thickness;
866 	*heightPtr = MIN_THUMB_SIZE;
867     } else {
868 	*widthPtr = MIN_THUMB_SIZE;
869 	*heightPtr = thickness;
870     }
871 }
872 
ThumbElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)873 static void ThumbElementDraw(
874     void *clientData, void *elementRecord, Tk_Window tkwin,
875     Drawable d, Ttk_Box b, unsigned int state)
876 {
877     ThumbElement *thumb = elementRecord;
878     Tk_3DBorder  border = Tk_Get3DBorderFromObj(tkwin, thumb->borderObj);
879     int borderWidth = 2, relief = TK_RELIEF_RAISED;
880 
881     Tk_GetPixelsFromObj(NULL, tkwin, thumb->borderWidthObj, &borderWidth);
882     Tk_GetReliefFromObj(NULL, thumb->reliefObj, &relief);
883     Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height,
884 	    borderWidth, relief);
885 }
886 
887 static Ttk_ElementSpec ThumbElementSpec = {
888     TK_STYLE_VERSION_2,
889     sizeof(ThumbElement),
890     ThumbElementOptions,
891     ThumbElementSize,
892     ThumbElementDraw
893 };
894 
895 /*
896  *----------------------------------------------------------------------
897  * +++ Slider element.
898  *
899  * This is the moving part of the scale widget.  Drawn as a raised box.
900  */
901 
902 typedef struct {
903     Tcl_Obj *orientObj;	     /* orientation of overall slider */
904     Tcl_Obj *lengthObj;      /* slider length */
905     Tcl_Obj *thicknessObj;   /* slider thickness */
906     Tcl_Obj *reliefObj;      /* the relief for this object */
907     Tcl_Obj *borderObj;      /* the background color */
908     Tcl_Obj *borderWidthObj; /* the size of the border */
909 } SliderElement;
910 
911 static Ttk_ElementOptionSpec SliderElementOptions[] = {
912     { "-sliderlength", TK_OPTION_PIXELS, Tk_Offset(SliderElement,lengthObj),
913 	"30" },
914     { "-sliderthickness",TK_OPTION_PIXELS,Tk_Offset(SliderElement,thicknessObj),
915 	"15" },
916     { "-sliderrelief", TK_OPTION_RELIEF, Tk_Offset(SliderElement,reliefObj),
917 	"raised" },
918     { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(SliderElement,borderWidthObj),
919 	DEFAULT_BORDERWIDTH },
920     { "-background", TK_OPTION_BORDER, Tk_Offset(SliderElement,borderObj),
921 	DEFAULT_BACKGROUND },
922     { "-orient", TK_OPTION_ANY, Tk_Offset(SliderElement,orientObj),
923 	"horizontal" },
924     { NULL, 0, 0, NULL }
925 };
926 
SliderElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)927 static void SliderElementSize(
928     void *clientData, void *elementRecord, Tk_Window tkwin,
929     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
930 {
931     SliderElement *slider = elementRecord;
932     int orient, length, thickness;
933 
934     Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient);
935     Tk_GetPixelsFromObj(NULL, tkwin, slider->lengthObj, &length);
936     Tk_GetPixelsFromObj(NULL, tkwin, slider->thicknessObj, &thickness);
937 
938     switch (orient) {
939 	case TTK_ORIENT_VERTICAL:
940 	    *widthPtr = thickness;
941 	    *heightPtr = length;
942 	    break;
943 
944 	case TTK_ORIENT_HORIZONTAL:
945 	    *widthPtr = length;
946 	    *heightPtr = thickness;
947 	    break;
948     }
949 }
950 
SliderElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)951 static void SliderElementDraw(
952     void *clientData, void *elementRecord, Tk_Window tkwin,
953     Drawable d, Ttk_Box b, unsigned int state)
954 {
955     SliderElement *slider = elementRecord;
956     Tk_3DBorder border = NULL;
957     int relief = TK_RELIEF_RAISED, borderWidth = 2, orient;
958 
959     border = Tk_Get3DBorderFromObj(tkwin, slider->borderObj);
960     Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient);
961     Tk_GetPixelsFromObj(NULL, tkwin, slider->borderWidthObj, &borderWidth);
962     Tk_GetReliefFromObj(NULL, slider->reliefObj, &relief);
963 
964     Tk_Fill3DRectangle(tkwin, d, border,
965 	b.x, b.y, b.width, b.height,
966 	borderWidth, relief);
967 
968     if (relief != TK_RELIEF_FLAT) {
969 	if (orient == TTK_ORIENT_HORIZONTAL) {
970 	    if (b.width > 4) {
971 		b.x += b.width/2;
972 		XDrawLine(Tk_Display(tkwin), d,
973 		    Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC),
974 		    b.x-1, b.y+borderWidth, b.x-1, b.y+b.height-borderWidth);
975 		XDrawLine(Tk_Display(tkwin), d,
976 		    Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC),
977 		    b.x, b.y+borderWidth, b.x, b.y+b.height-borderWidth);
978 	    }
979 	} else {
980 	    if (b.height > 4) {
981 		b.y += b.height/2;
982 		XDrawLine(Tk_Display(tkwin), d,
983 		    Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC),
984 		    b.x+borderWidth, b.y-1, b.x+b.width-borderWidth, b.y-1);
985 		XDrawLine(Tk_Display(tkwin), d,
986 		    Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC),
987 		    b.x+borderWidth, b.y, b.x+b.width-borderWidth, b.y);
988 	    }
989 	}
990     }
991 }
992 
993 static Ttk_ElementSpec SliderElementSpec = {
994     TK_STYLE_VERSION_2,
995     sizeof(SliderElement),
996     SliderElementOptions,
997     SliderElementSize,
998     SliderElementDraw
999 };
1000 
1001 /*------------------------------------------------------------------------
1002  * +++ Progress bar element:
1003  *	Draws the moving part of the progress bar.
1004  *
1005  *	-thickness specifies the size along the short axis of the bar.
1006  *	-length specifies the default size along the long axis;
1007  *	the bar will be this long in indeterminate mode.
1008  */
1009 
1010 #define DEFAULT_PBAR_THICKNESS "15"
1011 #define DEFAULT_PBAR_LENGTH "30"
1012 
1013 typedef struct {
1014     Tcl_Obj *orientObj; 	/* widget orientation */
1015     Tcl_Obj *thicknessObj;	/* the height/width of the bar */
1016     Tcl_Obj *lengthObj;		/* default width/height of the bar */
1017     Tcl_Obj *reliefObj; 	/* border relief for this object */
1018     Tcl_Obj *borderObj; 	/* background color */
1019     Tcl_Obj *borderWidthObj; 	/* thickness of the border */
1020 } PbarElement;
1021 
1022 static Ttk_ElementOptionSpec PbarElementOptions[] = {
1023     { "-orient", TK_OPTION_ANY, Tk_Offset(PbarElement,orientObj),
1024 	"horizontal" },
1025     { "-thickness", TK_OPTION_PIXELS, Tk_Offset(PbarElement,thicknessObj),
1026 	DEFAULT_PBAR_THICKNESS },
1027     { "-barsize", TK_OPTION_PIXELS, Tk_Offset(PbarElement,lengthObj),
1028 	DEFAULT_PBAR_LENGTH },
1029     { "-pbarrelief", TK_OPTION_RELIEF, Tk_Offset(PbarElement,reliefObj),
1030 	"raised" },
1031     { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(PbarElement,borderWidthObj),
1032 	DEFAULT_BORDERWIDTH },
1033     { "-background", TK_OPTION_BORDER, Tk_Offset(PbarElement,borderObj),
1034 	DEFAULT_BACKGROUND },
1035     { NULL, 0, 0, NULL }
1036 };
1037 
PbarElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)1038 static void PbarElementSize(
1039     void *clientData, void *elementRecord, Tk_Window tkwin,
1040     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1041 {
1042     PbarElement *pbar = elementRecord;
1043     int orient, thickness = 15, length = 30, borderWidth = 2;
1044 
1045     Ttk_GetOrientFromObj(NULL, pbar->orientObj, &orient);
1046     Tk_GetPixelsFromObj(NULL, tkwin, pbar->thicknessObj, &thickness);
1047     Tk_GetPixelsFromObj(NULL, tkwin, pbar->lengthObj, &length);
1048     Tk_GetPixelsFromObj(NULL, tkwin, pbar->borderWidthObj, &borderWidth);
1049 
1050     switch (orient) {
1051 	case TTK_ORIENT_HORIZONTAL:
1052 	    *widthPtr	= length + 2 * borderWidth;
1053 	    *heightPtr	= thickness + 2 * borderWidth;
1054 	    break;
1055 	case TTK_ORIENT_VERTICAL:
1056 	    *widthPtr	= thickness + 2 * borderWidth;
1057 	    *heightPtr	= length + 2 * borderWidth;
1058 	    break;
1059     }
1060 }
1061 
PbarElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,Ttk_State state)1062 static void PbarElementDraw(
1063     void *clientData, void *elementRecord, Tk_Window tkwin,
1064     Drawable d, Ttk_Box b, Ttk_State state)
1065 {
1066     PbarElement *pbar = elementRecord;
1067     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, pbar->borderObj);
1068     int relief = TK_RELIEF_RAISED, borderWidth = 2;
1069 
1070     Tk_GetPixelsFromObj(NULL, tkwin, pbar->borderWidthObj, &borderWidth);
1071     Tk_GetReliefFromObj(NULL, pbar->reliefObj, &relief);
1072 
1073     Tk_Fill3DRectangle(tkwin, d, border,
1074 	b.x, b.y, b.width, b.height,
1075 	borderWidth, relief);
1076 }
1077 
1078 static Ttk_ElementSpec PbarElementSpec = {
1079     TK_STYLE_VERSION_2,
1080     sizeof(PbarElement),
1081     PbarElementOptions,
1082     PbarElementSize,
1083     PbarElementDraw
1084 };
1085 
1086 /*------------------------------------------------------------------------
1087  * +++ Notebook tabs and client area.
1088  */
1089 
1090 typedef struct {
1091     Tcl_Obj *borderWidthObj;
1092     Tcl_Obj *backgroundObj;
1093 } TabElement;
1094 
1095 static Ttk_ElementOptionSpec TabElementOptions[] = {
1096     { "-borderwidth", TK_OPTION_PIXELS,
1097 	Tk_Offset(TabElement,borderWidthObj),"1" },
1098     { "-background", TK_OPTION_BORDER,
1099 	Tk_Offset(TabElement,backgroundObj), DEFAULT_BACKGROUND },
1100     {0,0,0,0}
1101 };
1102 
TabElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)1103 static void TabElementSize(
1104     void *clientData, void *elementRecord, Tk_Window tkwin,
1105     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1106 {
1107     TabElement *tab = elementRecord;
1108     int borderWidth = 1;
1109     Tk_GetPixelsFromObj(0, tkwin, tab->borderWidthObj, &borderWidth);
1110     paddingPtr->top = paddingPtr->left = paddingPtr->right = borderWidth;
1111     paddingPtr->bottom = 0;
1112 }
1113 
TabElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)1114 static void TabElementDraw(
1115     void *clientData, void *elementRecord, Tk_Window tkwin,
1116     Drawable d, Ttk_Box b, unsigned int state)
1117 {
1118     TabElement *tab = elementRecord;
1119     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, tab->backgroundObj);
1120     int borderWidth = 1;
1121     int cut = 2;
1122     XPoint pts[6];
1123     int n = 0;
1124 
1125     Tcl_GetIntFromObj(NULL, tab->borderWidthObj, &borderWidth);
1126 
1127     if (state & TTK_STATE_SELECTED) {
1128 	/*
1129 	 * Draw slightly outside of the allocated parcel,
1130 	 * to overwrite the client area border.
1131 	 */
1132 	b.height += borderWidth;
1133     }
1134 
1135     pts[n].x = b.x; 			pts[n].y = b.y + b.height - 1; ++n;
1136     pts[n].x = b.x;			pts[n].y = b.y + cut; ++n;
1137     pts[n].x = b.x + cut;  		pts[n].y = b.y; ++n;
1138     pts[n].x = b.x + b.width-1-cut;	pts[n].y = b.y; ++n;
1139     pts[n].x = b.x + b.width-1; 	pts[n].y = b.y + cut; ++n;
1140     pts[n].x = b.x + b.width-1; 	pts[n].y = b.y + b.height; ++n;
1141 
1142     XFillPolygon(Tk_Display(tkwin), d,
1143 	Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC),
1144 	pts, 6, Convex, CoordModeOrigin);
1145 
1146 #ifndef _WIN32
1147     /*
1148      * Account for whether XDrawLines draws endpoints by platform
1149      */
1150     --pts[5].y;
1151 #endif
1152 
1153     while (borderWidth--) {
1154 	XDrawLines(Tk_Display(tkwin), d,
1155 		Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC),
1156 		pts, 4, CoordModeOrigin);
1157 	XDrawLines(Tk_Display(tkwin), d,
1158 		Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC),
1159 		pts+3, 3, CoordModeOrigin);
1160 	++pts[0].x; ++pts[1].x; ++pts[2].x;             --pts[4].x; --pts[5].x;
1161 	                        ++pts[2].y; ++pts[3].y;
1162     }
1163 
1164 }
1165 
1166 static Ttk_ElementSpec TabElementSpec = {
1167     TK_STYLE_VERSION_2,
1168     sizeof(TabElement),
1169     TabElementOptions,
1170     TabElementSize,
1171     TabElementDraw
1172 };
1173 
1174 /*
1175  * Client area element:
1176  * Uses same resources as tab element.
1177  */
1178 typedef TabElement ClientElement;
1179 #define ClientElementOptions TabElementOptions
1180 
ClientElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)1181 static void ClientElementDraw(
1182     void *clientData, void *elementRecord, Tk_Window tkwin,
1183     Drawable d, Ttk_Box b, unsigned int state)
1184 {
1185     ClientElement *ce = elementRecord;
1186     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, ce->backgroundObj);
1187     int borderWidth = 1;
1188 
1189     Tcl_GetIntFromObj(NULL, ce->borderWidthObj, &borderWidth);
1190 
1191     Tk_Fill3DRectangle(tkwin, d, border,
1192 	b.x, b.y, b.width, b.height, borderWidth,TK_RELIEF_RAISED);
1193 }
1194 
ClientElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)1195 static void ClientElementSize(
1196     void *clientData, void *elementRecord, Tk_Window tkwin,
1197     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1198 {
1199     ClientElement *ce = elementRecord;
1200     int borderWidth = 1;
1201     Tk_GetPixelsFromObj(0, tkwin, ce->borderWidthObj, &borderWidth);
1202     *paddingPtr = Ttk_UniformPadding((short)borderWidth);
1203 }
1204 
1205 static Ttk_ElementSpec ClientElementSpec = {
1206     TK_STYLE_VERSION_2,
1207     sizeof(ClientElement),
1208     ClientElementOptions,
1209     ClientElementSize,
1210     ClientElementDraw
1211 };
1212 
1213 /*----------------------------------------------------------------------
1214  * TtkElements_Init --
1215  *	Register default element implementations.
1216  */
1217 
1218 MODULE_SCOPE
TtkElements_Init(Tcl_Interp * interp)1219 void TtkElements_Init(Tcl_Interp *interp)
1220 {
1221     Ttk_Theme theme =  Ttk_GetDefaultTheme(interp);
1222 
1223     /*
1224      * Elements:
1225      */
1226     Ttk_RegisterElement(interp, theme, "background",
1227 	    &BackgroundElementSpec,NULL);
1228 
1229     Ttk_RegisterElement(interp, theme, "fill", &FillElementSpec, NULL);
1230     Ttk_RegisterElement(interp, theme, "border", &BorderElementSpec, NULL);
1231     Ttk_RegisterElement(interp, theme, "field", &FieldElementSpec, NULL);
1232     Ttk_RegisterElement(interp, theme, "focus", &FocusElementSpec, NULL);
1233 
1234     Ttk_RegisterElement(interp, theme, "padding", &PaddingElementSpec, NULL);
1235 
1236     Ttk_RegisterElement(interp, theme, "Checkbutton.indicator",
1237 	    &CheckbuttonIndicatorElementSpec, NULL);
1238     Ttk_RegisterElement(interp, theme, "Radiobutton.indicator",
1239 	    &RadiobuttonIndicatorElementSpec, NULL);
1240     Ttk_RegisterElement(interp, theme, "Menubutton.indicator",
1241 	    &MenuIndicatorElementSpec, NULL);
1242 
1243     Ttk_RegisterElement(interp, theme, "indicator", &ttkNullElementSpec,NULL);
1244 
1245     Ttk_RegisterElement(interp, theme, "uparrow",
1246 	    &ArrowElementSpec, &ArrowElements[0]);
1247     Ttk_RegisterElement(interp, theme, "downarrow",
1248 	    &ArrowElementSpec, &ArrowElements[1]);
1249     Ttk_RegisterElement(interp, theme, "leftarrow",
1250 	    &ArrowElementSpec, &ArrowElements[2]);
1251     Ttk_RegisterElement(interp, theme, "rightarrow",
1252 	    &ArrowElementSpec, &ArrowElements[3]);
1253     Ttk_RegisterElement(interp, theme, "arrow",
1254 	    &ArrowElementSpec, &ArrowElements[0]);
1255 
1256     Ttk_RegisterElement(interp, theme, "trough", &TroughElementSpec, NULL);
1257     Ttk_RegisterElement(interp, theme, "thumb", &ThumbElementSpec, NULL);
1258     Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL);
1259     Ttk_RegisterElement(interp, theme, "pbar", &PbarElementSpec, NULL);
1260 
1261     Ttk_RegisterElement(interp, theme, "separator",
1262 	    &SeparatorElementSpec, NULL);
1263     Ttk_RegisterElement(interp, theme, "hseparator",
1264 	    &HorizontalSeparatorElementSpec, NULL);
1265     Ttk_RegisterElement(interp, theme, "vseparator",
1266 	    &VerticalSeparatorElementSpec, NULL);
1267 
1268     Ttk_RegisterElement(interp, theme, "sizegrip", &SizegripElementSpec, NULL);
1269 
1270     Ttk_RegisterElement(interp, theme, "tab", &TabElementSpec, NULL);
1271     Ttk_RegisterElement(interp, theme, "client", &ClientElementSpec, NULL);
1272 
1273     /*
1274      * Register "default" as a user-loadable theme (for now):
1275      */
1276     Tcl_PkgProvideEx(interp, "ttk::theme::default", TTK_VERSION, NULL);
1277 }
1278 
1279 /*EOF*/
1280