diff options
Diffstat (limited to 'generic/ttk/ttkDefaultTheme.c')
-rw-r--r-- | generic/ttk/ttkDefaultTheme.c | 1130 |
1 files changed, 1130 insertions, 0 deletions
diff --git a/generic/ttk/ttkDefaultTheme.c b/generic/ttk/ttkDefaultTheme.c new file mode 100644 index 0000000..d2deee8 --- /dev/null +++ b/generic/ttk/ttkDefaultTheme.c @@ -0,0 +1,1130 @@ +/* + * Copyright (c) 2003, Joe English + * + * Tk alternate theme, intended to match the MSUE and Gtk's (old) default theme + */ + +#include <math.h> +#include <string.h> + +#include <tkInt.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "ttkTheme.h" + +#if defined(WIN32) +static const int WIN32_XDRAWLINE_HACK = 1; +#else +static const int WIN32_XDRAWLINE_HACK = 0; +#endif + +#define BORDERWIDTH 2 +#define SCROLLBAR_WIDTH 14 +#define MIN_THUMB_SIZE 8 + +/* + *---------------------------------------------------------------------- + * + * Helper routines for border drawing: + * + * NOTE: MSUE specifies a slightly different arrangement + * for button borders than for other elements; "shadowColors" + * is for button borders. + * + * Please excuse the gross misspelling "LITE" for "LIGHT", + * but it makes things line up nicer. + */ + +enum BorderColor { FLAT = 1, LITE = 2, DARK = 3, BRDR = 4 }; + +/* top-left outer, top-left inner, bottom-right inner, bottom-right outer */ +static int const shadowColors[6][4] = { + { FLAT, FLAT, FLAT, FLAT }, /* TK_RELIEF_FLAT = 0*/ + { DARK, LITE, DARK, LITE }, /* TK_RELIEF_GROOVE = 1*/ + { LITE, FLAT, DARK, BRDR }, /* TK_RELIEF_RAISED = 2*/ + { LITE, DARK, LITE, DARK }, /* TK_RELIEF_RIDGE = 3*/ + { BRDR, BRDR, BRDR, BRDR }, /* TK_RELIEF_SOLID = 4*/ + { BRDR, DARK, FLAT, LITE } /* TK_RELIEF_SUNKEN = 5*/ +}; + +/* top-left, bottom-right */ +static int const thinShadowColors[6][4] = { + { FLAT, FLAT }, /* TK_RELIEF_FLAT = 0*/ + { DARK, LITE }, /* TK_RELIEF_GROOVE = 1*/ + { LITE, DARK }, /* TK_RELIEF_RAISED = 2*/ + { LITE, DARK }, /* TK_RELIEF_RIDGE = 3*/ + { BRDR, BRDR }, /* TK_RELIEF_SOLID = 4*/ + { DARK, LITE } /* TK_RELIEF_SUNKEN = 5*/ +}; + +static void DrawCorner( + Tk_Window tkwin, + Drawable d, + Tk_3DBorder border, /* get most GCs from here... */ + GC borderGC, /* "window border" color GC */ + int x,int y, int width,int height, /* where to draw */ + int corner, /* 0 => top left; 1 => bottom right */ + enum BorderColor color) +{ + XPoint points[3]; + GC gc; + + --width; --height; + points[0].x = x; points[0].y = y+height; + points[1].x = x+width*corner; points[1].y = y+height*corner; + points[2].x = x+width; points[2].y = y; + + if (color == BRDR) + gc = borderGC; + else + gc = Tk_3DBorderGC(tkwin, border, (int)color); + + XDrawLines(Tk_Display(tkwin), d, gc, points, 3, CoordModeOrigin); +} + +static void DrawBorder( + Tk_Window tkwin, Drawable d, Tk_3DBorder border, XColor *borderColor, + Ttk_Box b, int borderWidth, int relief) +{ + GC borderGC = Tk_GCForColor(borderColor, d); + + switch (borderWidth) { + case 2: /* "thick" border */ + DrawCorner(tkwin, d, border, borderGC, + b.x, b.y, b.width, b.height, 0,shadowColors[relief][0]); + DrawCorner(tkwin, d, border, borderGC, + b.x+1, b.y+1, b.width-2, b.height-2, 0,shadowColors[relief][1]); + DrawCorner(tkwin, d, border, borderGC, + b.x+1, b.y+1, b.width-2, b.height-2, 1,shadowColors[relief][2]); + DrawCorner(tkwin, d, border, borderGC, + b.x, b.y, b.width, b.height, 1,shadowColors[relief][3]); + break; + case 1: /* "thin" border */ + DrawCorner(tkwin, d, border, borderGC, + b.x, b.y, b.width, b.height, 0, thinShadowColors[relief][0]); + DrawCorner(tkwin, d, border, borderGC, + b.x, b.y, b.width, b.height, 1, thinShadowColors[relief][1]); + break; + case 0: /* no border -- do nothing */ + break; + default: /* Fall back to Motif-style borders: */ + Tk_Draw3DRectangle(tkwin, d, border, + b.x, b.y, b.width, b.height, borderWidth,relief); + break; + } +} + +/* Alternate shadow colors for entry fields: + * NOTE: FLAT color is normally white, and the LITE color is a darker shade. + */ +static int fieldShadowColors[4] = { DARK, BRDR, LITE, FLAT }; + +static void DrawFieldBorder( + Tk_Window tkwin, Drawable d, Tk_3DBorder border, XColor *borderColor, + Ttk_Box b) +{ + GC borderGC = Tk_GCForColor(borderColor, d); + DrawCorner(tkwin, d, border, borderGC, + b.x, b.y, b.width, b.height, 0,fieldShadowColors[0]); + DrawCorner(tkwin, d, border, borderGC, + b.x+1, b.y+1, b.width-2, b.height-2, 0,fieldShadowColors[1]); + DrawCorner(tkwin, d, border, borderGC, + b.x+1, b.y+1, b.width-2, b.height-2, 1,fieldShadowColors[2]); + DrawCorner(tkwin, d, border, borderGC, + b.x, b.y, b.width, b.height, 1,fieldShadowColors[3]); + return; +} + +/* + * ArrowPoints -- + * Compute points of arrow polygon. + */ +static void ArrowPoints(Ttk_Box b, ArrowDirection dir, XPoint points[4]) +{ + int cx, cy, h; + + switch (dir) { + case ARROW_UP: + h = (b.width - 1)/2; + cx = b.x + h; + cy = b.y; + if (b.height <= h) h = b.height - 1; + points[0].x = cx; points[0].y = cy; + points[1].x = cx - h; points[1].y = cy + h; + points[2].x = cx + h; points[2].y = cy + h; + break; + case ARROW_DOWN: + h = (b.width - 1)/2; + cx = b.x + h; + cy = b.y + b.height - 1; + if (b.height <= h) h = b.height - 1; + points[0].x = cx; points[0].y = cy; + points[1].x = cx - h; points[1].y = cy - h; + points[2].x = cx + h; points[2].y = cy - h; + break; + case ARROW_LEFT: + h = (b.height - 1)/2; + cx = b.x; + cy = b.y + h; + if (b.width <= h) h = b.width - 1; + points[0].x = cx; points[0].y = cy; + points[1].x = cx + h; points[1].y = cy - h; + points[2].x = cx + h; points[2].y = cy + h; + break; + case ARROW_RIGHT: + h = (b.height - 1)/2; + cx = b.x + b.width - 1; + cy = b.y + h; + if (b.width <= h) h = b.width - 1; + points[0].x = cx; points[0].y = cy; + points[1].x = cx - h; points[1].y = cy - h; + points[2].x = cx - h; points[2].y = cy + h; + break; + } + + points[3].x = points[0].x; + points[3].y = points[0].y; +} + +/*public*/ +void TtkArrowSize(int h, ArrowDirection dir, int *widthPtr, int *heightPtr) +{ + switch (dir) { + case ARROW_UP: + case ARROW_DOWN: *widthPtr = 2*h+1; *heightPtr = h+1; break; + case ARROW_LEFT: + case ARROW_RIGHT: *widthPtr = h+1; *heightPtr = 2*h+1; + } +} + +/* + * TtkDrawArrow, TtkFillArrow -- + * Draw an arrow in the indicated direction inside the specified box. + */ +/*public*/ +void TtkFillArrow( + Display *display, Drawable d, GC gc, Ttk_Box b, ArrowDirection dir) +{ + XPoint points[4]; + ArrowPoints(b, dir, points); + XFillPolygon(display, d, gc, points, 3, Convex, CoordModeOrigin); + XDrawLines(display, d, gc, points, 4, CoordModeOrigin); +} + +/*public*/ +void TtkDrawArrow( + Display *display, Drawable d, GC gc, Ttk_Box b, ArrowDirection dir) +{ + XPoint points[4]; + ArrowPoints(b, dir, points); + XDrawLines(display, d, gc, points, 4, CoordModeOrigin); +} + +/* + *---------------------------------------------------------------------- + * +++ Border element implementation. + * + * This border consists of (from outside-in): + * + * + a 1-pixel thick default indicator (defaultable widgets only) + * + 1- or 2- pixel shaded border (controlled by -background and -relief) + * + 1 pixel padding (???) + */ + +typedef struct { + Tcl_Obj *borderObj; + Tcl_Obj *borderColorObj; /* Extra border color */ + Tcl_Obj *borderWidthObj; + Tcl_Obj *reliefObj; + Tcl_Obj *defaultStateObj; /* for buttons */ +} BorderElement; + +static Ttk_ElementOptionSpec BorderElementOptions[] = { + { "-background", TK_OPTION_BORDER, Tk_Offset(BorderElement,borderObj), + DEFAULT_BACKGROUND }, + { "-bordercolor",TK_OPTION_COLOR, + Tk_Offset(BorderElement,borderColorObj), "black" }, + { "-default", TK_OPTION_ANY, Tk_Offset(BorderElement,defaultStateObj), + "disabled" }, + { "-borderwidth",TK_OPTION_PIXELS,Tk_Offset(BorderElement,borderWidthObj), + STRINGIFY(BORDERWIDTH) }, + { "-relief", TK_OPTION_RELIEF, Tk_Offset(BorderElement,reliefObj), + "flat" }, + { NULL, 0, 0, NULL } +}; + +static void BorderElementSize( + void *clientData, void *elementRecord, Tk_Window tkwin, + int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +{ + BorderElement *bd = elementRecord; + int borderWidth = 0; + int defaultState = TTK_BUTTON_DEFAULT_DISABLED; + + Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth); + Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState); + + if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) { + ++borderWidth; + } + + *paddingPtr = Ttk_UniformPadding((short)borderWidth); +} + +static void BorderElementDraw( + void *clientData, void *elementRecord, + Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) +{ + BorderElement *bd = elementRecord; + Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, bd->borderObj); + XColor *borderColor = Tk_GetColorFromObj(tkwin, bd->borderColorObj); + int borderWidth = 2; + int relief = TK_RELIEF_FLAT; + int defaultState = TTK_BUTTON_DEFAULT_DISABLED; + + /* + * Get option values. + */ + Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth); + Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief); + Ttk_GetButtonDefaultStateFromObj(NULL, bd->defaultStateObj, &defaultState); + + if (defaultState == TTK_BUTTON_DEFAULT_ACTIVE) { + GC gc = Tk_GCForColor(borderColor, d); + XDrawRectangle(Tk_Display(tkwin), d, gc, + b.x, b.y, b.width-1, b.height-1); + } + if (defaultState != TTK_BUTTON_DEFAULT_DISABLED) { + /* Space for default ring: */ + b = Ttk_PadBox(b, Ttk_UniformPadding(1)); + } + + DrawBorder(tkwin, d, border, borderColor, b, borderWidth, relief); +} + +static Ttk_ElementSpec BorderElementSpec = { + TK_STYLE_VERSION_2, + sizeof(BorderElement), + BorderElementOptions, + BorderElementSize, + BorderElementDraw +}; + +/*---------------------------------------------------------------------- + * +++ Field element: + * Used for editable fields. + */ +typedef struct { + Tcl_Obj *borderObj; + Tcl_Obj *borderColorObj; /* Extra border color */ +} FieldElement; + +static Ttk_ElementOptionSpec FieldElementOptions[] = { + { "-fieldbackground", TK_OPTION_BORDER, Tk_Offset(FieldElement,borderObj), + "white" }, + { "-bordercolor",TK_OPTION_COLOR, Tk_Offset(FieldElement,borderColorObj), + "black" }, + { NULL, 0, 0, NULL } +}; + +static void FieldElementSize( + void *clientData, void *elementRecord, Tk_Window tkwin, + int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +{ + *paddingPtr = Ttk_UniformPadding(2); +} + +static void FieldElementDraw( + void *clientData, void *elementRecord, Tk_Window tkwin, + Drawable d, Ttk_Box b, unsigned int state) +{ + FieldElement *field = elementRecord; + Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, field->borderObj); + XColor *borderColor = Tk_GetColorFromObj(tkwin, field->borderColorObj); + + Tk_Fill3DRectangle( + tkwin, d, border, b.x, b.y, b.width, b.height, 0, TK_RELIEF_SUNKEN); + DrawFieldBorder(tkwin, d, border, borderColor, b); +} + +static Ttk_ElementSpec FieldElementSpec = { + TK_STYLE_VERSION_2, + sizeof(FieldElement), + FieldElementOptions, + FieldElementSize, + FieldElementDraw +}; + +/*------------------------------------------------------------------------ + * Indicators -- + * + * Code derived (probably incorrectly) from TIP 109 implementation, + * unix/tkUnixButton.c r 1.15. + */ + +/* + * Indicator bitmap descriptor: + */ +typedef struct { + int width; /* Width of each image */ + int height; /* Height of each image */ + int nimages; /* #images / row */ + const char *const *pixels; /* array[height] of char[width*nimage] */ + Ttk_StateTable *map;/* used to look up image index by state */ +} IndicatorSpec; + +#if 0 +/*XPM*/ +static const char *const button_images[] = { + /* width height ncolors chars_per_pixel */ + "52 13 8 1", + /* colors */ + "A c #808000000000 s shadow", + "B c #000080800000 s highlight", + "C c #808080800000 s 3dlight", + "D c #000000008080 s window", + "E c #808000008080 s 3ddark", + "F c #000080808080 s frame", + "G c #000000000000 s foreground", + "H c #000080800000 s disabledfg", +}; +#endif + +static Ttk_StateTable checkbutton_states[] = { + { 0, 0, TTK_STATE_SELECTED|TTK_STATE_DISABLED }, + { 1, TTK_STATE_SELECTED, TTK_STATE_DISABLED }, + { 2, TTK_STATE_DISABLED, TTK_STATE_SELECTED }, + { 3, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0 }, + { 0, 0, 0 } +}; + +static const char *const checkbutton_pixels[] = { + "AAAAAAAAAAAABAAAAAAAAAAAABAAAAAAAAAAAABAAAAAAAAAAAAB", + "AEEEEEEEEEECBAEEEEEEEEEECBAEEEEEEEEEECBAEEEEEEEEEECB", + "AEDDDDDDDDDCBAEDDDDDDDDDCBAEFFFFFFFFFCBAEFFFFFFFFFCB", + "AEDDDDDDDDDCBAEDDDDDDDGDCBAEFFFFFFFFFCBAEFFFFFFFHFCB", + "AEDDDDDDDDDCBAEDDDDDDGGDCBAEFFFFFFFFFCBAEFFFFFFHHFCB", + "AEDDDDDDDDDCBAEDGDDDGGGDCBAEFFFFFFFFFCBAEFHFFFHHHFCB", + "AEDDDDDDDDDCBAEDGGDGGGDDCBAEFFFFFFFFFCBAEFHHFHHHFFCB", + "AEDDDDDDDDDCBAEDGGGGGDDDCBAEFFFFFFFFFCBAEFHHHHHFFFCB", + "AEDDDDDDDDDCBAEDDGGGDDDDCBAEFFFFFFFFFCBAEFFHHHFFFFCB", + "AEDDDDDDDDDCBAEDDDGDDDDDCBAEFFFFFFFFFCBAEFFFHFFFFFCB", + "AEDDDDDDDDDCBAEDDDDDDDDDCBAEFFFFFFFFFCBAEFFFFFFFFFCB", + "ACCCCCCCCCCCBACCCCCCCCCCCBACCCCCCCCCCCBACCCCCCCCCCCB", + "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB", +}; + +static IndicatorSpec checkbutton_spec = { + 13, 13, 4, /* width, height, nimages */ + checkbutton_pixels, + checkbutton_states +}; + +static Ttk_StateTable radiobutton_states[] = { + { 0, 0, TTK_STATE_SELECTED|TTK_STATE_DISABLED }, + { 1, TTK_STATE_SELECTED, TTK_STATE_DISABLED }, + { 2, TTK_STATE_DISABLED, TTK_STATE_SELECTED }, + { 3, TTK_STATE_SELECTED|TTK_STATE_DISABLED, 0 }, + { 0, 0, 0 } +}; + +static const char *const radiobutton_pixels[] = { + "FFFFAAAAFFFFFFFFFAAAAFFFFFFFFFAAAAFFFFFFFFFAAAAFFFFF", + "FFAAEEEEAAFFFFFAAEEEEAAFFFFFAAEEEEAAFFFFFAAEEEEAAFFF", + "FAEEDDDDEEBFFFAEEDDDDEEBFFFAEEFFFFEEBFFFAEEFFFFEEBFF", + "FAEDDDDDDCBFFFAEDDDDDDCBFFFAEFFFFFFCBFFFAEFFFFFFCBFF", + "AEDDDDDDDDCBFAEDDDGGDDDCBFAEFFFFFFFFCBFAEFFFHHFFFCBF", + "AEDDDDDDDDCBFAEDDGGGGDDCBFAEFFFFFFFFCBFAEFFHHHHFFCBF", + "AEDDDDDDDDCBFAEDDGGGGDDCBFAEFFFFFFFFCBFAEFFHHHHFFCBF", + "AEDDDDDDDDCBFAEDDDGGDDDCBFAEFFFFFFFFCBFAEFFFHHFFFCBF", + "FAEDDDDDDCBFFFAEDDDDDDCBFFFAEFFFFFFCBFFFAEFFFFFFCBFF", + "FACCDDDDCCBFFFACCDDDDCCBFFFACCFFFFCCBFFFACCFFFFCCBFF", + "FFBBCCCCBBFFFFFBBCCCCBBFFFFFBBCCCCBBFFFFFBBCCCCBBFFF", + "FFFFBBBBFFFFFFFFFBBBBFFFFFFFFFBBBBFFFFFFFFFBBBBFFFFF", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", +}; + +static IndicatorSpec radiobutton_spec = { + 13, 13, 4, /* width, height, nimages */ + radiobutton_pixels, + radiobutton_states +}; + +typedef struct { + Tcl_Obj *backgroundObj; + Tcl_Obj *foregroundObj; + Tcl_Obj *colorObj; + Tcl_Obj *lightColorObj; + Tcl_Obj *shadeColorObj; + Tcl_Obj *borderColorObj; + Tcl_Obj *marginObj; +} IndicatorElement; + +static Ttk_ElementOptionSpec IndicatorElementOptions[] = { + { "-background", TK_OPTION_COLOR, + Tk_Offset(IndicatorElement,backgroundObj), DEFAULT_BACKGROUND }, + { "-foreground", TK_OPTION_COLOR, + Tk_Offset(IndicatorElement,foregroundObj), DEFAULT_FOREGROUND }, + { "-indicatorcolor", TK_OPTION_COLOR, + Tk_Offset(IndicatorElement,colorObj), "#FFFFFF" }, + { "-lightcolor", TK_OPTION_COLOR, + Tk_Offset(IndicatorElement,lightColorObj), "#DDDDDD" }, + { "-shadecolor", TK_OPTION_COLOR, + Tk_Offset(IndicatorElement,shadeColorObj), "#888888" }, + { "-bordercolor", TK_OPTION_COLOR, + Tk_Offset(IndicatorElement,borderColorObj), "black" }, + { "-indicatormargin", TK_OPTION_STRING, + Tk_Offset(IndicatorElement,marginObj), "0 2 4 2" }, + { NULL, 0, 0, NULL } +}; + +static void IndicatorElementSize( + void *clientData, void *elementRecord, Tk_Window tkwin, + int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +{ + IndicatorSpec *spec = clientData; + IndicatorElement *indicator = elementRecord; + Ttk_Padding margins; + Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins); + *widthPtr = spec->width + Ttk_PaddingWidth(margins); + *heightPtr = spec->height + Ttk_PaddingHeight(margins); +} + +static void IndicatorElementDraw( + void *clientData, void *elementRecord, Tk_Window tkwin, + Drawable d, Ttk_Box b, unsigned int state) +{ + IndicatorSpec *spec = clientData; + IndicatorElement *indicator = elementRecord; + Display *display = Tk_Display(tkwin); + Ttk_Padding padding; + XColor *fgColor, *frameColor, *shadeColor, *indicatorColor, *borderColor; + + int index, ix, iy; + XGCValues gcValues; + GC copyGC; + unsigned long imgColors[8]; + XImage *img; + + Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding); + b = Ttk_PadBox(b, padding); + + if ( b.x < 0 + || b.y < 0 + || Tk_Width(tkwin) < b.x + spec->width + || Tk_Height(tkwin) < b.y + spec->height) + { + /* Oops! not enough room to display the image. + * Don't draw anything. + */ + return; + } + + /* + * Fill in imgColors palette: + * + * (SHOULD: take light and shade colors from the border object, + * but Tk doesn't provide easy access to these in the public API.) + */ + fgColor = Tk_GetColorFromObj(tkwin, indicator->foregroundObj); + frameColor = Tk_GetColorFromObj(tkwin, indicator->backgroundObj); + shadeColor = Tk_GetColorFromObj(tkwin, indicator->shadeColorObj); + indicatorColor = Tk_GetColorFromObj(tkwin, indicator->colorObj); + borderColor = Tk_GetColorFromObj(tkwin, indicator->borderColorObj); + + imgColors[0 /*A*/] = shadeColor->pixel; + imgColors[1 /*B*/] = indicatorColor->pixel; + imgColors[2 /*C*/] = frameColor->pixel; + imgColors[3 /*D*/] = indicatorColor->pixel; + imgColors[4 /*E*/] = borderColor->pixel; + imgColors[5 /*F*/] = frameColor->pixel; + imgColors[6 /*G*/] = fgColor->pixel; + imgColors[7 /*H*/] = fgColor->pixel; + + /* + * Create a scratch buffer to store the image: + */ + img = XGetImage(display,d, 0, 0, + (unsigned int)spec->width, (unsigned int)spec->height, + AllPlanes, ZPixmap); + if (img == NULL) + return; + + /* + * Create the image, painting it into an XImage one pixel at a time. + */ + index = Ttk_StateTableLookup(spec->map, state); + for (iy=0 ; iy<spec->height ; iy++) { + for (ix=0 ; ix<spec->width ; ix++) { + XPutPixel(img, ix, iy, + imgColors[spec->pixels[iy][index*spec->width+ix] - 'A'] ); + } + } + + /* + * Copy onto our target drawable surface. + */ + memset(&gcValues, 0, sizeof(gcValues)); + copyGC = Tk_GetGC(tkwin, 0, &gcValues); + + TkPutImage(NULL, 0, display, d, copyGC, img, 0, 0, b.x, b.y, + spec->width, spec->height); + + /* + * Tidy up. + */ + Tk_FreeGC(display, copyGC); + XDestroyImage(img); +} + +static Ttk_ElementSpec IndicatorElementSpec = { + TK_STYLE_VERSION_2, + sizeof(IndicatorElement), + IndicatorElementOptions, + IndicatorElementSize, + IndicatorElementDraw +}; + +/*---------------------------------------------------------------------- + * +++ Arrow element(s). + * + * Draws a solid triangle, inside a box. + * clientData is an enum ArrowDirection pointer. + */ + +static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT }; +typedef struct { + Tcl_Obj *sizeObj; + Tcl_Obj *borderObj; + Tcl_Obj *borderColorObj; /* Extra color for borders */ + Tcl_Obj *reliefObj; + Tcl_Obj *colorObj; /* Arrow color */ +} ArrowElement; + +static Ttk_ElementOptionSpec ArrowElementOptions[] = { + { "-arrowsize", TK_OPTION_PIXELS, + Tk_Offset(ArrowElement,sizeObj), STRINGIFY(SCROLLBAR_WIDTH) }, + { "-background", TK_OPTION_BORDER, + Tk_Offset(ArrowElement,borderObj), DEFAULT_BACKGROUND }, + { "-bordercolor", TK_OPTION_COLOR, + Tk_Offset(ArrowElement,borderColorObj), "black" }, + { "-relief", TK_OPTION_RELIEF, + Tk_Offset(ArrowElement,reliefObj),"raised"}, + { "-arrowcolor", TK_OPTION_COLOR, + Tk_Offset(ArrowElement,colorObj),"black"}, + { NULL, 0, 0, NULL } +}; + +/* + * Note asymmetric padding: + * top/left padding is 1 less than bottom/right, + * since in this theme 2-pixel borders are asymmetric. + */ +static Ttk_Padding ArrowPadding = { 3,3,4,4 }; + +static void ArrowElementSize( + void *clientData, void *elementRecord, Tk_Window tkwin, + int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +{ + ArrowElement *arrow = elementRecord; + int direction = *(int *)clientData; + int width = SCROLLBAR_WIDTH; + + Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &width); + width -= Ttk_PaddingWidth(ArrowPadding); + TtkArrowSize(width/2, direction, widthPtr, heightPtr); + *widthPtr += Ttk_PaddingWidth(ArrowPadding); + *heightPtr += Ttk_PaddingHeight(ArrowPadding); +} + +static void ArrowElementDraw( + void *clientData, void *elementRecord, Tk_Window tkwin, + Drawable d, Ttk_Box b, unsigned int state) +{ + int direction = *(int *)clientData; + ArrowElement *arrow = elementRecord; + Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, arrow->borderObj); + XColor *borderColor = Tk_GetColorFromObj(tkwin, arrow->borderColorObj); + XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj); + int relief = TK_RELIEF_RAISED; + int borderWidth = 2; + + Tk_GetReliefFromObj(NULL, arrow->reliefObj, &relief); + + Tk_Fill3DRectangle( + tkwin, d, border, b.x, b.y, b.width, b.height, 0, TK_RELIEF_FLAT); + DrawBorder(tkwin,d,border,borderColor,b,borderWidth,relief); + + TtkFillArrow(Tk_Display(tkwin), d, Tk_GCForColor(arrowColor, d), + Ttk_PadBox(b, ArrowPadding), direction); +} + +static Ttk_ElementSpec ArrowElementSpec = { + TK_STYLE_VERSION_2, + sizeof(ArrowElement), + ArrowElementOptions, + ArrowElementSize, + ArrowElementDraw +}; + +/*---------------------------------------------------------------------- + * +++ Menubutton indicator: + * Draw an arrow in the direction where the menu will be posted. + */ + +#define MENUBUTTON_ARROW_SIZE 5 + +typedef struct { + Tcl_Obj *directionObj; + Tcl_Obj *sizeObj; + Tcl_Obj *colorObj; +} MenubuttonArrowElement; + +static const char *directionStrings[] = { /* See also: button.c */ + "above", "below", "left", "right", "flush", NULL +}; +enum { POST_ABOVE, POST_BELOW, POST_LEFT, POST_RIGHT, POST_FLUSH }; + +static Ttk_ElementOptionSpec MenubuttonArrowElementOptions[] = { + { "-direction", TK_OPTION_STRING, + Tk_Offset(MenubuttonArrowElement,directionObj), "below" }, + { "-arrowsize", TK_OPTION_PIXELS, + Tk_Offset(MenubuttonArrowElement,sizeObj), STRINGIFY(MENUBUTTON_ARROW_SIZE)}, + { "-arrowcolor",TK_OPTION_COLOR, + Tk_Offset(MenubuttonArrowElement,colorObj), "black"}, + { NULL, 0, 0, NULL } +}; + +static Ttk_Padding MenubuttonArrowPadding = { 3, 0, 3, 0 }; + +static void MenubuttonArrowElementSize( + void *clientData, void *elementRecord, Tk_Window tkwin, + int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +{ + MenubuttonArrowElement *arrow = elementRecord; + int size = MENUBUTTON_ARROW_SIZE; + Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &size); + *widthPtr = *heightPtr = 2 * size + 1; + *widthPtr += Ttk_PaddingWidth(MenubuttonArrowPadding); + *heightPtr += Ttk_PaddingHeight(MenubuttonArrowPadding); +} + +static void MenubuttonArrowElementDraw( + void *clientData, void *elementRecord, Tk_Window tkwin, + Drawable d, Ttk_Box b, unsigned int state) +{ + MenubuttonArrowElement *arrow = elementRecord; + XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj); + GC gc = Tk_GCForColor(arrowColor, d); + int size = MENUBUTTON_ARROW_SIZE; + int postDirection = POST_BELOW; + ArrowDirection arrowDirection = ARROW_DOWN; + int width = 0, height = 0; + + Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &size); + Tcl_GetIndexFromObj(NULL, arrow->directionObj, directionStrings, + ""/*message*/, 0/*flags*/, &postDirection); + + /* ... this might not be such a great idea ... */ + switch (postDirection) { + case POST_ABOVE: arrowDirection = ARROW_UP; break; + case POST_BELOW: arrowDirection = ARROW_DOWN; break; + case POST_LEFT: arrowDirection = ARROW_LEFT; break; + case POST_RIGHT: arrowDirection = ARROW_RIGHT; break; + case POST_FLUSH: arrowDirection = ARROW_DOWN; break; + } + + TtkArrowSize(size, arrowDirection, &width, &height); + b = Ttk_PadBox(b, MenubuttonArrowPadding); + b = Ttk_AnchorBox(b, width, height, TK_ANCHOR_CENTER); + TtkFillArrow(Tk_Display(tkwin), d, gc, b, arrowDirection); +} + +static Ttk_ElementSpec MenubuttonArrowElementSpec = { + TK_STYLE_VERSION_2, + sizeof(MenubuttonArrowElement), + MenubuttonArrowElementOptions, + MenubuttonArrowElementSize, + MenubuttonArrowElementDraw +}; + +/*---------------------------------------------------------------------- + * +++ Trough element + * + * Used in scrollbars and the scale. + * + * The -groovewidth option can be used to set the size of the short axis + * for the drawn area. This will not affect the geometry, but can be used + * to draw a thin centered trough inside the packet alloted. This is used + * to show a win32-style scale widget. Use -1 or a large number to use the + * full area (default). + * + */ + +typedef struct { + Tcl_Obj *colorObj; + Tcl_Obj *borderWidthObj; + Tcl_Obj *reliefObj; + Tcl_Obj *grooveWidthObj; + Tcl_Obj *orientObj; +} TroughElement; + +static Ttk_ElementOptionSpec TroughElementOptions[] = { + { "-orient", TK_OPTION_ANY, + Tk_Offset(TroughElement, orientObj), "horizontal" }, + { "-troughborderwidth", TK_OPTION_PIXELS, + Tk_Offset(TroughElement,borderWidthObj), "1" }, + { "-troughcolor", TK_OPTION_BORDER, + Tk_Offset(TroughElement,colorObj), DEFAULT_BACKGROUND }, + { "-troughrelief",TK_OPTION_RELIEF, + Tk_Offset(TroughElement,reliefObj), "sunken" }, + { "-groovewidth", TK_OPTION_PIXELS, + Tk_Offset(TroughElement,grooveWidthObj), "-1" }, + { NULL, 0, 0, NULL } +}; + +static void TroughElementSize( + void *clientData, void *elementRecord, Tk_Window tkwin, + int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +{ + TroughElement *troughPtr = elementRecord; + int borderWidth = 2, grooveWidth = 0; + + Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth); + Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->grooveWidthObj, &grooveWidth); + + if (grooveWidth <= 0) { + *paddingPtr = Ttk_UniformPadding((short)borderWidth); + } +} + +static void TroughElementDraw( + void *clientData, void *elementRecord, Tk_Window tkwin, + Drawable d, Ttk_Box b, unsigned int state) +{ + TroughElement *troughPtr = elementRecord; + Tk_3DBorder border = NULL; + int borderWidth = 2, relief = TK_RELIEF_SUNKEN, groove = -1, orient; + + border = Tk_Get3DBorderFromObj(tkwin, troughPtr->colorObj); + Ttk_GetOrientFromObj(NULL, troughPtr->orientObj, &orient); + Tk_GetReliefFromObj(NULL, troughPtr->reliefObj, &relief); + Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth); + Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->grooveWidthObj, &groove); + + if (groove != -1 && groove < b.height && groove < b.width) { + if (orient == TTK_ORIENT_HORIZONTAL) { + b.y = b.y + b.height/2 - groove/2; + b.height = groove; + } else { + b.x = b.x + b.width/2 - groove/2; + b.width = groove; + } + } + + Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, + borderWidth, relief); +} + +static Ttk_ElementSpec TroughElementSpec = { + TK_STYLE_VERSION_2, + sizeof(TroughElement), + TroughElementOptions, + TroughElementSize, + TroughElementDraw +}; + +/* + *---------------------------------------------------------------------- + * +++ Thumb element. + */ + +typedef struct { + Tcl_Obj *sizeObj; + Tcl_Obj *firstObj; + Tcl_Obj *lastObj; + Tcl_Obj *borderObj; + Tcl_Obj *borderColorObj; + Tcl_Obj *reliefObj; + Tcl_Obj *orientObj; +} ThumbElement; + +static Ttk_ElementOptionSpec ThumbElementOptions[] = { + { "-width", TK_OPTION_PIXELS, Tk_Offset(ThumbElement,sizeObj), + STRINGIFY(SCROLLBAR_WIDTH) }, + { "-background", TK_OPTION_BORDER, Tk_Offset(ThumbElement,borderObj), + DEFAULT_BACKGROUND }, + { "-bordercolor", TK_OPTION_COLOR, Tk_Offset(ThumbElement,borderColorObj), + "black" }, + { "-relief", TK_OPTION_RELIEF,Tk_Offset(ThumbElement,reliefObj),"raised" }, + { "-orient", TK_OPTION_ANY,Tk_Offset(ThumbElement,orientObj),"horizontal"}, + { NULL, 0, 0, NULL } +}; + +static void ThumbElementSize( + void *clientData, void *elementRecord, Tk_Window tkwin, + int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +{ + ThumbElement *thumb = elementRecord; + int orient, size; + Tk_GetPixelsFromObj(NULL, tkwin, thumb->sizeObj, &size); + Ttk_GetOrientFromObj(NULL, thumb->orientObj, &orient); + + if (orient == TTK_ORIENT_VERTICAL) { + *widthPtr = size; + *heightPtr = MIN_THUMB_SIZE; + } else { + *widthPtr = MIN_THUMB_SIZE; + *heightPtr = size; + } +} + +static void ThumbElementDraw( + void *clientData, void *elementRecord, Tk_Window tkwin, + Drawable d, Ttk_Box b, unsigned int state) +{ + ThumbElement *thumb = elementRecord; + Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, thumb->borderObj); + XColor *borderColor = Tk_GetColorFromObj(tkwin, thumb->borderColorObj); + int relief = TK_RELIEF_RAISED; + int borderWidth = 2; + + /* + * Don't draw the thumb if we are disabled. + * This makes it behave like Windows ... if that's what we want. + if (state & TTK_STATE_DISABLED) + return; + */ + + Tk_GetReliefFromObj(NULL, thumb->reliefObj, &relief); + + Tk_Fill3DRectangle( + tkwin, d, border, b.x,b.y,b.width,b.height, 0, TK_RELIEF_FLAT); + DrawBorder(tkwin, d, border, borderColor, b, borderWidth, relief); +} + +static Ttk_ElementSpec ThumbElementSpec = { + TK_STYLE_VERSION_2, + sizeof(ThumbElement), + ThumbElementOptions, + ThumbElementSize, + ThumbElementDraw +}; + +/* + *---------------------------------------------------------------------- + * +++ Slider element. + * + * This is the moving part of the scale widget. + * + * The slider element is the thumb in the scale widget. This is drawn + * as an arrow-type element that can point up, down, left or right. + * + */ + +typedef struct { + Tcl_Obj *lengthObj; /* Long axis dimension */ + Tcl_Obj *thicknessObj; /* Short axis dimension */ + Tcl_Obj *reliefObj; /* Relief for this object */ + Tcl_Obj *borderObj; /* Border / background color */ + Tcl_Obj *borderColorObj; /* Additional border color */ + Tcl_Obj *borderWidthObj; + Tcl_Obj *orientObj; /* Orientation of overall slider */ +} SliderElement; + +static Ttk_ElementOptionSpec SliderElementOptions[] = { + { "-sliderlength", TK_OPTION_PIXELS, Tk_Offset(SliderElement,lengthObj), + "15" }, + { "-sliderthickness",TK_OPTION_PIXELS,Tk_Offset(SliderElement,thicknessObj), + "15" }, + { "-sliderrelief", TK_OPTION_RELIEF, Tk_Offset(SliderElement,reliefObj), + "raised" }, + { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(SliderElement,borderWidthObj), + STRINGIFY(BORDERWIDTH) }, + { "-background", TK_OPTION_BORDER, Tk_Offset(SliderElement,borderObj), + DEFAULT_BACKGROUND }, + { "-bordercolor", TK_OPTION_COLOR, Tk_Offset(ThumbElement,borderColorObj), + "black" }, + { "-orient", TK_OPTION_ANY, Tk_Offset(SliderElement,orientObj), + "horizontal" }, + { NULL, 0, 0, NULL } +}; + +static void SliderElementSize( + void *clientData, void *elementRecord, Tk_Window tkwin, + int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +{ + SliderElement *slider = elementRecord; + int orient, length, thickness, borderWidth; + + Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient); + Tk_GetPixelsFromObj(NULL, tkwin, slider->borderWidthObj, &borderWidth); + Tk_GetPixelsFromObj(NULL, tkwin, slider->lengthObj, &length); + Tk_GetPixelsFromObj(NULL, tkwin, slider->thicknessObj, &thickness); + + switch (orient) { + case TTK_ORIENT_VERTICAL: + *widthPtr = thickness + (borderWidth *2); + *heightPtr = *widthPtr/2; + break; + + case TTK_ORIENT_HORIZONTAL: + *heightPtr = thickness + (borderWidth *2); + *widthPtr = *heightPtr/2; + break; + } +} + +static void SliderElementDraw( + void *clientData, void *elementRecord, Tk_Window tkwin, + Drawable d, Ttk_Box b, unsigned int state) +{ + SliderElement *slider = elementRecord; + Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, slider->borderObj); + XColor *borderColor = Tk_GetColorFromObj(tkwin, slider->borderColorObj); + int relief = TK_RELIEF_RAISED, borderWidth = 2; + + Tk_GetPixelsFromObj(NULL, tkwin, slider->borderWidthObj, &borderWidth); + Tk_GetReliefFromObj(NULL, slider->reliefObj, &relief); + + Tk_Fill3DRectangle(tkwin, d, border, + b.x, b.y, b.width, b.height, + borderWidth, TK_RELIEF_FLAT); + DrawBorder(tkwin, d, border, borderColor, b, borderWidth, relief); +} + +static Ttk_ElementSpec SliderElementSpec = { + TK_STYLE_VERSION_2, + sizeof(SliderElement), + SliderElementOptions, + SliderElementSize, + SliderElementDraw +}; + +/*------------------------------------------------------------------------ + * +++ Tree indicator element. + */ + +#define TTK_STATE_OPEN TTK_STATE_USER1 /* XREF: treeview.c */ +#define TTK_STATE_LEAF TTK_STATE_USER2 + +typedef struct { + Tcl_Obj *colorObj; + Tcl_Obj *marginObj; + Tcl_Obj *diameterObj; +} TreeitemIndicator; + +static Ttk_ElementOptionSpec TreeitemIndicatorOptions[] = { + { "-foreground", TK_OPTION_COLOR, + Tk_Offset(TreeitemIndicator,colorObj), DEFAULT_FOREGROUND }, + { "-diameter", TK_OPTION_PIXELS, + Tk_Offset(TreeitemIndicator,diameterObj), "9" }, + { "-indicatormargins", TK_OPTION_STRING, + Tk_Offset(TreeitemIndicator,marginObj), "2 2 4 2" }, + { NULL, 0, 0, NULL } +}; + +static void TreeitemIndicatorSize( + void *clientData, void *elementRecord, Tk_Window tkwin, + int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +{ + TreeitemIndicator *indicator = elementRecord; + int diameter = 0; + Ttk_Padding margins; + + Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins); + Tk_GetPixelsFromObj(NULL, tkwin, indicator->diameterObj, &diameter); + *widthPtr = diameter + Ttk_PaddingWidth(margins); + *heightPtr = diameter + Ttk_PaddingHeight(margins); +} + +static void TreeitemIndicatorDraw( + void *clientData, void *elementRecord, Tk_Window tkwin, + Drawable d, Ttk_Box b, Ttk_State state) +{ + TreeitemIndicator *indicator = elementRecord; + XColor *color = Tk_GetColorFromObj(tkwin, indicator->colorObj); + GC gc = Tk_GCForColor(color, d); + Ttk_Padding padding = Ttk_UniformPadding(0); + int w = WIN32_XDRAWLINE_HACK; + int cx, cy; + + if (state & TTK_STATE_LEAF) { + /* don't draw anything ... */ + return; + } + + Ttk_GetPaddingFromObj(NULL,tkwin,indicator->marginObj,&padding); + b = Ttk_PadBox(b, padding); + + XDrawRectangle(Tk_Display(tkwin), d, gc, + b.x, b.y, b.width - 1, b.height - 1); + + cx = b.x + (b.width - 1) / 2; + cy = b.y + (b.height - 1) / 2; + XDrawLine(Tk_Display(tkwin), d, gc, b.x+2, cy, b.x+b.width-3+w, cy); + + if (!(state & TTK_STATE_OPEN)) { + /* turn '-' into a '+' */ + XDrawLine(Tk_Display(tkwin), d, gc, cx, b.y+2, cx, b.y+b.height-3+w); + } +} + +static Ttk_ElementSpec TreeitemIndicatorElementSpec = { + TK_STYLE_VERSION_2, + sizeof(TreeitemIndicator), + TreeitemIndicatorOptions, + TreeitemIndicatorSize, + TreeitemIndicatorDraw +}; + +/*------------------------------------------------------------------------ + * TtkAltTheme_Init -- + * Install alternate theme. + */ +MODULE_SCOPE int TtkAltTheme_Init(Tcl_Interp *interp) +{ + Ttk_Theme theme = Ttk_CreateTheme(interp, "alt", NULL); + + if (!theme) { + return TCL_ERROR; + } + + Ttk_RegisterElement(interp, theme, "border", &BorderElementSpec, NULL); + + Ttk_RegisterElement(interp, theme, "Checkbutton.indicator", + &IndicatorElementSpec, &checkbutton_spec); + Ttk_RegisterElement(interp, theme, "Radiobutton.indicator", + &IndicatorElementSpec, &radiobutton_spec); + Ttk_RegisterElement(interp, theme, "Menubutton.indicator", + &MenubuttonArrowElementSpec, NULL); + + Ttk_RegisterElement(interp, theme, "field", &FieldElementSpec, NULL); + + Ttk_RegisterElement(interp, theme, "trough", &TroughElementSpec, NULL); + Ttk_RegisterElement(interp, theme, "thumb", &ThumbElementSpec, NULL); + Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL); + + Ttk_RegisterElement(interp, theme, "uparrow", + &ArrowElementSpec, &ArrowElements[0]); + Ttk_RegisterElement(interp, theme, "downarrow", + &ArrowElementSpec, &ArrowElements[1]); + Ttk_RegisterElement(interp, theme, "leftarrow", + &ArrowElementSpec, &ArrowElements[2]); + Ttk_RegisterElement(interp, theme, "rightarrow", + &ArrowElementSpec, &ArrowElements[3]); + Ttk_RegisterElement(interp, theme, "arrow", + &ArrowElementSpec, &ArrowElements[0]); + + Ttk_RegisterElement(interp, theme, "arrow", + &ArrowElementSpec, &ArrowElements[0]); + + Ttk_RegisterElement(interp, theme, "Treeitem.indicator", + &TreeitemIndicatorElementSpec, 0); + + Tcl_PkgProvide(interp, "ttk::theme::alt", TTK_VERSION); + + return TCL_OK; +} + +/*EOF*/ |