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