1 /*
2  * Copyright (c) 2003, Joe English
3  *
4  * Tk alternate theme, intended to match the MSUE and Gtk's (old) default theme
5  */
6 
7 #include "tkInt.h"
8 #include "ttkTheme.h"
9 
10 #if defined(_WIN32)
11 static const int WIN32_XDRAWLINE_HACK = 1;
12 #else
13 static const int WIN32_XDRAWLINE_HACK = 0;
14 #endif
15 
16 #if defined(MAC_OSX_TK)
17   #define IGNORES_VISUAL
18 #endif
19 
20 #define BORDERWIDTH     2
21 #define SCROLLBAR_WIDTH 14
22 #define MIN_THUMB_SIZE  8
23 
24 /*
25  *----------------------------------------------------------------------
26  *
27  * Helper routines for border drawing:
28  *
29  * NOTE: MSUE specifies a slightly different arrangement
30  * for button borders than for other elements; "shadowColors"
31  * is for button borders.
32  *
33  * Please excuse the gross misspelling "LITE" for "LIGHT",
34  * but it makes things line up nicer.
35  */
36 
37 enum BorderColor { FLAT = 1, LITE = 2, DARK = 3, BRDR = 4 };
38 
39 /* top-left outer, top-left inner, bottom-right inner, bottom-right outer */
40 static int const shadowColors[6][4] = {
41     { FLAT, FLAT, FLAT, FLAT },	/* TK_RELIEF_FLAT   = 0*/
42     { DARK, LITE, DARK, LITE },	/* TK_RELIEF_GROOVE = 1*/
43     { LITE, FLAT, DARK, BRDR },	/* TK_RELIEF_RAISED = 2*/
44     { LITE, DARK, LITE, DARK },	/* TK_RELIEF_RIDGE  = 3*/
45     { BRDR, BRDR, BRDR, BRDR },	/* TK_RELIEF_SOLID  = 4*/
46     { BRDR, DARK, FLAT, LITE }	/* TK_RELIEF_SUNKEN = 5*/
47 };
48 
49 /* top-left, bottom-right */
50 static int const thinShadowColors[6][4] = {
51     { FLAT, FLAT },	/* TK_RELIEF_FLAT   = 0*/
52     { DARK, LITE },	/* TK_RELIEF_GROOVE = 1*/
53     { LITE, DARK },	/* TK_RELIEF_RAISED = 2*/
54     { LITE, DARK },	/* TK_RELIEF_RIDGE  = 3*/
55     { BRDR, BRDR },	/* TK_RELIEF_SOLID  = 4*/
56     { DARK, LITE }	/* TK_RELIEF_SUNKEN = 5*/
57 };
58 
DrawCorner(Tk_Window tkwin,Drawable d,Tk_3DBorder border,GC borderGC,int x,int y,int width,int height,int corner,enum BorderColor color)59 static void DrawCorner(
60     Tk_Window tkwin,
61     Drawable d,
62     Tk_3DBorder border,			/* get most GCs from here... */
63     GC borderGC,			/* "window border" color GC */
64     int x,int y, int width,int height,	/* where to draw */
65     int corner,				/* 0 => top left; 1 => bottom right */
66     enum BorderColor color)
67 {
68     XPoint points[3];
69     GC gc;
70 
71     --width; --height;
72     points[0].x = x;			points[0].y = y+height;
73     points[1].x = x+width*corner;	points[1].y = y+height*corner;
74     points[2].x = x+width;		points[2].y = y;
75 
76     if (color == BRDR)
77 	gc = borderGC;
78     else
79 	gc = Tk_3DBorderGC(tkwin, border, (int)color);
80 
81     XDrawLines(Tk_Display(tkwin), d, gc, points, 3, CoordModeOrigin);
82 }
83 
DrawBorder(Tk_Window tkwin,Drawable d,Tk_3DBorder border,XColor * borderColor,Ttk_Box b,int borderWidth,int relief)84 static void DrawBorder(
85     Tk_Window tkwin, Drawable d, Tk_3DBorder border, XColor *borderColor,
86     Ttk_Box b, int borderWidth, int relief)
87 {
88     GC borderGC = Tk_GCForColor(borderColor, d);
89 
90     switch (borderWidth) {
91 	case 2: /* "thick" border */
92 	    DrawCorner(tkwin, d, border, borderGC,
93 		b.x, b.y, b.width, b.height, 0,shadowColors[relief][0]);
94 	    DrawCorner(tkwin, d, border, borderGC,
95 		b.x+1, b.y+1, b.width-2, b.height-2, 0,shadowColors[relief][1]);
96 	    DrawCorner(tkwin, d, border, borderGC,
97 		b.x+1, b.y+1, b.width-2, b.height-2, 1,shadowColors[relief][2]);
98 	    DrawCorner(tkwin, d, border, borderGC,
99 		b.x, b.y, b.width, b.height, 1,shadowColors[relief][3]);
100 	    break;
101 	case 1: /* "thin" border */
102 	    DrawCorner(tkwin, d, border, borderGC,
103 		b.x, b.y, b.width, b.height, 0, thinShadowColors[relief][0]);
104 	    DrawCorner(tkwin, d, border, borderGC,
105 		b.x, b.y, b.width, b.height, 1, thinShadowColors[relief][1]);
106 	    break;
107 	case 0:	/* no border -- do nothing */
108 	    break;
109 	default: /* Fall back to Motif-style borders: */
110 	    Tk_Draw3DRectangle(tkwin, d, border,
111 		b.x, b.y, b.width, b.height, borderWidth,relief);
112 	    break;
113     }
114 }
115 
116 /* Alternate shadow colors for entry fields:
117  * NOTE: FLAT color is normally white, and the LITE color is a darker shade.
118  */
119 static int fieldShadowColors[4] = { DARK, BRDR, LITE, FLAT };
120 
DrawFieldBorder(Tk_Window tkwin,Drawable d,Tk_3DBorder border,XColor * borderColor,Ttk_Box b)121 static void DrawFieldBorder(
122     Tk_Window tkwin, Drawable d, Tk_3DBorder border, XColor *borderColor,
123     Ttk_Box b)
124 {
125     GC borderGC = Tk_GCForColor(borderColor, d);
126     DrawCorner(tkwin, d, border, borderGC,
127 	b.x, b.y, b.width, b.height, 0,fieldShadowColors[0]);
128     DrawCorner(tkwin, d, border, borderGC,
129 	b.x+1, b.y+1, b.width-2, b.height-2, 0,fieldShadowColors[1]);
130     DrawCorner(tkwin, d, border, borderGC,
131 	b.x+1, b.y+1, b.width-2, b.height-2, 1,fieldShadowColors[2]);
132     DrawCorner(tkwin, d, border, borderGC,
133 	b.x, b.y, b.width, b.height, 1,fieldShadowColors[3]);
134     return;
135 }
136 
137 /*
138  * ArrowPoints --
139  * 	Compute points of arrow polygon.
140  */
ArrowPoints(Ttk_Box b,ArrowDirection dir,XPoint points[4])141 static void ArrowPoints(Ttk_Box b, ArrowDirection dir, XPoint points[4])
142 {
143     int cx, cy, h;
144 
145     switch (dir) {
146 	case ARROW_UP:
147 	    h = (b.width - 1)/2;
148 	    cx = b.x + h;
149 	    cy = b.y;
150 	    if (b.height <= h) h = b.height - 1;
151 	    points[0].x = cx;		points[0].y = cy;
152 	    points[1].x = cx - h;  	points[1].y = cy + h;
153 	    points[2].x = cx + h; 	points[2].y = cy + h;
154 	    break;
155 	case ARROW_DOWN:
156 	    h = (b.width - 1)/2;
157 	    cx = b.x + h;
158 	    cy = b.y + b.height - 1;
159 	    if (b.height <= h) h = b.height - 1;
160 	    points[0].x = cx; 		points[0].y = cy;
161 	    points[1].x = cx - h;	points[1].y = cy - h;
162 	    points[2].x = cx + h; 	points[2].y = cy - h;
163 	    break;
164 	case ARROW_LEFT:
165 	    h = (b.height - 1)/2;
166 	    cx = b.x;
167 	    cy = b.y + h;
168 	    if (b.width <= h) h = b.width - 1;
169 	    points[0].x = cx; 		points[0].y = cy;
170 	    points[1].x = cx + h;	points[1].y = cy - h;
171 	    points[2].x = cx + h; 	points[2].y = cy + h;
172 	    break;
173 	case ARROW_RIGHT:
174 	    h = (b.height - 1)/2;
175 	    cx = b.x + b.width - 1;
176 	    cy = b.y + h;
177 	    if (b.width <= h) h = b.width - 1;
178 	    points[0].x = cx; 		points[0].y = cy;
179 	    points[1].x = cx - h;	points[1].y = cy - h;
180 	    points[2].x = cx - h; 	points[2].y = cy + h;
181 	    break;
182     }
183 
184     points[3].x = points[0].x;
185     points[3].y = points[0].y;
186 }
187 
188 /*public*/
TtkArrowSize(int h,ArrowDirection dir,int * widthPtr,int * heightPtr)189 void TtkArrowSize(int h, ArrowDirection dir, int *widthPtr, int *heightPtr)
190 {
191     switch (dir) {
192 	case ARROW_UP:
193 	case ARROW_DOWN:	*widthPtr = 2*h+1; *heightPtr = h+1; break;
194 	case ARROW_LEFT:
195 	case ARROW_RIGHT:	*widthPtr = h+1; *heightPtr = 2*h+1;
196     }
197 }
198 
199 /*
200  * TtkDrawArrow, TtkFillArrow --
201  * 	Draw an arrow in the indicated direction inside the specified box.
202  */
203 /*public*/
TtkFillArrow(Display * display,Drawable d,GC gc,Ttk_Box b,ArrowDirection dir)204 void TtkFillArrow(
205     Display *display, Drawable d, GC gc, Ttk_Box b, ArrowDirection dir)
206 {
207     XPoint points[4];
208     ArrowPoints(b, dir, points);
209     XFillPolygon(display, d, gc, points, 3, Convex, CoordModeOrigin);
210     XDrawLines(display, d, gc, points, 4, CoordModeOrigin);
211 
212     /* Work around bug [77527326e5] - ttk artifacts on Ubuntu */
213     XDrawPoint(display, d, gc, points[2].x, points[2].y);
214 }
215 
216 /*public*/
TtkDrawArrow(Display * display,Drawable d,GC gc,Ttk_Box b,ArrowDirection dir)217 void TtkDrawArrow(
218     Display *display, Drawable d, GC gc, Ttk_Box b, ArrowDirection dir)
219 {
220     XPoint points[4];
221     ArrowPoints(b, dir, points);
222     XDrawLines(display, d, gc, points, 4, CoordModeOrigin);
223 
224     /* Work around bug [77527326e5] - ttk artifacts on Ubuntu */
225     XDrawPoint(display, d, gc, points[2].x, points[2].y);
226 }
227 
228 /*
229  *----------------------------------------------------------------------
230  * +++ Border element implementation.
231  *
232  * This border consists of (from outside-in):
233  *
234  * + a 1-pixel thick default indicator (defaultable widgets only)
235  * + 1- or 2- pixel shaded border (controlled by -background and -relief)
236  * + 1 pixel padding (???)
237  */
238 
239 typedef struct {
240     Tcl_Obj	*borderObj;
241     Tcl_Obj	*borderColorObj;	/* Extra border color */
242     Tcl_Obj	*borderWidthObj;
243     Tcl_Obj	*reliefObj;
244     Tcl_Obj	*defaultStateObj;	/* for buttons */
245 } BorderElement;
246 
247 static Ttk_ElementOptionSpec BorderElementOptions[] = {
248     { "-background", TK_OPTION_BORDER, Tk_Offset(BorderElement,borderObj),
249     	DEFAULT_BACKGROUND },
250     { "-bordercolor",TK_OPTION_COLOR,
251 	Tk_Offset(BorderElement,borderColorObj), "black" },
252     { "-default", TK_OPTION_ANY, Tk_Offset(BorderElement,defaultStateObj),
253     	"disabled" },
254     { "-borderwidth",TK_OPTION_PIXELS,Tk_Offset(BorderElement,borderWidthObj),
255     	STRINGIFY(BORDERWIDTH) },
256     { "-relief", TK_OPTION_RELIEF, Tk_Offset(BorderElement,reliefObj),
257     	"flat" },
258         { NULL, 0, 0, NULL }
259 };
260 
BorderElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)261 static void BorderElementSize(
262     void *clientData, void *elementRecord, Tk_Window tkwin,
263     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
264 {
265     BorderElement *bd = elementRecord;
266     int borderWidth = 0;
267     int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
268 
269     Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
270     Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
271 
272     if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
273 	++borderWidth;
274     }
275 
276     *paddingPtr = Ttk_UniformPadding((short)borderWidth);
277 }
278 
BorderElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)279 static void BorderElementDraw(
280     void *clientData, void *elementRecord,
281     Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state)
282 {
283     BorderElement *bd = elementRecord;
284     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, bd->borderObj);
285     XColor *borderColor = Tk_GetColorFromObj(tkwin, bd->borderColorObj);
286     int borderWidth = 2;
287     int relief = TK_RELIEF_FLAT;
288     int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
289 
290     /*
291      * Get option values.
292      */
293     Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
294     Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
295     Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
296 
297     if (defaultState == TTK_BUTTON_DEFAULT_ACTIVE) {
298 	GC gc = Tk_GCForColor(borderColor, d);
299 	XDrawRectangle(Tk_Display(tkwin), d, gc,
300 		b.x, b.y, b.width-1, b.height-1);
301     }
302     if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
303 	/* Space for default ring: */
304 	b = Ttk_PadBox(b, Ttk_UniformPadding(1));
305     }
306 
307     DrawBorder(tkwin, d, border, borderColor, b, borderWidth, relief);
308 }
309 
310 static Ttk_ElementSpec BorderElementSpec = {
311     TK_STYLE_VERSION_2,
312     sizeof(BorderElement),
313     BorderElementOptions,
314     BorderElementSize,
315     BorderElementDraw
316 };
317 
318 /*----------------------------------------------------------------------
319  * +++ Field element:
320  * 	Used for editable fields.
321  */
322 typedef struct {
323     Tcl_Obj	*borderObj;
324     Tcl_Obj	*borderColorObj;	/* Extra border color */
325 } FieldElement;
326 
327 static Ttk_ElementOptionSpec FieldElementOptions[] = {
328     { "-fieldbackground", TK_OPTION_BORDER, Tk_Offset(FieldElement,borderObj),
329     	"white" },
330     { "-bordercolor",TK_OPTION_COLOR, Tk_Offset(FieldElement,borderColorObj),
331 	"black" },
332     { NULL, 0, 0, NULL }
333 };
334 
FieldElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)335 static void FieldElementSize(
336     void *clientData, void *elementRecord, Tk_Window tkwin,
337     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
338 {
339     *paddingPtr = Ttk_UniformPadding(2);
340 }
341 
FieldElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)342 static void FieldElementDraw(
343     void *clientData, void *elementRecord, Tk_Window tkwin,
344     Drawable d, Ttk_Box b, unsigned int state)
345 {
346     FieldElement *field = elementRecord;
347     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, field->borderObj);
348     XColor *borderColor = Tk_GetColorFromObj(tkwin, field->borderColorObj);
349 
350     Tk_Fill3DRectangle(
351 	tkwin, d, border, b.x, b.y, b.width, b.height, 0, TK_RELIEF_SUNKEN);
352     DrawFieldBorder(tkwin, d, border, borderColor, b);
353 }
354 
355 static Ttk_ElementSpec FieldElementSpec = {
356     TK_STYLE_VERSION_2,
357     sizeof(FieldElement),
358     FieldElementOptions,
359     FieldElementSize,
360     FieldElementDraw
361 };
362 
363 /*------------------------------------------------------------------------
364  * Indicators --
365  *
366  * 	Code derived (probably incorrectly) from TIP 109 implementation,
367  * 	unix/tkUnixButton.c r 1.15.
368  */
369 
370 /*
371  * Indicator bitmap descriptor:
372  */
373 typedef struct {
374     int width;		/* Width of each image */
375     int height;		/* Height of each image */
376     int nimages;	/* #images / row */
377     const char *const *pixels;	/* array[height] of char[width*nimage] */
378     Ttk_StateTable *map;/* used to look up image index by state */
379 } IndicatorSpec;
380 
381 #if 0
382 /*XPM*/
383 static const char *const button_images[] = {
384     /* width height ncolors chars_per_pixel */
385     "52 13 8 1",
386     /* colors */
387     "A c #808000000000 s shadow",
388     "B c #000080800000 s highlight",
389     "C c #808080800000 s 3dlight",
390     "D c #000000008080 s window",
391     "E c #808000008080 s 3ddark",
392     "F c #000080808080 s frame",
393     "G c #000000000000 s foreground",
394     "H c #000080800000 s disabledfg",
395 };
396 #endif
397 
398 static Ttk_StateTable checkbutton_states[] = {
399     { 0, 0, TTK_STATE_SELECTED|TTK_STATE_DISABLED },
400     { 1, TTK_STATE_SELECTED, TTK_STATE_DISABLED },
401     { 2, TTK_STATE_DISABLED, TTK_STATE_SELECTED },
402     { 3, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0 },
403     { 0, 0, 0 }
404 };
405 
406 static const char *const checkbutton_pixels[] = {
407     "AAAAAAAAAAAABAAAAAAAAAAAABAAAAAAAAAAAABAAAAAAAAAAAAB",
408     "AEEEEEEEEEECBAEEEEEEEEEECBAEEEEEEEEEECBAEEEEEEEEEECB",
409     "AEDDDDDDDDDCBAEDDDDDDDDDCBAEFFFFFFFFFCBAEFFFFFFFFFCB",
410     "AEDDDDDDDDDCBAEDDDDDDDGDCBAEFFFFFFFFFCBAEFFFFFFFHFCB",
411     "AEDDDDDDDDDCBAEDDDDDDGGDCBAEFFFFFFFFFCBAEFFFFFFHHFCB",
412     "AEDDDDDDDDDCBAEDGDDDGGGDCBAEFFFFFFFFFCBAEFHFFFHHHFCB",
413     "AEDDDDDDDDDCBAEDGGDGGGDDCBAEFFFFFFFFFCBAEFHHFHHHFFCB",
414     "AEDDDDDDDDDCBAEDGGGGGDDDCBAEFFFFFFFFFCBAEFHHHHHFFFCB",
415     "AEDDDDDDDDDCBAEDDGGGDDDDCBAEFFFFFFFFFCBAEFFHHHFFFFCB",
416     "AEDDDDDDDDDCBAEDDDGDDDDDCBAEFFFFFFFFFCBAEFFFHFFFFFCB",
417     "AEDDDDDDDDDCBAEDDDDDDDDDCBAEFFFFFFFFFCBAEFFFFFFFFFCB",
418     "ACCCCCCCCCCCBACCCCCCCCCCCBACCCCCCCCCCCBACCCCCCCCCCCB",
419     "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
420 };
421 
422 static IndicatorSpec checkbutton_spec = {
423     13, 13, 4,		/* width, height, nimages */
424     checkbutton_pixels,
425     checkbutton_states
426 };
427 
428 static Ttk_StateTable radiobutton_states[] = {
429     { 0, 0, TTK_STATE_SELECTED|TTK_STATE_DISABLED },
430     { 1, TTK_STATE_SELECTED, TTK_STATE_DISABLED },
431     { 2, TTK_STATE_DISABLED, TTK_STATE_SELECTED },
432     { 3, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0 },
433     { 0, 0, 0 }
434 };
435 
436 static const char *const radiobutton_pixels[] = {
437     "FFFFAAAAFFFFFFFFFAAAAFFFFFFFFFAAAAFFFFFFFFFAAAAFFFFF",
438     "FFAAEEEEAAFFFFFAAEEEEAAFFFFFAAEEEEAAFFFFFAAEEEEAAFFF",
439     "FAEEDDDDEEBFFFAEEDDDDEEBFFFAEEFFFFEEBFFFAEEFFFFEEBFF",
440     "FAEDDDDDDCBFFFAEDDDDDDCBFFFAEFFFFFFCBFFFAEFFFFFFCBFF",
441     "AEDDDDDDDDCBFAEDDDGGDDDCBFAEFFFFFFFFCBFAEFFFHHFFFCBF",
442     "AEDDDDDDDDCBFAEDDGGGGDDCBFAEFFFFFFFFCBFAEFFHHHHFFCBF",
443     "AEDDDDDDDDCBFAEDDGGGGDDCBFAEFFFFFFFFCBFAEFFHHHHFFCBF",
444     "AEDDDDDDDDCBFAEDDDGGDDDCBFAEFFFFFFFFCBFAEFFFHHFFFCBF",
445     "FAEDDDDDDCBFFFAEDDDDDDCBFFFAEFFFFFFCBFFFAEFFFFFFCBFF",
446     "FACCDDDDCCBFFFACCDDDDCCBFFFACCFFFFCCBFFFACCFFFFCCBFF",
447     "FFBBCCCCBBFFFFFBBCCCCBBFFFFFBBCCCCBBFFFFFBBCCCCBBFFF",
448     "FFFFBBBBFFFFFFFFFBBBBFFFFFFFFFBBBBFFFFFFFFFBBBBFFFFF",
449     "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
450 };
451 
452 static IndicatorSpec radiobutton_spec = {
453     13, 13, 4,		/* width, height, nimages */
454     radiobutton_pixels,
455     radiobutton_states
456 };
457 
458 typedef struct {
459     Tcl_Obj *backgroundObj;
460     Tcl_Obj *foregroundObj;
461     Tcl_Obj *colorObj;
462     Tcl_Obj *lightColorObj;
463     Tcl_Obj *shadeColorObj;
464     Tcl_Obj *borderColorObj;
465     Tcl_Obj *marginObj;
466 } IndicatorElement;
467 
468 static Ttk_ElementOptionSpec IndicatorElementOptions[] = {
469     { "-background", TK_OPTION_COLOR,
470 	    Tk_Offset(IndicatorElement,backgroundObj), DEFAULT_BACKGROUND },
471     { "-foreground", TK_OPTION_COLOR,
472 	    Tk_Offset(IndicatorElement,foregroundObj), DEFAULT_FOREGROUND },
473     { "-indicatorcolor", TK_OPTION_COLOR,
474 	    Tk_Offset(IndicatorElement,colorObj), "#FFFFFF" },
475     { "-lightcolor", TK_OPTION_COLOR,
476 	    Tk_Offset(IndicatorElement,lightColorObj), "#DDDDDD" },
477     { "-shadecolor", TK_OPTION_COLOR,
478 	    Tk_Offset(IndicatorElement,shadeColorObj), "#888888" },
479     { "-bordercolor", TK_OPTION_COLOR,
480 	    Tk_Offset(IndicatorElement,borderColorObj), "black" },
481     { "-indicatormargin", TK_OPTION_STRING,
482 	    Tk_Offset(IndicatorElement,marginObj), "0 2 4 2" },
483 	    { NULL, 0, 0, NULL }
484 };
485 
IndicatorElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)486 static void IndicatorElementSize(
487     void *clientData, void *elementRecord, Tk_Window tkwin,
488     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
489 {
490     IndicatorSpec *spec = clientData;
491     IndicatorElement *indicator = elementRecord;
492     Ttk_Padding margins;
493     Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
494     *widthPtr = spec->width + Ttk_PaddingWidth(margins);
495     *heightPtr = spec->height + Ttk_PaddingHeight(margins);
496 }
497 
IndicatorElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)498 static void IndicatorElementDraw(
499     void *clientData, void *elementRecord, Tk_Window tkwin,
500     Drawable d, Ttk_Box b, unsigned int state)
501 {
502     IndicatorSpec *spec = clientData;
503     IndicatorElement *indicator = elementRecord;
504     Display *display = Tk_Display(tkwin);
505     Ttk_Padding padding;
506     XColor *fgColor, *frameColor, *shadeColor, *indicatorColor, *borderColor;
507 
508     int index, ix, iy;
509     XGCValues gcValues;
510     GC copyGC;
511     unsigned long imgColors[8];
512     XImage *img = NULL;
513 
514     Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding);
515     b = Ttk_PadBox(b, padding);
516 
517     if (   b.x < 0
518 	|| b.y < 0
519 	|| Tk_Width(tkwin) < b.x + spec->width
520 	|| Tk_Height(tkwin) < b.y + spec->height)
521     {
522 	/* Oops!  not enough room to display the image.
523 	 * Don't draw anything.
524 	 */
525 	return;
526     }
527 
528     /*
529      * Fill in imgColors palette:
530      *
531      * (SHOULD: take light and shade colors from the border object,
532      * but Tk doesn't provide easy access to these in the public API.)
533      */
534     fgColor = Tk_GetColorFromObj(tkwin, indicator->foregroundObj);
535     frameColor = Tk_GetColorFromObj(tkwin, indicator->backgroundObj);
536     shadeColor = Tk_GetColorFromObj(tkwin, indicator->shadeColorObj);
537     indicatorColor = Tk_GetColorFromObj(tkwin, indicator->colorObj);
538     borderColor = Tk_GetColorFromObj(tkwin, indicator->borderColorObj);
539 
540     imgColors[0 /*A*/] = shadeColor->pixel;
541     imgColors[1 /*B*/] = indicatorColor->pixel;
542     imgColors[2 /*C*/] = frameColor->pixel;
543     imgColors[3 /*D*/] = indicatorColor->pixel;
544     imgColors[4 /*E*/] = borderColor->pixel;
545     imgColors[5 /*F*/] = frameColor->pixel;
546     imgColors[6 /*G*/] = fgColor->pixel;
547     imgColors[7 /*H*/] = fgColor->pixel;
548 
549     /*
550      * Create a scratch buffer to store the image:
551      */
552 
553 #if defined(IGNORES_VISUAL)
554 
555     /*
556      * Platforms which ignore the VisualInfo can use XCreateImage to get the
557      * scratch image.  This is essential on macOS, where it is not safe to call
558      * XGetImage in a display procedure.
559      */
560 
561     img = XCreateImage(display, NULL, 32, ZPixmap, 0, NULL,
562 		       (unsigned int)spec->width, (unsigned int)spec->height,
563 		       0, 0);
564 #else
565 
566     /*
567      * This trick allows creating the scratch XImage without having to
568      * construct a VisualInfo.
569      */
570 
571     img = XGetImage(display, d, 0, 0,
572 		    (unsigned int)spec->width, (unsigned int)spec->height,
573 		    AllPlanes, ZPixmap);
574 #endif
575 
576     if (img == NULL) {
577         return;
578     }
579 
580 #if defined(IGNORES_VISUAL)
581 
582     img->data = ckalloc(img->bytes_per_line * img->height);
583     if (img->data == NULL) {
584         XDestroyImage(img);
585 	return;
586     }
587 
588 #endif
589 
590     /*
591      * Create the image, painting it into the XImage one pixel at a time.
592      */
593 
594     index = Ttk_StateTableLookup(spec->map, state);
595     for (iy=0 ; iy<spec->height ; iy++) {
596 	for (ix=0 ; ix<spec->width ; ix++) {
597 	    XPutPixel(img, ix, iy,
598 		imgColors[spec->pixels[iy][index*spec->width+ix] - 'A'] );
599 	}
600     }
601 
602     /*
603      * Copy the image onto our target drawable surface.
604      */
605 
606     memset(&gcValues, 0, sizeof(gcValues));
607     copyGC = Tk_GetGC(tkwin, 0, &gcValues);
608     TkPutImage(NULL, 0, display, d, copyGC, img, 0, 0, b.x, b.y,
609                spec->width, spec->height);
610 
611     /*
612      * Tidy up.
613      */
614 
615     Tk_FreeGC(display, copyGC);
616 
617     /*
618      * Protect against the possibility that some future platform might
619      * not use the Tk memory manager in its implementation of XDestroyImage,
620      * even though that would be an extremely strange thing to do.
621      */
622 
623 #if defined(IGNORES_VISUAL)
624     ckfree(img->data);
625     img->data = NULL;
626 #endif
627 
628     XDestroyImage(img);
629 }
630 
631 static Ttk_ElementSpec IndicatorElementSpec = {
632     TK_STYLE_VERSION_2,
633     sizeof(IndicatorElement),
634     IndicatorElementOptions,
635     IndicatorElementSize,
636     IndicatorElementDraw
637 };
638 
639 /*----------------------------------------------------------------------
640  * +++ Arrow element(s).
641  *
642  * 	Draws a solid triangle, inside a box.
643  * 	clientData is an enum ArrowDirection pointer.
644  */
645 
646 static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT };
647 typedef struct {
648     Tcl_Obj *sizeObj;
649     Tcl_Obj *borderObj;
650     Tcl_Obj *borderColorObj;	/* Extra color for borders */
651     Tcl_Obj *reliefObj;
652     Tcl_Obj *colorObj;		/* Arrow color */
653 } ArrowElement;
654 
655 static Ttk_ElementOptionSpec ArrowElementOptions[] = {
656     { "-arrowsize", TK_OPTION_PIXELS,
657 	Tk_Offset(ArrowElement,sizeObj), STRINGIFY(SCROLLBAR_WIDTH) },
658     { "-background", TK_OPTION_BORDER,
659 	Tk_Offset(ArrowElement,borderObj), DEFAULT_BACKGROUND },
660     { "-bordercolor", TK_OPTION_COLOR,
661 	Tk_Offset(ArrowElement,borderColorObj), "black" },
662     { "-relief", TK_OPTION_RELIEF,
663 	Tk_Offset(ArrowElement,reliefObj),"raised"},
664     { "-arrowcolor", TK_OPTION_COLOR,
665 	Tk_Offset(ArrowElement,colorObj),"black"},
666     { NULL, 0, 0, NULL }
667 };
668 
669 /*
670  * Note asymmetric padding:
671  * top/left padding is 1 less than bottom/right,
672  * since in this theme 2-pixel borders are asymmetric.
673  */
674 static Ttk_Padding ArrowPadding = { 3,3,4,4 };
675 
ArrowElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)676 static void ArrowElementSize(
677     void *clientData, void *elementRecord, Tk_Window tkwin,
678     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
679 {
680     ArrowElement *arrow = elementRecord;
681     int direction = *(int *)clientData;
682     int width = SCROLLBAR_WIDTH;
683 
684     Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &width);
685     width -= Ttk_PaddingWidth(ArrowPadding);
686     TtkArrowSize(width/2, direction, widthPtr, heightPtr);
687     *widthPtr += Ttk_PaddingWidth(ArrowPadding);
688     *heightPtr += Ttk_PaddingHeight(ArrowPadding);
689 }
690 
ArrowElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)691 static void ArrowElementDraw(
692     void *clientData, void *elementRecord, Tk_Window tkwin,
693     Drawable d, Ttk_Box b, unsigned int state)
694 {
695     int direction = *(int *)clientData;
696     ArrowElement *arrow = elementRecord;
697     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, arrow->borderObj);
698     XColor *borderColor = Tk_GetColorFromObj(tkwin, arrow->borderColorObj);
699     XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj);
700     int relief = TK_RELIEF_RAISED;
701     int borderWidth = 2;
702 
703     Tk_GetReliefFromObj(NULL, arrow->reliefObj, &relief);
704 
705     Tk_Fill3DRectangle(
706 	tkwin, d, border, b.x, b.y, b.width, b.height, 0, TK_RELIEF_FLAT);
707     DrawBorder(tkwin,d,border,borderColor,b,borderWidth,relief);
708 
709     TtkFillArrow(Tk_Display(tkwin), d, Tk_GCForColor(arrowColor, d),
710 	Ttk_PadBox(b, ArrowPadding), direction);
711 }
712 
713 static Ttk_ElementSpec ArrowElementSpec = {
714     TK_STYLE_VERSION_2,
715     sizeof(ArrowElement),
716     ArrowElementOptions,
717     ArrowElementSize,
718     ArrowElementDraw
719 };
720 
721 /*----------------------------------------------------------------------
722  * +++ Menubutton indicator:
723  * 	Draw an arrow in the direction where the menu will be posted.
724  */
725 
726 #define MENUBUTTON_ARROW_SIZE 5
727 
728 typedef struct {
729     Tcl_Obj *directionObj;
730     Tcl_Obj *sizeObj;
731     Tcl_Obj *colorObj;
732 } MenubuttonArrowElement;
733 
734 static const char *directionStrings[] = {	/* See also: button.c */
735     "above", "below", "left", "right", "flush", NULL
736 };
737 enum { POST_ABOVE, POST_BELOW, POST_LEFT, POST_RIGHT, POST_FLUSH };
738 
739 static Ttk_ElementOptionSpec MenubuttonArrowElementOptions[] = {
740     { "-direction", TK_OPTION_STRING,
741 	Tk_Offset(MenubuttonArrowElement,directionObj), "below" },
742     { "-arrowsize", TK_OPTION_PIXELS,
743 	Tk_Offset(MenubuttonArrowElement,sizeObj), STRINGIFY(MENUBUTTON_ARROW_SIZE)},
744     { "-arrowcolor",TK_OPTION_COLOR,
745 	Tk_Offset(MenubuttonArrowElement,colorObj), "black"},
746     { NULL, 0, 0, NULL }
747 };
748 
749 static Ttk_Padding MenubuttonArrowPadding = { 3, 0, 3, 0 };
750 
MenubuttonArrowElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)751 static void MenubuttonArrowElementSize(
752     void *clientData, void *elementRecord, Tk_Window tkwin,
753     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
754 {
755     MenubuttonArrowElement *arrow = elementRecord;
756     int size = MENUBUTTON_ARROW_SIZE;
757     Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &size);
758     *widthPtr = *heightPtr = 2 * size + 1;
759     *widthPtr += Ttk_PaddingWidth(MenubuttonArrowPadding);
760     *heightPtr += Ttk_PaddingHeight(MenubuttonArrowPadding);
761 }
762 
MenubuttonArrowElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)763 static void MenubuttonArrowElementDraw(
764     void *clientData, void *elementRecord, Tk_Window tkwin,
765     Drawable d, Ttk_Box b, unsigned int state)
766 {
767     MenubuttonArrowElement *arrow = elementRecord;
768     XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj);
769     GC gc = Tk_GCForColor(arrowColor, d);
770     int size = MENUBUTTON_ARROW_SIZE;
771     int postDirection = POST_BELOW;
772     ArrowDirection arrowDirection = ARROW_DOWN;
773     int width = 0, height = 0;
774 
775     Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &size);
776     Tcl_GetIndexFromObjStruct(NULL, arrow->directionObj, directionStrings,
777 	   sizeof(char *), ""/*message*/, 0/*flags*/, &postDirection);
778 
779     /* ... this might not be such a great idea ... */
780     switch (postDirection) {
781 	case POST_ABOVE:	arrowDirection = ARROW_UP; break;
782 	case POST_BELOW:	arrowDirection = ARROW_DOWN; break;
783 	case POST_LEFT:		arrowDirection = ARROW_LEFT; break;
784 	case POST_RIGHT:	arrowDirection = ARROW_RIGHT; break;
785 	case POST_FLUSH:	arrowDirection = ARROW_DOWN; break;
786     }
787 
788     TtkArrowSize(size, arrowDirection, &width, &height);
789     b = Ttk_PadBox(b, MenubuttonArrowPadding);
790     b = Ttk_AnchorBox(b, width, height, TK_ANCHOR_CENTER);
791     TtkFillArrow(Tk_Display(tkwin), d, gc, b, arrowDirection);
792 }
793 
794 static Ttk_ElementSpec MenubuttonArrowElementSpec = {
795     TK_STYLE_VERSION_2,
796     sizeof(MenubuttonArrowElement),
797     MenubuttonArrowElementOptions,
798     MenubuttonArrowElementSize,
799     MenubuttonArrowElementDraw
800 };
801 
802 /*----------------------------------------------------------------------
803  * +++ Trough element
804  *
805  * Used in scrollbars and the scale.
806  *
807  * The -groovewidth option can be used to set the size of the short axis
808  * for the drawn area. This will not affect the geometry, but can be used
809  * to draw a thin centered trough inside the packet alloted. This is used
810  * to show a win32-style scale widget. Use -1 or a large number to use the
811  * full area (default).
812  *
813  */
814 
815 typedef struct {
816     Tcl_Obj *colorObj;
817     Tcl_Obj *borderWidthObj;
818     Tcl_Obj *reliefObj;
819     Tcl_Obj *grooveWidthObj;
820     Tcl_Obj *orientObj;
821 } TroughElement;
822 
823 static Ttk_ElementOptionSpec TroughElementOptions[] = {
824     { "-orient", TK_OPTION_ANY,
825 	Tk_Offset(TroughElement, orientObj), "horizontal" },
826     { "-troughborderwidth", TK_OPTION_PIXELS,
827 	Tk_Offset(TroughElement,borderWidthObj), "1" },
828     { "-troughcolor", TK_OPTION_BORDER,
829 	Tk_Offset(TroughElement,colorObj), DEFAULT_BACKGROUND },
830     { "-troughrelief",TK_OPTION_RELIEF,
831 	Tk_Offset(TroughElement,reliefObj), "sunken" },
832     { "-groovewidth", TK_OPTION_PIXELS,
833 	Tk_Offset(TroughElement,grooveWidthObj), "-1" },
834     { NULL, 0, 0, NULL }
835 };
836 
TroughElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)837 static void TroughElementSize(
838     void *clientData, void *elementRecord, Tk_Window tkwin,
839     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
840 {
841     TroughElement *troughPtr = elementRecord;
842     int borderWidth = 2, grooveWidth = 0;
843 
844     Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth);
845     Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->grooveWidthObj, &grooveWidth);
846 
847     if (grooveWidth <= 0) {
848 	*paddingPtr = Ttk_UniformPadding((short)borderWidth);
849     }
850 }
851 
TroughElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)852 static void TroughElementDraw(
853     void *clientData, void *elementRecord, Tk_Window tkwin,
854     Drawable d, Ttk_Box b, unsigned int state)
855 {
856     TroughElement *troughPtr = elementRecord;
857     Tk_3DBorder border = NULL;
858     int borderWidth = 2, relief = TK_RELIEF_SUNKEN, groove = -1, orient;
859 
860     border = Tk_Get3DBorderFromObj(tkwin, troughPtr->colorObj);
861     Ttk_GetOrientFromObj(NULL, troughPtr->orientObj, &orient);
862     Tk_GetReliefFromObj(NULL, troughPtr->reliefObj, &relief);
863     Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth);
864     Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->grooveWidthObj, &groove);
865 
866     if (groove != -1 && groove < b.height && groove < b.width) {
867 	if (orient == TTK_ORIENT_HORIZONTAL) {
868 	    b.y = b.y + b.height/2 - groove/2;
869 	    b.height = groove;
870 	} else {
871 	    b.x = b.x + b.width/2 - groove/2;
872 	    b.width = groove;
873 	}
874     }
875 
876     Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height,
877 	    borderWidth, relief);
878 }
879 
880 static Ttk_ElementSpec TroughElementSpec = {
881     TK_STYLE_VERSION_2,
882     sizeof(TroughElement),
883     TroughElementOptions,
884     TroughElementSize,
885     TroughElementDraw
886 };
887 
888 /*
889  *----------------------------------------------------------------------
890  * +++ Thumb element.
891  */
892 
893 typedef struct {
894     Tcl_Obj *sizeObj;
895     Tcl_Obj *firstObj;
896     Tcl_Obj *lastObj;
897     Tcl_Obj *borderObj;
898     Tcl_Obj *borderColorObj;
899     Tcl_Obj *reliefObj;
900     Tcl_Obj *orientObj;
901 } ThumbElement;
902 
903 static Ttk_ElementOptionSpec ThumbElementOptions[] = {
904     { "-width", TK_OPTION_PIXELS, Tk_Offset(ThumbElement,sizeObj),
905         STRINGIFY(SCROLLBAR_WIDTH) },
906     { "-background", TK_OPTION_BORDER, Tk_Offset(ThumbElement,borderObj),
907 	DEFAULT_BACKGROUND },
908     { "-bordercolor", TK_OPTION_COLOR, Tk_Offset(ThumbElement,borderColorObj),
909 	"black" },
910     { "-relief", TK_OPTION_RELIEF,Tk_Offset(ThumbElement,reliefObj),"raised" },
911     { "-orient", TK_OPTION_ANY,Tk_Offset(ThumbElement,orientObj),"horizontal"},
912     { NULL, 0, 0, NULL }
913 };
914 
ThumbElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)915 static void ThumbElementSize(
916     void *clientData, void *elementRecord, Tk_Window tkwin,
917     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
918 {
919     ThumbElement *thumb = elementRecord;
920     int orient, size;
921     Tk_GetPixelsFromObj(NULL, tkwin, thumb->sizeObj, &size);
922     Ttk_GetOrientFromObj(NULL, thumb->orientObj, &orient);
923 
924     if (orient == TTK_ORIENT_VERTICAL) {
925 	*widthPtr = size;
926 	*heightPtr = MIN_THUMB_SIZE;
927     } else {
928 	*widthPtr = MIN_THUMB_SIZE;
929 	*heightPtr = size;
930     }
931 }
932 
ThumbElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)933 static void ThumbElementDraw(
934     void *clientData, void *elementRecord, Tk_Window tkwin,
935     Drawable d, Ttk_Box b, unsigned int state)
936 {
937     ThumbElement *thumb = elementRecord;
938     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, thumb->borderObj);
939     XColor *borderColor = Tk_GetColorFromObj(tkwin, thumb->borderColorObj);
940     int relief = TK_RELIEF_RAISED;
941     int borderWidth = 2;
942 
943     /*
944      * Don't draw the thumb if we are disabled.
945      * This makes it behave like Windows ... if that's what we want.
946     if (state & TTK_STATE_DISABLED)
947 	return;
948      */
949 
950     Tk_GetReliefFromObj(NULL, thumb->reliefObj, &relief);
951 
952     Tk_Fill3DRectangle(
953 	tkwin, d, border, b.x,b.y,b.width,b.height, 0, TK_RELIEF_FLAT);
954     DrawBorder(tkwin, d, border, borderColor, b, borderWidth, relief);
955 }
956 
957 static Ttk_ElementSpec ThumbElementSpec = {
958     TK_STYLE_VERSION_2,
959     sizeof(ThumbElement),
960     ThumbElementOptions,
961     ThumbElementSize,
962     ThumbElementDraw
963 };
964 
965 /*
966  *----------------------------------------------------------------------
967  * +++ Slider element.
968  *
969  * This is the moving part of the scale widget.
970  *
971  * The slider element is the thumb in the scale widget. This is drawn
972  * as an arrow-type element that can point up, down, left or right.
973  *
974  */
975 
976 typedef struct {
977     Tcl_Obj *lengthObj;		/* Long axis dimension */
978     Tcl_Obj *thicknessObj;	/* Short axis dimension */
979     Tcl_Obj *reliefObj;		/* Relief for this object */
980     Tcl_Obj *borderObj;		/* Border / background color */
981     Tcl_Obj *borderColorObj;	/* Additional border color */
982     Tcl_Obj *borderWidthObj;
983     Tcl_Obj *orientObj;		/* Orientation of overall slider */
984 } SliderElement;
985 
986 static Ttk_ElementOptionSpec SliderElementOptions[] = {
987     { "-sliderlength", TK_OPTION_PIXELS, Tk_Offset(SliderElement,lengthObj),
988 	"15" },
989     { "-sliderthickness",TK_OPTION_PIXELS,Tk_Offset(SliderElement,thicknessObj),
990 	"15" },
991     { "-sliderrelief", TK_OPTION_RELIEF, Tk_Offset(SliderElement,reliefObj),
992 	"raised" },
993     { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(SliderElement,borderWidthObj),
994 	STRINGIFY(BORDERWIDTH) },
995     { "-background", TK_OPTION_BORDER, Tk_Offset(SliderElement,borderObj),
996 	DEFAULT_BACKGROUND },
997     { "-bordercolor", TK_OPTION_COLOR, Tk_Offset(ThumbElement,borderColorObj),
998 	"black" },
999     { "-orient", TK_OPTION_ANY, Tk_Offset(SliderElement,orientObj),
1000 	"horizontal" },
1001     { NULL, 0, 0, NULL }
1002 };
1003 
SliderElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)1004 static void SliderElementSize(
1005     void *clientData, void *elementRecord, Tk_Window tkwin,
1006     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1007 {
1008     SliderElement *slider = elementRecord;
1009     int orient, length, thickness, borderWidth;
1010 
1011     Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient);
1012     Tk_GetPixelsFromObj(NULL, tkwin, slider->borderWidthObj, &borderWidth);
1013     Tk_GetPixelsFromObj(NULL, tkwin, slider->lengthObj, &length);
1014     Tk_GetPixelsFromObj(NULL, tkwin, slider->thicknessObj, &thickness);
1015 
1016     switch (orient) {
1017 	case TTK_ORIENT_VERTICAL:
1018 	    *widthPtr = thickness + (borderWidth *2);
1019 	    *heightPtr = *widthPtr/2;
1020 	    break;
1021 
1022 	case TTK_ORIENT_HORIZONTAL:
1023 	    *heightPtr = thickness + (borderWidth *2);
1024 	    *widthPtr = *heightPtr/2;
1025 	    break;
1026     }
1027 }
1028 
SliderElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)1029 static void SliderElementDraw(
1030     void *clientData, void *elementRecord, Tk_Window tkwin,
1031     Drawable d, Ttk_Box b, unsigned int state)
1032 {
1033     SliderElement *slider = elementRecord;
1034     Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, slider->borderObj);
1035     XColor *borderColor = Tk_GetColorFromObj(tkwin, slider->borderColorObj);
1036     int relief = TK_RELIEF_RAISED, borderWidth = 2;
1037 
1038     Tk_GetPixelsFromObj(NULL, tkwin, slider->borderWidthObj, &borderWidth);
1039     Tk_GetReliefFromObj(NULL, slider->reliefObj, &relief);
1040 
1041     Tk_Fill3DRectangle(tkwin, d, border,
1042 	b.x, b.y, b.width, b.height,
1043 	borderWidth, TK_RELIEF_FLAT);
1044     DrawBorder(tkwin, d, border, borderColor, b, borderWidth, relief);
1045 }
1046 
1047 static Ttk_ElementSpec SliderElementSpec = {
1048     TK_STYLE_VERSION_2,
1049     sizeof(SliderElement),
1050     SliderElementOptions,
1051     SliderElementSize,
1052     SliderElementDraw
1053 };
1054 
1055 /*------------------------------------------------------------------------
1056  * +++ Tree indicator element.
1057  */
1058 
1059 #define TTK_STATE_OPEN TTK_STATE_USER1		/* XREF: treeview.c */
1060 #define TTK_STATE_LEAF TTK_STATE_USER2
1061 
1062 typedef struct {
1063     Tcl_Obj *colorObj;
1064     Tcl_Obj *marginObj;
1065     Tcl_Obj *diameterObj;
1066 } TreeitemIndicator;
1067 
1068 static Ttk_ElementOptionSpec TreeitemIndicatorOptions[] = {
1069     { "-foreground", TK_OPTION_COLOR,
1070 	Tk_Offset(TreeitemIndicator,colorObj), DEFAULT_FOREGROUND },
1071     { "-diameter", TK_OPTION_PIXELS,
1072 	Tk_Offset(TreeitemIndicator,diameterObj), "9" },
1073     { "-indicatormargins", TK_OPTION_STRING,
1074 	Tk_Offset(TreeitemIndicator,marginObj), "2 2 4 2" },
1075     { NULL, 0, 0, NULL }
1076 };
1077 
TreeitemIndicatorSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)1078 static void TreeitemIndicatorSize(
1079     void *clientData, void *elementRecord, Tk_Window tkwin,
1080     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1081 {
1082     TreeitemIndicator *indicator = elementRecord;
1083     int diameter = 0;
1084     Ttk_Padding margins;
1085 
1086     Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
1087     Tk_GetPixelsFromObj(NULL, tkwin, indicator->diameterObj, &diameter);
1088     *widthPtr = diameter + Ttk_PaddingWidth(margins);
1089     *heightPtr = diameter + Ttk_PaddingHeight(margins);
1090 }
1091 
TreeitemIndicatorDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,Ttk_State state)1092 static void TreeitemIndicatorDraw(
1093     void *clientData, void *elementRecord, Tk_Window tkwin,
1094     Drawable d, Ttk_Box b, Ttk_State state)
1095 {
1096     TreeitemIndicator *indicator = elementRecord;
1097     XColor *color = Tk_GetColorFromObj(tkwin, indicator->colorObj);
1098     GC gc = Tk_GCForColor(color, d);
1099     Ttk_Padding padding = Ttk_UniformPadding(0);
1100     int w = WIN32_XDRAWLINE_HACK;
1101     int cx, cy;
1102 
1103     if (state & TTK_STATE_LEAF) {
1104 	/* don't draw anything ... */
1105 	return;
1106     }
1107 
1108     Ttk_GetPaddingFromObj(NULL,tkwin,indicator->marginObj,&padding);
1109     b = Ttk_PadBox(b, padding);
1110 
1111     XDrawRectangle(Tk_Display(tkwin), d, gc,
1112 	    b.x, b.y, b.width - 1, b.height - 1);
1113 
1114     cx = b.x + (b.width - 1) / 2;
1115     cy = b.y + (b.height - 1) / 2;
1116     XDrawLine(Tk_Display(tkwin), d, gc, b.x+2, cy, b.x+b.width-3+w, cy);
1117 
1118     if (!(state & TTK_STATE_OPEN)) {
1119 	/* turn '-' into a '+' */
1120 	XDrawLine(Tk_Display(tkwin), d, gc, cx, b.y+2, cx, b.y+b.height-3+w);
1121     }
1122 }
1123 
1124 static Ttk_ElementSpec TreeitemIndicatorElementSpec = {
1125     TK_STYLE_VERSION_2,
1126     sizeof(TreeitemIndicator),
1127     TreeitemIndicatorOptions,
1128     TreeitemIndicatorSize,
1129     TreeitemIndicatorDraw
1130 };
1131 
1132 /*------------------------------------------------------------------------
1133  * TtkAltTheme_Init --
1134  * 	Install alternate theme.
1135  */
TtkAltTheme_Init(Tcl_Interp * interp)1136 MODULE_SCOPE int TtkAltTheme_Init(Tcl_Interp *interp)
1137 {
1138     Ttk_Theme theme =  Ttk_CreateTheme(interp, "alt", NULL);
1139 
1140     if (!theme) {
1141 	return TCL_ERROR;
1142     }
1143 
1144     Ttk_RegisterElement(interp, theme, "border", &BorderElementSpec, NULL);
1145 
1146     Ttk_RegisterElement(interp, theme, "Checkbutton.indicator",
1147 	    &IndicatorElementSpec, &checkbutton_spec);
1148     Ttk_RegisterElement(interp, theme, "Radiobutton.indicator",
1149 	    &IndicatorElementSpec, &radiobutton_spec);
1150     Ttk_RegisterElement(interp, theme, "Menubutton.indicator",
1151 	    &MenubuttonArrowElementSpec, NULL);
1152 
1153     Ttk_RegisterElement(interp, theme, "field", &FieldElementSpec, NULL);
1154 
1155     Ttk_RegisterElement(interp, theme, "trough", &TroughElementSpec, NULL);
1156     Ttk_RegisterElement(interp, theme, "thumb", &ThumbElementSpec, NULL);
1157     Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL);
1158 
1159     Ttk_RegisterElement(interp, theme, "uparrow",
1160 	    &ArrowElementSpec, &ArrowElements[0]);
1161     Ttk_RegisterElement(interp, theme, "downarrow",
1162 	    &ArrowElementSpec, &ArrowElements[1]);
1163     Ttk_RegisterElement(interp, theme, "leftarrow",
1164 	    &ArrowElementSpec, &ArrowElements[2]);
1165     Ttk_RegisterElement(interp, theme, "rightarrow",
1166 	    &ArrowElementSpec, &ArrowElements[3]);
1167     Ttk_RegisterElement(interp, theme, "arrow",
1168 	    &ArrowElementSpec, &ArrowElements[0]);
1169 
1170     Ttk_RegisterElement(interp, theme, "arrow",
1171 	    &ArrowElementSpec, &ArrowElements[0]);
1172 
1173     Ttk_RegisterElement(interp, theme, "Treeitem.indicator",
1174 	    &TreeitemIndicatorElementSpec, 0);
1175 
1176     Tcl_PkgProvide(interp, "ttk::theme::alt", TTK_VERSION);
1177 
1178     return TCL_OK;
1179 }
1180 
1181 /*EOF*/
1182