1 /* winTheme.c - Copyright © 2004 Pat Thoyts <patthoyts@users.sf.net>
2  */
3 
4 #ifdef _MSC_VER
5 #define WIN32_LEAN_AND_MEAN
6 #endif
7 
8 #include <tkWinInt.h>
9 
10 #ifndef DFCS_HOT	/* Windows 98/Me, Windows 2000/XP only */
11 #define DFCS_HOT 0
12 #endif
13 
14 #include "ttk/ttkTheme.h"
15 
16 /*
17  * BoxToRect --
18  * 	Helper routine.  Converts a Ttk_Box to a Win32 RECT.
19  */
BoxToRect(Ttk_Box b)20 static RECT BoxToRect(Ttk_Box b)
21 {
22     RECT rc;
23     rc.top = b.y;
24     rc.left = b.x;
25     rc.bottom = b.y + b.height;
26     rc.right = b.x + b.width;
27     return rc;
28 }
29 
30 /*
31  * ReliefToEdge --
32  * 	Convert a Tk "relief" value into an Windows "edge" value.
33  * 	NB: Caller must check for RELIEF_FLAT and RELIEF_SOLID,
34  *	which must be handled specially.
35  *
36  *	Passing the BF_FLAT flag to DrawEdge() yields something similar
37  * 	to TK_RELIEF_SOLID. TK_RELIEF_FLAT can be implemented by not
38  *	drawing anything.
39  */
ReliefToEdge(int relief)40 static unsigned int ReliefToEdge(int relief)
41 {
42     switch (relief) {
43 	case TK_RELIEF_RAISED: return EDGE_RAISED;
44 	case TK_RELIEF_SUNKEN: return EDGE_SUNKEN;
45 	case TK_RELIEF_RIDGE:  return EDGE_BUMP;
46 	case TK_RELIEF_GROOVE: return EDGE_ETCHED;
47 	case TK_RELIEF_SOLID:  return BDR_RAISEDOUTER;
48 	default:
49 	case TK_RELIEF_FLAT:   return BDR_RAISEDOUTER;
50     }
51 }
52 
53 /*------------------------------------------------------------------------
54  * +++ State tables for FrameControlElements.
55  */
56 
57 static const Ttk_StateTable checkbutton_statemap[] = { /* see also SF#1865898 */
58     { DFCS_BUTTON3STATE|DFCS_CHECKED|DFCS_INACTIVE,
59     	TTK_STATE_ALTERNATE|TTK_STATE_DISABLED, 0 },
60     { DFCS_BUTTON3STATE|DFCS_CHECKED|DFCS_PUSHED,
61     	TTK_STATE_ALTERNATE|TTK_STATE_PRESSED, 0 },
62     { DFCS_BUTTON3STATE|DFCS_CHECKED|DFCS_HOT,
63     	TTK_STATE_ALTERNATE|TTK_STATE_ACTIVE, 0 },
64     { DFCS_BUTTON3STATE|DFCS_CHECKED,
65     	TTK_STATE_ALTERNATE, 0 },
66 
67     { DFCS_CHECKED|DFCS_INACTIVE, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0 },
68     { DFCS_CHECKED|DFCS_PUSHED,   TTK_STATE_SELECTED|TTK_STATE_PRESSED, 0 },
69     { DFCS_CHECKED|DFCS_HOT,      TTK_STATE_SELECTED|TTK_STATE_ACTIVE, 0 },
70     { DFCS_CHECKED,	          TTK_STATE_SELECTED, 0 },
71 
72     { DFCS_INACTIVE, TTK_STATE_DISABLED, 0 },
73     { DFCS_PUSHED,   TTK_STATE_PRESSED, 0 },
74     { DFCS_HOT,      TTK_STATE_ACTIVE, 0 },
75     { 0, 0, 0 },
76 };
77 
78 static const Ttk_StateTable pushbutton_statemap[] = {
79     { DFCS_INACTIVE,	  TTK_STATE_DISABLED, 0 },
80     { DFCS_PUSHED,	  TTK_STATE_PRESSED, 0 },
81     { DFCS_HOT,		  TTK_STATE_ACTIVE, 0 },
82     { 0, 0, 0 }
83 };
84 
85 static const Ttk_StateTable arrow_statemap[] = {
86     { DFCS_INACTIVE,            TTK_STATE_DISABLED, 0 },
87     { DFCS_PUSHED | DFCS_FLAT,  TTK_STATE_PRESSED,  0 },
88     { 0, 0, 0 }
89 };
90 
91 /*------------------------------------------------------------------------
92  * +++ FrameControlElement --
93  * 	General-purpose element for things drawn with DrawFrameControl
94  */
95 typedef struct {
96     const char *name;		/* element name */
97     int classId;		/* class id for DrawFrameControl */
98     int partId;			/* part id for DrawFrameControl  */
99     unsigned cxId;			/* system metric ids for width/height... */
100     unsigned cyId;			/* ... or size if FIXEDSIZE bit set */
101     const Ttk_StateTable *stateMap;	/* map Tk states to Win32 flags */
102     Ttk_Padding margins;	/* additional placement padding */
103 } FrameControlElementData;
104 
105 #define _FIXEDSIZE  0x80000000UL
106 #define _HALFMETRIC 0x40000000UL
107 #define FIXEDSIZE(id) (id|_FIXEDSIZE)
108 #define HALFMETRIC(id) (id|_HALFMETRIC)
109 #define GETMETRIC(m) \
110     ((m) & _FIXEDSIZE ? (int)((m) & ~_FIXEDSIZE) : GetSystemMetrics((m)&0xFFFFFFF))
111 
112 static const FrameControlElementData FrameControlElements[] = {
113     { "Checkbutton.indicator",
114 	DFC_BUTTON, DFCS_BUTTONCHECK, FIXEDSIZE(13), FIXEDSIZE(13),
115 	checkbutton_statemap, {0,0,4,0} },
116     { "Radiobutton.indicator",
117     	DFC_BUTTON, DFCS_BUTTONRADIO, FIXEDSIZE(13), FIXEDSIZE(13),
118 	checkbutton_statemap, {0,0,4,0} },
119     { "uparrow",
120     	DFC_SCROLL, DFCS_SCROLLUP, SM_CXVSCROLL, SM_CYVSCROLL,
121 	arrow_statemap, {0,0,0,0} },
122     { "downarrow",
123     	DFC_SCROLL, DFCS_SCROLLDOWN, SM_CXVSCROLL, SM_CYVSCROLL,
124 	arrow_statemap, {0,0,0,0} },
125     { "leftarrow",
126 	DFC_SCROLL, DFCS_SCROLLLEFT, SM_CXHSCROLL, SM_CYHSCROLL,
127 	arrow_statemap, {0,0,0,0} },
128     { "rightarrow",
129 	DFC_SCROLL, DFCS_SCROLLRIGHT, SM_CXHSCROLL, SM_CYHSCROLL,
130 	arrow_statemap, {0,0,0,0} },
131     { "sizegrip",
132     	DFC_SCROLL, DFCS_SCROLLSIZEGRIP, SM_CXVSCROLL, SM_CYHSCROLL,
133 	arrow_statemap, {0,0,0,0} },
134     { "Spinbox.uparrow",
135 	DFC_SCROLL, DFCS_SCROLLUP, SM_CXVSCROLL, HALFMETRIC(SM_CYVSCROLL),
136 	arrow_statemap, {0,0,0,0} },
137     { "Spinbox.downarrow",
138 	DFC_SCROLL, DFCS_SCROLLDOWN, SM_CXVSCROLL, HALFMETRIC(SM_CYVSCROLL),
139 	arrow_statemap, {0,0,0,0} },
140 
141     { 0,0,0,0,0,0, {0,0,0,0} }
142 };
143 
144 /* ---------------------------------------------------------------------- */
145 
FrameControlElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)146 static void FrameControlElementSize(
147     void *clientData, void *elementRecord, Tk_Window tkwin,
148     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
149 {
150     FrameControlElementData *p = (FrameControlElementData *)clientData;
151     int cx = GETMETRIC(p->cxId);
152     int cy = GETMETRIC(p->cyId);
153     (void)elementRecord;
154     (void)tkwin;
155     (void)paddingPtr;
156 
157     if (p->cxId & _HALFMETRIC) cx /= 2;
158     if (p->cyId & _HALFMETRIC) cy /= 2;
159     *widthPtr = cx + Ttk_PaddingWidth(p->margins);
160     *heightPtr = cy + Ttk_PaddingHeight(p->margins);
161 }
162 
FrameControlElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)163 static void FrameControlElementDraw(
164     void *clientData, void *elementRecord, Tk_Window tkwin,
165     Drawable d, Ttk_Box b, unsigned int state)
166 {
167     FrameControlElementData *elementData = (FrameControlElementData *)clientData;
168     RECT rc = BoxToRect(Ttk_PadBox(b, elementData->margins));
169     TkWinDCState dcState;
170     HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
171     (void)elementRecord;
172 
173     DrawFrameControl(hdc, &rc,
174 	elementData->classId,
175 	elementData->partId|Ttk_StateTableLookup(elementData->stateMap, state));
176     TkWinReleaseDrawableDC(d, hdc, &dcState);
177 }
178 
179 static const Ttk_ElementSpec FrameControlElementSpec = {
180     TK_STYLE_VERSION_2,
181     sizeof(NullElement),
182     TtkNullElementOptions,
183     FrameControlElementSize,
184     FrameControlElementDraw
185 };
186 
187 /*----------------------------------------------------------------------
188  * +++ Border element implementation.
189  */
190 
191 typedef struct {
192     Tcl_Obj	*reliefObj;
193 } BorderElement;
194 
195 static const Ttk_ElementOptionSpec BorderElementOptions[] = {
196     { "-relief",TK_OPTION_RELIEF, offsetof(BorderElement,reliefObj), "flat" },
197     {NULL, TK_OPTION_BOOLEAN, 0, NULL}
198 };
199 
BorderElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)200 static void BorderElementSize(
201     void *dummy, void *elementRecord, Tk_Window tkwin,
202     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
203 {
204     (void)dummy;
205     (void)elementRecord;
206     (void)tkwin;
207     (void)widthPtr;
208     (void)heightPtr;
209 
210     paddingPtr->left = paddingPtr->right = GetSystemMetrics(SM_CXEDGE);
211     paddingPtr->top = paddingPtr->bottom = GetSystemMetrics(SM_CYEDGE);
212 }
213 
BorderElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)214 static void BorderElementDraw(
215     void *dummy, void *elementRecord, Tk_Window tkwin,
216     Drawable d, Ttk_Box b, unsigned int state)
217 {
218     BorderElement *border = (BorderElement *)elementRecord;
219     RECT rc = BoxToRect(b);
220     int relief = TK_RELIEF_FLAT;
221     TkWinDCState dcState;
222     HDC hdc;
223     (void)dummy;
224     (void)state;
225 
226     Tk_GetReliefFromObj(NULL, border->reliefObj, &relief);
227 
228     if (relief != TK_RELIEF_FLAT) {
229 	UINT xFlags = (relief == TK_RELIEF_SOLID) ? BF_FLAT : 0;
230 	hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
231 	DrawEdge(hdc, &rc, ReliefToEdge(relief), BF_RECT | xFlags);
232 	TkWinReleaseDrawableDC(d, hdc, &dcState);
233     }
234 }
235 
236 static const Ttk_ElementSpec BorderElementSpec = {
237     TK_STYLE_VERSION_2,
238     sizeof(BorderElement),
239     BorderElementOptions,
240     BorderElementSize,
241     BorderElementDraw
242 };
243 
244 /*
245  * Entry field borders:
246  * Sunken border; also fill with window color.
247  */
248 
249 typedef struct {
250     Tcl_Obj	*backgroundObj;
251 } FieldElement;
252 
253 static const Ttk_ElementOptionSpec FieldElementOptions[] = {
254     { "-fieldbackground", TK_OPTION_BORDER,
255     	offsetof(FieldElement,backgroundObj), "white" },
256     { NULL, TK_OPTION_BOOLEAN, 0, NULL }
257 };
258 
FieldElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)259 static void FieldElementSize(
260     void *dummy, void *elementRecord, Tk_Window tkwin,
261     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
262 {
263     (void)dummy;
264     (void)elementRecord;
265     (void)tkwin;
266     (void)widthPtr;
267     (void)heightPtr;
268 
269     paddingPtr->left = paddingPtr->right = GetSystemMetrics(SM_CXEDGE);
270     paddingPtr->top = paddingPtr->bottom = GetSystemMetrics(SM_CYEDGE);
271 }
272 
FieldElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)273 static void FieldElementDraw(
274     void *dummy, void *elementRecord, Tk_Window tkwin,
275     Drawable d, Ttk_Box b, unsigned int state)
276 {
277     FieldElement *field = (FieldElement *)elementRecord;
278     Tk_3DBorder bg = Tk_Get3DBorderFromObj(tkwin, field->backgroundObj);
279     RECT rc = BoxToRect(b);
280     TkWinDCState dcState;
281     HDC hdc;
282     (void)dummy;
283     (void)state;
284 
285     Tk_Fill3DRectangle(
286 	tkwin, d, bg, b.x, b.y, b.width, b.height, 0, TK_RELIEF_FLAT);
287 
288     hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
289     DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT);
290     TkWinReleaseDrawableDC(d, hdc, &dcState);
291 }
292 
293 static const Ttk_ElementSpec FieldElementSpec = {
294     TK_STYLE_VERSION_2,
295     sizeof(FieldElement),
296     FieldElementOptions,
297     FieldElementSize,
298     FieldElementDraw
299 };
300 
301 /*------------------------------------------------------------------------
302  * +++ Button borders.
303  *	Drawn with DrawFrameControl instead of DrawEdge;
304  *	Also draw default indicator and focus ring.
305  */
306 typedef struct {
307     Tcl_Obj	*reliefObj;
308     Tcl_Obj	*highlightColorObj;
309     Tcl_Obj	*defaultStateObj;
310 } ButtonBorderElement;
311 
312 static const Ttk_ElementOptionSpec ButtonBorderElementOptions[] = {
313     { "-relief",TK_OPTION_RELIEF,
314 	offsetof(ButtonBorderElement,reliefObj), "flat" },
315     { "-highlightcolor",TK_OPTION_COLOR,
316 	offsetof(ButtonBorderElement,highlightColorObj), "black" },
317     { "-default", TK_OPTION_ANY,
318 	offsetof(ButtonBorderElement,defaultStateObj), "disabled" },
319     {NULL, TK_OPTION_BOOLEAN, 0, NULL}
320 };
321 
ButtonBorderElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)322 static void ButtonBorderElementSize(
323     void *dummy, void *elementRecord, Tk_Window tkwin,
324     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
325 {
326     ButtonBorderElement *bd = (ButtonBorderElement *)elementRecord;
327     int relief = TK_RELIEF_RAISED;
328     Ttk_ButtonDefaultState defaultState = TTK_BUTTON_DEFAULT_DISABLED;
329     short int cx, cy;
330     (void)dummy;
331     (void)tkwin;
332     (void)widthPtr;
333     (void)heightPtr;
334 
335     Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
336     Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
337     cx = GetSystemMetrics(SM_CXEDGE);
338     cy = GetSystemMetrics(SM_CYEDGE);
339 
340     /* Space for default indicator:
341      */
342     if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
343     	++cx; ++cy;
344     }
345 
346     /* Space for focus ring:
347      */
348     cx += 2;
349     cy += 2;
350 
351     *paddingPtr = Ttk_MakePadding(cx,cy,cx,cy);
352 }
353 
ButtonBorderElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)354 static void ButtonBorderElementDraw(
355     void *dummy, void *elementRecord, Tk_Window tkwin,
356     Drawable d, Ttk_Box b, unsigned int state)
357 {
358     ButtonBorderElement *bd = (ButtonBorderElement *)elementRecord;
359     int relief = TK_RELIEF_FLAT;
360     Ttk_ButtonDefaultState defaultState = TTK_BUTTON_DEFAULT_DISABLED;
361     TkWinDCState dcState;
362     HDC hdc;
363     RECT rc;
364     (void)dummy;
365 
366     Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
367     Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
368 
369     if (defaultState == TTK_BUTTON_DEFAULT_ACTIVE) {
370 	XColor *highlightColor =
371 	    Tk_GetColorFromObj(tkwin, bd->highlightColorObj);
372 	GC gc = Tk_GCForColor(highlightColor, d);
373 	XDrawRectangle(Tk_Display(tkwin), d, gc, b.x,b.y,b.width-1,b.height-1);
374     }
375     if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
376 	++b.x; ++b.y; b.width -= 2; b.height -= 2;
377     }
378 
379     hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
380 
381     rc = BoxToRect(b);
382     DrawFrameControl(hdc, &rc,
383 	DFC_BUTTON,	/* classId */
384 	DFCS_BUTTONPUSH | Ttk_StateTableLookup(pushbutton_statemap, state));
385 
386     /* Draw focus ring:
387      */
388     if (state & TTK_STATE_FOCUS) {
389 	short int borderWidth = 3;	/* @@@ Use GetSystemMetrics?*/
390 	rc = BoxToRect(Ttk_PadBox(b, Ttk_UniformPadding(borderWidth)));
391     	DrawFocusRect(hdc, &rc);
392     }
393     TkWinReleaseDrawableDC(d, hdc, &dcState);
394 }
395 
396 static const Ttk_ElementSpec ButtonBorderElementSpec = {
397     TK_STYLE_VERSION_2,
398     sizeof(ButtonBorderElement),
399     ButtonBorderElementOptions,
400     ButtonBorderElementSize,
401     ButtonBorderElementDraw
402 };
403 
404 /*------------------------------------------------------------------------
405  * +++ Focus element.
406  * 	Draw dashed focus rectangle.
407  */
408 
FocusElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)409 static void FocusElementSize(
410     void *dummy, void *elementRecord, Tk_Window tkwin,
411     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
412 {
413     (void)dummy;
414     (void)elementRecord;
415     (void)tkwin;
416     (void)widthPtr;
417     (void)heightPtr;
418 
419     *paddingPtr = Ttk_UniformPadding(1);
420 }
421 
FocusElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)422 static void FocusElementDraw(
423     void *dummy, void *elementRecord, Tk_Window tkwin,
424     Drawable d, Ttk_Box b, unsigned int state)
425 {
426     (void)dummy;
427     (void)elementRecord;
428 
429     if (state & TTK_STATE_FOCUS) {
430 	RECT rc = BoxToRect(b);
431 	TkWinDCState dcState;
432 	HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
433     	DrawFocusRect(hdc, &rc);
434 	TkWinReleaseDrawableDC(d, hdc, &dcState);
435     }
436 }
437 
438 static const Ttk_ElementSpec FocusElementSpec = {
439     TK_STYLE_VERSION_2,
440     sizeof(NullElement),
441     TtkNullElementOptions,
442     FocusElementSize,
443     FocusElementDraw
444 };
445 
446 /* FillFocusElement --
447  * 	Draws a focus ring filled with the selection color
448  */
449 
450 typedef struct {
451     Tcl_Obj *fillColorObj;
452 } FillFocusElement;
453 
454 static const Ttk_ElementOptionSpec FillFocusElementOptions[] = {
455     { "-focusfill", TK_OPTION_COLOR,
456 	offsetof(FillFocusElement,fillColorObj), "white" },
457     {NULL, TK_OPTION_BOOLEAN, 0, NULL}
458 };
459 
460 	/* @@@ FIX THIS */
FillFocusElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)461 static void FillFocusElementDraw(
462     void *dummy, void *elementRecord, Tk_Window tkwin,
463     Drawable d, Ttk_Box b, unsigned int state)
464 {
465     FillFocusElement *focus = (FillFocusElement *)elementRecord;
466     (void)dummy;
467 
468     if (state & TTK_STATE_FOCUS) {
469 	RECT rc = BoxToRect(b);
470 	TkWinDCState dcState;
471 	XColor *fillColor = Tk_GetColorFromObj(tkwin, focus->fillColorObj);
472 	GC gc = Tk_GCForColor(fillColor, d);
473 	HDC hdc;
474 
475 	XFillRectangle(Tk_Display(tkwin),d,gc, b.x,b.y,b.width,b.height);
476 	hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
477     	DrawFocusRect(hdc, &rc);
478 	TkWinReleaseDrawableDC(d, hdc, &dcState);
479     }
480 }
481 
482 /*
483  * ComboboxFocusElement --
484  * 	Read-only comboboxes have a filled focus ring, editable ones do not.
485  */
ComboboxFocusElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)486 static void ComboboxFocusElementDraw(
487     void *clientData, void *elementRecord, Tk_Window tkwin,
488     Drawable d, Ttk_Box b, unsigned int state)
489 {
490     if (state & TTK_STATE_READONLY) {
491     	FillFocusElementDraw(clientData, elementRecord, tkwin, d, b, state);
492     }
493 }
494 
495 static const Ttk_ElementSpec ComboboxFocusElementSpec = {
496     TK_STYLE_VERSION_2,
497     sizeof(FillFocusElement),
498     FillFocusElementOptions,
499     FocusElementSize,
500     ComboboxFocusElementDraw
501 };
502 
503 /*----------------------------------------------------------------------
504  * +++ Scrollbar trough element.
505  *
506  * The native windows scrollbar is drawn using a pattern brush giving a
507  * stippled appearance when the trough might otherwise be invisible.
508  * We can deal with this here.
509  */
510 
511 typedef struct {	/* clientData for Trough element */
512     HBRUSH     PatternBrush;
513     HBITMAP    PatternBitmap;
514 } TroughClientData;
515 
516 static const WORD Pattern[] = {
517     0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa
518 };
519 
TroughClientDataDeleteProc(void * clientData)520 static void TroughClientDataDeleteProc(void *clientData)
521 {
522     TroughClientData *cd = (TroughClientData *)clientData;
523     DeleteObject(cd->PatternBrush);
524     DeleteObject(cd->PatternBitmap);
525     ckfree(clientData);
526 }
527 
TroughClientDataInit(Tcl_Interp * interp)528 static TroughClientData *TroughClientDataInit(Tcl_Interp *interp)
529 {
530     TroughClientData *cd = (TroughClientData *)ckalloc(sizeof(*cd));
531     cd->PatternBitmap = CreateBitmap(8, 8, 1, 1, Pattern);
532     cd->PatternBrush  = CreatePatternBrush(cd->PatternBitmap);
533     Ttk_RegisterCleanup(interp, cd, TroughClientDataDeleteProc);
534     return cd;
535 }
536 
TroughElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)537 static void TroughElementDraw(
538     void *clientData, void *elementRecord, Tk_Window tkwin,
539     Drawable d, Ttk_Box b, unsigned int state)
540 {
541     TroughClientData *cd = (TroughClientData *)clientData;
542     TkWinDCState dcState;
543     HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
544     HBRUSH hbr;
545     COLORREF bk, oldbk, oldtxt;
546     (void)elementRecord;
547     (void)state;
548 
549     hbr = (HBRUSH)SelectObject(hdc, GetSysColorBrush(COLOR_SCROLLBAR));
550     bk = GetSysColor(COLOR_3DHIGHLIGHT);
551     oldtxt = SetTextColor(hdc, GetSysColor(COLOR_3DFACE));
552     oldbk = SetBkColor(hdc, bk);
553 
554     /* WAS: if (bk (COLOR_3DHIGHLIGHT) == GetSysColor(COLOR_WINDOW)) ... */
555     if (GetSysColor(COLOR_SCROLLBAR) == GetSysColor(COLOR_BTNFACE)) {
556 	/* Draw using the pattern brush */
557 	SelectObject(hdc, cd->PatternBrush);
558     }
559 
560     PatBlt(hdc, b.x, b.y, b.width, b.height, PATCOPY);
561     SetBkColor(hdc, oldbk);
562     SetTextColor(hdc, oldtxt);
563     SelectObject(hdc, hbr);
564     TkWinReleaseDrawableDC(d, hdc, &dcState);
565 }
566 
567 static const Ttk_ElementSpec TroughElementSpec = {
568     TK_STYLE_VERSION_2,
569     sizeof(NullElement),
570     TtkNullElementOptions,
571     TtkNullElementSize,
572     TroughElementDraw
573 };
574 
575 /*------------------------------------------------------------------------
576  * +++ Thumb element.
577  */
578 
579 typedef struct {
580     Tcl_Obj *orientObj;
581 } ThumbElement;
582 
583 static const Ttk_ElementOptionSpec ThumbElementOptions[] = {
584     { "-orient", TK_OPTION_ANY, offsetof(ThumbElement,orientObj),"horizontal"},
585     { NULL, TK_OPTION_BOOLEAN, 0, NULL }
586 };
587 
ThumbElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)588 static void ThumbElementSize(
589     void *dummy, void *elementRecord, Tk_Window tkwin,
590     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
591 {
592     ThumbElement *thumbPtr = (ThumbElement *)elementRecord;
593     Ttk_Orient orient;
594     (void)dummy;
595     (void)tkwin;
596     (void)paddingPtr;
597 
598     TtkGetOrientFromObj(NULL, thumbPtr->orientObj, &orient);
599     if (orient == TTK_ORIENT_HORIZONTAL) {
600 	*widthPtr = GetSystemMetrics(SM_CXHTHUMB);
601 	*heightPtr = GetSystemMetrics(SM_CYHSCROLL);
602     } else {
603 	*widthPtr = GetSystemMetrics(SM_CXVSCROLL);
604 	*heightPtr = GetSystemMetrics(SM_CYVTHUMB);
605     }
606 }
607 
ThumbElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)608 static void ThumbElementDraw(
609     void *dummy, void *elementRecord, Tk_Window tkwin,
610     Drawable d, Ttk_Box b, unsigned int state)
611 {
612     RECT rc = BoxToRect(b);
613     TkWinDCState dcState;
614     HDC hdc;
615     (void)dummy;
616     (void)elementRecord;
617 
618     /* Windows doesn't show a thumb when the scrollbar is disabled */
619     if (state & TTK_STATE_DISABLED)
620 	return;
621 
622     hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
623     DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_MIDDLE);
624     TkWinReleaseDrawableDC(d, hdc, &dcState);
625 }
626 
627 static const Ttk_ElementSpec ThumbElementSpec = {
628     TK_STYLE_VERSION_2,
629     sizeof(ThumbElement),
630     ThumbElementOptions,
631     ThumbElementSize,
632     ThumbElementDraw
633 };
634 
635 /* ----------------------------------------------------------------------
636  * The slider element is the shaped thumb used in the slider widget.
637  * Windows likes to call this a trackbar.
638  */
639 
640 typedef struct {
641     Tcl_Obj *orientObj;  /* orientation of the slider widget */
642 } SliderElement;
643 
644 static const Ttk_ElementOptionSpec SliderElementOptions[] = {
645     { "-orient", TK_OPTION_ANY, offsetof(SliderElement,orientObj),
646       "horizontal" },
647       { NULL, TK_OPTION_BOOLEAN, 0, NULL }
648 };
649 
SliderElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)650 static void SliderElementSize(
651     void *dummy, void *elementRecord, Tk_Window tkwin,
652     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
653 {
654     SliderElement *slider = (SliderElement *)elementRecord;
655     Ttk_Orient orient;
656     (void)dummy;
657     (void)tkwin;
658     (void)paddingPtr;
659 
660     TtkGetOrientFromObj(NULL, slider->orientObj, &orient);
661     if (orient == TTK_ORIENT_HORIZONTAL) {
662 	*widthPtr = (GetSystemMetrics(SM_CXHTHUMB) / 2) | 1;
663 	*heightPtr = GetSystemMetrics(SM_CYHSCROLL);
664     } else {
665 	*widthPtr = GetSystemMetrics(SM_CXVSCROLL);
666 	*heightPtr = (GetSystemMetrics(SM_CYVTHUMB) / 2) | 1;
667     }
668 }
669 
SliderElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)670 static void SliderElementDraw(
671     void *dummy, void *elementRecord, Tk_Window tkwin,
672     Drawable d, Ttk_Box b, unsigned int state)
673 {
674     RECT rc = BoxToRect(b);
675     TkWinDCState dcState;
676     HDC hdc;
677     (void)dummy;
678     (void)elementRecord;
679     (void)state;
680 
681     hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
682     DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_MIDDLE);
683     TkWinReleaseDrawableDC(d, hdc, &dcState);
684 }
685 
686 static const Ttk_ElementSpec SliderElementSpec = {
687     TK_STYLE_VERSION_2,
688     sizeof(SliderElement),
689     SliderElementOptions,
690     SliderElementSize,
691     SliderElementDraw
692 };
693 
694 /*------------------------------------------------------------------------
695  * +++ Notebook elements.
696  */
697 
ClientElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)698 static void ClientElementSize(
699     void *dummy, void *elementRecord, Tk_Window tkwin,
700     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
701 {
702     (void)dummy;
703     (void)elementRecord;
704     (void)tkwin;
705     (void)widthPtr;
706     (void)heightPtr;
707 
708     paddingPtr->left = paddingPtr->right = GetSystemMetrics(SM_CXEDGE);
709     paddingPtr->top = paddingPtr->bottom = GetSystemMetrics(SM_CYEDGE);
710 }
711 
ClientElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)712 static void ClientElementDraw(
713     void *dummy, void *elementRecord, Tk_Window tkwin,
714     Drawable d, Ttk_Box b, unsigned int state)
715 {
716     RECT rc = BoxToRect(b);
717     TkWinDCState dcState;
718     HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
719     (void)dummy;
720     (void)elementRecord;
721     (void)state;
722 
723     DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_SOFT);
724     TkWinReleaseDrawableDC(d, hdc, &dcState);
725 }
726 
727 static const Ttk_ElementSpec ClientElementSpec = {
728     TK_STYLE_VERSION_2,
729     sizeof(NullElement),
730     TtkNullElementOptions,
731     ClientElementSize,
732     ClientElementDraw
733 };
734 
735 /*------------------------------------------------------------------------
736  * +++ Layouts.
737  */
738 
739 TTK_BEGIN_LAYOUT_TABLE(LayoutTable)
740 
741 TTK_LAYOUT("TButton",
742     TTK_GROUP("Button.border", TTK_FILL_BOTH,
743 	TTK_GROUP("Button.padding", TTK_FILL_BOTH,
744 	    TTK_NODE("Button.label", TTK_FILL_BOTH))))
745 
746 TTK_LAYOUT("TCombobox",
747     TTK_GROUP("Combobox.field", TTK_FILL_BOTH,
748 	TTK_NODE("Combobox.downarrow", TTK_PACK_RIGHT|TTK_FILL_Y)
749 	TTK_GROUP("Combobox.padding", TTK_FILL_BOTH,
750 	    TTK_GROUP("Combobox.focus", TTK_FILL_BOTH,
751 		TTK_NODE("Combobox.textarea", TTK_FILL_BOTH)))))
752 
753 TTK_END_LAYOUT_TABLE
754 
755 /* ---------------------------------------------------------------------- */
756 
757 MODULE_SCOPE
TtkWinTheme_Init(Tcl_Interp * interp,HWND hwnd)758 int TtkWinTheme_Init(Tcl_Interp *interp, HWND hwnd)
759 {
760     Ttk_Theme themePtr, parentPtr;
761     const FrameControlElementData *fce = FrameControlElements;
762     (void)hwnd;
763 
764     parentPtr = Ttk_GetTheme(interp, "alt");
765     themePtr = Ttk_CreateTheme(interp, "winnative", parentPtr);
766     if (!themePtr) {
767         return TCL_ERROR;
768     }
769 
770     Ttk_RegisterElementSpec(themePtr, "border", &BorderElementSpec, NULL);
771     Ttk_RegisterElementSpec(themePtr, "Button.border",
772 	&ButtonBorderElementSpec, NULL);
773     Ttk_RegisterElementSpec(themePtr, "field", &FieldElementSpec, NULL);
774     Ttk_RegisterElementSpec(themePtr, "focus", &FocusElementSpec, NULL);
775     Ttk_RegisterElementSpec(themePtr, "Combobox.focus",
776     	&ComboboxFocusElementSpec, NULL);
777     Ttk_RegisterElementSpec(themePtr, "thumb", &ThumbElementSpec, NULL);
778     Ttk_RegisterElementSpec(themePtr, "slider", &SliderElementSpec, NULL);
779     Ttk_RegisterElementSpec(themePtr, "Scrollbar.trough", &TroughElementSpec,
780     	TroughClientDataInit(interp));
781 
782     Ttk_RegisterElementSpec(themePtr, "client", &ClientElementSpec, NULL);
783 
784     for (fce = FrameControlElements; fce->name != 0; ++fce) {
785 	Ttk_RegisterElementSpec(themePtr, fce->name,
786 		&FrameControlElementSpec, (void *)fce);
787     }
788 
789     Ttk_RegisterLayouts(themePtr, LayoutTable);
790 
791     Tcl_PkgProvide(interp, "ttk::theme::winnative", TTK_VERSION);
792     return TCL_OK;
793 }
794 
795