1 /*
2 * Copyright (c) 2003, Joe English
3 *
4 * Tk alternate theme, intended to match the MSUE and Gtk's (old) default theme
5 */
6
7 #include "tkInt.h"
8 #include "ttkTheme.h"
9
10 #if defined(_WIN32)
11 static const int WIN32_XDRAWLINE_HACK = 1;
12 #else
13 static const int WIN32_XDRAWLINE_HACK = 0;
14 #endif
15
16 #if defined(MAC_OSX_TK)
17 #define IGNORES_VISUAL
18 #endif
19
20 #define BORDERWIDTH 2
21 #define SCROLLBAR_WIDTH 14
22 #define MIN_THUMB_SIZE 8
23
24 /*
25 *----------------------------------------------------------------------
26 *
27 * Helper routines for border drawing:
28 *
29 * NOTE: MSUE specifies a slightly different arrangement
30 * for button borders than for other elements; "shadowColors"
31 * is for button borders.
32 *
33 * Please excuse the gross misspelling "LITE" for "LIGHT",
34 * but it makes things line up nicer.
35 */
36
37 enum BorderColor { FLAT = 1, LITE = 2, DARK = 3, BRDR = 4 };
38
39 /* top-left outer, top-left inner, bottom-right inner, bottom-right outer */
40 static int const shadowColors[6][4] = {
41 { FLAT, FLAT, FLAT, FLAT }, /* TK_RELIEF_FLAT = 0*/
42 { DARK, LITE, DARK, LITE }, /* TK_RELIEF_GROOVE = 1*/
43 { LITE, FLAT, DARK, BRDR }, /* TK_RELIEF_RAISED = 2*/
44 { LITE, DARK, LITE, DARK }, /* TK_RELIEF_RIDGE = 3*/
45 { BRDR, BRDR, BRDR, BRDR }, /* TK_RELIEF_SOLID = 4*/
46 { BRDR, DARK, FLAT, LITE } /* TK_RELIEF_SUNKEN = 5*/
47 };
48
49 /* top-left, bottom-right */
50 static int const thinShadowColors[6][4] = {
51 { FLAT, FLAT }, /* TK_RELIEF_FLAT = 0*/
52 { DARK, LITE }, /* TK_RELIEF_GROOVE = 1*/
53 { LITE, DARK }, /* TK_RELIEF_RAISED = 2*/
54 { LITE, DARK }, /* TK_RELIEF_RIDGE = 3*/
55 { BRDR, BRDR }, /* TK_RELIEF_SOLID = 4*/
56 { DARK, LITE } /* TK_RELIEF_SUNKEN = 5*/
57 };
58
DrawCorner(Tk_Window tkwin,Drawable d,Tk_3DBorder border,GC borderGC,int x,int y,int width,int height,int corner,enum BorderColor color)59 static void DrawCorner(
60 Tk_Window tkwin,
61 Drawable d,
62 Tk_3DBorder border, /* get most GCs from here... */
63 GC borderGC, /* "window border" color GC */
64 int x,int y, int width,int height, /* where to draw */
65 int corner, /* 0 => top left; 1 => bottom right */
66 enum BorderColor color)
67 {
68 XPoint points[3];
69 GC gc;
70
71 --width; --height;
72 points[0].x = x; points[0].y = y+height;
73 points[1].x = x+width*corner; points[1].y = y+height*corner;
74 points[2].x = x+width; points[2].y = y;
75
76 if (color == BRDR)
77 gc = borderGC;
78 else
79 gc = Tk_3DBorderGC(tkwin, border, (int)color);
80
81 XDrawLines(Tk_Display(tkwin), d, gc, points, 3, CoordModeOrigin);
82 }
83
DrawBorder(Tk_Window tkwin,Drawable d,Tk_3DBorder border,XColor * borderColor,Ttk_Box b,int borderWidth,int relief)84 static void DrawBorder(
85 Tk_Window tkwin, Drawable d, Tk_3DBorder border, XColor *borderColor,
86 Ttk_Box b, int borderWidth, int relief)
87 {
88 GC borderGC = Tk_GCForColor(borderColor, d);
89
90 switch (borderWidth) {
91 case 2: /* "thick" border */
92 DrawCorner(tkwin, d, border, borderGC,
93 b.x, b.y, b.width, b.height, 0,shadowColors[relief][0]);
94 DrawCorner(tkwin, d, border, borderGC,
95 b.x+1, b.y+1, b.width-2, b.height-2, 0,shadowColors[relief][1]);
96 DrawCorner(tkwin, d, border, borderGC,
97 b.x+1, b.y+1, b.width-2, b.height-2, 1,shadowColors[relief][2]);
98 DrawCorner(tkwin, d, border, borderGC,
99 b.x, b.y, b.width, b.height, 1,shadowColors[relief][3]);
100 break;
101 case 1: /* "thin" border */
102 DrawCorner(tkwin, d, border, borderGC,
103 b.x, b.y, b.width, b.height, 0, thinShadowColors[relief][0]);
104 DrawCorner(tkwin, d, border, borderGC,
105 b.x, b.y, b.width, b.height, 1, thinShadowColors[relief][1]);
106 break;
107 case 0: /* no border -- do nothing */
108 break;
109 default: /* Fall back to Motif-style borders: */
110 Tk_Draw3DRectangle(tkwin, d, border,
111 b.x, b.y, b.width, b.height, borderWidth,relief);
112 break;
113 }
114 }
115
116 /* Alternate shadow colors for entry fields:
117 * NOTE: FLAT color is normally white, and the LITE color is a darker shade.
118 */
119 static int fieldShadowColors[4] = { DARK, BRDR, LITE, FLAT };
120
DrawFieldBorder(Tk_Window tkwin,Drawable d,Tk_3DBorder border,XColor * borderColor,Ttk_Box b)121 static void DrawFieldBorder(
122 Tk_Window tkwin, Drawable d, Tk_3DBorder border, XColor *borderColor,
123 Ttk_Box b)
124 {
125 GC borderGC = Tk_GCForColor(borderColor, d);
126 DrawCorner(tkwin, d, border, borderGC,
127 b.x, b.y, b.width, b.height, 0,fieldShadowColors[0]);
128 DrawCorner(tkwin, d, border, borderGC,
129 b.x+1, b.y+1, b.width-2, b.height-2, 0,fieldShadowColors[1]);
130 DrawCorner(tkwin, d, border, borderGC,
131 b.x+1, b.y+1, b.width-2, b.height-2, 1,fieldShadowColors[2]);
132 DrawCorner(tkwin, d, border, borderGC,
133 b.x, b.y, b.width, b.height, 1,fieldShadowColors[3]);
134 return;
135 }
136
137 /*
138 * ArrowPoints --
139 * Compute points of arrow polygon.
140 */
ArrowPoints(Ttk_Box b,ArrowDirection dir,XPoint points[4])141 static void ArrowPoints(Ttk_Box b, ArrowDirection dir, XPoint points[4])
142 {
143 int cx, cy, h;
144
145 switch (dir) {
146 case ARROW_UP:
147 h = (b.width - 1)/2;
148 cx = b.x + h;
149 cy = b.y;
150 if (b.height <= h) h = b.height - 1;
151 points[0].x = cx; points[0].y = cy;
152 points[1].x = cx - h; points[1].y = cy + h;
153 points[2].x = cx + h; points[2].y = cy + h;
154 break;
155 case ARROW_DOWN:
156 h = (b.width - 1)/2;
157 cx = b.x + h;
158 cy = b.y + b.height - 1;
159 if (b.height <= h) h = b.height - 1;
160 points[0].x = cx; points[0].y = cy;
161 points[1].x = cx - h; points[1].y = cy - h;
162 points[2].x = cx + h; points[2].y = cy - h;
163 break;
164 case ARROW_LEFT:
165 h = (b.height - 1)/2;
166 cx = b.x;
167 cy = b.y + h;
168 if (b.width <= h) h = b.width - 1;
169 points[0].x = cx; points[0].y = cy;
170 points[1].x = cx + h; points[1].y = cy - h;
171 points[2].x = cx + h; points[2].y = cy + h;
172 break;
173 case ARROW_RIGHT:
174 h = (b.height - 1)/2;
175 cx = b.x + b.width - 1;
176 cy = b.y + h;
177 if (b.width <= h) h = b.width - 1;
178 points[0].x = cx; points[0].y = cy;
179 points[1].x = cx - h; points[1].y = cy - h;
180 points[2].x = cx - h; points[2].y = cy + h;
181 break;
182 }
183
184 points[3].x = points[0].x;
185 points[3].y = points[0].y;
186 }
187
188 /*public*/
TtkArrowSize(int h,ArrowDirection dir,int * widthPtr,int * heightPtr)189 void TtkArrowSize(int h, ArrowDirection dir, int *widthPtr, int *heightPtr)
190 {
191 switch (dir) {
192 case ARROW_UP:
193 case ARROW_DOWN: *widthPtr = 2*h+1; *heightPtr = h+1; break;
194 case ARROW_LEFT:
195 case ARROW_RIGHT: *widthPtr = h+1; *heightPtr = 2*h+1;
196 }
197 }
198
199 /*
200 * TtkDrawArrow, TtkFillArrow --
201 * Draw an arrow in the indicated direction inside the specified box.
202 */
203 /*public*/
TtkFillArrow(Display * display,Drawable d,GC gc,Ttk_Box b,ArrowDirection dir)204 void TtkFillArrow(
205 Display *display, Drawable d, GC gc, Ttk_Box b, ArrowDirection dir)
206 {
207 XPoint points[4];
208 ArrowPoints(b, dir, points);
209 XFillPolygon(display, d, gc, points, 3, Convex, CoordModeOrigin);
210 XDrawLines(display, d, gc, points, 4, CoordModeOrigin);
211
212 /* Work around bug [77527326e5] - ttk artifacts on Ubuntu */
213 XDrawPoint(display, d, gc, points[2].x, points[2].y);
214 }
215
216 /*public*/
TtkDrawArrow(Display * display,Drawable d,GC gc,Ttk_Box b,ArrowDirection dir)217 void TtkDrawArrow(
218 Display *display, Drawable d, GC gc, Ttk_Box b, ArrowDirection dir)
219 {
220 XPoint points[4];
221 ArrowPoints(b, dir, points);
222 XDrawLines(display, d, gc, points, 4, CoordModeOrigin);
223
224 /* Work around bug [77527326e5] - ttk artifacts on Ubuntu */
225 XDrawPoint(display, d, gc, points[2].x, points[2].y);
226 }
227
228 /*
229 *----------------------------------------------------------------------
230 * +++ Border element implementation.
231 *
232 * This border consists of (from outside-in):
233 *
234 * + a 1-pixel thick default indicator (defaultable widgets only)
235 * + 1- or 2- pixel shaded border (controlled by -background and -relief)
236 * + 1 pixel padding (???)
237 */
238
239 typedef struct {
240 Tcl_Obj *borderObj;
241 Tcl_Obj *borderColorObj; /* Extra border color */
242 Tcl_Obj *borderWidthObj;
243 Tcl_Obj *reliefObj;
244 Tcl_Obj *defaultStateObj; /* for buttons */
245 } BorderElement;
246
247 static Ttk_ElementOptionSpec BorderElementOptions[] = {
248 { "-background", TK_OPTION_BORDER, Tk_Offset(BorderElement,borderObj),
249 DEFAULT_BACKGROUND },
250 { "-bordercolor",TK_OPTION_COLOR,
251 Tk_Offset(BorderElement,borderColorObj), "black" },
252 { "-default", TK_OPTION_ANY, Tk_Offset(BorderElement,defaultStateObj),
253 "disabled" },
254 { "-borderwidth",TK_OPTION_PIXELS,Tk_Offset(BorderElement,borderWidthObj),
255 STRINGIFY(BORDERWIDTH) },
256 { "-relief", TK_OPTION_RELIEF, Tk_Offset(BorderElement,reliefObj),
257 "flat" },
258 { NULL, 0, 0, NULL }
259 };
260
BorderElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)261 static void BorderElementSize(
262 void *clientData, void *elementRecord, Tk_Window tkwin,
263 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
264 {
265 BorderElement *bd = elementRecord;
266 int borderWidth = 0;
267 int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
268
269 Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
270 Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
271
272 if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
273 ++borderWidth;
274 }
275
276 *paddingPtr = Ttk_UniformPadding((short)borderWidth);
277 }
278
BorderElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)279 static void BorderElementDraw(
280 void *clientData, void *elementRecord,
281 Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state)
282 {
283 BorderElement *bd = elementRecord;
284 Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, bd->borderObj);
285 XColor *borderColor = Tk_GetColorFromObj(tkwin, bd->borderColorObj);
286 int borderWidth = 2;
287 int relief = TK_RELIEF_FLAT;
288 int defaultState = TTK_BUTTON_DEFAULT_DISABLED;
289
290 /*
291 * Get option values.
292 */
293 Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
294 Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
295 Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState);
296
297 if (defaultState == TTK_BUTTON_DEFAULT_ACTIVE) {
298 GC gc = Tk_GCForColor(borderColor, d);
299 XDrawRectangle(Tk_Display(tkwin), d, gc,
300 b.x, b.y, b.width-1, b.height-1);
301 }
302 if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) {
303 /* Space for default ring: */
304 b = Ttk_PadBox(b, Ttk_UniformPadding(1));
305 }
306
307 DrawBorder(tkwin, d, border, borderColor, b, borderWidth, relief);
308 }
309
310 static Ttk_ElementSpec BorderElementSpec = {
311 TK_STYLE_VERSION_2,
312 sizeof(BorderElement),
313 BorderElementOptions,
314 BorderElementSize,
315 BorderElementDraw
316 };
317
318 /*----------------------------------------------------------------------
319 * +++ Field element:
320 * Used for editable fields.
321 */
322 typedef struct {
323 Tcl_Obj *borderObj;
324 Tcl_Obj *borderColorObj; /* Extra border color */
325 } FieldElement;
326
327 static Ttk_ElementOptionSpec FieldElementOptions[] = {
328 { "-fieldbackground", TK_OPTION_BORDER, Tk_Offset(FieldElement,borderObj),
329 "white" },
330 { "-bordercolor",TK_OPTION_COLOR, Tk_Offset(FieldElement,borderColorObj),
331 "black" },
332 { NULL, 0, 0, NULL }
333 };
334
FieldElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)335 static void FieldElementSize(
336 void *clientData, void *elementRecord, Tk_Window tkwin,
337 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
338 {
339 *paddingPtr = Ttk_UniformPadding(2);
340 }
341
FieldElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)342 static void FieldElementDraw(
343 void *clientData, void *elementRecord, Tk_Window tkwin,
344 Drawable d, Ttk_Box b, unsigned int state)
345 {
346 FieldElement *field = elementRecord;
347 Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, field->borderObj);
348 XColor *borderColor = Tk_GetColorFromObj(tkwin, field->borderColorObj);
349
350 Tk_Fill3DRectangle(
351 tkwin, d, border, b.x, b.y, b.width, b.height, 0, TK_RELIEF_SUNKEN);
352 DrawFieldBorder(tkwin, d, border, borderColor, b);
353 }
354
355 static Ttk_ElementSpec FieldElementSpec = {
356 TK_STYLE_VERSION_2,
357 sizeof(FieldElement),
358 FieldElementOptions,
359 FieldElementSize,
360 FieldElementDraw
361 };
362
363 /*------------------------------------------------------------------------
364 * Indicators --
365 *
366 * Code derived (probably incorrectly) from TIP 109 implementation,
367 * unix/tkUnixButton.c r 1.15.
368 */
369
370 /*
371 * Indicator bitmap descriptor:
372 */
373 typedef struct {
374 int width; /* Width of each image */
375 int height; /* Height of each image */
376 int nimages; /* #images / row */
377 const char *const *pixels; /* array[height] of char[width*nimage] */
378 Ttk_StateTable *map;/* used to look up image index by state */
379 } IndicatorSpec;
380
381 #if 0
382 /*XPM*/
383 static const char *const button_images[] = {
384 /* width height ncolors chars_per_pixel */
385 "52 13 8 1",
386 /* colors */
387 "A c #808000000000 s shadow",
388 "B c #000080800000 s highlight",
389 "C c #808080800000 s 3dlight",
390 "D c #000000008080 s window",
391 "E c #808000008080 s 3ddark",
392 "F c #000080808080 s frame",
393 "G c #000000000000 s foreground",
394 "H c #000080800000 s disabledfg",
395 };
396 #endif
397
398 static Ttk_StateTable checkbutton_states[] = {
399 { 0, 0, TTK_STATE_SELECTED|TTK_STATE_DISABLED },
400 { 1, TTK_STATE_SELECTED, TTK_STATE_DISABLED },
401 { 2, TTK_STATE_DISABLED, TTK_STATE_SELECTED },
402 { 3, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0 },
403 { 0, 0, 0 }
404 };
405
406 static const char *const checkbutton_pixels[] = {
407 "AAAAAAAAAAAABAAAAAAAAAAAABAAAAAAAAAAAABAAAAAAAAAAAAB",
408 "AEEEEEEEEEECBAEEEEEEEEEECBAEEEEEEEEEECBAEEEEEEEEEECB",
409 "AEDDDDDDDDDCBAEDDDDDDDDDCBAEFFFFFFFFFCBAEFFFFFFFFFCB",
410 "AEDDDDDDDDDCBAEDDDDDDDGDCBAEFFFFFFFFFCBAEFFFFFFFHFCB",
411 "AEDDDDDDDDDCBAEDDDDDDGGDCBAEFFFFFFFFFCBAEFFFFFFHHFCB",
412 "AEDDDDDDDDDCBAEDGDDDGGGDCBAEFFFFFFFFFCBAEFHFFFHHHFCB",
413 "AEDDDDDDDDDCBAEDGGDGGGDDCBAEFFFFFFFFFCBAEFHHFHHHFFCB",
414 "AEDDDDDDDDDCBAEDGGGGGDDDCBAEFFFFFFFFFCBAEFHHHHHFFFCB",
415 "AEDDDDDDDDDCBAEDDGGGDDDDCBAEFFFFFFFFFCBAEFFHHHFFFFCB",
416 "AEDDDDDDDDDCBAEDDDGDDDDDCBAEFFFFFFFFFCBAEFFFHFFFFFCB",
417 "AEDDDDDDDDDCBAEDDDDDDDDDCBAEFFFFFFFFFCBAEFFFFFFFFFCB",
418 "ACCCCCCCCCCCBACCCCCCCCCCCBACCCCCCCCCCCBACCCCCCCCCCCB",
419 "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
420 };
421
422 static IndicatorSpec checkbutton_spec = {
423 13, 13, 4, /* width, height, nimages */
424 checkbutton_pixels,
425 checkbutton_states
426 };
427
428 static Ttk_StateTable radiobutton_states[] = {
429 { 0, 0, TTK_STATE_SELECTED|TTK_STATE_DISABLED },
430 { 1, TTK_STATE_SELECTED, TTK_STATE_DISABLED },
431 { 2, TTK_STATE_DISABLED, TTK_STATE_SELECTED },
432 { 3, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0 },
433 { 0, 0, 0 }
434 };
435
436 static const char *const radiobutton_pixels[] = {
437 "FFFFAAAAFFFFFFFFFAAAAFFFFFFFFFAAAAFFFFFFFFFAAAAFFFFF",
438 "FFAAEEEEAAFFFFFAAEEEEAAFFFFFAAEEEEAAFFFFFAAEEEEAAFFF",
439 "FAEEDDDDEEBFFFAEEDDDDEEBFFFAEEFFFFEEBFFFAEEFFFFEEBFF",
440 "FAEDDDDDDCBFFFAEDDDDDDCBFFFAEFFFFFFCBFFFAEFFFFFFCBFF",
441 "AEDDDDDDDDCBFAEDDDGGDDDCBFAEFFFFFFFFCBFAEFFFHHFFFCBF",
442 "AEDDDDDDDDCBFAEDDGGGGDDCBFAEFFFFFFFFCBFAEFFHHHHFFCBF",
443 "AEDDDDDDDDCBFAEDDGGGGDDCBFAEFFFFFFFFCBFAEFFHHHHFFCBF",
444 "AEDDDDDDDDCBFAEDDDGGDDDCBFAEFFFFFFFFCBFAEFFFHHFFFCBF",
445 "FAEDDDDDDCBFFFAEDDDDDDCBFFFAEFFFFFFCBFFFAEFFFFFFCBFF",
446 "FACCDDDDCCBFFFACCDDDDCCBFFFACCFFFFCCBFFFACCFFFFCCBFF",
447 "FFBBCCCCBBFFFFFBBCCCCBBFFFFFBBCCCCBBFFFFFBBCCCCBBFFF",
448 "FFFFBBBBFFFFFFFFFBBBBFFFFFFFFFBBBBFFFFFFFFFBBBBFFFFF",
449 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
450 };
451
452 static IndicatorSpec radiobutton_spec = {
453 13, 13, 4, /* width, height, nimages */
454 radiobutton_pixels,
455 radiobutton_states
456 };
457
458 typedef struct {
459 Tcl_Obj *backgroundObj;
460 Tcl_Obj *foregroundObj;
461 Tcl_Obj *colorObj;
462 Tcl_Obj *lightColorObj;
463 Tcl_Obj *shadeColorObj;
464 Tcl_Obj *borderColorObj;
465 Tcl_Obj *marginObj;
466 } IndicatorElement;
467
468 static Ttk_ElementOptionSpec IndicatorElementOptions[] = {
469 { "-background", TK_OPTION_COLOR,
470 Tk_Offset(IndicatorElement,backgroundObj), DEFAULT_BACKGROUND },
471 { "-foreground", TK_OPTION_COLOR,
472 Tk_Offset(IndicatorElement,foregroundObj), DEFAULT_FOREGROUND },
473 { "-indicatorcolor", TK_OPTION_COLOR,
474 Tk_Offset(IndicatorElement,colorObj), "#FFFFFF" },
475 { "-lightcolor", TK_OPTION_COLOR,
476 Tk_Offset(IndicatorElement,lightColorObj), "#DDDDDD" },
477 { "-shadecolor", TK_OPTION_COLOR,
478 Tk_Offset(IndicatorElement,shadeColorObj), "#888888" },
479 { "-bordercolor", TK_OPTION_COLOR,
480 Tk_Offset(IndicatorElement,borderColorObj), "black" },
481 { "-indicatormargin", TK_OPTION_STRING,
482 Tk_Offset(IndicatorElement,marginObj), "0 2 4 2" },
483 { NULL, 0, 0, NULL }
484 };
485
IndicatorElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)486 static void IndicatorElementSize(
487 void *clientData, void *elementRecord, Tk_Window tkwin,
488 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
489 {
490 IndicatorSpec *spec = clientData;
491 IndicatorElement *indicator = elementRecord;
492 Ttk_Padding margins;
493 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
494 *widthPtr = spec->width + Ttk_PaddingWidth(margins);
495 *heightPtr = spec->height + Ttk_PaddingHeight(margins);
496 }
497
IndicatorElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)498 static void IndicatorElementDraw(
499 void *clientData, void *elementRecord, Tk_Window tkwin,
500 Drawable d, Ttk_Box b, unsigned int state)
501 {
502 IndicatorSpec *spec = clientData;
503 IndicatorElement *indicator = elementRecord;
504 Display *display = Tk_Display(tkwin);
505 Ttk_Padding padding;
506 XColor *fgColor, *frameColor, *shadeColor, *indicatorColor, *borderColor;
507
508 int index, ix, iy;
509 XGCValues gcValues;
510 GC copyGC;
511 unsigned long imgColors[8];
512 XImage *img = NULL;
513
514 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding);
515 b = Ttk_PadBox(b, padding);
516
517 if ( b.x < 0
518 || b.y < 0
519 || Tk_Width(tkwin) < b.x + spec->width
520 || Tk_Height(tkwin) < b.y + spec->height)
521 {
522 /* Oops! not enough room to display the image.
523 * Don't draw anything.
524 */
525 return;
526 }
527
528 /*
529 * Fill in imgColors palette:
530 *
531 * (SHOULD: take light and shade colors from the border object,
532 * but Tk doesn't provide easy access to these in the public API.)
533 */
534 fgColor = Tk_GetColorFromObj(tkwin, indicator->foregroundObj);
535 frameColor = Tk_GetColorFromObj(tkwin, indicator->backgroundObj);
536 shadeColor = Tk_GetColorFromObj(tkwin, indicator->shadeColorObj);
537 indicatorColor = Tk_GetColorFromObj(tkwin, indicator->colorObj);
538 borderColor = Tk_GetColorFromObj(tkwin, indicator->borderColorObj);
539
540 imgColors[0 /*A*/] = shadeColor->pixel;
541 imgColors[1 /*B*/] = indicatorColor->pixel;
542 imgColors[2 /*C*/] = frameColor->pixel;
543 imgColors[3 /*D*/] = indicatorColor->pixel;
544 imgColors[4 /*E*/] = borderColor->pixel;
545 imgColors[5 /*F*/] = frameColor->pixel;
546 imgColors[6 /*G*/] = fgColor->pixel;
547 imgColors[7 /*H*/] = fgColor->pixel;
548
549 /*
550 * Create a scratch buffer to store the image:
551 */
552
553 #if defined(IGNORES_VISUAL)
554
555 /*
556 * Platforms which ignore the VisualInfo can use XCreateImage to get the
557 * scratch image. This is essential on macOS, where it is not safe to call
558 * XGetImage in a display procedure.
559 */
560
561 img = XCreateImage(display, NULL, 32, ZPixmap, 0, NULL,
562 (unsigned int)spec->width, (unsigned int)spec->height,
563 0, 0);
564 #else
565
566 /*
567 * This trick allows creating the scratch XImage without having to
568 * construct a VisualInfo.
569 */
570
571 img = XGetImage(display, d, 0, 0,
572 (unsigned int)spec->width, (unsigned int)spec->height,
573 AllPlanes, ZPixmap);
574 #endif
575
576 if (img == NULL) {
577 return;
578 }
579
580 #if defined(IGNORES_VISUAL)
581
582 img->data = ckalloc(img->bytes_per_line * img->height);
583 if (img->data == NULL) {
584 XDestroyImage(img);
585 return;
586 }
587
588 #endif
589
590 /*
591 * Create the image, painting it into the XImage one pixel at a time.
592 */
593
594 index = Ttk_StateTableLookup(spec->map, state);
595 for (iy=0 ; iy<spec->height ; iy++) {
596 for (ix=0 ; ix<spec->width ; ix++) {
597 XPutPixel(img, ix, iy,
598 imgColors[spec->pixels[iy][index*spec->width+ix] - 'A'] );
599 }
600 }
601
602 /*
603 * Copy the image onto our target drawable surface.
604 */
605
606 memset(&gcValues, 0, sizeof(gcValues));
607 copyGC = Tk_GetGC(tkwin, 0, &gcValues);
608 TkPutImage(NULL, 0, display, d, copyGC, img, 0, 0, b.x, b.y,
609 spec->width, spec->height);
610
611 /*
612 * Tidy up.
613 */
614
615 Tk_FreeGC(display, copyGC);
616
617 /*
618 * Protect against the possibility that some future platform might
619 * not use the Tk memory manager in its implementation of XDestroyImage,
620 * even though that would be an extremely strange thing to do.
621 */
622
623 #if defined(IGNORES_VISUAL)
624 ckfree(img->data);
625 img->data = NULL;
626 #endif
627
628 XDestroyImage(img);
629 }
630
631 static Ttk_ElementSpec IndicatorElementSpec = {
632 TK_STYLE_VERSION_2,
633 sizeof(IndicatorElement),
634 IndicatorElementOptions,
635 IndicatorElementSize,
636 IndicatorElementDraw
637 };
638
639 /*----------------------------------------------------------------------
640 * +++ Arrow element(s).
641 *
642 * Draws a solid triangle, inside a box.
643 * clientData is an enum ArrowDirection pointer.
644 */
645
646 static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT };
647 typedef struct {
648 Tcl_Obj *sizeObj;
649 Tcl_Obj *borderObj;
650 Tcl_Obj *borderColorObj; /* Extra color for borders */
651 Tcl_Obj *reliefObj;
652 Tcl_Obj *colorObj; /* Arrow color */
653 } ArrowElement;
654
655 static Ttk_ElementOptionSpec ArrowElementOptions[] = {
656 { "-arrowsize", TK_OPTION_PIXELS,
657 Tk_Offset(ArrowElement,sizeObj), STRINGIFY(SCROLLBAR_WIDTH) },
658 { "-background", TK_OPTION_BORDER,
659 Tk_Offset(ArrowElement,borderObj), DEFAULT_BACKGROUND },
660 { "-bordercolor", TK_OPTION_COLOR,
661 Tk_Offset(ArrowElement,borderColorObj), "black" },
662 { "-relief", TK_OPTION_RELIEF,
663 Tk_Offset(ArrowElement,reliefObj),"raised"},
664 { "-arrowcolor", TK_OPTION_COLOR,
665 Tk_Offset(ArrowElement,colorObj),"black"},
666 { NULL, 0, 0, NULL }
667 };
668
669 /*
670 * Note asymmetric padding:
671 * top/left padding is 1 less than bottom/right,
672 * since in this theme 2-pixel borders are asymmetric.
673 */
674 static Ttk_Padding ArrowPadding = { 3,3,4,4 };
675
ArrowElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)676 static void ArrowElementSize(
677 void *clientData, void *elementRecord, Tk_Window tkwin,
678 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
679 {
680 ArrowElement *arrow = elementRecord;
681 int direction = *(int *)clientData;
682 int width = SCROLLBAR_WIDTH;
683
684 Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &width);
685 width -= Ttk_PaddingWidth(ArrowPadding);
686 TtkArrowSize(width/2, direction, widthPtr, heightPtr);
687 *widthPtr += Ttk_PaddingWidth(ArrowPadding);
688 *heightPtr += Ttk_PaddingHeight(ArrowPadding);
689 }
690
ArrowElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)691 static void ArrowElementDraw(
692 void *clientData, void *elementRecord, Tk_Window tkwin,
693 Drawable d, Ttk_Box b, unsigned int state)
694 {
695 int direction = *(int *)clientData;
696 ArrowElement *arrow = elementRecord;
697 Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, arrow->borderObj);
698 XColor *borderColor = Tk_GetColorFromObj(tkwin, arrow->borderColorObj);
699 XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj);
700 int relief = TK_RELIEF_RAISED;
701 int borderWidth = 2;
702
703 Tk_GetReliefFromObj(NULL, arrow->reliefObj, &relief);
704
705 Tk_Fill3DRectangle(
706 tkwin, d, border, b.x, b.y, b.width, b.height, 0, TK_RELIEF_FLAT);
707 DrawBorder(tkwin,d,border,borderColor,b,borderWidth,relief);
708
709 TtkFillArrow(Tk_Display(tkwin), d, Tk_GCForColor(arrowColor, d),
710 Ttk_PadBox(b, ArrowPadding), direction);
711 }
712
713 static Ttk_ElementSpec ArrowElementSpec = {
714 TK_STYLE_VERSION_2,
715 sizeof(ArrowElement),
716 ArrowElementOptions,
717 ArrowElementSize,
718 ArrowElementDraw
719 };
720
721 /*----------------------------------------------------------------------
722 * +++ Menubutton indicator:
723 * Draw an arrow in the direction where the menu will be posted.
724 */
725
726 #define MENUBUTTON_ARROW_SIZE 5
727
728 typedef struct {
729 Tcl_Obj *directionObj;
730 Tcl_Obj *sizeObj;
731 Tcl_Obj *colorObj;
732 } MenubuttonArrowElement;
733
734 static const char *directionStrings[] = { /* See also: button.c */
735 "above", "below", "left", "right", "flush", NULL
736 };
737 enum { POST_ABOVE, POST_BELOW, POST_LEFT, POST_RIGHT, POST_FLUSH };
738
739 static Ttk_ElementOptionSpec MenubuttonArrowElementOptions[] = {
740 { "-direction", TK_OPTION_STRING,
741 Tk_Offset(MenubuttonArrowElement,directionObj), "below" },
742 { "-arrowsize", TK_OPTION_PIXELS,
743 Tk_Offset(MenubuttonArrowElement,sizeObj), STRINGIFY(MENUBUTTON_ARROW_SIZE)},
744 { "-arrowcolor",TK_OPTION_COLOR,
745 Tk_Offset(MenubuttonArrowElement,colorObj), "black"},
746 { NULL, 0, 0, NULL }
747 };
748
749 static Ttk_Padding MenubuttonArrowPadding = { 3, 0, 3, 0 };
750
MenubuttonArrowElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)751 static void MenubuttonArrowElementSize(
752 void *clientData, void *elementRecord, Tk_Window tkwin,
753 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
754 {
755 MenubuttonArrowElement *arrow = elementRecord;
756 int size = MENUBUTTON_ARROW_SIZE;
757 Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &size);
758 *widthPtr = *heightPtr = 2 * size + 1;
759 *widthPtr += Ttk_PaddingWidth(MenubuttonArrowPadding);
760 *heightPtr += Ttk_PaddingHeight(MenubuttonArrowPadding);
761 }
762
MenubuttonArrowElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)763 static void MenubuttonArrowElementDraw(
764 void *clientData, void *elementRecord, Tk_Window tkwin,
765 Drawable d, Ttk_Box b, unsigned int state)
766 {
767 MenubuttonArrowElement *arrow = elementRecord;
768 XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj);
769 GC gc = Tk_GCForColor(arrowColor, d);
770 int size = MENUBUTTON_ARROW_SIZE;
771 int postDirection = POST_BELOW;
772 ArrowDirection arrowDirection = ARROW_DOWN;
773 int width = 0, height = 0;
774
775 Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &size);
776 Tcl_GetIndexFromObjStruct(NULL, arrow->directionObj, directionStrings,
777 sizeof(char *), ""/*message*/, 0/*flags*/, &postDirection);
778
779 /* ... this might not be such a great idea ... */
780 switch (postDirection) {
781 case POST_ABOVE: arrowDirection = ARROW_UP; break;
782 case POST_BELOW: arrowDirection = ARROW_DOWN; break;
783 case POST_LEFT: arrowDirection = ARROW_LEFT; break;
784 case POST_RIGHT: arrowDirection = ARROW_RIGHT; break;
785 case POST_FLUSH: arrowDirection = ARROW_DOWN; break;
786 }
787
788 TtkArrowSize(size, arrowDirection, &width, &height);
789 b = Ttk_PadBox(b, MenubuttonArrowPadding);
790 b = Ttk_AnchorBox(b, width, height, TK_ANCHOR_CENTER);
791 TtkFillArrow(Tk_Display(tkwin), d, gc, b, arrowDirection);
792 }
793
794 static Ttk_ElementSpec MenubuttonArrowElementSpec = {
795 TK_STYLE_VERSION_2,
796 sizeof(MenubuttonArrowElement),
797 MenubuttonArrowElementOptions,
798 MenubuttonArrowElementSize,
799 MenubuttonArrowElementDraw
800 };
801
802 /*----------------------------------------------------------------------
803 * +++ Trough element
804 *
805 * Used in scrollbars and the scale.
806 *
807 * The -groovewidth option can be used to set the size of the short axis
808 * for the drawn area. This will not affect the geometry, but can be used
809 * to draw a thin centered trough inside the packet alloted. This is used
810 * to show a win32-style scale widget. Use -1 or a large number to use the
811 * full area (default).
812 *
813 */
814
815 typedef struct {
816 Tcl_Obj *colorObj;
817 Tcl_Obj *borderWidthObj;
818 Tcl_Obj *reliefObj;
819 Tcl_Obj *grooveWidthObj;
820 Tcl_Obj *orientObj;
821 } TroughElement;
822
823 static Ttk_ElementOptionSpec TroughElementOptions[] = {
824 { "-orient", TK_OPTION_ANY,
825 Tk_Offset(TroughElement, orientObj), "horizontal" },
826 { "-troughborderwidth", TK_OPTION_PIXELS,
827 Tk_Offset(TroughElement,borderWidthObj), "1" },
828 { "-troughcolor", TK_OPTION_BORDER,
829 Tk_Offset(TroughElement,colorObj), DEFAULT_BACKGROUND },
830 { "-troughrelief",TK_OPTION_RELIEF,
831 Tk_Offset(TroughElement,reliefObj), "sunken" },
832 { "-groovewidth", TK_OPTION_PIXELS,
833 Tk_Offset(TroughElement,grooveWidthObj), "-1" },
834 { NULL, 0, 0, NULL }
835 };
836
TroughElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)837 static void TroughElementSize(
838 void *clientData, void *elementRecord, Tk_Window tkwin,
839 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
840 {
841 TroughElement *troughPtr = elementRecord;
842 int borderWidth = 2, grooveWidth = 0;
843
844 Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth);
845 Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->grooveWidthObj, &grooveWidth);
846
847 if (grooveWidth <= 0) {
848 *paddingPtr = Ttk_UniformPadding((short)borderWidth);
849 }
850 }
851
TroughElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)852 static void TroughElementDraw(
853 void *clientData, void *elementRecord, Tk_Window tkwin,
854 Drawable d, Ttk_Box b, unsigned int state)
855 {
856 TroughElement *troughPtr = elementRecord;
857 Tk_3DBorder border = NULL;
858 int borderWidth = 2, relief = TK_RELIEF_SUNKEN, groove = -1, orient;
859
860 border = Tk_Get3DBorderFromObj(tkwin, troughPtr->colorObj);
861 Ttk_GetOrientFromObj(NULL, troughPtr->orientObj, &orient);
862 Tk_GetReliefFromObj(NULL, troughPtr->reliefObj, &relief);
863 Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth);
864 Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->grooveWidthObj, &groove);
865
866 if (groove != -1 && groove < b.height && groove < b.width) {
867 if (orient == TTK_ORIENT_HORIZONTAL) {
868 b.y = b.y + b.height/2 - groove/2;
869 b.height = groove;
870 } else {
871 b.x = b.x + b.width/2 - groove/2;
872 b.width = groove;
873 }
874 }
875
876 Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height,
877 borderWidth, relief);
878 }
879
880 static Ttk_ElementSpec TroughElementSpec = {
881 TK_STYLE_VERSION_2,
882 sizeof(TroughElement),
883 TroughElementOptions,
884 TroughElementSize,
885 TroughElementDraw
886 };
887
888 /*
889 *----------------------------------------------------------------------
890 * +++ Thumb element.
891 */
892
893 typedef struct {
894 Tcl_Obj *sizeObj;
895 Tcl_Obj *firstObj;
896 Tcl_Obj *lastObj;
897 Tcl_Obj *borderObj;
898 Tcl_Obj *borderColorObj;
899 Tcl_Obj *reliefObj;
900 Tcl_Obj *orientObj;
901 } ThumbElement;
902
903 static Ttk_ElementOptionSpec ThumbElementOptions[] = {
904 { "-width", TK_OPTION_PIXELS, Tk_Offset(ThumbElement,sizeObj),
905 STRINGIFY(SCROLLBAR_WIDTH) },
906 { "-background", TK_OPTION_BORDER, Tk_Offset(ThumbElement,borderObj),
907 DEFAULT_BACKGROUND },
908 { "-bordercolor", TK_OPTION_COLOR, Tk_Offset(ThumbElement,borderColorObj),
909 "black" },
910 { "-relief", TK_OPTION_RELIEF,Tk_Offset(ThumbElement,reliefObj),"raised" },
911 { "-orient", TK_OPTION_ANY,Tk_Offset(ThumbElement,orientObj),"horizontal"},
912 { NULL, 0, 0, NULL }
913 };
914
ThumbElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)915 static void ThumbElementSize(
916 void *clientData, void *elementRecord, Tk_Window tkwin,
917 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
918 {
919 ThumbElement *thumb = elementRecord;
920 int orient, size;
921 Tk_GetPixelsFromObj(NULL, tkwin, thumb->sizeObj, &size);
922 Ttk_GetOrientFromObj(NULL, thumb->orientObj, &orient);
923
924 if (orient == TTK_ORIENT_VERTICAL) {
925 *widthPtr = size;
926 *heightPtr = MIN_THUMB_SIZE;
927 } else {
928 *widthPtr = MIN_THUMB_SIZE;
929 *heightPtr = size;
930 }
931 }
932
ThumbElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)933 static void ThumbElementDraw(
934 void *clientData, void *elementRecord, Tk_Window tkwin,
935 Drawable d, Ttk_Box b, unsigned int state)
936 {
937 ThumbElement *thumb = elementRecord;
938 Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, thumb->borderObj);
939 XColor *borderColor = Tk_GetColorFromObj(tkwin, thumb->borderColorObj);
940 int relief = TK_RELIEF_RAISED;
941 int borderWidth = 2;
942
943 /*
944 * Don't draw the thumb if we are disabled.
945 * This makes it behave like Windows ... if that's what we want.
946 if (state & TTK_STATE_DISABLED)
947 return;
948 */
949
950 Tk_GetReliefFromObj(NULL, thumb->reliefObj, &relief);
951
952 Tk_Fill3DRectangle(
953 tkwin, d, border, b.x,b.y,b.width,b.height, 0, TK_RELIEF_FLAT);
954 DrawBorder(tkwin, d, border, borderColor, b, borderWidth, relief);
955 }
956
957 static Ttk_ElementSpec ThumbElementSpec = {
958 TK_STYLE_VERSION_2,
959 sizeof(ThumbElement),
960 ThumbElementOptions,
961 ThumbElementSize,
962 ThumbElementDraw
963 };
964
965 /*
966 *----------------------------------------------------------------------
967 * +++ Slider element.
968 *
969 * This is the moving part of the scale widget.
970 *
971 * The slider element is the thumb in the scale widget. This is drawn
972 * as an arrow-type element that can point up, down, left or right.
973 *
974 */
975
976 typedef struct {
977 Tcl_Obj *lengthObj; /* Long axis dimension */
978 Tcl_Obj *thicknessObj; /* Short axis dimension */
979 Tcl_Obj *reliefObj; /* Relief for this object */
980 Tcl_Obj *borderObj; /* Border / background color */
981 Tcl_Obj *borderColorObj; /* Additional border color */
982 Tcl_Obj *borderWidthObj;
983 Tcl_Obj *orientObj; /* Orientation of overall slider */
984 } SliderElement;
985
986 static Ttk_ElementOptionSpec SliderElementOptions[] = {
987 { "-sliderlength", TK_OPTION_PIXELS, Tk_Offset(SliderElement,lengthObj),
988 "15" },
989 { "-sliderthickness",TK_OPTION_PIXELS,Tk_Offset(SliderElement,thicknessObj),
990 "15" },
991 { "-sliderrelief", TK_OPTION_RELIEF, Tk_Offset(SliderElement,reliefObj),
992 "raised" },
993 { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(SliderElement,borderWidthObj),
994 STRINGIFY(BORDERWIDTH) },
995 { "-background", TK_OPTION_BORDER, Tk_Offset(SliderElement,borderObj),
996 DEFAULT_BACKGROUND },
997 { "-bordercolor", TK_OPTION_COLOR, Tk_Offset(ThumbElement,borderColorObj),
998 "black" },
999 { "-orient", TK_OPTION_ANY, Tk_Offset(SliderElement,orientObj),
1000 "horizontal" },
1001 { NULL, 0, 0, NULL }
1002 };
1003
SliderElementSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)1004 static void SliderElementSize(
1005 void *clientData, void *elementRecord, Tk_Window tkwin,
1006 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1007 {
1008 SliderElement *slider = elementRecord;
1009 int orient, length, thickness, borderWidth;
1010
1011 Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient);
1012 Tk_GetPixelsFromObj(NULL, tkwin, slider->borderWidthObj, &borderWidth);
1013 Tk_GetPixelsFromObj(NULL, tkwin, slider->lengthObj, &length);
1014 Tk_GetPixelsFromObj(NULL, tkwin, slider->thicknessObj, &thickness);
1015
1016 switch (orient) {
1017 case TTK_ORIENT_VERTICAL:
1018 *widthPtr = thickness + (borderWidth *2);
1019 *heightPtr = *widthPtr/2;
1020 break;
1021
1022 case TTK_ORIENT_HORIZONTAL:
1023 *heightPtr = thickness + (borderWidth *2);
1024 *widthPtr = *heightPtr/2;
1025 break;
1026 }
1027 }
1028
SliderElementDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,unsigned int state)1029 static void SliderElementDraw(
1030 void *clientData, void *elementRecord, Tk_Window tkwin,
1031 Drawable d, Ttk_Box b, unsigned int state)
1032 {
1033 SliderElement *slider = elementRecord;
1034 Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, slider->borderObj);
1035 XColor *borderColor = Tk_GetColorFromObj(tkwin, slider->borderColorObj);
1036 int relief = TK_RELIEF_RAISED, borderWidth = 2;
1037
1038 Tk_GetPixelsFromObj(NULL, tkwin, slider->borderWidthObj, &borderWidth);
1039 Tk_GetReliefFromObj(NULL, slider->reliefObj, &relief);
1040
1041 Tk_Fill3DRectangle(tkwin, d, border,
1042 b.x, b.y, b.width, b.height,
1043 borderWidth, TK_RELIEF_FLAT);
1044 DrawBorder(tkwin, d, border, borderColor, b, borderWidth, relief);
1045 }
1046
1047 static Ttk_ElementSpec SliderElementSpec = {
1048 TK_STYLE_VERSION_2,
1049 sizeof(SliderElement),
1050 SliderElementOptions,
1051 SliderElementSize,
1052 SliderElementDraw
1053 };
1054
1055 /*------------------------------------------------------------------------
1056 * +++ Tree indicator element.
1057 */
1058
1059 #define TTK_STATE_OPEN TTK_STATE_USER1 /* XREF: treeview.c */
1060 #define TTK_STATE_LEAF TTK_STATE_USER2
1061
1062 typedef struct {
1063 Tcl_Obj *colorObj;
1064 Tcl_Obj *marginObj;
1065 Tcl_Obj *diameterObj;
1066 } TreeitemIndicator;
1067
1068 static Ttk_ElementOptionSpec TreeitemIndicatorOptions[] = {
1069 { "-foreground", TK_OPTION_COLOR,
1070 Tk_Offset(TreeitemIndicator,colorObj), DEFAULT_FOREGROUND },
1071 { "-diameter", TK_OPTION_PIXELS,
1072 Tk_Offset(TreeitemIndicator,diameterObj), "9" },
1073 { "-indicatormargins", TK_OPTION_STRING,
1074 Tk_Offset(TreeitemIndicator,marginObj), "2 2 4 2" },
1075 { NULL, 0, 0, NULL }
1076 };
1077
TreeitemIndicatorSize(void * clientData,void * elementRecord,Tk_Window tkwin,int * widthPtr,int * heightPtr,Ttk_Padding * paddingPtr)1078 static void TreeitemIndicatorSize(
1079 void *clientData, void *elementRecord, Tk_Window tkwin,
1080 int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1081 {
1082 TreeitemIndicator *indicator = elementRecord;
1083 int diameter = 0;
1084 Ttk_Padding margins;
1085
1086 Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
1087 Tk_GetPixelsFromObj(NULL, tkwin, indicator->diameterObj, &diameter);
1088 *widthPtr = diameter + Ttk_PaddingWidth(margins);
1089 *heightPtr = diameter + Ttk_PaddingHeight(margins);
1090 }
1091
TreeitemIndicatorDraw(void * clientData,void * elementRecord,Tk_Window tkwin,Drawable d,Ttk_Box b,Ttk_State state)1092 static void TreeitemIndicatorDraw(
1093 void *clientData, void *elementRecord, Tk_Window tkwin,
1094 Drawable d, Ttk_Box b, Ttk_State state)
1095 {
1096 TreeitemIndicator *indicator = elementRecord;
1097 XColor *color = Tk_GetColorFromObj(tkwin, indicator->colorObj);
1098 GC gc = Tk_GCForColor(color, d);
1099 Ttk_Padding padding = Ttk_UniformPadding(0);
1100 int w = WIN32_XDRAWLINE_HACK;
1101 int cx, cy;
1102
1103 if (state & TTK_STATE_LEAF) {
1104 /* don't draw anything ... */
1105 return;
1106 }
1107
1108 Ttk_GetPaddingFromObj(NULL,tkwin,indicator->marginObj,&padding);
1109 b = Ttk_PadBox(b, padding);
1110
1111 XDrawRectangle(Tk_Display(tkwin), d, gc,
1112 b.x, b.y, b.width - 1, b.height - 1);
1113
1114 cx = b.x + (b.width - 1) / 2;
1115 cy = b.y + (b.height - 1) / 2;
1116 XDrawLine(Tk_Display(tkwin), d, gc, b.x+2, cy, b.x+b.width-3+w, cy);
1117
1118 if (!(state & TTK_STATE_OPEN)) {
1119 /* turn '-' into a '+' */
1120 XDrawLine(Tk_Display(tkwin), d, gc, cx, b.y+2, cx, b.y+b.height-3+w);
1121 }
1122 }
1123
1124 static Ttk_ElementSpec TreeitemIndicatorElementSpec = {
1125 TK_STYLE_VERSION_2,
1126 sizeof(TreeitemIndicator),
1127 TreeitemIndicatorOptions,
1128 TreeitemIndicatorSize,
1129 TreeitemIndicatorDraw
1130 };
1131
1132 /*------------------------------------------------------------------------
1133 * TtkAltTheme_Init --
1134 * Install alternate theme.
1135 */
TtkAltTheme_Init(Tcl_Interp * interp)1136 MODULE_SCOPE int TtkAltTheme_Init(Tcl_Interp *interp)
1137 {
1138 Ttk_Theme theme = Ttk_CreateTheme(interp, "alt", NULL);
1139
1140 if (!theme) {
1141 return TCL_ERROR;
1142 }
1143
1144 Ttk_RegisterElement(interp, theme, "border", &BorderElementSpec, NULL);
1145
1146 Ttk_RegisterElement(interp, theme, "Checkbutton.indicator",
1147 &IndicatorElementSpec, &checkbutton_spec);
1148 Ttk_RegisterElement(interp, theme, "Radiobutton.indicator",
1149 &IndicatorElementSpec, &radiobutton_spec);
1150 Ttk_RegisterElement(interp, theme, "Menubutton.indicator",
1151 &MenubuttonArrowElementSpec, NULL);
1152
1153 Ttk_RegisterElement(interp, theme, "field", &FieldElementSpec, NULL);
1154
1155 Ttk_RegisterElement(interp, theme, "trough", &TroughElementSpec, NULL);
1156 Ttk_RegisterElement(interp, theme, "thumb", &ThumbElementSpec, NULL);
1157 Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL);
1158
1159 Ttk_RegisterElement(interp, theme, "uparrow",
1160 &ArrowElementSpec, &ArrowElements[0]);
1161 Ttk_RegisterElement(interp, theme, "downarrow",
1162 &ArrowElementSpec, &ArrowElements[1]);
1163 Ttk_RegisterElement(interp, theme, "leftarrow",
1164 &ArrowElementSpec, &ArrowElements[2]);
1165 Ttk_RegisterElement(interp, theme, "rightarrow",
1166 &ArrowElementSpec, &ArrowElements[3]);
1167 Ttk_RegisterElement(interp, theme, "arrow",
1168 &ArrowElementSpec, &ArrowElements[0]);
1169
1170 Ttk_RegisterElement(interp, theme, "arrow",
1171 &ArrowElementSpec, &ArrowElements[0]);
1172
1173 Ttk_RegisterElement(interp, theme, "Treeitem.indicator",
1174 &TreeitemIndicatorElementSpec, 0);
1175
1176 Tcl_PkgProvide(interp, "ttk::theme::alt", TTK_VERSION);
1177
1178 return TCL_OK;
1179 }
1180
1181 /*EOF*/
1182