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