OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / tk8.6.12 / win / ttkWinTheme.c
1 /* winTheme.c - Copyright (C) 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  */
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  */
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 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 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 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     int cxId;                   /* system metric ids for width/height... */
100     int cyId;                   /* ... or size if FIXEDSIZE bit set */
101     Ttk_StateTable *stateMap;   /* map Tk states to Win32 flags */
102     Ttk_Padding margins;        /* additional placement padding */
103 } FrameControlElementData;
104
105 #define _FIXEDSIZE  0x80000000L
106 #define _HALFMETRIC 0x40000000L
107 #define FIXEDSIZE(id) (id|_FIXEDSIZE)
108 #define HALFMETRIC(id) (id|_HALFMETRIC)
109 #define GETMETRIC(m) \
110     ((m) & _FIXEDSIZE ? (int)((m) & ~_FIXEDSIZE) : GetSystemMetrics((m)&0x0fffffff))
111
112 static 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
146 static void FrameControlElementSize(
147     void *clientData, void *elementRecord, Tk_Window tkwin,
148     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
149 {
150     FrameControlElementData *p = clientData;
151     int cx = GETMETRIC(p->cxId);
152     int cy = GETMETRIC(p->cyId);
153     if (p->cxId & _HALFMETRIC) cx /= 2;
154     if (p->cyId & _HALFMETRIC) cy /= 2;
155     *widthPtr = cx + Ttk_PaddingWidth(p->margins);
156     *heightPtr = cy + Ttk_PaddingHeight(p->margins);
157 }
158
159 static void FrameControlElementDraw(
160     void *clientData, void *elementRecord, Tk_Window tkwin,
161     Drawable d, Ttk_Box b, unsigned int state)
162 {
163     FrameControlElementData *elementData = clientData;
164     RECT rc = BoxToRect(Ttk_PadBox(b, elementData->margins));
165     TkWinDCState dcState;
166     HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
167
168     DrawFrameControl(hdc, &rc,
169         elementData->classId,
170         elementData->partId|Ttk_StateTableLookup(elementData->stateMap, state));
171     TkWinReleaseDrawableDC(d, hdc, &dcState);
172 }
173
174 static Ttk_ElementSpec FrameControlElementSpec = {
175     TK_STYLE_VERSION_2,
176     sizeof(NullElement),
177     TtkNullElementOptions,
178     FrameControlElementSize,
179     FrameControlElementDraw
180 };
181
182 /*----------------------------------------------------------------------
183  * +++ Border element implementation.
184  */
185
186 typedef struct {
187     Tcl_Obj     *reliefObj;
188 } BorderElement;
189
190 static Ttk_ElementOptionSpec BorderElementOptions[] = {
191     { "-relief",TK_OPTION_RELIEF,Tk_Offset(BorderElement,reliefObj), "flat" },
192     {NULL, 0, 0, NULL}
193 };
194
195 static void BorderElementSize(
196     void *clientData, void *elementRecord, Tk_Window tkwin,
197     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
198 {
199     paddingPtr->left = paddingPtr->right = GetSystemMetrics(SM_CXEDGE);
200     paddingPtr->top = paddingPtr->bottom = GetSystemMetrics(SM_CYEDGE);
201 }
202
203 static void BorderElementDraw(
204     void *clientData, void *elementRecord, Tk_Window tkwin,
205     Drawable d, Ttk_Box b, unsigned int state)
206 {
207     BorderElement *border = elementRecord;
208     RECT rc = BoxToRect(b);
209     int relief = TK_RELIEF_FLAT;
210     TkWinDCState dcState;
211     HDC hdc;
212
213     Tk_GetReliefFromObj(NULL, border->reliefObj, &relief);
214
215     if (relief != TK_RELIEF_FLAT) {
216         UINT xFlags = (relief == TK_RELIEF_SOLID) ? BF_FLAT : 0;
217         hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
218         DrawEdge(hdc, &rc, ReliefToEdge(relief), BF_RECT | xFlags);
219         TkWinReleaseDrawableDC(d, hdc, &dcState);
220     }
221 }
222
223 static Ttk_ElementSpec BorderElementSpec = {
224     TK_STYLE_VERSION_2,
225     sizeof(BorderElement),
226     BorderElementOptions,
227     BorderElementSize,
228     BorderElementDraw
229 };
230
231 /*
232  * Entry field borders:
233  * Sunken border; also fill with window color.
234  */
235
236 typedef struct {
237     Tcl_Obj     *backgroundObj;
238 } FieldElement;
239
240 static Ttk_ElementOptionSpec FieldElementOptions[] = {
241     { "-fieldbackground", TK_OPTION_BORDER,
242         Tk_Offset(FieldElement,backgroundObj), "white" },
243     { NULL, 0, 0, NULL }
244 };
245
246 static void FieldElementSize(
247     void *clientData, void *elementRecord, Tk_Window tkwin,
248     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
249 {
250     paddingPtr->left = paddingPtr->right = GetSystemMetrics(SM_CXEDGE);
251     paddingPtr->top = paddingPtr->bottom = GetSystemMetrics(SM_CYEDGE);
252 }
253
254 static void FieldElementDraw(
255     void *clientData, void *elementRecord, Tk_Window tkwin,
256     Drawable d, Ttk_Box b, unsigned int state)
257 {
258     FieldElement *field = elementRecord;
259     Tk_3DBorder bg = Tk_Get3DBorderFromObj(tkwin, field->backgroundObj);
260     RECT rc = BoxToRect(b);
261     TkWinDCState dcState;
262     HDC hdc;
263
264     Tk_Fill3DRectangle(
265         tkwin, d, bg, b.x, b.y, b.width, b.height, 0, TK_RELIEF_FLAT);
266
267     hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
268     DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT);
269     TkWinReleaseDrawableDC(d, hdc, &dcState);
270 }
271
272 static Ttk_ElementSpec FieldElementSpec = {
273     TK_STYLE_VERSION_2,
274     sizeof(FieldElement),
275     FieldElementOptions,
276     FieldElementSize,
277     FieldElementDraw
278 };
279
280 /*------------------------------------------------------------------------
281  * +++ Button borders.
282  *      Drawn with DrawFrameControl instead of DrawEdge;
283  *      Also draw default indicator and focus ring.
284  */
285 typedef struct {
286     Tcl_Obj     *reliefObj;
287     Tcl_Obj     *highlightColorObj;
288     Tcl_Obj     *defaultStateObj;
289 } ButtonBorderElement;
290
291 static Ttk_ElementOptionSpec ButtonBorderElementOptions[] = {
292     { "-relief",TK_OPTION_RELIEF,
293         Tk_Offset(ButtonBorderElement,reliefObj), "flat" },
294     { "-highlightcolor",TK_OPTION_COLOR,
295         Tk_Offset(ButtonBorderElement,highlightColorObj), "black" },
296     { "-default", TK_OPTION_ANY,
297         Tk_Offset(ButtonBorderElement,defaultStateObj), "disabled" },
298     {NULL, 0, 0, NULL}
299 };
300
301 static void ButtonBorderElementSize(
302     void *clientData, void *elementRecord, Tk_Window tkwin,
303     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
304 {
305     ButtonBorderElement *bd = elementRecord;
306     int relief = TK_RELIEF_RAISED;
307     int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
308     short int cx, cy;
309
310     Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
311     Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
312     cx = GetSystemMetrics(SM_CXEDGE);
313     cy = GetSystemMetrics(SM_CYEDGE);
314
315     /* Space for default indicator:
316      */
317     if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
318         ++cx; ++cy;
319     }
320
321     /* Space for focus ring:
322      */
323     cx += 2;
324     cy += 2;
325
326     *paddingPtr = Ttk_MakePadding(cx,cy,cx,cy);
327 }
328
329 static void ButtonBorderElementDraw(
330     void *clientData, void *elementRecord, Tk_Window tkwin,
331     Drawable d, Ttk_Box b, unsigned int state)
332 {
333     ButtonBorderElement *bd = elementRecord;
334     int relief = TK_RELIEF_FLAT;
335     int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
336     TkWinDCState dcState;
337     HDC hdc;
338     RECT rc;
339
340     Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
341     Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
342
343     if (defaultState == TTK_BUTTON_DEFAULT_ACTIVE) {
344         XColor *highlightColor =
345             Tk_GetColorFromObj(tkwin, bd->highlightColorObj);
346         GC gc = Tk_GCForColor(highlightColor, d);
347         XDrawRectangle(Tk_Display(tkwin), d, gc, b.x,b.y,b.width-1,b.height-1);
348     }
349     if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
350         ++b.x; ++b.y; b.width -= 2; b.height -= 2;
351     }
352
353     hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
354
355     rc = BoxToRect(b);
356     DrawFrameControl(hdc, &rc,
357         DFC_BUTTON,     /* classId */
358         DFCS_BUTTONPUSH | Ttk_StateTableLookup(pushbutton_statemap, state));
359
360     /* Draw focus ring:
361      */
362     if (state & TTK_STATE_FOCUS) {
363         short int borderWidth = 3;      /* @@@ Use GetSystemMetrics?*/
364         rc = BoxToRect(Ttk_PadBox(b, Ttk_UniformPadding(borderWidth)));
365         DrawFocusRect(hdc, &rc);
366     }
367     TkWinReleaseDrawableDC(d, hdc, &dcState);
368 }
369
370 static Ttk_ElementSpec ButtonBorderElementSpec = {
371     TK_STYLE_VERSION_2,
372     sizeof(ButtonBorderElement),
373     ButtonBorderElementOptions,
374     ButtonBorderElementSize,
375     ButtonBorderElementDraw
376 };
377
378 /*------------------------------------------------------------------------
379  * +++ Focus element.
380  *      Draw dashed focus rectangle.
381  */
382
383 static void FocusElementSize(
384     void *clientData, void *elementRecord, Tk_Window tkwin,
385     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
386 {
387     *paddingPtr = Ttk_UniformPadding(1);
388 }
389
390 static void FocusElementDraw(
391     void *clientData, void *elementRecord, Tk_Window tkwin,
392     Drawable d, Ttk_Box b, unsigned int state)
393 {
394     if (state & TTK_STATE_FOCUS) {
395         RECT rc = BoxToRect(b);
396         TkWinDCState dcState;
397         HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
398         DrawFocusRect(hdc, &rc);
399         TkWinReleaseDrawableDC(d, hdc, &dcState);
400     }
401 }
402
403 static Ttk_ElementSpec FocusElementSpec = {
404     TK_STYLE_VERSION_2,
405     sizeof(NullElement),
406     TtkNullElementOptions,
407     FocusElementSize,
408     FocusElementDraw
409 };
410
411 /* FillFocusElement --
412  *      Draws a focus ring filled with the selection color
413  */
414
415 typedef struct {
416     Tcl_Obj *fillColorObj;
417 } FillFocusElement;
418
419 static Ttk_ElementOptionSpec FillFocusElementOptions[] = {
420     { "-focusfill", TK_OPTION_COLOR,
421         Tk_Offset(FillFocusElement,fillColorObj), "white" },
422     {NULL, 0, 0, NULL}
423 };
424
425         /* @@@ FIX THIS */
426 static void FillFocusElementDraw(
427     void *clientData, void *elementRecord, Tk_Window tkwin,
428     Drawable d, Ttk_Box b, unsigned int state)
429 {
430     FillFocusElement *focus = elementRecord;
431     if (state & TTK_STATE_FOCUS) {
432         RECT rc = BoxToRect(b);
433         TkWinDCState dcState;
434         XColor *fillColor = Tk_GetColorFromObj(tkwin, focus->fillColorObj);
435         GC gc = Tk_GCForColor(fillColor, d);
436         HDC hdc;
437
438         XFillRectangle(Tk_Display(tkwin),d,gc, b.x,b.y,b.width,b.height);
439         hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
440         DrawFocusRect(hdc, &rc);
441         TkWinReleaseDrawableDC(d, hdc, &dcState);
442     }
443 }
444
445 /*
446  * ComboboxFocusElement --
447  *      Read-only comboboxes have a filled focus ring, editable ones do not.
448  */
449 static void ComboboxFocusElementDraw(
450     void *clientData, void *elementRecord, Tk_Window tkwin,
451     Drawable d, Ttk_Box b, unsigned int state)
452 {
453     if (state & TTK_STATE_READONLY) {
454         FillFocusElementDraw(clientData, elementRecord, tkwin, d, b, state);
455     }
456 }
457
458 static Ttk_ElementSpec ComboboxFocusElementSpec = {
459     TK_STYLE_VERSION_2,
460     sizeof(FillFocusElement),
461     FillFocusElementOptions,
462     FocusElementSize,
463     ComboboxFocusElementDraw
464 };
465
466 /*----------------------------------------------------------------------
467  * +++ Scrollbar trough element.
468  *
469  * The native windows scrollbar is drawn using a pattern brush giving a
470  * stippled appearance when the trough might otherwise be invisible.
471  * We can deal with this here.
472  */
473
474 typedef struct {        /* clientData for Trough element */
475     HBRUSH     PatternBrush;
476     HBITMAP    PatternBitmap;
477 } TroughClientData;
478
479 static const WORD Pattern[] = {
480     0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa
481 };
482
483 static void TroughClientDataDeleteProc(void *clientData)
484 {
485     TroughClientData *cd = clientData;
486     DeleteObject(cd->PatternBrush);
487     DeleteObject(cd->PatternBitmap);
488     ckfree(clientData);
489 }
490
491 static TroughClientData *TroughClientDataInit(Tcl_Interp *interp)
492 {
493     TroughClientData *cd = ckalloc(sizeof(*cd));
494     cd->PatternBitmap = CreateBitmap(8, 8, 1, 1, Pattern);
495     cd->PatternBrush  = CreatePatternBrush(cd->PatternBitmap);
496     Ttk_RegisterCleanup(interp, cd, TroughClientDataDeleteProc);
497     return cd;
498 }
499
500 static void TroughElementDraw(
501     void *clientData, void *elementRecord, Tk_Window tkwin,
502     Drawable d, Ttk_Box b, unsigned int state)
503 {
504     TroughClientData *cd = clientData;
505     TkWinDCState dcState;
506     HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
507     HBRUSH hbr;
508     COLORREF bk, oldbk, oldtxt;
509
510     hbr = SelectObject(hdc, GetSysColorBrush(COLOR_SCROLLBAR));
511     bk = GetSysColor(COLOR_3DHIGHLIGHT);
512     oldtxt = SetTextColor(hdc, GetSysColor(COLOR_3DFACE));
513     oldbk = SetBkColor(hdc, bk);
514
515     /* WAS: if (bk (COLOR_3DHIGHLIGHT) == GetSysColor(COLOR_WINDOW)) ... */
516     if (GetSysColor(COLOR_SCROLLBAR) == GetSysColor(COLOR_BTNFACE)) {
517         /* Draw using the pattern brush */
518         SelectObject(hdc, cd->PatternBrush);
519     }
520
521     PatBlt(hdc, b.x, b.y, b.width, b.height, PATCOPY);
522     SetBkColor(hdc, oldbk);
523     SetTextColor(hdc, oldtxt);
524     SelectObject(hdc, hbr);
525     TkWinReleaseDrawableDC(d, hdc, &dcState);
526 }
527
528 static Ttk_ElementSpec TroughElementSpec = {
529     TK_STYLE_VERSION_2,
530     sizeof(NullElement),
531     TtkNullElementOptions,
532     TtkNullElementSize,
533     TroughElementDraw
534 };
535
536 /*------------------------------------------------------------------------
537  * +++ Thumb element.
538  */
539
540 typedef struct {
541     Tcl_Obj *orientObj;
542 } ThumbElement;
543
544 static Ttk_ElementOptionSpec ThumbElementOptions[] = {
545     { "-orient", TK_OPTION_ANY,Tk_Offset(ThumbElement,orientObj),"horizontal"},
546     { NULL, 0, 0, NULL }
547 };
548
549 static void ThumbElementSize(
550     void *clientData, void *elementRecord, Tk_Window tkwin,
551     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
552 {
553     ThumbElement *thumbPtr = elementRecord;
554     int orient;
555
556     Ttk_GetOrientFromObj(NULL, thumbPtr->orientObj, &orient);
557     if (orient == TTK_ORIENT_HORIZONTAL) {
558         *widthPtr = GetSystemMetrics(SM_CXHTHUMB);
559         *heightPtr = GetSystemMetrics(SM_CYHSCROLL);
560     } else {
561         *widthPtr = GetSystemMetrics(SM_CXVSCROLL);
562         *heightPtr = GetSystemMetrics(SM_CYVTHUMB);
563     }
564 }
565
566 static void ThumbElementDraw(
567     void *clientData, void *elementRecord, Tk_Window tkwin,
568     Drawable d, Ttk_Box b, unsigned int state)
569 {
570     RECT rc = BoxToRect(b);
571     TkWinDCState dcState;
572     HDC hdc;
573
574     /* Windows doesn't show a thumb when the scrollbar is disabled */
575     if (state & TTK_STATE_DISABLED)
576         return;
577
578     hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
579     DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_MIDDLE);
580     TkWinReleaseDrawableDC(d, hdc, &dcState);
581 }
582
583 static Ttk_ElementSpec ThumbElementSpec = {
584     TK_STYLE_VERSION_2,
585     sizeof(ThumbElement),
586     ThumbElementOptions,
587     ThumbElementSize,
588     ThumbElementDraw
589 };
590
591 /* ----------------------------------------------------------------------
592  * The slider element is the shaped thumb used in the slider widget.
593  * Windows likes to call this a trackbar.
594  */
595
596 typedef struct {
597     Tcl_Obj *orientObj;  /* orientation of the slider widget */
598 } SliderElement;
599
600 static Ttk_ElementOptionSpec SliderElementOptions[] = {
601     { "-orient", TK_OPTION_ANY, Tk_Offset(SliderElement,orientObj),
602       "horizontal" },
603       { NULL, 0, 0, NULL }
604 };
605
606 static void SliderElementSize(
607     void *clientData, void *elementRecord, Tk_Window tkwin,
608     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
609 {
610     SliderElement *slider = elementRecord;
611     int orient;
612
613     Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient);
614     if (orient == TTK_ORIENT_HORIZONTAL) {
615         *widthPtr = (GetSystemMetrics(SM_CXHTHUMB) / 2) | 1;
616         *heightPtr = GetSystemMetrics(SM_CYHSCROLL);
617     } else {
618         *widthPtr = GetSystemMetrics(SM_CXVSCROLL);
619         *heightPtr = (GetSystemMetrics(SM_CYVTHUMB) / 2) | 1;
620     }
621 }
622
623 static void SliderElementDraw(
624     void *clientData, void *elementRecord, Tk_Window tkwin,
625     Drawable d, Ttk_Box b, unsigned int state)
626 {
627     RECT rc = BoxToRect(b);
628     TkWinDCState dcState;
629     HDC hdc;
630
631     hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
632     DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_MIDDLE);
633     TkWinReleaseDrawableDC(d, hdc, &dcState);
634 }
635
636 static Ttk_ElementSpec SliderElementSpec = {
637     TK_STYLE_VERSION_2,
638     sizeof(SliderElement),
639     SliderElementOptions,
640     SliderElementSize,
641     SliderElementDraw
642 };
643
644 /*------------------------------------------------------------------------
645  * +++ Notebook elements.
646  */
647
648 static void ClientElementSize(
649     void *clientData, void *elementRecord, Tk_Window tkwin,
650     int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
651 {
652     paddingPtr->left = paddingPtr->right = GetSystemMetrics(SM_CXEDGE);
653     paddingPtr->top = paddingPtr->bottom = GetSystemMetrics(SM_CYEDGE);
654 }
655
656 static void ClientElementDraw(
657     void *clientData, void *elementRecord, Tk_Window tkwin,
658     Drawable d, Ttk_Box b, unsigned int state)
659 {
660     RECT rc = BoxToRect(b);
661     TkWinDCState dcState;
662     HDC hdc = TkWinGetDrawableDC(Tk_Display(tkwin), d, &dcState);
663     DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | BF_SOFT);
664     TkWinReleaseDrawableDC(d, hdc, &dcState);
665 }
666
667 static Ttk_ElementSpec ClientElementSpec = {
668     TK_STYLE_VERSION_2,
669     sizeof(NullElement),
670     TtkNullElementOptions,
671     ClientElementSize,
672     ClientElementDraw
673 };
674
675 /*------------------------------------------------------------------------
676  * +++ Layouts.
677  */
678
679 TTK_BEGIN_LAYOUT_TABLE(LayoutTable)
680
681 TTK_LAYOUT("TButton",
682     TTK_GROUP("Button.border", TTK_FILL_BOTH,
683         TTK_GROUP("Button.padding", TTK_FILL_BOTH,
684             TTK_NODE("Button.label", TTK_FILL_BOTH))))
685
686 TTK_LAYOUT("TCombobox",
687     TTK_GROUP("Combobox.field", TTK_FILL_BOTH,
688         TTK_NODE("Combobox.downarrow", TTK_PACK_RIGHT|TTK_FILL_Y)
689         TTK_GROUP("Combobox.padding", TTK_FILL_BOTH,
690             TTK_GROUP("Combobox.focus", TTK_FILL_BOTH,
691                 TTK_NODE("Combobox.textarea", TTK_FILL_BOTH)))))
692
693 TTK_END_LAYOUT_TABLE
694
695 /* ---------------------------------------------------------------------- */
696
697 MODULE_SCOPE
698 int TtkWinTheme_Init(Tcl_Interp *interp, HWND hwnd)
699 {
700     Ttk_Theme themePtr, parentPtr;
701     FrameControlElementData *fce = FrameControlElements;
702
703     parentPtr = Ttk_GetTheme(interp, "alt");
704     themePtr = Ttk_CreateTheme(interp, "winnative", parentPtr);
705     if (!themePtr) {
706         return TCL_ERROR;
707     }
708
709     Ttk_RegisterElementSpec(themePtr, "border", &BorderElementSpec, NULL);
710     Ttk_RegisterElementSpec(themePtr, "Button.border",
711         &ButtonBorderElementSpec, NULL);
712     Ttk_RegisterElementSpec(themePtr, "field", &FieldElementSpec, NULL);
713     Ttk_RegisterElementSpec(themePtr, "focus", &FocusElementSpec, NULL);
714     Ttk_RegisterElementSpec(themePtr, "Combobox.focus",
715         &ComboboxFocusElementSpec, NULL);
716     Ttk_RegisterElementSpec(themePtr, "thumb", &ThumbElementSpec, NULL);
717     Ttk_RegisterElementSpec(themePtr, "slider", &SliderElementSpec, NULL);
718     Ttk_RegisterElementSpec(themePtr, "Scrollbar.trough", &TroughElementSpec,
719         TroughClientDataInit(interp));
720
721     Ttk_RegisterElementSpec(themePtr, "client", &ClientElementSpec, NULL);
722
723     for (fce = FrameControlElements; fce->name != 0; ++fce) {
724         Ttk_RegisterElementSpec(themePtr, fce->name,
725                 &FrameControlElementSpec, fce);
726     }
727
728     Ttk_RegisterLayouts(themePtr, LayoutTable);
729
730     Tcl_PkgProvide(interp, "ttk::theme::winnative", TTK_VERSION);
731     return TCL_OK;
732 }
733