1 /*
2 * Copyright (C) 2004 Joe English
3 *
4 * "clam" theme; inspired by the XFCE family of Gnome themes.
5 */
6
7 #include "tkInt.h"
8 #include "ttkTheme.h"
9
10 /*
11 * Under windows, the Tk-provided XDrawLine and XDrawArc have an
12 * off-by-one error in the end point. This is especially apparent with this
13 * theme. Defining this macro as true handles this case.
14 */
15 #if defined(_WIN32) && !defined(WIN32_XDRAWLINE_HACK)
16 # define WIN32_XDRAWLINE_HACK 1
17 #else
18 # define WIN32_XDRAWLINE_HACK 0
19 #endif
20
21 #define STR(x) StR(x)
22 #define StR(x) #x
23
24 #define SCROLLBAR_THICKNESS 14
25
26 #define FRAME_COLOR "#dcdad5"
27 #define LIGHT_COLOR "#ffffff"
28 #define DARK_COLOR "#cfcdc8"
29 #define DARKER_COLOR "#bab5ab"
30 #define DARKEST_COLOR "#9e9a91"
31
32 /*------------------------------------------------------------------------
33 * +++ Utilities.
34 */
35
Ttk_GCForColor(Tk_Window tkwin,Tcl_Obj * colorObj,Drawable d)36 static GC Ttk_GCForColor(Tk_Window tkwin, Tcl_Obj* colorObj, Drawable d)
37 {
38 GC gc = Tk_GCForColor(Tk_GetColorFromObj(tkwin, colorObj), d);
39
40 #ifdef MAC_OSX_TK
41 /*
42 * Workaround for Tk bug under Aqua where the default line width is 0.
43 */
44 Display *display = Tk_Display(tkwin);
45 unsigned long mask = 0ul;
46 XGCValues gcValues;
47
48 gcValues.line_width = 1;
49 mask = GCLineWidth;
50
51 XChangeGC(display, gc, mask, &gcValues);
52 #endif
53
54 return gc;
55 }
56
DrawSmoothBorder(Tk_Window tkwin,Drawable d,Ttk_Box b,Tcl_Obj * outerColorObj,Tcl_Obj * upperColorObj,Tcl_Obj * lowerColorObj)57 static void DrawSmoothBorder(
58 Tk_Window tkwin, Drawable d, Ttk_Box b,
59 Tcl_Obj *outerColorObj, Tcl_Obj *upperColorObj, Tcl_Obj *lowerColorObj)
60 {
61 Display *display = Tk_Display(tkwin);
62 int x1 = b.x, x2 = b.x + b.width - 1;
63 int y1 = b.y, y2 = b.y + b.height - 1;
64 const int w = WIN32_XDRAWLINE_HACK;
65 GC gc;
66
67 if ( outerColorObj
68 && (gc=Ttk_GCForColor(tkwin,outerColorObj,d)))
69 {
70 XDrawLine(display,d,gc, x1+1,y1, x2-1+w,y1); /* N */
71 XDrawLine(display,d,gc, x1+1,y2, x2-1+w,y2); /* S */
72 XDrawLine(display,d,gc, x1,y1+1, x1,y2-1+w); /* E */
73 XDrawLine(display,d,gc, x2,y1+1, x2,y2-1+w); /* W */
74 }
75
76 if ( upperColorObj
77 && (gc=Ttk_GCForColor(tkwin,upperColorObj,d)))
78 {
79 XDrawLine(display,d,gc, x1+1,y1+1, x2-1+w,y1+1); /* N */
80 XDrawLine(display,d,gc, x1+1,y1+1, x1+1,y2-1); /* E */
81 }
82
83 if ( lowerColorObj
84 && (gc=Ttk_GCForColor(tkwin,lowerColorObj,d)))
85 {
86 XDrawLine(display,d,gc, x2-1,y2-1, x1+1-w,y2-1); /* S */
87 XDrawLine(display,d,gc, x2-1,y2-1, x2-1,y1+1-w); /* W */
88 }
89 }
90
BackgroundGC(Tk_Window tkwin,Tcl_Obj * backgroundObj)91 static GC BackgroundGC(Tk_Window tkwin, Tcl_Obj *backgroundObj)
92 {
93 Tk_3DBorder bd = Tk_Get3DBorderFromObj(tkwin, backgroundObj);
94 return Tk_3DBorderGC(tkwin, bd, TK_3D_FLAT_GC);
95 }
96
97 /*------------------------------------------------------------------------
98 * +++ Border element.
99 */
100
101 typedef struct {
102 Tcl_Obj *borderColorObj;
103 Tcl_Obj *lightColorObj;
104 Tcl_Obj *darkColorObj;
105 Tcl_Obj *reliefObj;
106 Tcl_Obj *borderWidthObj; /* See <<NOTE-BORDERWIDTH>> */
107 } BorderElement;
108
109 static Ttk_ElementOptionSpec BorderElementOptions[] = {
110 { "-bordercolor", TK_OPTION_COLOR,
111 Tk_Offset(BorderElement,borderColorObj), DARKEST_COLOR },
112 { "-lightcolor", TK_OPTION_COLOR,
113 Tk_Offset(BorderElement,lightColorObj), LIGHT_COLOR },
114 { "-darkcolor", TK_OPTION_COLOR,
115 Tk_Offset(BorderElement,darkColorObj), DARK_COLOR },
116 { "-relief", TK_OPTION_RELIEF,
117 Tk_Offset(BorderElement,reliefObj), "flat" },
118 { "-borderwidth", TK_OPTION_PIXELS,
119 Tk_Offset(BorderElement,borderWidthObj), "2" },
120 { NULL, TK_OPTION_BOOLEAN, 0, NULL }
121 };
122
123 /*
124 * <<NOTE-BORDERWIDTH>>: -borderwidth is only partially supported:
125 * in this theme, borders are always exactly 2 pixels thick.
126 * With -borderwidth 0, border is not drawn at all;
127 * otherwise a 2-pixel border is used. For -borderwidth > 2,
128 * the excess is used as padding.
129 */
130
BorderElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)131 static void BorderElementSize(
132 void *dummy, void *elementRecord, Tk_Window tkwin,
133 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
134 {
135 BorderElement *border = (BorderElement*)elementRecord;
136 int borderWidth = 2;
137 (void)dummy;
138 (void)widthPtr;
139 (void)heightPtr;
140
141 Tk_GetPixelsFromObj(NULL, tkwin, border->borderWidthObj, &borderWidth);
142 if (borderWidth == 1) ++borderWidth;
143 *paddingPtr = Ttk_UniformPadding((short)borderWidth);
144 }
145
BorderElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)146 static void BorderElementDraw(
147 void *dummy, void *elementRecord, Tk_Window tkwin,
148 Drawable d, Ttk_Box b, unsigned state)
149 {
150 BorderElement *border = (BorderElement *)elementRecord;
151 int relief = TK_RELIEF_FLAT;
152 int borderWidth = 2;
153 Tcl_Obj *outer = 0, *upper = 0, *lower = 0;
154 (void)dummy;
155 (void)state;
156
157 Tk_GetReliefFromObj(NULL, border->reliefObj, &relief);
158 Tk_GetPixelsFromObj(NULL, tkwin, border->borderWidthObj, &borderWidth);
159
160 if (borderWidth == 0) return;
161
162 switch (relief) {
163 case TK_RELIEF_GROOVE :
164 case TK_RELIEF_RIDGE :
165 case TK_RELIEF_RAISED :
166 outer = border->borderColorObj;
167 upper = border->lightColorObj;
168 lower = border->darkColorObj;
169 break;
170 case TK_RELIEF_SUNKEN :
171 outer = border->borderColorObj;
172 upper = border->darkColorObj;
173 lower = border->lightColorObj;
174 break;
175 case TK_RELIEF_FLAT :
176 outer = upper = lower = 0;
177 break;
178 case TK_RELIEF_SOLID :
179 outer = upper = lower = border->borderColorObj;
180 break;
181 }
182
183 DrawSmoothBorder(tkwin, d, b, outer, upper, lower);
184 }
185
186 static Ttk_ElementSpec BorderElementSpec = {
187 TK_STYLE_VERSION_2,
188 sizeof(BorderElement),
189 BorderElementOptions,
190 BorderElementSize,
191 BorderElementDraw
192 };
193
194 /*------------------------------------------------------------------------
195 * +++ Field element.
196 */
197
198 typedef struct {
199 Tcl_Obj *borderColorObj;
200 Tcl_Obj *lightColorObj;
201 Tcl_Obj *darkColorObj;
202 Tcl_Obj *backgroundObj;
203 } FieldElement;
204
205 static Ttk_ElementOptionSpec FieldElementOptions[] = {
206 { "-bordercolor", TK_OPTION_COLOR,
207 Tk_Offset(FieldElement,borderColorObj), DARKEST_COLOR },
208 { "-lightcolor", TK_OPTION_COLOR,
209 Tk_Offset(FieldElement,lightColorObj), LIGHT_COLOR },
210 { "-darkcolor", TK_OPTION_COLOR,
211 Tk_Offset(FieldElement,darkColorObj), DARK_COLOR },
212 { "-fieldbackground", TK_OPTION_BORDER,
213 Tk_Offset(FieldElement,backgroundObj), "white" },
214 { NULL, TK_OPTION_BOOLEAN, 0, NULL }
215 };
216
FieldElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)217 static void FieldElementSize(
218 void *dummy, void *elementRecord, Tk_Window tkwin,
219 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
220 {
221 (void)dummy;
222 (void)elementRecord;
223 (void)tkwin;
224 (void)widthPtr;
225 (void)heightPtr;
226
227 *paddingPtr = Ttk_UniformPadding(2);
228 }
229
FieldElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)230 static void FieldElementDraw(
231 void *dummy, void *elementRecord, Tk_Window tkwin,
232 Drawable d, Ttk_Box b, unsigned state)
233 {
234 FieldElement *field = (FieldElement *)elementRecord;
235 Tk_3DBorder bg = Tk_Get3DBorderFromObj(tkwin, field->backgroundObj);
236 Ttk_Box f = Ttk_PadBox(b, Ttk_UniformPadding(2));
237 Tcl_Obj *outer = field->borderColorObj,
238 *inner = field->lightColorObj;
239 (void)dummy;
240 (void)state;
241
242 DrawSmoothBorder(tkwin, d, b, outer, inner, inner);
243 Tk_Fill3DRectangle(
244 tkwin, d, bg, f.x, f.y, f.width, f.height, 0, TK_RELIEF_SUNKEN);
245 }
246
247 static Ttk_ElementSpec FieldElementSpec = {
248 TK_STYLE_VERSION_2,
249 sizeof(FieldElement),
250 FieldElementOptions,
251 FieldElementSize,
252 FieldElementDraw
253 };
254
255 /*
256 * Modified field element for comboboxes:
257 * Right edge is expanded to overlap the dropdown button.
258 */
ComboboxFieldElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)259 static void ComboboxFieldElementDraw(
260 void *clientData, void *elementRecord, Tk_Window tkwin,
261 Drawable d, Ttk_Box b, unsigned state)
262 {
263 FieldElement *field = (FieldElement *)elementRecord;
264 GC gc = Ttk_GCForColor(tkwin,field->borderColorObj,d);
265
266 ++b.width;
267 FieldElementDraw(clientData, elementRecord, tkwin, d, b, state);
268
269 XDrawLine(Tk_Display(tkwin), d, gc,
270 b.x + b.width - 1, b.y,
271 b.x + b.width - 1, b.y + b.height - 1 + WIN32_XDRAWLINE_HACK);
272 }
273
274 static Ttk_ElementSpec ComboboxFieldElementSpec = {
275 TK_STYLE_VERSION_2,
276 sizeof(FieldElement),
277 FieldElementOptions,
278 FieldElementSize,
279 ComboboxFieldElementDraw
280 };
281
282 /*------------------------------------------------------------------------
283 * +++ Indicator elements for check and radio buttons.
284 */
285
286 typedef struct {
287 Tcl_Obj *sizeObj;
288 Tcl_Obj *marginObj;
289 Tcl_Obj *backgroundObj;
290 Tcl_Obj *foregroundObj;
291 Tcl_Obj *upperColorObj;
292 Tcl_Obj *lowerColorObj;
293 } IndicatorElement;
294
295 static Ttk_ElementOptionSpec IndicatorElementOptions[] = {
296 { "-indicatorsize", TK_OPTION_PIXELS,
297 Tk_Offset(IndicatorElement,sizeObj), "10" },
298 { "-indicatormargin", TK_OPTION_STRING,
299 Tk_Offset(IndicatorElement,marginObj), "1" },
300 { "-indicatorbackground", TK_OPTION_COLOR,
301 Tk_Offset(IndicatorElement,backgroundObj), "white" },
302 { "-indicatorforeground", TK_OPTION_COLOR,
303 Tk_Offset(IndicatorElement,foregroundObj), "black" },
304 { "-upperbordercolor", TK_OPTION_COLOR,
305 Tk_Offset(IndicatorElement,upperColorObj), DARKEST_COLOR },
306 { "-lowerbordercolor", TK_OPTION_COLOR,
307 Tk_Offset(IndicatorElement,lowerColorObj), DARK_COLOR },
308 { NULL, TK_OPTION_BOOLEAN, 0, NULL }
309 };
310
IndicatorElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)311 static void IndicatorElementSize(
312 void *dummy, void *elementRecord, Tk_Window tkwin,
313 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
314 {
315 IndicatorElement *indicator = (IndicatorElement *)elementRecord;
316 Ttk_Padding margins;
317 int size = 10;
318 (void)dummy;
319 (void)paddingPtr;
320
321 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
322 Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size);
323 *widthPtr = size + Ttk_PaddingWidth(margins);
324 *heightPtr = size + Ttk_PaddingHeight(margins);
325 }
326
RadioIndicatorElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)327 static void RadioIndicatorElementDraw(
328 void *dummy, void *elementRecord, Tk_Window tkwin,
329 Drawable d, Ttk_Box b, unsigned state)
330 {
331 IndicatorElement *indicator = (IndicatorElement *)elementRecord;
332 GC gcb=Ttk_GCForColor(tkwin,indicator->backgroundObj,d);
333 GC gcf=Ttk_GCForColor(tkwin,indicator->foregroundObj,d);
334 GC gcu=Ttk_GCForColor(tkwin,indicator->upperColorObj,d);
335 GC gcl=Ttk_GCForColor(tkwin,indicator->lowerColorObj,d);
336 Ttk_Padding padding;
337 (void)dummy;
338
339 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding);
340 b = Ttk_PadBox(b, padding);
341
342 XFillArc(Tk_Display(tkwin),d,gcb, b.x,b.y,b.width,b.height, 0,360*64);
343 XDrawArc(Tk_Display(tkwin),d,gcl, b.x,b.y,b.width,b.height, 225*64,180*64);
344 XDrawArc(Tk_Display(tkwin),d,gcu, b.x,b.y,b.width,b.height, 45*64,180*64);
345
346 if (state & TTK_STATE_SELECTED) {
347 b = Ttk_PadBox(b,Ttk_UniformPadding(3));
348 XFillArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 0,360*64);
349 XDrawArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 0,360*64);
350 #if WIN32_XDRAWLINE_HACK
351 XDrawArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 300*64,360*64);
352 #endif
353 }
354 }
355
CheckIndicatorElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)356 static void CheckIndicatorElementDraw(
357 void *dummy, void *elementRecord, Tk_Window tkwin,
358 Drawable d, Ttk_Box b, unsigned state)
359 {
360 Display *display = Tk_Display(tkwin);
361 IndicatorElement *indicator = (IndicatorElement *)elementRecord;
362
363 GC gcb=Ttk_GCForColor(tkwin,indicator->backgroundObj,d);
364 GC gcf=Ttk_GCForColor(tkwin,indicator->foregroundObj,d);
365 GC gcu=Ttk_GCForColor(tkwin,indicator->upperColorObj,d);
366 GC gcl=Ttk_GCForColor(tkwin,indicator->lowerColorObj,d);
367 Ttk_Padding padding;
368 const int w = WIN32_XDRAWLINE_HACK;
369 (void)dummy;
370
371 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding);
372 b = Ttk_PadBox(b, padding);
373
374 XFillRectangle(display,d,gcb, b.x,b.y,b.width,b.height);
375 XDrawLine(display,d,gcl,b.x,b.y+b.height,b.x+b.width+w,b.y+b.height);/*S*/
376 XDrawLine(display,d,gcl,b.x+b.width,b.y,b.x+b.width,b.y+b.height+w); /*E*/
377 XDrawLine(display,d,gcu,b.x,b.y, b.x,b.y+b.height+w); /*W*/
378 XDrawLine(display,d,gcu,b.x,b.y, b.x+b.width+w,b.y); /*N*/
379
380 if (state & TTK_STATE_SELECTED) {
381 int p,q,r,s;
382
383 b = Ttk_PadBox(b,Ttk_UniformPadding(2));
384 p = b.x, q = b.y, r = b.x+b.width, s = b.y+b.height;
385
386 r+=w, s+=w;
387 XDrawLine(display, d, gcf, p, q, r, s);
388 XDrawLine(display, d, gcf, p+1, q, r, s-1);
389 XDrawLine(display, d, gcf, p, q+1, r-1, s);
390
391 s-=w, q-=w;
392 XDrawLine(display, d, gcf, p, s, r, q);
393 XDrawLine(display, d, gcf, p+1, s, r, q+1);
394 XDrawLine(display, d, gcf, p, s-1, r-1, q);
395 }
396 }
397
398 static Ttk_ElementSpec RadioIndicatorElementSpec = {
399 TK_STYLE_VERSION_2,
400 sizeof(IndicatorElement),
401 IndicatorElementOptions,
402 IndicatorElementSize,
403 RadioIndicatorElementDraw
404 };
405
406 static Ttk_ElementSpec CheckIndicatorElementSpec = {
407 TK_STYLE_VERSION_2,
408 sizeof(IndicatorElement),
409 IndicatorElementOptions,
410 IndicatorElementSize,
411 CheckIndicatorElementDraw
412 };
413
414 #define MENUBUTTON_ARROW_SIZE 5
415
416 typedef struct {
417 Tcl_Obj *sizeObj;
418 Tcl_Obj *colorObj;
419 Tcl_Obj *paddingObj;
420 } MenuIndicatorElement;
421
422 static Ttk_ElementOptionSpec MenuIndicatorElementOptions[] =
423 {
424 { "-arrowsize", TK_OPTION_PIXELS,
425 Tk_Offset(MenuIndicatorElement,sizeObj),
426 STR(MENUBUTTON_ARROW_SIZE)},
427 { "-arrowcolor",TK_OPTION_COLOR,
428 Tk_Offset(MenuIndicatorElement,colorObj),
429 "black" },
430 { "-arrowpadding",TK_OPTION_STRING,
431 Tk_Offset(MenuIndicatorElement,paddingObj),
432 "3" },
433 { NULL, TK_OPTION_BOOLEAN, 0, NULL }
434 };
435
MenuIndicatorElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)436 static void MenuIndicatorElementSize(
437 void *dummy, void *elementRecord, Tk_Window tkwin,
438 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
439 {
440 MenuIndicatorElement *indicator = (MenuIndicatorElement *)elementRecord;
441 Ttk_Padding margins;
442 int size = MENUBUTTON_ARROW_SIZE;
443 (void)dummy;
444 (void)paddingPtr;
445
446 Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size);
447 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->paddingObj, &margins);
448 TtkArrowSize(size, ARROW_DOWN, widthPtr, heightPtr);
449 *widthPtr += Ttk_PaddingWidth(margins);
450 *heightPtr += Ttk_PaddingHeight(margins);
451 }
452
MenuIndicatorElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)453 static void MenuIndicatorElementDraw(
454 void *dummy, void *elementRecord, Tk_Window tkwin,
455 Drawable d, Ttk_Box b, unsigned int state)
456 {
457 MenuIndicatorElement *indicator = (MenuIndicatorElement *)elementRecord;
458 XColor *arrowColor = Tk_GetColorFromObj(tkwin, indicator->colorObj);
459 GC gc = Tk_GCForColor(arrowColor, d);
460 int size = MENUBUTTON_ARROW_SIZE;
461 int width, height;
462 (void)dummy;
463 (void)state;
464
465 Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size);
466
467 TtkArrowSize(size, ARROW_DOWN, &width, &height);
468 b = Ttk_StickBox(b, width, height, 0);
469 TtkFillArrow(Tk_Display(tkwin), d, gc, b, ARROW_DOWN);
470 }
471
472 static Ttk_ElementSpec MenuIndicatorElementSpec =
473 {
474 TK_STYLE_VERSION_2,
475 sizeof(MenuIndicatorElement),
476 MenuIndicatorElementOptions,
477 MenuIndicatorElementSize,
478 MenuIndicatorElementDraw
479 };
480
481 /*------------------------------------------------------------------------
482 * +++ Grips.
483 *
484 * TODO: factor this with ThumbElementDraw
485 */
486
487 static Ttk_Orient GripClientData[] = {
488 TTK_ORIENT_HORIZONTAL, TTK_ORIENT_VERTICAL
489 };
490
491 typedef struct {
492 Tcl_Obj *lightColorObj;
493 Tcl_Obj *borderColorObj;
494 Tcl_Obj *gripCountObj;
495 } GripElement;
496
497 static Ttk_ElementOptionSpec GripElementOptions[] = {
498 { "-lightcolor", TK_OPTION_COLOR,
499 Tk_Offset(GripElement,lightColorObj), LIGHT_COLOR },
500 { "-bordercolor", TK_OPTION_COLOR,
501 Tk_Offset(GripElement,borderColorObj), DARKEST_COLOR },
502 { "-gripcount", TK_OPTION_INT,
503 Tk_Offset(GripElement,gripCountObj), "5" },
504 { NULL, TK_OPTION_BOOLEAN, 0, NULL }
505 };
506
GripElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)507 static void GripElementSize(
508 void *clientData, void *elementRecord, Tk_Window tkwin,
509 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
510 {
511 int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL;
512 GripElement *grip = (GripElement *)elementRecord;
513 int gripCount = 0;
514 (void)tkwin;
515 (void)paddingPtr;
516
517 Tcl_GetIntFromObj(NULL, grip->gripCountObj, &gripCount);
518 if (horizontal) {
519 *widthPtr = 2*gripCount;
520 } else {
521 *heightPtr = 2*gripCount;
522 }
523 }
524
GripElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)525 static void GripElementDraw(
526 void *clientData, void *elementRecord, Tk_Window tkwin,
527 Drawable d, Ttk_Box b, unsigned state)
528 {
529 const int w = WIN32_XDRAWLINE_HACK;
530 int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL;
531 GripElement *grip = (GripElement *)elementRecord;
532 GC lightGC = Ttk_GCForColor(tkwin,grip->lightColorObj,d);
533 GC darkGC = Ttk_GCForColor(tkwin,grip->borderColorObj,d);
534 int gripPad = 1, gripCount = 0;
535 int i;
536
537 Tcl_GetIntFromObj(NULL, grip->gripCountObj, &gripCount);
538
539 if (horizontal) {
540 int x = b.x + b.width / 2 - gripCount;
541 int y1 = b.y + gripPad, y2 = b.y + b.height - gripPad - 1 + w;
542 for (i=0; i<gripCount; ++i) {
543 XDrawLine(Tk_Display(tkwin), d, darkGC, x,y1, x,y2); ++x;
544 XDrawLine(Tk_Display(tkwin), d, lightGC, x,y1, x,y2); ++x;
545 }
546 } else {
547 int y = b.y + b.height / 2 - gripCount;
548 int x1 = b.x + gripPad, x2 = b.x + b.width - gripPad - 1 + w;
549 for (i=0; i<gripCount; ++i) {
550 XDrawLine(Tk_Display(tkwin), d, darkGC, x1,y, x2,y); ++y;
551 XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y, x2,y); ++y;
552 }
553 }
554 }
555
556 static Ttk_ElementSpec GripElementSpec = {
557 TK_STYLE_VERSION_2,
558 sizeof(GripElement),
559 GripElementOptions,
560 GripElementSize,
561 GripElementDraw
562 };
563
564 /*------------------------------------------------------------------------
565 * +++ Scrollbar elements: trough, arrows, thumb.
566 *
567 * Notice that the trough element has 0 internal padding;
568 * that way the thumb and arrow borders overlap the trough.
569 */
570
571 typedef struct { /* Common element record for scrollbar elements */
572 Tcl_Obj *orientObj;
573 Tcl_Obj *backgroundObj;
574 Tcl_Obj *borderColorObj;
575 Tcl_Obj *troughColorObj;
576 Tcl_Obj *lightColorObj;
577 Tcl_Obj *darkColorObj;
578 Tcl_Obj *arrowColorObj;
579 Tcl_Obj *arrowSizeObj;
580 Tcl_Obj *gripCountObj;
581 Tcl_Obj *sliderlengthObj;
582 } ScrollbarElement;
583
584 static Ttk_ElementOptionSpec ScrollbarElementOptions[] = {
585 { "-orient", TK_OPTION_ANY,
586 Tk_Offset(ScrollbarElement, orientObj), "horizontal" },
587 { "-background", TK_OPTION_BORDER,
588 Tk_Offset(ScrollbarElement,backgroundObj), FRAME_COLOR },
589 { "-bordercolor", TK_OPTION_COLOR,
590 Tk_Offset(ScrollbarElement,borderColorObj), DARKEST_COLOR },
591 { "-troughcolor", TK_OPTION_COLOR,
592 Tk_Offset(ScrollbarElement,troughColorObj), DARKER_COLOR },
593 { "-lightcolor", TK_OPTION_COLOR,
594 Tk_Offset(ScrollbarElement,lightColorObj), LIGHT_COLOR },
595 { "-darkcolor", TK_OPTION_COLOR,
596 Tk_Offset(ScrollbarElement,darkColorObj), DARK_COLOR },
597 { "-arrowcolor", TK_OPTION_COLOR,
598 Tk_Offset(ScrollbarElement,arrowColorObj), "#000000" },
599 { "-arrowsize", TK_OPTION_PIXELS,
600 Tk_Offset(ScrollbarElement,arrowSizeObj), STR(SCROLLBAR_THICKNESS) },
601 { "-gripcount", TK_OPTION_INT,
602 Tk_Offset(ScrollbarElement,gripCountObj), "5" },
603 { "-sliderlength", TK_OPTION_INT,
604 Tk_Offset(ScrollbarElement,sliderlengthObj), "30" },
605 { NULL, TK_OPTION_BOOLEAN, 0, NULL }
606 };
607
TroughElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)608 static void TroughElementDraw(
609 void *dummy, void *elementRecord, Tk_Window tkwin,
610 Drawable d, Ttk_Box b, unsigned state)
611 {
612 ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
613 GC gcb = Ttk_GCForColor(tkwin,sb->borderColorObj,d);
614 GC gct = Ttk_GCForColor(tkwin,sb->troughColorObj,d);
615 (void)dummy;
616 (void)state;
617
618 XFillRectangle(Tk_Display(tkwin), d, gct, b.x, b.y, b.width-1, b.height-1);
619 XDrawRectangle(Tk_Display(tkwin), d, gcb, b.x, b.y, b.width-1, b.height-1);
620 }
621
622 static Ttk_ElementSpec TroughElementSpec = {
623 TK_STYLE_VERSION_2,
624 sizeof(ScrollbarElement),
625 ScrollbarElementOptions,
626 TtkNullElementSize,
627 TroughElementDraw
628 };
629
ThumbElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)630 static void ThumbElementSize(
631 void *dummy, void *elementRecord, Tk_Window tkwin,
632 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
633 {
634 ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
635 int size = SCROLLBAR_THICKNESS;
636 (void)dummy;
637 (void)tkwin;
638 (void)paddingPtr;
639
640 Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &size);
641 *widthPtr = *heightPtr = size;
642 }
643
ThumbElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)644 static void ThumbElementDraw(
645 void *dummy, void *elementRecord, Tk_Window tkwin,
646 Drawable d, Ttk_Box b, unsigned state)
647 {
648 ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
649 int gripCount = 0;
650 int orient = TTK_ORIENT_HORIZONTAL;
651 GC lightGC, darkGC;
652 int x1, y1, x2, y2, dx, dy, i;
653 const int w = WIN32_XDRAWLINE_HACK;
654 (void)dummy;
655 (void)state;
656
657 DrawSmoothBorder(tkwin, d, b,
658 sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
659 XFillRectangle(
660 Tk_Display(tkwin), d, BackgroundGC(tkwin, sb->backgroundObj),
661 b.x+2, b.y+2, b.width-4, b.height-4);
662
663 /*
664 * Draw grip:
665 */
666 Ttk_GetOrientFromObj(NULL, sb->orientObj, &orient);
667 Tcl_GetIntFromObj(NULL, sb->gripCountObj, &gripCount);
668 lightGC = Ttk_GCForColor(tkwin,sb->lightColorObj,d);
669 darkGC = Ttk_GCForColor(tkwin,sb->borderColorObj,d);
670
671 if (orient == TTK_ORIENT_HORIZONTAL) {
672 dx = 1; dy = 0;
673 x1 = x2 = b.x + b.width / 2 - gripCount;
674 y1 = b.y + 2;
675 y2 = b.y + b.height - 3 + w;
676 } else {
677 dx = 0; dy = 1;
678 y1 = y2 = b.y + b.height / 2 - gripCount;
679 x1 = b.x + 2;
680 x2 = b.x + b.width - 3 + w;
681 }
682
683 for (i=0; i<gripCount; ++i) {
684 XDrawLine(Tk_Display(tkwin), d, darkGC, x1,y1, x2,y2);
685 x1 += dx; x2 += dx; y1 += dy; y2 += dy;
686 XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y1, x2,y2);
687 x1 += dx; x2 += dx; y1 += dy; y2 += dy;
688 }
689 }
690
691 static Ttk_ElementSpec ThumbElementSpec = {
692 TK_STYLE_VERSION_2,
693 sizeof(ScrollbarElement),
694 ScrollbarElementOptions,
695 ThumbElementSize,
696 ThumbElementDraw
697 };
698
699 /*------------------------------------------------------------------------
700 * +++ Slider element.
701 */
SliderElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)702 static void SliderElementSize(
703 void *dummy, void *elementRecord, Tk_Window tkwin,
704 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
705 {
706 ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
707 int length, thickness;
708 int orient;
709 (void)dummy;
710 (void)paddingPtr;
711
712 length = thickness = SCROLLBAR_THICKNESS;
713 Ttk_GetOrientFromObj(NULL, sb->orientObj, &orient);
714 Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &thickness);
715 Tk_GetPixelsFromObj(NULL, tkwin, sb->sliderlengthObj, &length);
716 if (orient == TTK_ORIENT_VERTICAL) {
717 *heightPtr = length;
718 *widthPtr = thickness;
719 } else {
720 *heightPtr = thickness;
721 *widthPtr = length;
722 }
723
724 }
725
726 static Ttk_ElementSpec SliderElementSpec = {
727 TK_STYLE_VERSION_2,
728 sizeof(ScrollbarElement),
729 ScrollbarElementOptions,
730 SliderElementSize,
731 ThumbElementDraw
732 };
733
734 /*------------------------------------------------------------------------
735 * +++ Progress bar element
736 */
PbarElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)737 static void PbarElementSize(
738 void *clientData, void *elementRecord, Tk_Window tkwin,
739 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
740 {
741 SliderElementSize(clientData, elementRecord, tkwin,
742 widthPtr, heightPtr, paddingPtr);
743 *paddingPtr = Ttk_UniformPadding(2);
744 *widthPtr += 4;
745 *heightPtr += 4;
746 }
747
PbarElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)748 static void PbarElementDraw(
749 void *dummy, void *elementRecord, Tk_Window tkwin,
750 Drawable d, Ttk_Box b, unsigned state)
751 {
752 ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
753 (void)dummy;
754 (void)state;
755
756 b = Ttk_PadBox(b, Ttk_UniformPadding(2));
757 if (b.width > 4 && b.height > 4) {
758 DrawSmoothBorder(tkwin, d, b,
759 sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
760 XFillRectangle(Tk_Display(tkwin), d,
761 BackgroundGC(tkwin, sb->backgroundObj),
762 b.x+2, b.y+2, b.width-4, b.height-4);
763 }
764 }
765
766 static Ttk_ElementSpec PbarElementSpec = {
767 TK_STYLE_VERSION_2,
768 sizeof(ScrollbarElement),
769 ScrollbarElementOptions,
770 PbarElementSize,
771 PbarElementDraw
772 };
773
774
775 /*------------------------------------------------------------------------
776 * +++ Scrollbar arrows.
777 */
778 static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT };
779
ArrowElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)780 static void ArrowElementSize(
781 void *dummy, void *elementRecord, Tk_Window tkwin,
782 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
783 {
784 ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
785 int size = SCROLLBAR_THICKNESS;
786 (void)dummy;
787 (void)tkwin;
788 (void)paddingPtr;
789
790 Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &size);
791 *widthPtr = *heightPtr = size;
792 }
793
ArrowElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned state)794 static void ArrowElementDraw(
795 void *clientData, void *elementRecord, Tk_Window tkwin,
796 Drawable d, Ttk_Box b, unsigned state)
797 {
798 ArrowDirection direction = *(ArrowDirection*)clientData;
799 ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
800 GC gc = Ttk_GCForColor(tkwin,sb->arrowColorObj, d);
801 int h, cx, cy;
802
803 DrawSmoothBorder(tkwin, d, b,
804 sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
805
806 XFillRectangle(
807 Tk_Display(tkwin), d, BackgroundGC(tkwin, sb->backgroundObj),
808 b.x+2, b.y+2, b.width-4, b.height-4);
809
810 b = Ttk_PadBox(b, Ttk_UniformPadding(3));
811 h = b.width < b.height ? b.width : b.height;
812 TtkArrowSize(h/2, direction, &cx, &cy);
813 b = Ttk_AnchorBox(b, cx, cy, TK_ANCHOR_CENTER);
814
815 TtkFillArrow(Tk_Display(tkwin), d, gc, b, direction);
816 }
817
818 static Ttk_ElementSpec ArrowElementSpec = {
819 TK_STYLE_VERSION_2,
820 sizeof(ScrollbarElement),
821 ScrollbarElementOptions,
822 ArrowElementSize,
823 ArrowElementDraw
824 };
825
826
827 /*------------------------------------------------------------------------
828 * +++ Notebook elements.
829 *
830 * Note: Tabs, except for the rightmost, overlap the neighbor to
831 * their right by one pixel.
832 */
833
834 typedef struct {
835 Tcl_Obj *backgroundObj;
836 Tcl_Obj *borderColorObj;
837 Tcl_Obj *lightColorObj;
838 Tcl_Obj *darkColorObj;
839 } NotebookElement;
840
841 static Ttk_ElementOptionSpec NotebookElementOptions[] = {
842 { "-background", TK_OPTION_BORDER,
843 Tk_Offset(NotebookElement,backgroundObj), FRAME_COLOR },
844 { "-bordercolor", TK_OPTION_COLOR,
845 Tk_Offset(NotebookElement,borderColorObj), DARKEST_COLOR },
846 { "-lightcolor", TK_OPTION_COLOR,
847 Tk_Offset(NotebookElement,lightColorObj), LIGHT_COLOR },
848 { "-darkcolor", TK_OPTION_COLOR,
849 Tk_Offset(NotebookElement,darkColorObj), DARK_COLOR },
850 { NULL, TK_OPTION_BOOLEAN, 0, NULL }
851 };
852
TabElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)853 static void TabElementSize(
854 void *dummy, void *elementRecord, Tk_Window tkwin,
855 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
856 {
857 int borderWidth = 2;
858 (void)dummy;
859 (void)elementRecord;
860 (void)tkwin;
861 (void)widthPtr;
862 (void)heightPtr;
863
864 paddingPtr->top = paddingPtr->left = paddingPtr->right = borderWidth;
865 paddingPtr->bottom = 0;
866 }
867
TabElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)868 static void TabElementDraw(
869 void *dummy, void *elementRecord, Tk_Window tkwin,
870 Drawable d, Ttk_Box b, unsigned int state)
871 {
872 NotebookElement *tab = (NotebookElement *)elementRecord;
873 Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, tab->backgroundObj);
874 Display *display = Tk_Display(tkwin);
875 int borderWidth = 2, dh = 0;
876 int x1,y1,x2,y2;
877 GC gc;
878 const int w = WIN32_XDRAWLINE_HACK;
879 (void)dummy;
880
881 if (state & TTK_STATE_SELECTED) {
882 dh = borderWidth;
883 }
884
885 if (state & TTK_STATE_USER2) { /* Rightmost tab */
886 --b.width;
887 }
888
889 Tk_Fill3DRectangle(tkwin, d, border,
890 b.x+2, b.y+2, b.width-1, b.height-2+dh, borderWidth, TK_RELIEF_FLAT);
891
892 x1 = b.x, x2 = b.x + b.width;
893 y1 = b.y, y2 = b.y + b.height;
894
895
896 gc=Ttk_GCForColor(tkwin,tab->borderColorObj,d);
897 XDrawLine(display,d,gc, x1,y1+1, x1,y2+w);
898 XDrawLine(display,d,gc, x2,y1+1, x2,y2+w);
899 XDrawLine(display,d,gc, x1+1,y1, x2-1+w,y1);
900
901 gc=Ttk_GCForColor(tkwin,tab->lightColorObj,d);
902 XDrawLine(display,d,gc, x1+1,y1+1, x1+1,y2-1+dh+w);
903 XDrawLine(display,d,gc, x1+1,y1+1, x2-1+w,y1+1);
904 }
905
906 static Ttk_ElementSpec TabElementSpec =
907 {
908 TK_STYLE_VERSION_2,
909 sizeof(NotebookElement),
910 NotebookElementOptions,
911 TabElementSize,
912 TabElementDraw
913 };
914
ClientElementSize(void * dummy,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)915 static void ClientElementSize(
916 void *dummy, void *elementRecord, Tk_Window tkwin,
917 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
918 {
919 int borderWidth = 2;
920 (void)dummy;
921 (void)elementRecord;
922 (void)tkwin;
923 (void)widthPtr;
924 (void)heightPtr;
925
926 *paddingPtr = Ttk_UniformPadding((short)borderWidth);
927 }
928
ClientElementDraw(void * dummy,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)929 static void ClientElementDraw(
930 void *dummy, void *elementRecord, Tk_Window tkwin,
931 Drawable d, Ttk_Box b, unsigned int state)
932 {
933 NotebookElement *ce = (NotebookElement *)elementRecord;
934 Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, ce->backgroundObj);
935 int borderWidth = 2;
936 (void)dummy;
937 (void)state;
938
939 Tk_Fill3DRectangle(tkwin, d, border,
940 b.x, b.y, b.width, b.height, borderWidth,TK_RELIEF_FLAT);
941 DrawSmoothBorder(tkwin, d, b,
942 ce->borderColorObj, ce->lightColorObj, ce->darkColorObj);
943 }
944
945 static Ttk_ElementSpec ClientElementSpec =
946 {
947 TK_STYLE_VERSION_2,
948 sizeof(NotebookElement),
949 NotebookElementOptions,
950 ClientElementSize,
951 ClientElementDraw
952 };
953
954 /*------------------------------------------------------------------------
955 * +++ Modified widget layouts.
956 */
957
958 TTK_BEGIN_LAYOUT_TABLE(LayoutTable)
959
960 TTK_LAYOUT("TCombobox",
961 TTK_NODE("Combobox.downarrow", TTK_PACK_RIGHT|TTK_FILL_Y)
962 TTK_GROUP("Combobox.field", TTK_FILL_BOTH,
963 TTK_GROUP("Combobox.padding", TTK_FILL_BOTH,
964 TTK_NODE("Combobox.textarea", TTK_FILL_BOTH))))
965
966 TTK_LAYOUT("Horizontal.Sash",
967 TTK_GROUP("Sash.hsash", TTK_FILL_BOTH,
968 TTK_NODE("Sash.hgrip", TTK_FILL_BOTH)))
969
970 TTK_LAYOUT("Vertical.Sash",
971 TTK_GROUP("Sash.vsash", TTK_FILL_BOTH,
972 TTK_NODE("Sash.vgrip", TTK_FILL_BOTH)))
973
974 TTK_END_LAYOUT_TABLE
975
976 /*------------------------------------------------------------------------
977 * +++ Initialization.
978 */
979
980 MODULE_SCOPE int
TtkClamTheme_Init(Tcl_Interp * interp)981 TtkClamTheme_Init(Tcl_Interp *interp)
982 {
983 Ttk_Theme theme = Ttk_CreateTheme(interp, "clam", 0);
984
985 if (!theme) {
986 return TCL_ERROR;
987 }
988
989 Ttk_RegisterElement(interp,
990 theme, "border", &BorderElementSpec, NULL);
991 Ttk_RegisterElement(interp,
992 theme, "field", &FieldElementSpec, NULL);
993 Ttk_RegisterElement(interp,
994 theme, "Combobox.field", &ComboboxFieldElementSpec, NULL);
995 Ttk_RegisterElement(interp,
996 theme, "trough", &TroughElementSpec, NULL);
997 Ttk_RegisterElement(interp,
998 theme, "thumb", &ThumbElementSpec, NULL);
999 Ttk_RegisterElement(interp,
1000 theme, "uparrow", &ArrowElementSpec, &ArrowElements[0]);
1001 Ttk_RegisterElement(interp,
1002 theme, "downarrow", &ArrowElementSpec, &ArrowElements[1]);
1003 Ttk_RegisterElement(interp,
1004 theme, "leftarrow", &ArrowElementSpec, &ArrowElements[2]);
1005 Ttk_RegisterElement(interp,
1006 theme, "rightarrow", &ArrowElementSpec, &ArrowElements[3]);
1007
1008 Ttk_RegisterElement(interp,
1009 theme, "Radiobutton.indicator", &RadioIndicatorElementSpec, NULL);
1010 Ttk_RegisterElement(interp,
1011 theme, "Checkbutton.indicator", &CheckIndicatorElementSpec, NULL);
1012 Ttk_RegisterElement(interp,
1013 theme, "Menubutton.indicator", &MenuIndicatorElementSpec, NULL);
1014
1015 Ttk_RegisterElement(interp, theme, "tab", &TabElementSpec, NULL);
1016 Ttk_RegisterElement(interp, theme, "client", &ClientElementSpec, NULL);
1017
1018 Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL);
1019 Ttk_RegisterElement(interp, theme, "bar", &PbarElementSpec, NULL);
1020 Ttk_RegisterElement(interp, theme, "pbar", &PbarElementSpec, NULL);
1021
1022 Ttk_RegisterElement(interp, theme, "hgrip",
1023 &GripElementSpec, &GripClientData[0]);
1024 Ttk_RegisterElement(interp, theme, "vgrip",
1025 &GripElementSpec, &GripClientData[1]);
1026
1027 Ttk_RegisterLayouts(theme, LayoutTable);
1028
1029 Tcl_PkgProvide(interp, "ttk::theme::clam", TTK_VERSION);
1030
1031 return TCL_OK;
1032 }
1033