1/* $Id$
2 *
3 * Copyright (c) 2003, Joe English
4 *
5 * Default implementation for themed elements.
6 *
7 */
8
9#include <tcl.h>
10#include <tk.h>
11#include <string.h>
12#include "ttkTheme.h"
13#include "ttkWidget.h"
14
15#define DEFAULT_BORDERWIDTH "2"
16#define DEFAULT_ARROW_SIZE "15"
17#define MIN_THUMB_SIZE 10
18
19/*----------------------------------------------------------------------
20 * +++ Null element.  Does nothing; used as a stub.
21 * Null element methods, option table and element spec are public,
22 * and may be used in other engines.
23 */
24
25/* public */ Ttk_ElementOptionSpec TtkNullElementOptions[] = { { NULL, 0, 0, NULL } };
26
27/* public */ void
28TtkNullElementSize(
29    void *clientData, void *elementRecord, Tk_Window tkwin,
30    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
31{
32}
33
34/* public */ void
35TtkNullElementDraw(
36    void *clientData, void *elementRecord, Tk_Window tkwin,
37    Drawable d, Ttk_Box b, unsigned int state)
38{
39}
40
41/* public */ Ttk_ElementSpec ttkNullElementSpec = {
42    TK_STYLE_VERSION_2,
43    sizeof(NullElement),
44    TtkNullElementOptions,
45    TtkNullElementSize,
46    TtkNullElementDraw
47};
48
49/*----------------------------------------------------------------------
50 * +++ Background and fill elements.
51 *
52 * The fill element fills its parcel with the background color.
53 * The background element ignores the parcel, and fills the entire window.
54 *
55 * Ttk_GetLayout() automatically includes a background element.
56 */
57
58typedef struct {
59    Tcl_Obj	*backgroundObj;
60} BackgroundElement;
61
62static Ttk_ElementOptionSpec BackgroundElementOptions[] = {
63    { "-background", TK_OPTION_BORDER,
64	    Tk_Offset(BackgroundElement,backgroundObj), DEFAULT_BACKGROUND },
65    { NULL, 0, 0, NULL }
66};
67
68static void FillElementDraw(
69    void *clientData, void *elementRecord, Tk_Window tkwin,
70    Drawable d, Ttk_Box b, unsigned int state)
71{
72    BackgroundElement *bg = elementRecord;
73    Tk_3DBorder backgroundPtr = Tk_Get3DBorderFromObj(tkwin,bg->backgroundObj);
74
75    XFillRectangle(Tk_Display(tkwin), d,
76	Tk_3DBorderGC(tkwin, backgroundPtr, TK_3D_FLAT_GC),
77	b.x, b.y, b.width, b.height);
78}
79
80static void BackgroundElementDraw(
81    void *clientData, void *elementRecord, Tk_Window tkwin,
82    Drawable d, Ttk_Box b, unsigned int state)
83{
84    FillElementDraw(
85	clientData, elementRecord, tkwin,
86	d, Ttk_WinBox(tkwin), state);
87}
88
89static Ttk_ElementSpec FillElementSpec = {
90    TK_STYLE_VERSION_2,
91    sizeof(BackgroundElement),
92    BackgroundElementOptions,
93    TtkNullElementSize,
94    FillElementDraw
95};
96
97static Ttk_ElementSpec BackgroundElementSpec = {
98    TK_STYLE_VERSION_2,
99    sizeof(BackgroundElement),
100    BackgroundElementOptions,
101    TtkNullElementSize,
102    BackgroundElementDraw
103};
104
105/*----------------------------------------------------------------------
106 * +++ Border element.
107 */
108
109typedef struct {
110    Tcl_Obj	*borderObj;
111    Tcl_Obj	*borderWidthObj;
112    Tcl_Obj	*reliefObj;
113} BorderElement;
114
115static Ttk_ElementOptionSpec BorderElementOptions[] = {
116    { "-background", TK_OPTION_BORDER,
117	Tk_Offset(BorderElement,borderObj), DEFAULT_BACKGROUND },
118    { "-borderwidth", TK_OPTION_PIXELS,
119	Tk_Offset(BorderElement,borderWidthObj), DEFAULT_BORDERWIDTH },
120    { "-relief", TK_OPTION_RELIEF,
121	Tk_Offset(BorderElement,reliefObj), "flat" },
122    { NULL, 0, 0, NULL }
123};
124
125static void BorderElementSize(
126    void *clientData, void *elementRecord, Tk_Window tkwin,
127    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
128{
129    BorderElement *bd = elementRecord;
130    int borderWidth = 0;
131    Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
132    *paddingPtr = Ttk_UniformPadding((short)borderWidth);
133}
134
135static void BorderElementDraw(
136    void *clientData, void *elementRecord, Tk_Window tkwin,
137    Drawable d, Ttk_Box b, unsigned int state)
138{
139    BorderElement *bd = elementRecord;
140    Tk_3DBorder border = NULL;
141    int borderWidth = 1, relief = TK_RELIEF_FLAT;
142
143    border = Tk_Get3DBorderFromObj(tkwin, bd->borderObj);
144    Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth);
145    Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief);
146
147    if (border && borderWidth > 0 && relief != TK_RELIEF_FLAT) {
148	Tk_Draw3DRectangle(tkwin, d, border,
149	    b.x, b.y, b.width, b.height, borderWidth,relief);
150    }
151}
152
153static Ttk_ElementSpec BorderElementSpec = {
154    TK_STYLE_VERSION_2,
155    sizeof(BorderElement),
156    BorderElementOptions,
157    BorderElementSize,
158    BorderElementDraw
159};
160
161/*----------------------------------------------------------------------
162 * +++ Field element.
163 * 	Used for editable fields.
164 */
165typedef struct {
166    Tcl_Obj	*borderObj;
167    Tcl_Obj	*borderWidthObj;
168} FieldElement;
169
170static Ttk_ElementOptionSpec FieldElementOptions[] = {
171    { "-fieldbackground", TK_OPTION_BORDER,
172	Tk_Offset(FieldElement,borderObj), "white" },
173    { "-borderwidth", TK_OPTION_PIXELS,
174	Tk_Offset(FieldElement,borderWidthObj), "2" },
175    { NULL, 0, 0, NULL }
176};
177
178static void FieldElementSize(
179    void *clientData, void *elementRecord, Tk_Window tkwin,
180    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
181{
182    FieldElement *field = elementRecord;
183    int borderWidth = 2;
184    Tk_GetPixelsFromObj(NULL, tkwin, field->borderWidthObj, &borderWidth);
185    *paddingPtr = Ttk_UniformPadding((short)borderWidth);
186}
187
188static void FieldElementDraw(
189    void *clientData, void *elementRecord, Tk_Window tkwin,
190    Drawable d, Ttk_Box b, unsigned int state)
191{
192    FieldElement *field = elementRecord;
193    Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, field->borderObj);
194    int borderWidth = 2;
195
196    Tk_GetPixelsFromObj(NULL, tkwin, field->borderWidthObj, &borderWidth);
197    Tk_Fill3DRectangle(tkwin, d, border,
198	    b.x, b.y, b.width, b.height, borderWidth, TK_RELIEF_SUNKEN);
199}
200
201static Ttk_ElementSpec FieldElementSpec = {
202    TK_STYLE_VERSION_2,
203    sizeof(FieldElement),
204    FieldElementOptions,
205    FieldElementSize,
206    FieldElementDraw
207};
208
209/*
210 *----------------------------------------------------------------------
211 * +++ Padding element.
212 *
213 * This element has no visual representation, only geometry.
214 * It adds a (possibly non-uniform) internal border.
215 * In addition, if "-shiftrelief" is specified,
216 * adds additional pixels to shift child elements "in" or "out"
217 * depending on the -relief.
218 */
219
220typedef struct {
221    Tcl_Obj	*paddingObj;
222    Tcl_Obj	*reliefObj;
223    Tcl_Obj	*shiftreliefObj;
224} PaddingElement;
225
226static Ttk_ElementOptionSpec PaddingElementOptions[] = {
227    { "-padding", TK_OPTION_STRING,
228	Tk_Offset(PaddingElement,paddingObj), "0" },
229    { "-relief", TK_OPTION_RELIEF,
230	Tk_Offset(PaddingElement,reliefObj), "flat" },
231    { "-shiftrelief", TK_OPTION_INT,
232	Tk_Offset(PaddingElement,shiftreliefObj), "0" },
233    { NULL, 0, 0, NULL }
234};
235
236static void PaddingElementSize(
237    void *clientData, void *elementRecord, Tk_Window tkwin,
238    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
239{
240    PaddingElement *padding = elementRecord;
241    int shiftRelief = 0;
242    int relief = TK_RELIEF_FLAT;
243    Ttk_Padding pad;
244
245    Tk_GetReliefFromObj(NULL, padding->reliefObj, &relief);
246    Tcl_GetIntFromObj(NULL, padding->shiftreliefObj, &shiftRelief);
247    Ttk_GetPaddingFromObj(NULL,tkwin,padding->paddingObj,&pad);
248    *paddingPtr = Ttk_RelievePadding(pad, relief, shiftRelief);
249}
250
251static Ttk_ElementSpec PaddingElementSpec = {
252    TK_STYLE_VERSION_2,
253    sizeof(PaddingElement),
254    PaddingElementOptions,
255    PaddingElementSize,
256    TtkNullElementDraw
257};
258
259/*----------------------------------------------------------------------
260 * +++ Focus ring element.
261 * 	Draws a dashed focus ring, if the widget has keyboard focus.
262 */
263typedef struct {
264    Tcl_Obj	*focusColorObj;
265    Tcl_Obj	*focusThicknessObj;
266} FocusElement;
267
268/*
269 * DrawFocusRing --
270 * 	Draw a dotted rectangle to indicate focus.
271 */
272static void DrawFocusRing(
273    Tk_Window tkwin, Drawable d, Tcl_Obj *colorObj, Ttk_Box b)
274{
275    XColor *color = Tk_GetColorFromObj(tkwin, colorObj);
276    unsigned long mask = 0UL;
277    XGCValues gcvalues;
278    GC gc;
279
280    gcvalues.foreground = color->pixel;
281    gcvalues.line_style = LineOnOffDash;
282    gcvalues.line_width = 1;
283    gcvalues.dashes = 1;
284    gcvalues.dash_offset = 1;
285    mask = GCForeground | GCLineStyle | GCDashList | GCDashOffset | GCLineWidth;
286
287    gc = Tk_GetGC(tkwin, mask, &gcvalues);
288    XDrawRectangle(Tk_Display(tkwin), d, gc, b.x, b.y, b.width-1, b.height-1);
289    Tk_FreeGC(Tk_Display(tkwin), gc);
290}
291
292static Ttk_ElementOptionSpec FocusElementOptions[] = {
293    { "-focuscolor",TK_OPTION_COLOR,
294	Tk_Offset(FocusElement,focusColorObj), "black" },
295    { "-focusthickness",TK_OPTION_PIXELS,
296	Tk_Offset(FocusElement,focusThicknessObj), "1" },
297    { NULL, 0, 0, NULL }
298};
299
300static void FocusElementSize(
301    void *clientData, void *elementRecord, Tk_Window tkwin,
302    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
303{
304    FocusElement *focus = elementRecord;
305    int focusThickness = 0;
306
307    Tcl_GetIntFromObj(NULL, focus->focusThicknessObj, &focusThickness);
308    *paddingPtr = Ttk_UniformPadding((short)focusThickness);
309}
310
311static void FocusElementDraw(
312    void *clientData, void *elementRecord, Tk_Window tkwin,
313    Drawable d, Ttk_Box b, unsigned int state)
314{
315    FocusElement *focus = elementRecord;
316    int focusThickness = 0;
317
318    if (state & TTK_STATE_FOCUS) {
319	Tcl_GetIntFromObj(NULL,focus->focusThicknessObj,&focusThickness);
320	DrawFocusRing(tkwin, d, focus->focusColorObj, b);
321    }
322}
323
324static Ttk_ElementSpec FocusElementSpec = {
325    TK_STYLE_VERSION_2,
326    sizeof(FocusElement),
327    FocusElementOptions,
328    FocusElementSize,
329    FocusElementDraw
330};
331
332/*----------------------------------------------------------------------
333 * +++ Separator element.
334 * 	Just draws a horizontal or vertical bar.
335 * 	Three elements are defined: horizontal, vertical, and general;
336 *	the general separator checks the "-orient" option.
337 */
338
339typedef struct {
340    Tcl_Obj	*orientObj;
341    Tcl_Obj	*borderObj;
342} SeparatorElement;
343
344static Ttk_ElementOptionSpec SeparatorElementOptions[] = {
345    { "-orient", TK_OPTION_ANY,
346	Tk_Offset(SeparatorElement, orientObj), "horizontal" },
347    { "-background", TK_OPTION_BORDER,
348	Tk_Offset(SeparatorElement,borderObj), DEFAULT_BACKGROUND },
349    { NULL, 0, 0, NULL }
350};
351
352static void SeparatorElementSize(
353    void *clientData, void *elementRecord, Tk_Window tkwin,
354    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
355{
356    *widthPtr = *heightPtr = 2;
357}
358
359static void HorizontalSeparatorElementDraw(
360    void *clientData, void *elementRecord, Tk_Window tkwin,
361    Drawable d, Ttk_Box b, unsigned int state)
362{
363    SeparatorElement *separator = elementRecord;
364    Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, separator->borderObj);
365    GC lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
366    GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
367
368    XDrawLine(Tk_Display(tkwin), d, darkGC, b.x, b.y, b.x + b.width, b.y);
369    XDrawLine(Tk_Display(tkwin), d, lightGC, b.x, b.y+1, b.x + b.width, b.y+1);
370}
371
372static void VerticalSeparatorElementDraw(
373    void *clientData, void *elementRecord, Tk_Window tkwin,
374    Drawable d, Ttk_Box b, unsigned int state)
375{
376    SeparatorElement *separator = elementRecord;
377    Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, separator->borderObj);
378    GC lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
379    GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
380
381    XDrawLine(Tk_Display(tkwin), d, darkGC, b.x, b.y, b.x, b.y + b.height);
382    XDrawLine(Tk_Display(tkwin), d, lightGC, b.x+1, b.y, b.x+1, b.y+b.height);
383}
384
385static void GeneralSeparatorElementDraw(
386    void *clientData, void *elementRecord, Tk_Window tkwin,
387    Drawable d, Ttk_Box b, unsigned int state)
388{
389    SeparatorElement *separator = elementRecord;
390    int orient;
391    Ttk_GetOrientFromObj(NULL, separator->orientObj, &orient);
392    switch (orient) {
393	case TTK_ORIENT_HORIZONTAL:
394	    HorizontalSeparatorElementDraw(
395		clientData, elementRecord, tkwin, d, b, state);
396	    break;
397	case TTK_ORIENT_VERTICAL:
398	    VerticalSeparatorElementDraw(
399		clientData, elementRecord, tkwin, d, b, state);
400	    break;
401    }
402}
403
404static Ttk_ElementSpec HorizontalSeparatorElementSpec = {
405    TK_STYLE_VERSION_2,
406    sizeof(SeparatorElement),
407    SeparatorElementOptions,
408    SeparatorElementSize,
409    HorizontalSeparatorElementDraw
410};
411
412static Ttk_ElementSpec VerticalSeparatorElementSpec = {
413    TK_STYLE_VERSION_2,
414    sizeof(SeparatorElement),
415    SeparatorElementOptions,
416    SeparatorElementSize,
417    HorizontalSeparatorElementDraw
418};
419
420static Ttk_ElementSpec SeparatorElementSpec = {
421    TK_STYLE_VERSION_2,
422    sizeof(SeparatorElement),
423    SeparatorElementOptions,
424    SeparatorElementSize,
425    GeneralSeparatorElementDraw
426};
427
428/*----------------------------------------------------------------------
429 * +++ Sizegrip: lower-right corner grip handle for resizing window.
430 */
431
432typedef struct {
433    Tcl_Obj	*backgroundObj;
434} SizegripElement;
435
436static Ttk_ElementOptionSpec SizegripOptions[] = {
437    { "-background", TK_OPTION_BORDER,
438	Tk_Offset(SizegripElement,backgroundObj), DEFAULT_BACKGROUND },
439    {0,0,0,0}
440};
441
442static void SizegripSize(
443    void *clientData, void *elementRecord, Tk_Window tkwin,
444    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
445{
446    int gripCount = 3, gripSpace = 2, gripThickness = 3;
447    *widthPtr = *heightPtr = gripCount * (gripSpace + gripThickness);
448}
449
450static void SizegripDraw(
451    void *clientData, void *elementRecord, Tk_Window tkwin,
452    Drawable d, Ttk_Box b, Ttk_State state)
453{
454    SizegripElement *grip = elementRecord;
455    int gripCount = 3, gripSpace = 2;
456    Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, grip->backgroundObj);
457    GC lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
458    GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
459    int x1 = b.x + b.width-1, y1 = b.y + b.height-1, x2 = x1, y2 = y1;
460
461    while (gripCount--) {
462	x1 -= gripSpace; y2 -= gripSpace;
463	XDrawLine(Tk_Display(tkwin), d, darkGC,  x1,y1, x2,y2); --x1; --y2;
464	XDrawLine(Tk_Display(tkwin), d, darkGC,  x1,y1, x2,y2); --x1; --y2;
465	XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y1, x2,y2); --x1; --y2;
466    }
467}
468
469static Ttk_ElementSpec SizegripElementSpec = {
470    TK_STYLE_VERSION_2,
471    sizeof(SizegripElement),
472    SizegripOptions,
473    SizegripSize,
474    SizegripDraw
475};
476
477/*----------------------------------------------------------------------
478 * +++ Indicator element.
479 *
480 * Draws the on/off indicator for checkbuttons and radiobuttons.
481 *
482 * Draws a 3-D square (or diamond), raised if off, sunken if on.
483 *
484 * This is actually a regression from Tk 8.5 back to the ugly old Motif
485 * style; use "altTheme" for the newer, nicer version.
486 */
487
488typedef struct {
489    Tcl_Obj *backgroundObj;
490    Tcl_Obj *reliefObj;
491    Tcl_Obj *colorObj;
492    Tcl_Obj *diameterObj;
493    Tcl_Obj *marginObj;
494    Tcl_Obj *borderWidthObj;
495} IndicatorElement;
496
497static Ttk_ElementOptionSpec IndicatorElementOptions[] = {
498    { "-background", TK_OPTION_BORDER,
499	Tk_Offset(IndicatorElement,backgroundObj), DEFAULT_BACKGROUND },
500    { "-indicatorcolor", TK_OPTION_BORDER,
501	Tk_Offset(IndicatorElement,colorObj), DEFAULT_BACKGROUND },
502    { "-indicatorrelief", TK_OPTION_RELIEF,
503	Tk_Offset(IndicatorElement,reliefObj), "raised" },
504    { "-indicatordiameter", TK_OPTION_PIXELS,
505	Tk_Offset(IndicatorElement,diameterObj), "12" },
506    { "-indicatormargin", TK_OPTION_STRING,
507	Tk_Offset(IndicatorElement,marginObj), "0 2 4 2" },
508    { "-borderwidth", TK_OPTION_PIXELS,
509	Tk_Offset(IndicatorElement,borderWidthObj), DEFAULT_BORDERWIDTH },
510    { NULL, 0, 0, NULL }
511};
512
513/*
514 * Checkbutton indicators (default): 3-D square.
515 */
516static void SquareIndicatorElementSize(
517    void *clientData, void *elementRecord, Tk_Window tkwin,
518    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
519{
520    IndicatorElement *indicator = elementRecord;
521    Ttk_Padding margins;
522    int diameter = 0;
523    Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
524    Tk_GetPixelsFromObj(NULL, tkwin, indicator->diameterObj, &diameter);
525    *widthPtr = diameter + Ttk_PaddingWidth(margins);
526    *heightPtr = diameter + Ttk_PaddingHeight(margins);
527}
528
529static void SquareIndicatorElementDraw(
530    void *clientData, void *elementRecord, Tk_Window tkwin,
531    Drawable d, Ttk_Box b, unsigned int state)
532{
533    IndicatorElement *indicator = elementRecord;
534    Tk_3DBorder border = 0, interior = 0;
535    int relief = TK_RELIEF_RAISED;
536    Ttk_Padding padding;
537    int borderWidth = 2;
538    int diameter;
539
540    interior = Tk_Get3DBorderFromObj(tkwin, indicator->colorObj);
541    border = Tk_Get3DBorderFromObj(tkwin, indicator->backgroundObj);
542    Tcl_GetIntFromObj(NULL,indicator->borderWidthObj,&borderWidth);
543    Tk_GetReliefFromObj(NULL,indicator->reliefObj,&relief);
544    Ttk_GetPaddingFromObj(NULL,tkwin,indicator->marginObj,&padding);
545
546    b = Ttk_PadBox(b, padding);
547
548    diameter = b.width < b.height ? b.width : b.height;
549    Tk_Fill3DRectangle(tkwin, d, interior, b.x, b.y,
550	    diameter, diameter,borderWidth, TK_RELIEF_FLAT);
551    Tk_Draw3DRectangle(tkwin, d, border, b.x, b.y,
552	    diameter, diameter, borderWidth, relief);
553}
554
555/*
556 * Radiobutton indicators:  3-D diamond.
557 */
558static void DiamondIndicatorElementSize(
559    void *clientData, void *elementRecord, Tk_Window tkwin,
560    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
561{
562    IndicatorElement *indicator = elementRecord;
563    Ttk_Padding margins;
564    int diameter = 0;
565    Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
566    Tk_GetPixelsFromObj(NULL, tkwin, indicator->diameterObj, &diameter);
567    *widthPtr = diameter + 3 + Ttk_PaddingWidth(margins);
568    *heightPtr = diameter + 3 + Ttk_PaddingHeight(margins);
569}
570
571static void DiamondIndicatorElementDraw(
572    void *clientData, void *elementRecord, Tk_Window tkwin,
573    Drawable d, Ttk_Box b, unsigned int state)
574{
575    IndicatorElement *indicator = elementRecord;
576    Tk_3DBorder border = 0, interior = 0;
577    int borderWidth = 2;
578    int relief = TK_RELIEF_RAISED;
579    int diameter, radius;
580    XPoint points[4];
581    Ttk_Padding padding;
582
583    interior = Tk_Get3DBorderFromObj(tkwin, indicator->colorObj);
584    border = Tk_Get3DBorderFromObj(tkwin, indicator->backgroundObj);
585    Tcl_GetIntFromObj(NULL,indicator->borderWidthObj,&borderWidth);
586    Tk_GetReliefFromObj(NULL,indicator->reliefObj,&relief);
587    Ttk_GetPaddingFromObj(NULL,tkwin,indicator->marginObj,&padding);
588
589    b = Ttk_PadBox(b, padding);
590
591    diameter = b.width < b.height ? b.width : b.height;
592    radius = diameter / 2;
593
594    points[0].x = b.x;
595    points[0].y = b.y + radius;
596    points[1].x = b.x + radius;
597    points[1].y = b.y + 2*radius;
598    points[2].x = b.x + 2*radius;
599    points[2].y = b.y + radius;
600    points[3].x = b.x + radius;
601    points[3].y = b.y;
602
603    Tk_Fill3DPolygon(tkwin,d,interior,points,4,borderWidth,TK_RELIEF_FLAT);
604    Tk_Draw3DPolygon(tkwin,d,border,points,4,borderWidth,relief);
605}
606
607static Ttk_ElementSpec CheckbuttonIndicatorElementSpec = {
608    TK_STYLE_VERSION_2,
609    sizeof(IndicatorElement),
610    IndicatorElementOptions,
611    SquareIndicatorElementSize,
612    SquareIndicatorElementDraw
613};
614
615static Ttk_ElementSpec RadiobuttonIndicatorElementSpec = {
616    TK_STYLE_VERSION_2,
617    sizeof(IndicatorElement),
618    IndicatorElementOptions,
619    DiamondIndicatorElementSize,
620    DiamondIndicatorElementDraw
621};
622
623/*
624 *----------------------------------------------------------------------
625 * +++ Menubutton indicators.
626 *
627 * These aren't functional like radio/check indicators,
628 * they're just affordability indicators.
629 *
630 * Standard Tk sets the indicator size to 4.0 mm by 1.7 mm.
631 * I have no idea where these numbers came from.
632 */
633
634typedef struct {
635    Tcl_Obj *backgroundObj;
636    Tcl_Obj *widthObj;
637    Tcl_Obj *heightObj;
638    Tcl_Obj *borderWidthObj;
639    Tcl_Obj *reliefObj;
640    Tcl_Obj *marginObj;
641} MenuIndicatorElement;
642
643static Ttk_ElementOptionSpec MenuIndicatorElementOptions[] = {
644    { "-background", TK_OPTION_BORDER,
645	Tk_Offset(MenuIndicatorElement,backgroundObj), DEFAULT_BACKGROUND },
646    { "-indicatorwidth", TK_OPTION_PIXELS,
647	Tk_Offset(MenuIndicatorElement,widthObj), "4.0m" },
648    { "-indicatorheight", TK_OPTION_PIXELS,
649	Tk_Offset(MenuIndicatorElement,heightObj), "1.7m" },
650    { "-borderwidth", TK_OPTION_PIXELS,
651	Tk_Offset(MenuIndicatorElement,borderWidthObj), DEFAULT_BORDERWIDTH },
652    { "-indicatorrelief", TK_OPTION_RELIEF,
653	Tk_Offset(MenuIndicatorElement,reliefObj),"raised" },
654    { "-indicatormargin", TK_OPTION_STRING,
655	    Tk_Offset(MenuIndicatorElement,marginObj), "5 0" },
656    { NULL, 0, 0, NULL }
657};
658
659static void MenuIndicatorElementSize(
660    void *clientData, void *elementRecord, Tk_Window tkwin,
661    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
662{
663    MenuIndicatorElement *mi = elementRecord;
664    Ttk_Padding margins;
665    Tk_GetPixelsFromObj(NULL, tkwin, mi->widthObj, widthPtr);
666    Tk_GetPixelsFromObj(NULL, tkwin, mi->heightObj, heightPtr);
667    Ttk_GetPaddingFromObj(NULL,tkwin,mi->marginObj, &margins);
668    *widthPtr += Ttk_PaddingWidth(margins);
669    *heightPtr += Ttk_PaddingHeight(margins);
670}
671
672static void MenuIndicatorElementDraw(
673    void *clientData, void *elementRecord, Tk_Window tkwin,
674    Drawable d, Ttk_Box b, unsigned int state)
675{
676    MenuIndicatorElement *mi = elementRecord;
677    Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, mi->backgroundObj);
678    Ttk_Padding margins;
679    int borderWidth = 2;
680
681    Ttk_GetPaddingFromObj(NULL,tkwin,mi->marginObj,&margins);
682    b = Ttk_PadBox(b, margins);
683    Tk_GetPixelsFromObj(NULL, tkwin, mi->borderWidthObj, &borderWidth);
684    Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height,
685	    borderWidth, TK_RELIEF_RAISED);
686}
687
688static Ttk_ElementSpec MenuIndicatorElementSpec = {
689    TK_STYLE_VERSION_2,
690    sizeof(MenuIndicatorElement),
691    MenuIndicatorElementOptions,
692    MenuIndicatorElementSize,
693    MenuIndicatorElementDraw
694};
695
696/*----------------------------------------------------------------------
697 * +++ Arrow elements.
698 *
699 * 	Draws a solid triangle inside a box.
700 * 	clientData is an enum ArrowDirection pointer.
701 */
702
703static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT };
704typedef struct {
705    Tcl_Obj *borderObj;
706    Tcl_Obj *borderWidthObj;
707    Tcl_Obj *reliefObj;
708    Tcl_Obj *sizeObj;
709    Tcl_Obj *colorObj;
710} ArrowElement;
711
712static Ttk_ElementOptionSpec ArrowElementOptions[] = {
713    { "-background", TK_OPTION_BORDER,
714	Tk_Offset(ArrowElement,borderObj), DEFAULT_BACKGROUND },
715    { "-relief",TK_OPTION_RELIEF,
716	Tk_Offset(ArrowElement,reliefObj),"raised"},
717    { "-borderwidth", TK_OPTION_PIXELS,
718	Tk_Offset(ArrowElement,borderWidthObj), "1" },
719    { "-arrowcolor",TK_OPTION_COLOR,
720	Tk_Offset(ArrowElement,colorObj),"black"},
721    { "-arrowsize", TK_OPTION_PIXELS,
722	Tk_Offset(ArrowElement,sizeObj), "14" },
723    { NULL, 0, 0, NULL }
724};
725
726static Ttk_Padding ArrowMargins = { 3,3,3,3 };
727
728static void ArrowElementSize(
729    void *clientData, void *elementRecord, Tk_Window tkwin,
730    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
731{
732    ArrowElement *arrow = elementRecord;
733    int direction = *(int *)clientData;
734    int width = 14;
735
736    Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &width);
737    width -= Ttk_PaddingWidth(ArrowMargins);
738    TtkArrowSize(width/2, direction, widthPtr, heightPtr);
739    *widthPtr += Ttk_PaddingWidth(ArrowMargins);
740    *heightPtr += Ttk_PaddingWidth(ArrowMargins);
741}
742
743static void ArrowElementDraw(
744    void *clientData, void *elementRecord, Tk_Window tkwin,
745    Drawable d, Ttk_Box b, unsigned int state)
746{
747    int direction = *(int *)clientData;
748    ArrowElement *arrow = elementRecord;
749    Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, arrow->borderObj);
750    XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj);
751    int relief = TK_RELIEF_RAISED;
752    int borderWidth = 1;
753
754    Tk_GetReliefFromObj(NULL, arrow->reliefObj, &relief);
755
756    Tk_Fill3DRectangle(
757	tkwin, d, border, b.x, b.y, b.width, b.height, borderWidth, relief);
758
759    TtkFillArrow(Tk_Display(tkwin), d, Tk_GCForColor(arrowColor, d),
760	Ttk_PadBox(b, ArrowMargins), direction);
761}
762
763static Ttk_ElementSpec ArrowElementSpec = {
764    TK_STYLE_VERSION_2,
765    sizeof(ArrowElement),
766    ArrowElementOptions,
767    ArrowElementSize,
768    ArrowElementDraw
769};
770
771/*----------------------------------------------------------------------
772 * +++ Trough element.
773 *
774 * Used in scrollbars and scales in place of "border".
775 */
776
777typedef struct {
778    Tcl_Obj *colorObj;
779    Tcl_Obj *borderWidthObj;
780    Tcl_Obj *reliefObj;
781} TroughElement;
782
783static Ttk_ElementOptionSpec TroughElementOptions[] = {
784    { "-borderwidth", TK_OPTION_PIXELS,
785	Tk_Offset(TroughElement,borderWidthObj), DEFAULT_BORDERWIDTH },
786    { "-troughcolor", TK_OPTION_BORDER,
787	Tk_Offset(TroughElement,colorObj), DEFAULT_BACKGROUND },
788    { "-troughrelief",TK_OPTION_RELIEF,
789	Tk_Offset(TroughElement,reliefObj), "sunken" },
790    { NULL, 0, 0, NULL }
791};
792
793static void TroughElementSize(
794    void *clientData, void *elementRecord, Tk_Window tkwin,
795    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
796{
797    TroughElement *troughPtr = elementRecord;
798    int borderWidth = 2;
799
800    Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth);
801    *paddingPtr = Ttk_UniformPadding((short)borderWidth);
802}
803
804static void TroughElementDraw(
805    void *clientData, void *elementRecord, Tk_Window tkwin,
806    Drawable d, Ttk_Box b, unsigned int state)
807{
808    TroughElement *troughPtr = elementRecord;
809    Tk_3DBorder border = NULL;
810    int borderWidth = 2, relief = TK_RELIEF_SUNKEN;
811
812    border = Tk_Get3DBorderFromObj(tkwin, troughPtr->colorObj);
813    Tk_GetReliefFromObj(NULL, troughPtr->reliefObj, &relief);
814    Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth);
815
816    Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height,
817	    borderWidth, relief);
818}
819
820static Ttk_ElementSpec TroughElementSpec = {
821    TK_STYLE_VERSION_2,
822    sizeof(TroughElement),
823    TroughElementOptions,
824    TroughElementSize,
825    TroughElementDraw
826};
827
828/*
829 *----------------------------------------------------------------------
830 * +++ Thumb element.
831 *
832 * Used in scrollbars.
833 */
834
835typedef struct {
836    Tcl_Obj *orientObj;
837    Tcl_Obj *thicknessObj;
838    Tcl_Obj *reliefObj;
839    Tcl_Obj *borderObj;
840    Tcl_Obj *borderWidthObj;
841} ThumbElement;
842
843static Ttk_ElementOptionSpec ThumbElementOptions[] = {
844    { "-orient", TK_OPTION_ANY,
845	Tk_Offset(ThumbElement, orientObj), "horizontal" },
846    { "-width", TK_OPTION_PIXELS,
847	Tk_Offset(ThumbElement,thicknessObj), DEFAULT_ARROW_SIZE },
848    { "-relief", TK_OPTION_RELIEF,
849	Tk_Offset(ThumbElement,reliefObj), "raised" },
850    { "-background", TK_OPTION_BORDER,
851	Tk_Offset(ThumbElement,borderObj), DEFAULT_BACKGROUND },
852    { "-borderwidth", TK_OPTION_PIXELS,
853	Tk_Offset(ThumbElement,borderWidthObj), DEFAULT_BORDERWIDTH },
854    { NULL, 0, 0, NULL }
855};
856
857static void ThumbElementSize(
858    void *clientData, void *elementRecord, Tk_Window tkwin,
859    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
860{
861    ThumbElement *thumb = elementRecord;
862    int orient, thickness;
863
864    Tk_GetPixelsFromObj(NULL, tkwin, thumb->thicknessObj, &thickness);
865    Ttk_GetOrientFromObj(NULL, thumb->orientObj, &orient);
866
867    if (orient == TTK_ORIENT_VERTICAL) {
868	*widthPtr = thickness;
869	*heightPtr = MIN_THUMB_SIZE;
870    } else {
871	*widthPtr = MIN_THUMB_SIZE;
872	*heightPtr = thickness;
873    }
874}
875
876static void ThumbElementDraw(
877    void *clientData, void *elementRecord, Tk_Window tkwin,
878    Drawable d, Ttk_Box b, unsigned int state)
879{
880    ThumbElement *thumb = elementRecord;
881    Tk_3DBorder  border = Tk_Get3DBorderFromObj(tkwin, thumb->borderObj);
882    int borderWidth = 2, relief = TK_RELIEF_RAISED;
883
884    Tk_GetPixelsFromObj(NULL, tkwin, thumb->borderWidthObj, &borderWidth);
885    Tk_GetReliefFromObj(NULL, thumb->reliefObj, &relief);
886    Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height,
887	    borderWidth, relief);
888}
889
890static Ttk_ElementSpec ThumbElementSpec = {
891    TK_STYLE_VERSION_2,
892    sizeof(ThumbElement),
893    ThumbElementOptions,
894    ThumbElementSize,
895    ThumbElementDraw
896};
897
898/*
899 *----------------------------------------------------------------------
900 * +++ Slider element.
901 *
902 * This is the moving part of the scale widget.  Drawn as a raised box.
903 */
904
905typedef struct {
906    Tcl_Obj *orientObj;	     /* orientation of overall slider */
907    Tcl_Obj *lengthObj;      /* slider length */
908    Tcl_Obj *thicknessObj;   /* slider thickness */
909    Tcl_Obj *reliefObj;      /* the relief for this object */
910    Tcl_Obj *borderObj;      /* the background color */
911    Tcl_Obj *borderWidthObj; /* the size of the border */
912} SliderElement;
913
914static Ttk_ElementOptionSpec SliderElementOptions[] = {
915    { "-sliderlength", TK_OPTION_PIXELS, Tk_Offset(SliderElement,lengthObj),
916	"30" },
917    { "-sliderthickness",TK_OPTION_PIXELS,Tk_Offset(SliderElement,thicknessObj),
918	"15" },
919    { "-sliderrelief", TK_OPTION_RELIEF, Tk_Offset(SliderElement,reliefObj),
920	"raised" },
921    { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(SliderElement,borderWidthObj),
922	DEFAULT_BORDERWIDTH },
923    { "-background", TK_OPTION_BORDER, Tk_Offset(SliderElement,borderObj),
924	DEFAULT_BACKGROUND },
925    { "-orient", TK_OPTION_ANY, Tk_Offset(SliderElement,orientObj),
926	"horizontal" },
927    { NULL, 0, 0, NULL }
928};
929
930static void SliderElementSize(
931    void *clientData, void *elementRecord, Tk_Window tkwin,
932    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
933{
934    SliderElement *slider = elementRecord;
935    int orient, length, thickness;
936
937    Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient);
938    Tk_GetPixelsFromObj(NULL, tkwin, slider->lengthObj, &length);
939    Tk_GetPixelsFromObj(NULL, tkwin, slider->thicknessObj, &thickness);
940
941    switch (orient) {
942	case TTK_ORIENT_VERTICAL:
943	    *widthPtr = thickness;
944	    *heightPtr = length;
945	    break;
946
947	case TTK_ORIENT_HORIZONTAL:
948	    *widthPtr = length;
949	    *heightPtr = thickness;
950	    break;
951    }
952}
953
954static void SliderElementDraw(
955    void *clientData, void *elementRecord, Tk_Window tkwin,
956    Drawable d, Ttk_Box b, unsigned int state)
957{
958    SliderElement *slider = elementRecord;
959    Tk_3DBorder border = NULL;
960    int relief = TK_RELIEF_RAISED, borderWidth = 2, orient;
961
962    border = Tk_Get3DBorderFromObj(tkwin, slider->borderObj);
963    Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient);
964    Tk_GetPixelsFromObj(NULL, tkwin, slider->borderWidthObj, &borderWidth);
965    Tk_GetReliefFromObj(NULL, slider->reliefObj, &relief);
966
967    Tk_Fill3DRectangle(tkwin, d, border,
968	b.x, b.y, b.width, b.height,
969	borderWidth, relief);
970
971    if (relief != TK_RELIEF_FLAT) {
972	if (orient == TTK_ORIENT_HORIZONTAL) {
973	    if (b.width > 4) {
974		b.x += b.width/2;
975		XDrawLine(Tk_Display(tkwin), d,
976		    Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC),
977		    b.x-1, b.y+borderWidth, b.x-1, b.y+b.height-borderWidth);
978		XDrawLine(Tk_Display(tkwin), d,
979		    Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC),
980		    b.x, b.y+borderWidth, b.x, b.y+b.height-borderWidth);
981	    }
982	} else {
983	    if (b.height > 4) {
984		b.y += b.height/2;
985		XDrawLine(Tk_Display(tkwin), d,
986		    Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC),
987		    b.x+borderWidth, b.y-1, b.x+b.width-borderWidth, b.y-1);
988		XDrawLine(Tk_Display(tkwin), d,
989		    Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC),
990		    b.x+borderWidth, b.y, b.x+b.width-borderWidth, b.y);
991	    }
992	}
993    }
994}
995
996static Ttk_ElementSpec SliderElementSpec = {
997    TK_STYLE_VERSION_2,
998    sizeof(SliderElement),
999    SliderElementOptions,
1000    SliderElementSize,
1001    SliderElementDraw
1002};
1003
1004/*------------------------------------------------------------------------
1005 * +++ Progress bar element:
1006 *	Draws the moving part of the progress bar.
1007 *
1008 *	-thickness specifies the size along the short axis of the bar.
1009 *	-length specifies the default size along the long axis;
1010 *	the bar will be this long in indeterminate mode.
1011 */
1012
1013#define DEFAULT_PBAR_THICKNESS "15"
1014#define DEFAULT_PBAR_LENGTH "30"
1015
1016typedef struct {
1017    Tcl_Obj *orientObj; 	/* widget orientation */
1018    Tcl_Obj *thicknessObj;	/* the height/width of the bar */
1019    Tcl_Obj *lengthObj;		/* default width/height of the bar */
1020    Tcl_Obj *reliefObj; 	/* border relief for this object */
1021    Tcl_Obj *borderObj; 	/* background color */
1022    Tcl_Obj *borderWidthObj; 	/* thickness of the border */
1023} PbarElement;
1024
1025static Ttk_ElementOptionSpec PbarElementOptions[] = {
1026    { "-orient", TK_OPTION_ANY, Tk_Offset(PbarElement,orientObj),
1027	"horizontal" },
1028    { "-thickness", TK_OPTION_PIXELS, Tk_Offset(PbarElement,thicknessObj),
1029	DEFAULT_PBAR_THICKNESS },
1030    { "-barsize", TK_OPTION_PIXELS, Tk_Offset(PbarElement,lengthObj),
1031	DEFAULT_PBAR_LENGTH },
1032    { "-pbarrelief", TK_OPTION_RELIEF, Tk_Offset(PbarElement,reliefObj),
1033	"raised" },
1034    { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(PbarElement,borderWidthObj),
1035	DEFAULT_BORDERWIDTH },
1036    { "-background", TK_OPTION_BORDER, Tk_Offset(PbarElement,borderObj),
1037	DEFAULT_BACKGROUND },
1038    { NULL, 0, 0, NULL }
1039};
1040
1041static void PbarElementSize(
1042    void *clientData, void *elementRecord, Tk_Window tkwin,
1043    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1044{
1045    PbarElement *pbar = elementRecord;
1046    int orient, thickness = 15, length = 30, borderWidth = 2;
1047
1048    Ttk_GetOrientFromObj(NULL, pbar->orientObj, &orient);
1049    Tk_GetPixelsFromObj(NULL, tkwin, pbar->thicknessObj, &thickness);
1050    Tk_GetPixelsFromObj(NULL, tkwin, pbar->lengthObj, &length);
1051    Tk_GetPixelsFromObj(NULL, tkwin, pbar->borderWidthObj, &borderWidth);
1052
1053    switch (orient) {
1054	case TTK_ORIENT_HORIZONTAL:
1055	    *widthPtr	= length + 2 * borderWidth;
1056	    *heightPtr	= thickness + 2 * borderWidth;
1057	    break;
1058	case TTK_ORIENT_VERTICAL:
1059	    *widthPtr	= thickness + 2 * borderWidth;
1060	    *heightPtr	= length + 2 * borderWidth;
1061	    break;
1062    }
1063}
1064
1065static void PbarElementDraw(
1066    void *clientData, void *elementRecord, Tk_Window tkwin,
1067    Drawable d, Ttk_Box b, Ttk_State state)
1068{
1069    PbarElement *pbar = elementRecord;
1070    Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, pbar->borderObj);
1071    int relief = TK_RELIEF_RAISED, borderWidth = 2;
1072
1073    Tk_GetPixelsFromObj(NULL, tkwin, pbar->borderWidthObj, &borderWidth);
1074    Tk_GetReliefFromObj(NULL, pbar->reliefObj, &relief);
1075
1076    Tk_Fill3DRectangle(tkwin, d, border,
1077	b.x, b.y, b.width, b.height,
1078	borderWidth, relief);
1079}
1080
1081static Ttk_ElementSpec PbarElementSpec = {
1082    TK_STYLE_VERSION_2,
1083    sizeof(PbarElement),
1084    PbarElementOptions,
1085    PbarElementSize,
1086    PbarElementDraw
1087};
1088
1089/*------------------------------------------------------------------------
1090 * +++ Notebook tabs and client area.
1091 */
1092
1093typedef struct {
1094    Tcl_Obj *borderWidthObj;
1095    Tcl_Obj *backgroundObj;
1096} TabElement;
1097
1098static Ttk_ElementOptionSpec TabElementOptions[] = {
1099    { "-borderwidth", TK_OPTION_PIXELS,
1100	Tk_Offset(TabElement,borderWidthObj),"1" },
1101    { "-background", TK_OPTION_BORDER,
1102	Tk_Offset(TabElement,backgroundObj), DEFAULT_BACKGROUND },
1103    {0,0,0,0}
1104};
1105
1106static void TabElementSize(
1107    void *clientData, void *elementRecord, Tk_Window tkwin,
1108    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1109{
1110    TabElement *tab = elementRecord;
1111    int borderWidth = 1;
1112    Tk_GetPixelsFromObj(0, tkwin, tab->borderWidthObj, &borderWidth);
1113    paddingPtr->top = paddingPtr->left = paddingPtr->right = borderWidth;
1114    paddingPtr->bottom = 0;
1115}
1116
1117static void TabElementDraw(
1118    void *clientData, void *elementRecord, Tk_Window tkwin,
1119    Drawable d, Ttk_Box b, unsigned int state)
1120{
1121    TabElement *tab = elementRecord;
1122    Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, tab->backgroundObj);
1123    int borderWidth = 1;
1124    int cut = 2;
1125    XPoint pts[6];
1126    int n = 0;
1127
1128    Tcl_GetIntFromObj(NULL, tab->borderWidthObj, &borderWidth);
1129
1130    if (state & TTK_STATE_SELECTED) {
1131	/*
1132	 * Draw slightly outside of the allocated parcel,
1133	 * to overwrite the client area border.
1134	 */
1135	b.height += borderWidth;
1136    }
1137
1138    pts[n].x = b.x; 			pts[n].y = b.y + b.height - 1; ++n;
1139    pts[n].x = b.x;			pts[n].y = b.y + cut; ++n;
1140    pts[n].x = b.x + cut;  		pts[n].y = b.y; ++n;
1141    pts[n].x = b.x + b.width-1-cut;	pts[n].y = b.y; ++n;
1142    pts[n].x = b.x + b.width-1; 	pts[n].y = b.y + cut; ++n;
1143    pts[n].x = b.x + b.width-1; 	pts[n].y = b.y + b.height; ++n;
1144
1145    XFillPolygon(Tk_Display(tkwin), d,
1146	Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC),
1147	pts, 6, Convex, CoordModeOrigin);
1148
1149#ifndef WIN32
1150    /*
1151     * Account for whether XDrawLines draws endpoints by platform
1152     */
1153    --pts[5].y;
1154#endif
1155
1156    while (borderWidth--) {
1157	XDrawLines(Tk_Display(tkwin), d,
1158		Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC),
1159		pts, 4, CoordModeOrigin);
1160	XDrawLines(Tk_Display(tkwin), d,
1161		Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC),
1162		pts+3, 3, CoordModeOrigin);
1163	++pts[0].x; ++pts[1].x; ++pts[2].x;             --pts[4].x; --pts[5].x;
1164	                        ++pts[2].y; ++pts[3].y;
1165    }
1166
1167}
1168
1169static Ttk_ElementSpec TabElementSpec = {
1170    TK_STYLE_VERSION_2,
1171    sizeof(TabElement),
1172    TabElementOptions,
1173    TabElementSize,
1174    TabElementDraw
1175};
1176
1177/*
1178 * Client area element:
1179 * Uses same resources as tab element.
1180 */
1181typedef TabElement ClientElement;
1182#define ClientElementOptions TabElementOptions
1183
1184static void ClientElementDraw(
1185    void *clientData, void *elementRecord, Tk_Window tkwin,
1186    Drawable d, Ttk_Box b, unsigned int state)
1187{
1188    ClientElement *ce = elementRecord;
1189    Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, ce->backgroundObj);
1190    int borderWidth = 1;
1191
1192    Tcl_GetIntFromObj(NULL, ce->borderWidthObj, &borderWidth);
1193
1194    Tk_Fill3DRectangle(tkwin, d, border,
1195	b.x, b.y, b.width, b.height, borderWidth,TK_RELIEF_RAISED);
1196}
1197
1198static void ClientElementSize(
1199    void *clientData, void *elementRecord, Tk_Window tkwin,
1200    int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
1201{
1202    ClientElement *ce = elementRecord;
1203    int borderWidth = 1;
1204    Tk_GetPixelsFromObj(0, tkwin, ce->borderWidthObj, &borderWidth);
1205    *paddingPtr = Ttk_UniformPadding((short)borderWidth);
1206}
1207
1208static Ttk_ElementSpec ClientElementSpec = {
1209    TK_STYLE_VERSION_2,
1210    sizeof(ClientElement),
1211    ClientElementOptions,
1212    ClientElementSize,
1213    ClientElementDraw
1214};
1215
1216/*----------------------------------------------------------------------
1217 * TtkElements_Init --
1218 *	Register default element implementations.
1219 */
1220
1221MODULE_SCOPE
1222void TtkElements_Init(Tcl_Interp *interp)
1223{
1224    Ttk_Theme theme =  Ttk_GetDefaultTheme(interp);
1225
1226    /*
1227     * Elements:
1228     */
1229    Ttk_RegisterElement(interp, theme, "background",
1230	    &BackgroundElementSpec,NULL);
1231
1232    Ttk_RegisterElement(interp, theme, "fill", &FillElementSpec, NULL);
1233    Ttk_RegisterElement(interp, theme, "border", &BorderElementSpec, NULL);
1234    Ttk_RegisterElement(interp, theme, "field", &FieldElementSpec, NULL);
1235    Ttk_RegisterElement(interp, theme, "focus", &FocusElementSpec, NULL);
1236
1237    Ttk_RegisterElement(interp, theme, "padding", &PaddingElementSpec, NULL);
1238
1239    Ttk_RegisterElement(interp, theme, "Checkbutton.indicator",
1240	    &CheckbuttonIndicatorElementSpec, NULL);
1241    Ttk_RegisterElement(interp, theme, "Radiobutton.indicator",
1242	    &RadiobuttonIndicatorElementSpec, NULL);
1243    Ttk_RegisterElement(interp, theme, "Menubutton.indicator",
1244	    &MenuIndicatorElementSpec, NULL);
1245
1246    Ttk_RegisterElement(interp, theme, "indicator", &ttkNullElementSpec,NULL);
1247
1248    Ttk_RegisterElement(interp, theme, "uparrow",
1249	    &ArrowElementSpec, &ArrowElements[0]);
1250    Ttk_RegisterElement(interp, theme, "downarrow",
1251	    &ArrowElementSpec, &ArrowElements[1]);
1252    Ttk_RegisterElement(interp, theme, "leftarrow",
1253	    &ArrowElementSpec, &ArrowElements[2]);
1254    Ttk_RegisterElement(interp, theme, "rightarrow",
1255	    &ArrowElementSpec, &ArrowElements[3]);
1256    Ttk_RegisterElement(interp, theme, "arrow",
1257	    &ArrowElementSpec, &ArrowElements[0]);
1258
1259    Ttk_RegisterElement(interp, theme, "trough", &TroughElementSpec, NULL);
1260    Ttk_RegisterElement(interp, theme, "thumb", &ThumbElementSpec, NULL);
1261    Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL);
1262    Ttk_RegisterElement(interp, theme, "pbar", &PbarElementSpec, NULL);
1263
1264    Ttk_RegisterElement(interp, theme, "separator",
1265	    &SeparatorElementSpec, NULL);
1266    Ttk_RegisterElement(interp, theme, "hseparator",
1267	    &HorizontalSeparatorElementSpec, NULL);
1268    Ttk_RegisterElement(interp, theme, "vseparator",
1269	    &VerticalSeparatorElementSpec, NULL);
1270
1271    Ttk_RegisterElement(interp, theme, "sizegrip", &SizegripElementSpec, NULL);
1272
1273    Ttk_RegisterElement(interp, theme, "tab", &TabElementSpec, NULL);
1274    Ttk_RegisterElement(interp, theme, "client", &ClientElementSpec, NULL);
1275
1276    /*
1277     * Register "default" as a user-loadable theme (for now):
1278     */
1279    Tcl_PkgProvide(interp, "ttk::theme::default", TTK_VERSION);
1280}
1281
1282/*EOF*/
1283