diff options
Diffstat (limited to 'generic/ttk/ttkElements.c')
-rw-r--r-- | generic/ttk/ttkElements.c | 1007 |
1 files changed, 644 insertions, 363 deletions
diff --git a/generic/ttk/ttkElements.c b/generic/ttk/ttkElements.c index d52c428..a5bd95c 100644 --- a/generic/ttk/ttkElements.c +++ b/generic/ttk/ttkElements.c @@ -1,12 +1,12 @@ /* - * Copyright (c) 2003 Joe English + * Copyright © 2003 Joe English * * Default implementation for themed elements. * */ #include "tkInt.h" -#include "ttkTheme.h" +#include "ttkThemeInt.h" #include "ttkWidget.h" #if defined(_WIN32) @@ -25,7 +25,7 @@ * and may be used in other engines. */ -/* public */ Ttk_ElementOptionSpec TtkNullElementOptions[] = { { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; +/* public */ const Ttk_ElementOptionSpec TtkNullElementOptions[] = { { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; /* public */ void TtkNullElementSize( @@ -70,9 +70,9 @@ typedef struct { Tcl_Obj *backgroundObj; } BackgroundElement; -static Ttk_ElementOptionSpec BackgroundElementOptions[] = { +static const Ttk_ElementOptionSpec BackgroundElementOptions[] = { { "-background", TK_OPTION_BORDER, - Tk_Offset(BackgroundElement,backgroundObj), DEFAULT_BACKGROUND }, + offsetof(BackgroundElement,backgroundObj), DEFAULT_BACKGROUND }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; @@ -103,7 +103,7 @@ static void BackgroundElementDraw( d, Ttk_WinBox(tkwin), state); } -static Ttk_ElementSpec FillElementSpec = { +static const Ttk_ElementSpec FillElementSpec = { TK_STYLE_VERSION_2, sizeof(BackgroundElement), BackgroundElementOptions, @@ -111,7 +111,7 @@ static Ttk_ElementSpec FillElementSpec = { FillElementDraw }; -static Ttk_ElementSpec BackgroundElementSpec = { +static const Ttk_ElementSpec BackgroundElementSpec = { TK_STYLE_VERSION_2, sizeof(BackgroundElement), BackgroundElementOptions, @@ -129,13 +129,13 @@ typedef struct { Tcl_Obj *reliefObj; } BorderElement; -static Ttk_ElementOptionSpec BorderElementOptions[] = { +static const Ttk_ElementOptionSpec BorderElementOptions[] = { { "-background", TK_OPTION_BORDER, - Tk_Offset(BorderElement,borderObj), DEFAULT_BACKGROUND }, + offsetof(BorderElement,borderObj), DEFAULT_BACKGROUND }, { "-borderwidth", TK_OPTION_PIXELS, - Tk_Offset(BorderElement,borderWidthObj), DEFAULT_BORDERWIDTH }, + offsetof(BorderElement,borderWidthObj), DEFAULT_BORDERWIDTH }, { "-relief", TK_OPTION_RELIEF, - Tk_Offset(BorderElement,reliefObj), "flat" }, + offsetof(BorderElement,reliefObj), "flat" }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; @@ -176,7 +176,7 @@ static void BorderElementDraw( } } -static Ttk_ElementSpec BorderElementSpec = { +static const Ttk_ElementSpec BorderElementSpec = { TK_STYLE_VERSION_2, sizeof(BorderElement), BorderElementOptions, @@ -195,15 +195,15 @@ typedef struct { Tcl_Obj *focusColorObj; } FieldElement; -static Ttk_ElementOptionSpec FieldElementOptions[] = { +static const Ttk_ElementOptionSpec FieldElementOptions[] = { { "-fieldbackground", TK_OPTION_BORDER, - Tk_Offset(FieldElement,borderObj), "white" }, + offsetof(FieldElement,borderObj), "white" }, { "-borderwidth", TK_OPTION_PIXELS, - Tk_Offset(FieldElement,borderWidthObj), "2" }, + offsetof(FieldElement,borderWidthObj), "2" }, { "-focuswidth", TK_OPTION_PIXELS, - Tk_Offset(FieldElement,focusWidthObj), "2" }, + offsetof(FieldElement,focusWidthObj), "2" }, { "-focuscolor", TK_OPTION_COLOR, - Tk_Offset(FieldElement,focusColorObj), "#4a6984" }, + offsetof(FieldElement,focusColorObj), "#4a6984" }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; @@ -291,7 +291,7 @@ static void FieldElementDraw( } } -static Ttk_ElementSpec FieldElementSpec = { +static const Ttk_ElementSpec FieldElementSpec = { TK_STYLE_VERSION_2, sizeof(FieldElement), FieldElementOptions, @@ -316,13 +316,13 @@ typedef struct { Tcl_Obj *shiftreliefObj; } PaddingElement; -static Ttk_ElementOptionSpec PaddingElementOptions[] = { +static const Ttk_ElementOptionSpec PaddingElementOptions[] = { { "-padding", TK_OPTION_STRING, - Tk_Offset(PaddingElement,paddingObj), "0" }, + offsetof(PaddingElement,paddingObj), "0" }, { "-relief", TK_OPTION_RELIEF, - Tk_Offset(PaddingElement,reliefObj), "flat" }, + offsetof(PaddingElement,reliefObj), "flat" }, { "-shiftrelief", TK_OPTION_PIXELS, - Tk_Offset(PaddingElement,shiftreliefObj), "0" }, + offsetof(PaddingElement,shiftreliefObj), "0" }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; @@ -345,7 +345,7 @@ static void PaddingElementSize( *paddingPtr = Ttk_RelievePadding(pad, relief, shiftRelief); } -static Ttk_ElementSpec PaddingElementSpec = { +static const Ttk_ElementSpec PaddingElementSpec = { TK_STYLE_VERSION_2, sizeof(PaddingElement), PaddingElementOptions, @@ -400,13 +400,13 @@ static void DrawFocusRing( Tk_FreeGC(Tk_Display(tkwin), gc); } -static Ttk_ElementOptionSpec FocusElementOptions[] = { +static const Ttk_ElementOptionSpec FocusElementOptions[] = { { "-focuscolor", TK_OPTION_COLOR, - Tk_Offset(FocusElement,focusColorObj), "black" }, + offsetof(FocusElement,focusColorObj), "black" }, { "-focusthickness", TK_OPTION_PIXELS, - Tk_Offset(FocusElement,focusThicknessObj), "1" }, + offsetof(FocusElement,focusThicknessObj), "1" }, { "-focussolid", TK_OPTION_BOOLEAN, - Tk_Offset(FocusElement,focusSolidObj), "0" }, + offsetof(FocusElement,focusSolidObj), "0" }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; @@ -445,7 +445,7 @@ static void FocusElementDraw( } } -static Ttk_ElementSpec FocusElementSpec = { +static const Ttk_ElementSpec FocusElementSpec = { TK_STYLE_VERSION_2, sizeof(FocusElement), FocusElementOptions, @@ -465,11 +465,11 @@ typedef struct { Tcl_Obj *borderObj; } SeparatorElement; -static Ttk_ElementOptionSpec SeparatorElementOptions[] = { +static const Ttk_ElementOptionSpec SeparatorElementOptions[] = { { "-orient", TK_OPTION_ANY, - Tk_Offset(SeparatorElement, orientObj), "horizontal" }, + offsetof(SeparatorElement, orientObj), "horizontal" }, { "-background", TK_OPTION_BORDER, - Tk_Offset(SeparatorElement,borderObj), DEFAULT_BACKGROUND }, + offsetof(SeparatorElement,borderObj), DEFAULT_BACKGROUND }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; @@ -523,9 +523,9 @@ static void GeneralSeparatorElementDraw( Drawable d, Ttk_Box b, Ttk_State state) { SeparatorElement *separator = (SeparatorElement *)elementRecord; - int orient; + Ttk_Orient orient; - Ttk_GetOrientFromObj(NULL, separator->orientObj, &orient); + TtkGetOrientFromObj(NULL, separator->orientObj, &orient); switch (orient) { case TTK_ORIENT_HORIZONTAL: HorizontalSeparatorElementDraw( @@ -538,7 +538,7 @@ static void GeneralSeparatorElementDraw( } } -static Ttk_ElementSpec HorizontalSeparatorElementSpec = { +static const Ttk_ElementSpec HorizontalSeparatorElementSpec = { TK_STYLE_VERSION_2, sizeof(SeparatorElement), SeparatorElementOptions, @@ -546,7 +546,7 @@ static Ttk_ElementSpec HorizontalSeparatorElementSpec = { HorizontalSeparatorElementDraw }; -static Ttk_ElementSpec VerticalSeparatorElementSpec = { +static const Ttk_ElementSpec VerticalSeparatorElementSpec = { TK_STYLE_VERSION_2, sizeof(SeparatorElement), SeparatorElementOptions, @@ -554,7 +554,7 @@ static Ttk_ElementSpec VerticalSeparatorElementSpec = { HorizontalSeparatorElementDraw }; -static Ttk_ElementSpec SeparatorElementSpec = { +static const Ttk_ElementSpec SeparatorElementSpec = { TK_STYLE_VERSION_2, sizeof(SeparatorElement), SeparatorElementOptions, @@ -568,11 +568,14 @@ static Ttk_ElementSpec SeparatorElementSpec = { typedef struct { Tcl_Obj *backgroundObj; + Tcl_Obj *gripSizeObj; } SizegripElement; -static Ttk_ElementOptionSpec SizegripOptions[] = { +static const Ttk_ElementOptionSpec SizegripOptions[] = { { "-background", TK_OPTION_BORDER, - Tk_Offset(SizegripElement,backgroundObj), DEFAULT_BACKGROUND }, + offsetof(SizegripElement,backgroundObj), DEFAULT_BACKGROUND }, + { "-gripsize", TK_OPTION_PIXELS, + offsetof(SizegripElement,gripSizeObj), "11.25p" }, {0, TK_OPTION_BOOLEAN, 0, 0} }; @@ -584,8 +587,11 @@ static void SizegripSize( int *heightPtr, TCL_UNUSED(Ttk_Padding *)) { - int gripCount = 3, gripSpace = 2, gripThickness = 3; - *widthPtr = *heightPtr = gripCount * (gripSpace + gripThickness); + SizegripElement *grip = (SizegripElement *)elementRecord; + int gripSize = 0; + + Tk_GetPixelsFromObj(NULL, tkwin, grip->gripSizeObj, &gripSize); + *widthPtr = *heightPtr = gripSize; } static void SizegripDraw( @@ -597,21 +603,26 @@ static void SizegripDraw( TCL_UNUSED(Ttk_State)) { SizegripElement *grip = (SizegripElement *)elementRecord; - int gripCount = 3, gripSpace = 2; + int gripSize = 0; + int gripCount = 3, gripSpace, gripThickness; Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, grip->backgroundObj); GC lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC); GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC); int x1 = b.x + b.width-1, y1 = b.y + b.height-1, x2 = x1, y2 = y1; + Tk_GetPixelsFromObj(NULL, tkwin, grip->gripSizeObj, &gripSize); + gripThickness = gripSize * 3 / (gripCount * 5); + gripSpace = gripSize / 3 - gripThickness; while (gripCount--) { x1 -= gripSpace; y2 -= gripSpace; - XDrawLine(Tk_Display(tkwin), d, darkGC, x1, y1, x2, y2); --x1; --y2; - XDrawLine(Tk_Display(tkwin), d, darkGC, x1, y1, x2, y2); --x1; --y2; - XDrawLine(Tk_Display(tkwin), d, lightGC, x1, y1, x2, y2); --x1; --y2; + for (int i = 1; i < gripThickness; i++) { + XDrawLine(Tk_Display(tkwin), d, darkGC, x1,y1, x2,y2); --x1; --y2; + } + XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y1, x2,y2); --x1; --y2; } } -static Ttk_ElementSpec SizegripElementSpec = { +static const Ttk_ElementSpec SizegripElementSpec = { TK_STYLE_VERSION_2, sizeof(SizegripElement), SizegripOptions, @@ -623,230 +634,278 @@ static Ttk_ElementSpec SizegripElementSpec = { * +++ Indicator element. * * Draws the on/off indicator for checkbuttons and radiobuttons. - * - * Draws a 3-D square (or diamond), raised if off, sunken if on. - * - * This is actually a regression from Tk 8.5 back to the ugly old Motif - * style; use "altTheme" for the newer, nicer version. */ +/* + * Indicator image descriptor: + */ +typedef struct { + int width; /* unscaled width */ + int height; /* unscaled height */ + const char *const offDataPtr; + const char *const onDataPtr; + const char *const triDataPtr; +} IndicatorSpec; + +static const char checkbtnOffData[] = "\ + <svg width='16' height='16' version='1.1' xmlns='http://www.w3.org/2000/svg'>\n\ + <rect x='.5' y='.5' width='15' height='15' rx='1.5' fill='#ffffff' stroke='#888888'/>\n\ + </svg>"; + +static const char checkbtnOnData[] = "\ + <svg width='16' height='16' version='1.1' xmlns='http://www.w3.org/2000/svg'>\n\ + <rect x='0' y='0' width='16' height='16' fill='#4a6984' rx='2'/>\n\ + <path d='m4.5 8 3 3 4-6' fill='none' stroke='#ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2'/>\n\ + </svg>"; + +static const char checkbtnTriData[] = "\ + <svg width='16' height='16' version='1.1' xmlns='http://www.w3.org/2000/svg'>\n\ + <rect x='0' y='0' width='16' height='16' fill='#4a6984' rx='2'/>\n\ + <path d='m4 8h8' fill='none' stroke='#ffffff' stroke-width='2'/>\n\ + </svg>"; + +static const IndicatorSpec checkbutton_spec = { + 16, 16, + checkbtnOffData, + checkbtnOnData, + checkbtnTriData +}; + +static const char radiobtnOffData[] = "\ + <svg width='16' height='16' version='1.1' xmlns='http://www.w3.org/2000/svg'>\n\ + <circle cx='8' cy='8' r='7.5' fill='#ffffff' stroke='#888888'/>\n\ + </svg>"; + +static const char radiobtnOnData[] = "\ + <svg width='16' height='16' version='1.1' xmlns='http://www.w3.org/2000/svg'>\n\ + <circle cx='8' cy='8' r='8' fill='#4a6984'/>\n\ + <circle cx='8' cy='8' r='3' fill='#ffffff'/>\n\ + </svg>"; + +static const char radiobtnTriData[] = "\ + <svg width='16' height='16' version='1.1' xmlns='http://www.w3.org/2000/svg'>\n\ + <circle cx='8' cy='8' r='8' fill='#4a6984'/>\n\ + <path d='m4 8h8' fill='none' stroke='#ffffff' stroke-width='2'/>\n\ + </svg>"; + +static const IndicatorSpec radiobutton_spec = { + 16, 16, + radiobtnOffData, + radiobtnOnData, + radiobtnTriData +}; + typedef struct { Tcl_Obj *backgroundObj; - Tcl_Obj *reliefObj; - Tcl_Obj *colorObj; - Tcl_Obj *diameterObj; + Tcl_Obj *foregroundObj; + Tcl_Obj *borderColorObj; Tcl_Obj *marginObj; - Tcl_Obj *borderWidthObj; } IndicatorElement; -static Ttk_ElementOptionSpec IndicatorElementOptions[] = { - { "-background", TK_OPTION_BORDER, - Tk_Offset(IndicatorElement,backgroundObj), DEFAULT_BACKGROUND }, - { "-indicatorcolor", TK_OPTION_BORDER, - Tk_Offset(IndicatorElement,colorObj), DEFAULT_BACKGROUND }, - { "-indicatorrelief", TK_OPTION_RELIEF, - Tk_Offset(IndicatorElement,reliefObj), "raised" }, - { "-indicatordiameter", TK_OPTION_PIXELS, - Tk_Offset(IndicatorElement,diameterObj), "12" }, +/* + * Note that the -indicatorbackground and -indicatorforeground options below + * have the same default value "#ffffff", but the -indicatorforeground option + * will only be used for the alternate and selected states, in which the + * -indicatorbackground option will have a different value (e.g., "#4a6984"). + */ +static const Ttk_ElementOptionSpec IndicatorElementOptions[] = { + { "-indicatorbackground", TK_OPTION_COLOR, + offsetof(IndicatorElement,backgroundObj), "#ffffff" }, + { "-indicatorforeground", TK_OPTION_COLOR, + offsetof(IndicatorElement,foregroundObj), "#ffffff" }, + { "-bordercolor", TK_OPTION_COLOR, + offsetof(IndicatorElement,borderColorObj), "#888888" }, { "-indicatormargin", TK_OPTION_STRING, - Tk_Offset(IndicatorElement,marginObj), "0 2 4 2" }, - { "-borderwidth", TK_OPTION_PIXELS, - Tk_Offset(IndicatorElement,borderWidthObj), DEFAULT_BORDERWIDTH }, + offsetof(IndicatorElement,marginObj), "0 2 4 2" }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; -/* - * Checkbutton indicators (default): 3-D square. - */ -static void SquareIndicatorElementSize( +static void IndicatorElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, - int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) + int *widthPtr, int *heightPtr, + TCL_UNUSED(Ttk_Padding *)) { - IndicatorElement *indicator = elementRecord; + const IndicatorSpec *spec = (const IndicatorSpec *)clientData; + IndicatorElement *indicator = (IndicatorElement *)elementRecord; Ttk_Padding margins; - int diameter = 0; + double scalingLevel = TkScalingLevel(tkwin); + Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins); - Tk_GetPixelsFromObj(NULL, tkwin, indicator->diameterObj, &diameter); - *widthPtr = diameter + Ttk_PaddingWidth(margins); - *heightPtr = diameter + Ttk_PaddingHeight(margins); + *widthPtr = spec->width * scalingLevel + Ttk_PaddingWidth(margins); + *heightPtr = spec->height * scalingLevel + Ttk_PaddingHeight(margins); } -static void SquareIndicatorElementDraw( - void *clientData, void *elementRecord, Tk_Window tkwin, - Drawable d, Ttk_Box b, unsigned int state) +static void ColorToStr( + const XColor *colorPtr, char *colorStr) /* in the format "RRGGBB" */ { - IndicatorElement *indicator = elementRecord; - Tk_3DBorder border = 0, interior = 0; - int relief = TK_RELIEF_RAISED; - Ttk_Padding padding; - int borderWidth = 2; - int diameter; - - interior = Tk_Get3DBorderFromObj(tkwin, indicator->colorObj); - border = Tk_Get3DBorderFromObj(tkwin, indicator->backgroundObj); - Tk_GetPixelsFromObj(NULL, tkwin, indicator->borderWidthObj, &borderWidth); - Tk_GetReliefFromObj(NULL, indicator->reliefObj, &relief); - Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding); - - b = Ttk_PadBox(b, padding); - - diameter = b.width < b.height ? b.width : b.height; - Tk_Fill3DRectangle(tkwin, d, interior, b.x, b.y, - diameter, diameter, borderWidth, TK_RELIEF_FLAT); - Tk_Draw3DRectangle(tkwin, d, border, b.x, b.y, - diameter, diameter, borderWidth, relief); + snprintf(colorStr, 7, "%02x%02x%02x", + colorPtr->red >> 8, colorPtr->green >> 8, colorPtr->blue >> 8); } -/* - * Radiobutton indicators: 3-D diamond. - */ -static void DiamondIndicatorElementSize( - void *clientData, void *elementRecord, Tk_Window tkwin, - int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) +static void ImageChanged( /* to be passed to Tk_GetImage() */ + TCL_UNUSED(void *), + TCL_UNUSED(int), + TCL_UNUSED(int), + TCL_UNUSED(int), + TCL_UNUSED(int), + TCL_UNUSED(int), + TCL_UNUSED(int)) { - IndicatorElement *indicator = (IndicatorElement *)elementRecord; - Ttk_Padding margins; - int diameter = 0; - Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins); - Tk_GetPixelsFromObj(NULL, tkwin, indicator->diameterObj, &diameter); - *widthPtr = diameter + 3 + Ttk_PaddingWidth(margins); - *heightPtr = diameter + 3 + Ttk_PaddingHeight(margins); } -static void DiamondIndicatorElementDraw( +static void IndicatorElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { IndicatorElement *indicator = (IndicatorElement *)elementRecord; - Tk_3DBorder border = 0, interior = 0; - int borderWidth = 2; - int relief = TK_RELIEF_RAISED; - int diameter, radius; - XPoint points[4]; Ttk_Padding padding; + const IndicatorSpec *spec = (const IndicatorSpec *)clientData; + double scalingLevel = TkScalingLevel(tkwin); + int width = spec->width * scalingLevel; + int height = spec->height * scalingLevel; + + char bgColorStr[7], fgColorStr[7], borderColorStr[7]; + unsigned int selected = (state & TTK_STATE_SELECTED); + unsigned int tristate = (state & TTK_STATE_ALTERNATE); + Tcl_Interp *interp = Tk_Interp(tkwin); + char imgName[60]; + Tk_Image img; + + const char *svgDataPtr; + size_t svgDataLen; + char *svgDataCopy; + char *bgColorPtr, *fgColorPtr, *borderColorPtr; + const char *cmdFmt; + size_t scriptSize; + char *script; + int code; - interior = Tk_Get3DBorderFromObj(tkwin, indicator->colorObj); - border = Tk_Get3DBorderFromObj(tkwin, indicator->backgroundObj); - Tk_GetPixelsFromObj(NULL, tkwin, indicator->borderWidthObj, &borderWidth); - Tk_GetReliefFromObj(NULL, indicator->reliefObj, &relief); Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding); - b = Ttk_PadBox(b, padding); - diameter = b.width < b.height ? b.width : b.height; - radius = diameter / 2; + /* + * Sanity check + */ + if ( b.x < 0 + || b.y < 0 + || Tk_Width(tkwin) < b.x + width + || Tk_Height(tkwin) < b.y + height) + { + /* Oops! Not enough room to display the image. + * Don't draw anything. + */ + return; + } - points[0].x = b.x; - points[0].y = b.y + radius; - points[1].x = b.x + radius; - points[1].y = b.y + 2*radius; - points[2].x = b.x + 2*radius; - points[2].y = b.y + radius; - points[3].x = b.x + radius; - points[3].y = b.y; + /* + * Construct the color strings bgColorStr, fgColorStr, and borderColorStr + */ + ColorToStr(Tk_GetColorFromObj(tkwin, indicator->backgroundObj), + bgColorStr); + ColorToStr(Tk_GetColorFromObj(tkwin, indicator->foregroundObj), + fgColorStr); + ColorToStr(Tk_GetColorFromObj(tkwin, indicator->borderColorObj), + borderColorStr); - Tk_Fill3DPolygon(tkwin, d, interior, points, 4, borderWidth, TK_RELIEF_FLAT); - Tk_Draw3DPolygon(tkwin, d, border, points, 4, borderWidth, relief); -} + /* + * Check whether there is an SVG image of this size for the + * indicator's type (0 = checkbtn, 1 = radiobtn), "state" + * (0 = off, 1 = on, 2 = tristate), and these color strings + */ + snprintf(imgName, sizeof(imgName), + "::tk::icons::indicator_default%d_%d,%d_%s_%s_%s", + width, + spec->offDataPtr == radiobtnOffData, + tristate ? 2 : (selected ? 1 : 0), + bgColorStr, + selected || tristate ? fgColorStr : "XXXXXX", + selected || tristate ? "XXXXXX" : borderColorStr); + img = Tk_GetImage(interp, tkwin, imgName, ImageChanged, NULL); + if (img == NULL) { + /* + * Determine the SVG data to use for the photo image + */ + svgDataPtr = (tristate ? spec->triDataPtr : + (selected ? spec->onDataPtr : spec->offDataPtr)); -static Ttk_ElementSpec CheckbuttonIndicatorElementSpec = { - TK_STYLE_VERSION_2, - sizeof(IndicatorElement), - IndicatorElementOptions, - SquareIndicatorElementSize, - SquareIndicatorElementDraw -}; + /* + * Copy the string pointed to by svgDataPtr to + * a newly allocated memory area svgDataCopy + */ + svgDataLen = strlen(svgDataPtr); + svgDataCopy = (char *)attemptckalloc(svgDataLen + 1); + if (svgDataCopy == NULL) { + return; + } + memcpy(svgDataCopy, svgDataPtr, svgDataLen); + svgDataCopy[svgDataLen] = '\0'; -static Ttk_ElementSpec RadiobuttonIndicatorElementSpec = { - TK_STYLE_VERSION_2, - sizeof(IndicatorElement), - IndicatorElementOptions, - DiamondIndicatorElementSize, - DiamondIndicatorElementDraw -}; + /* + * Update the colors within svgDataCopy + */ + if (selected || tristate) { + bgColorPtr = strstr(svgDataCopy, "4a6984"); + fgColorPtr = strstr(svgDataCopy, "ffffff"); -/* - *---------------------------------------------------------------------- - * +++ Menubutton indicators. - * - * These aren't functional like radio/check indicators, - * they're just affordability indicators. - * - * Standard Tk sets the indicator size to 4.0 mm by 1.7 mm. - * I have no idea where these numbers came from. - */ + assert(bgColorPtr); + assert(fgColorPtr); -typedef struct { - Tcl_Obj *backgroundObj; - Tcl_Obj *widthObj; - Tcl_Obj *heightObj; - Tcl_Obj *borderWidthObj; - Tcl_Obj *reliefObj; - Tcl_Obj *marginObj; -} MenuIndicatorElement; + memcpy(bgColorPtr, bgColorStr, 6); + memcpy(fgColorPtr, fgColorStr, 6); + } else { + bgColorPtr = strstr(svgDataCopy, "ffffff"); + borderColorPtr = strstr(svgDataCopy, "888888"); -static Ttk_ElementOptionSpec MenuIndicatorElementOptions[] = { - { "-background", TK_OPTION_BORDER, - Tk_Offset(MenuIndicatorElement,backgroundObj), DEFAULT_BACKGROUND }, - { "-indicatorwidth", TK_OPTION_PIXELS, - Tk_Offset(MenuIndicatorElement,widthObj), "4.0m" }, - { "-indicatorheight", TK_OPTION_PIXELS, - Tk_Offset(MenuIndicatorElement,heightObj), "1.7m" }, - { "-indicatorborderwidth", TK_OPTION_PIXELS, - Tk_Offset(MenuIndicatorElement,borderWidthObj), DEFAULT_BORDERWIDTH }, - { "-indicatorrelief", TK_OPTION_RELIEF, - Tk_Offset(MenuIndicatorElement,reliefObj), "raised" }, - { "-indicatormargin", TK_OPTION_STRING, - Tk_Offset(MenuIndicatorElement,marginObj), "5 0" }, - { NULL, 0, 0, NULL } -}; + assert(bgColorPtr); + assert(borderColorPtr); -static void MenuIndicatorElementSize( - void *clientData, void *elementRecord, Tk_Window tkwin, - int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) -{ - MenuIndicatorElement *mi = elementRecord; - Ttk_Padding margins; - Tk_GetPixelsFromObj(NULL, tkwin, mi->widthObj, widthPtr); - Tk_GetPixelsFromObj(NULL, tkwin, mi->heightObj, heightPtr); - Ttk_GetPaddingFromObj(NULL, tkwin, mi->marginObj, &margins); - *widthPtr += Ttk_PaddingWidth(margins); - *heightPtr += Ttk_PaddingHeight(margins); -} + memcpy(bgColorPtr, bgColorStr, 6); + memcpy(borderColorPtr, borderColorStr, 6); + } -static void MenuIndicatorElementDraw( - void *clientData, void *elementRecord, Tk_Window tkwin, - Drawable d, Ttk_Box b, unsigned int state) -{ - MenuIndicatorElement *mi = elementRecord; - Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, mi->backgroundObj); - Ttk_Padding margins; - int borderWidth = 2; + /* + * Create an SVG photo image from svgDataCopy + */ + cmdFmt = "image create photo %s -format $::tk::svgFmt -data {%s}"; + scriptSize = strlen(cmdFmt) + strlen(imgName) + svgDataLen; + script = (char *)attemptckalloc(scriptSize); + if (script == NULL) { + ckfree(svgDataCopy); + return; + } + snprintf(script, scriptSize, cmdFmt, imgName, svgDataCopy); + ckfree(svgDataCopy); + code = Tcl_EvalEx(interp, script, -1, TCL_EVAL_GLOBAL); + ckfree(script); + if (code != TCL_OK) { + Tcl_BackgroundException(interp, code); + return; + } + img = Tk_GetImage(interp, tkwin, imgName, ImageChanged, NULL); + } - Ttk_GetPaddingFromObj(NULL, tkwin, mi->marginObj, &margins); - b = Ttk_PadBox(b, margins); - Tk_GetPixelsFromObj(NULL, tkwin, mi->borderWidthObj, &borderWidth); - Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, - borderWidth, TK_RELIEF_RAISED); + /* + * Display the image + */ + Tk_RedrawImage(img, 0, 0, width, height, d, b.x, b.y); + Tk_FreeImage(img); } -static Ttk_ElementSpec MenuIndicatorElementSpec = { +static const Ttk_ElementSpec IndicatorElementSpec = { TK_STYLE_VERSION_2, - sizeof(MenuIndicatorElement), - MenuIndicatorElementOptions, - MenuIndicatorElementSize, - MenuIndicatorElementDraw + sizeof(IndicatorElement), + IndicatorElementOptions, + IndicatorElementSize, + IndicatorElementDraw }; /*---------------------------------------------------------------------- - * +++ Arrow elements. + * +++ 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 *colorObj; @@ -855,21 +914,21 @@ typedef struct { Tcl_Obj *reliefObj; } ArrowElement; -static Ttk_ElementOptionSpec ArrowElementOptions[] = { +static const Ttk_ElementOptionSpec ArrowElementOptions[] = { { "-arrowsize", TK_OPTION_PIXELS, - Tk_Offset(ArrowElement,sizeObj), "14" }, + offsetof(ArrowElement,sizeObj), "14" }, { "-arrowcolor", TK_OPTION_COLOR, - Tk_Offset(ArrowElement,colorObj), "black"}, + offsetof(ArrowElement,colorObj), "black"}, { "-background", TK_OPTION_BORDER, - Tk_Offset(ArrowElement,borderObj), DEFAULT_BACKGROUND }, + offsetof(ArrowElement,borderObj), DEFAULT_BACKGROUND }, { "-borderwidth", TK_OPTION_PIXELS, - Tk_Offset(ArrowElement,borderWidthObj), "1" }, + offsetof(ArrowElement,borderWidthObj), "1" }, { "-relief", TK_OPTION_RELIEF, - Tk_Offset(ArrowElement,reliefObj), "raised"}, + offsetof(ArrowElement,reliefObj), "raised"}, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; -static Ttk_Padding ArrowPadding = { 3, 3, 3, 3 }; +static const Ttk_Padding ArrowPadding = { 3, 3, 3, 3 }; static void ArrowElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, @@ -877,14 +936,21 @@ static void ArrowElementSize( TCL_UNUSED(Ttk_Padding *)) { ArrowElement *arrow = (ArrowElement *)elementRecord; - int direction = *(int *)clientData; + ArrowDirection direction = (ArrowDirection)PTR2INT(clientData); + double scalingLevel = TkScalingLevel(tkwin); + Ttk_Padding padding; int size = 14; + padding.left = round(ArrowPadding.left * scalingLevel); + padding.top = round(ArrowPadding.top * scalingLevel); + padding.right = round(ArrowPadding.right * scalingLevel); + padding.bottom = round(ArrowPadding.bottom * scalingLevel); + Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &size); - size -= Ttk_PaddingWidth(ArrowPadding); + size -= Ttk_PaddingWidth(padding); TtkArrowSize(size/2, direction, widthPtr, heightPtr); - *widthPtr += Ttk_PaddingWidth(ArrowPadding); - *heightPtr += Ttk_PaddingWidth(ArrowPadding); + *widthPtr += Ttk_PaddingWidth(padding); + *heightPtr += Ttk_PaddingHeight(padding); if (*widthPtr < *heightPtr) { *widthPtr = *heightPtr; } else { @@ -898,9 +964,11 @@ static void ArrowElementDraw( TCL_UNUSED(Ttk_State)) { ArrowElement *arrow = (ArrowElement *)elementRecord; - int direction = *(int *)clientData; + ArrowDirection direction = (ArrowDirection)PTR2INT(clientData); Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, arrow->borderObj); int borderWidth = 1, relief = TK_RELIEF_RAISED; + Ttk_Padding padding; + double scalingLevel = TkScalingLevel(tkwin); int cx = 0, cy = 0; XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj); GC gc = Tk_GCForColor(arrowColor, d); @@ -911,7 +979,12 @@ static void ArrowElementDraw( Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, borderWidth, relief); - b = Ttk_PadBox(b, ArrowPadding); + padding.left = round(ArrowPadding.left * scalingLevel); + padding.top = round(ArrowPadding.top * scalingLevel); + padding.right = round(ArrowPadding.right * scalingLevel); + padding.bottom = round(ArrowPadding.bottom * scalingLevel); + + b = Ttk_PadBox(b, padding); switch (direction) { case ARROW_UP: @@ -935,7 +1008,7 @@ static void ArrowElementDraw( TtkFillArrow(Tk_Display(tkwin), d, gc, b, direction); } -static Ttk_ElementSpec ArrowElementSpec = { +static const Ttk_ElementSpec ArrowElementSpec = { TK_STYLE_VERSION_2, sizeof(ArrowElement), ArrowElementOptions, @@ -955,14 +1028,21 @@ static void BoxArrowElementSize( TCL_UNUSED(Ttk_Padding *)) { ArrowElement *arrow = (ArrowElement *)elementRecord; - int direction = *(int *)clientData; + ArrowDirection direction = (ArrowDirection)PTR2INT(clientData); + double scalingLevel = TkScalingLevel(tkwin); + Ttk_Padding padding; int size = 14; + padding.left = round(ArrowPadding.left * scalingLevel); + padding.top = round(ArrowPadding.top * scalingLevel); + padding.right = round(ArrowPadding.right * scalingLevel); + padding.bottom = round(ArrowPadding.bottom * scalingLevel); + Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &size); - size -= Ttk_PaddingWidth(ArrowPadding); + size -= Ttk_PaddingWidth(padding); TtkArrowSize(size/2, direction, widthPtr, heightPtr); - *widthPtr += Ttk_PaddingWidth(ArrowPadding); - *heightPtr += Ttk_PaddingWidth(ArrowPadding); + *widthPtr += Ttk_PaddingWidth(padding); + *heightPtr += Ttk_PaddingHeight(padding); } static void BoxArrowElementDraw( @@ -971,12 +1051,14 @@ static void BoxArrowElementDraw( TCL_UNUSED(Ttk_State)) { ArrowElement *arrow = (ArrowElement *)elementRecord; - int direction = *(int *)clientData; + ArrowDirection direction = (ArrowDirection)PTR2INT(clientData); Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, arrow->borderObj); int borderWidth = 1, relief = TK_RELIEF_RAISED; Display *disp = Tk_Display(tkwin); GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC); int w = WIN32_XDRAWLINE_HACK; + Ttk_Padding padding; + double scalingLevel = TkScalingLevel(tkwin); int cx = 0, cy = 0; XColor *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj); GC arrowGC = Tk_GCForColor(arrowColor, d); @@ -986,7 +1068,12 @@ static void BoxArrowElementDraw( XDrawLine(disp, d, darkGC, b.x, b.y+1, b.x, b.y+b.height-1+w); - b = Ttk_PadBox(b, ArrowPadding); + padding.left = round(ArrowPadding.left * scalingLevel); + padding.top = round(ArrowPadding.top * scalingLevel); + padding.right = round(ArrowPadding.right * scalingLevel); + padding.bottom = round(ArrowPadding.bottom * scalingLevel); + + b = Ttk_PadBox(b, padding); TtkArrowSize(b.width/2, direction, &cx, &cy); if ((b.height - cy) % 2 == 1) { @@ -998,7 +1085,7 @@ static void BoxArrowElementDraw( TtkFillArrow(disp, d, arrowGC, b, direction); } -static Ttk_ElementSpec BoxArrowElementSpec = { +static const Ttk_ElementSpec BoxArrowElementSpec = { TK_STYLE_VERSION_2, sizeof(ArrowElement), ArrowElementOptions, @@ -1006,27 +1093,111 @@ static Ttk_ElementSpec BoxArrowElementSpec = { BoxArrowElementDraw }; +/* + *---------------------------------------------------------------------- + * +++ Menubutton indicators. + * + * These aren't functional like radio/check indicators, + * they're just affordability indicators. + */ + +#define MENUBUTTON_ARROW_SIZE 5 + +typedef struct { + Tcl_Obj *sizeObj; + Tcl_Obj *colorObj; + Tcl_Obj *paddingObj; +} MenuIndicatorElement; + +static const Ttk_ElementOptionSpec MenuIndicatorElementOptions[] = { + { "-arrowsize", TK_OPTION_PIXELS, + offsetof(MenuIndicatorElement,sizeObj), STRINGIFY(MENUBUTTON_ARROW_SIZE)}, + { "-arrowcolor", TK_OPTION_COLOR, + offsetof(MenuIndicatorElement,colorObj), "black" }, + { "-arrowpadding", TK_OPTION_STRING, + offsetof(MenuIndicatorElement,paddingObj), "3" }, + { NULL, TK_OPTION_BOOLEAN, 0, NULL } +}; + +static void MenuIndicatorElementSize( + TCL_UNUSED(void *), /* clientData */ + void *elementRecord, + Tk_Window tkwin, + int *widthPtr, + int *heightPtr, + TCL_UNUSED(Ttk_Padding *)) +{ + MenuIndicatorElement *indicator = (MenuIndicatorElement *)elementRecord; + Ttk_Padding margins; + int size = MENUBUTTON_ARROW_SIZE; + + Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size); + Ttk_GetPaddingFromObj(NULL, tkwin, indicator->paddingObj, &margins); + TtkArrowSize(size, ARROW_DOWN, widthPtr, heightPtr); + *widthPtr += Ttk_PaddingWidth(margins); + *heightPtr += Ttk_PaddingHeight(margins); +} + +static void MenuIndicatorElementDraw( + TCL_UNUSED(void *), /* clientData */ + void *elementRecord, + Tk_Window tkwin, + Drawable d, + Ttk_Box b, + TCL_UNUSED(Ttk_State)) +{ + MenuIndicatorElement *indicator = (MenuIndicatorElement *)elementRecord; + XColor *arrowColor = Tk_GetColorFromObj(tkwin, indicator->colorObj); + GC gc = Tk_GCForColor(arrowColor, d); + int size = MENUBUTTON_ARROW_SIZE; + int width, height; + + Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size); + + TtkArrowSize(size, ARROW_DOWN, &width, &height); + b = Ttk_StickBox(b, width, height, 0); + TtkFillArrow(Tk_Display(tkwin), d, gc, b, ARROW_DOWN); +} + +static const Ttk_ElementSpec MenuIndicatorElementSpec = { + TK_STYLE_VERSION_2, + sizeof(MenuIndicatorElement), + MenuIndicatorElementOptions, + MenuIndicatorElementSize, + MenuIndicatorElementDraw +}; /* *---------------------------------------------------------------------- * +++ Trough element. * * Used in scrollbars and scales in place of "border". + * + * 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. 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 *colorObj; + Tcl_Obj *grooveWidthObj; + Tcl_Obj *orientObj; } TroughElement; -static Ttk_ElementOptionSpec TroughElementOptions[] = { - { "-borderwidth", TK_OPTION_PIXELS, - Tk_Offset(TroughElement,borderWidthObj), DEFAULT_BORDERWIDTH }, +static const Ttk_ElementOptionSpec TroughElementOptions[] = { + { "-troughborderwidth", TK_OPTION_PIXELS, + offsetof(TroughElement,borderWidthObj), "1" }, + { "-troughrelief",TK_OPTION_RELIEF, + offsetof(TroughElement,reliefObj), "sunken" }, { "-troughcolor", TK_OPTION_BORDER, - Tk_Offset(TroughElement,colorObj), DEFAULT_BACKGROUND }, - { "-troughrelief", TK_OPTION_RELIEF, - Tk_Offset(TroughElement,reliefObj), "sunken" }, + offsetof(TroughElement,colorObj), DEFAULT_BACKGROUND }, + { "-groovewidth", TK_OPTION_PIXELS, + offsetof(TroughElement,grooveWidthObj), "-1" }, + { "-orient", TK_OPTION_ANY, + offsetof(TroughElement, orientObj), "horizontal" }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; @@ -1038,11 +1209,15 @@ static void TroughElementSize( TCL_UNUSED(int *), /* heightPtr */ Ttk_Padding *paddingPtr) { - TroughElement *troughPtr = elementRecord; - int borderWidth = 2; + TroughElement *troughPtr = (TroughElement *)elementRecord; + int borderWidth = 1, grooveWidth = -1; Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth); - *paddingPtr = Ttk_UniformPadding((short)borderWidth); + Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->grooveWidthObj, &grooveWidth); + + if (grooveWidth <= 0) { + *paddingPtr = Ttk_UniformPadding((short)borderWidth); + } } static void TroughElementDraw( @@ -1052,18 +1227,41 @@ static void TroughElementDraw( TCL_UNUSED(Ttk_State)) { TroughElement *troughPtr = (TroughElement *)elementRecord; - Tk_3DBorder border = NULL; - int borderWidth = 2, relief = TK_RELIEF_SUNKEN; + Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, troughPtr->colorObj); + int borderWidth = 1, grooveWidth = -1, relief = TK_RELIEF_SUNKEN; + Ttk_Orient orient; + TkMainInfo *mainInfoPtr = ((TkWindow *) tkwin)->mainPtr; - border = Tk_Get3DBorderFromObj(tkwin, troughPtr->colorObj); - Tk_GetReliefFromObj(NULL, troughPtr->reliefObj, &relief); Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth); + Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->grooveWidthObj, &grooveWidth); + Tk_GetReliefFromObj(NULL, troughPtr->reliefObj, &relief); + TtkGetOrientFromObj(NULL, troughPtr->orientObj, &orient); + + if (grooveWidth > 0 && grooveWidth < b.height && grooveWidth < b.width) { + if (orient == TTK_ORIENT_HORIZONTAL) { + b.y += (b.height - grooveWidth) / 2; + b.height = grooveWidth; + } else { + b.x += (b.width - grooveWidth) / 2; + b.width = grooveWidth; + } + + /* + * Save the data of the trough's inner box for later + */ + if (mainInfoPtr != NULL) { + mainInfoPtr->troughInnerX = b.x + borderWidth; + mainInfoPtr->troughInnerY = b.y + borderWidth; + mainInfoPtr->troughInnerWidth = b.width - 2*borderWidth; + mainInfoPtr->troughInnerHeight = b.height - 2*borderWidth; + } + } Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, borderWidth, relief); } -static Ttk_ElementSpec TroughElementSpec = { +static const Ttk_ElementSpec TroughElementSpec = { TK_STYLE_VERSION_2, sizeof(TroughElement), TroughElementOptions, @@ -1086,17 +1284,17 @@ typedef struct { Tcl_Obj *borderWidthObj; } ThumbElement; -static Ttk_ElementOptionSpec ThumbElementOptions[] = { +static const Ttk_ElementOptionSpec ThumbElementOptions[] = { { "-orient", TK_OPTION_ANY, - Tk_Offset(ThumbElement, orientObj), "horizontal" }, + offsetof(ThumbElement, orientObj), "horizontal" }, { "-width", TK_OPTION_PIXELS, - Tk_Offset(ThumbElement,thicknessObj), DEFAULT_ARROW_SIZE }, + offsetof(ThumbElement,thicknessObj), DEFAULT_ARROW_SIZE }, { "-relief", TK_OPTION_RELIEF, - Tk_Offset(ThumbElement,reliefObj), "raised" }, + offsetof(ThumbElement,reliefObj), "raised" }, { "-background", TK_OPTION_BORDER, - Tk_Offset(ThumbElement,borderObj), DEFAULT_BACKGROUND }, + offsetof(ThumbElement,borderObj), DEFAULT_BACKGROUND }, { "-borderwidth", TK_OPTION_PIXELS, - Tk_Offset(ThumbElement,borderWidthObj), DEFAULT_BORDERWIDTH }, + offsetof(ThumbElement,borderWidthObj), DEFAULT_BORDERWIDTH }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; @@ -1107,11 +1305,11 @@ static void ThumbElementSize( TCL_UNUSED(Ttk_Padding *)) { ThumbElement *thumb = (ThumbElement *)elementRecord; - int orient; + Ttk_Orient orient; int thickness; Tk_GetPixelsFromObj(NULL, tkwin, thumb->thicknessObj, &thickness); - Ttk_GetOrientFromObj(NULL, thumb->orientObj, &orient); + TtkGetOrientFromObj(NULL, thumb->orientObj, &orient); if (orient == TTK_ORIENT_VERTICAL) { *widthPtr = thickness; @@ -1138,7 +1336,7 @@ static void ThumbElementDraw( borderWidth, relief); } -static Ttk_ElementSpec ThumbElementSpec = { +static const Ttk_ElementSpec ThumbElementSpec = { TK_STYLE_VERSION_2, sizeof(ThumbElement), ThumbElementOptions, @@ -1150,101 +1348,183 @@ static Ttk_ElementSpec ThumbElementSpec = { *---------------------------------------------------------------------- * +++ Slider element. * - * This is the moving part of the scale widget. Drawn as a raised box. + * This is the moving part of the scale widget. Drawn as a filled circle. */ +#define SLIDER_DIM 16 + +static const char sliderData[] = "\ + <svg width='16' height='16' version='1.1' xmlns='http://www.w3.org/2000/svg'>\n\ + <circle cx='8' cy='8' r='7.5' fill='#ffffff' stroke='#c3c3c3'/>\n\ + <circle cx='8' cy='8' r='4' fill='#4a6984'/>\n\ + </svg>"; + typedef struct { - Tcl_Obj *orientObj; /* orientation of overall slider */ - Tcl_Obj *lengthObj; /* slider length */ - Tcl_Obj *thicknessObj; /* slider thickness */ - Tcl_Obj *reliefObj; /* the relief for this object */ - Tcl_Obj *borderObj; /* the background color */ - Tcl_Obj *borderWidthObj; /* the size of the border */ + Tcl_Obj *innerColorObj; + Tcl_Obj *outerColorObj; + Tcl_Obj *borderColorObj; + Tcl_Obj *orientObj; /* Orientation of overall slider */ } SliderElement; -static Ttk_ElementOptionSpec SliderElementOptions[] = { - { "-sliderlength", TK_OPTION_PIXELS, - Tk_Offset(SliderElement,lengthObj), "30" }, - { "-sliderthickness", TK_OPTION_PIXELS, - Tk_Offset(SliderElement,thicknessObj), "15" }, - { "-sliderrelief", TK_OPTION_RELIEF, - Tk_Offset(SliderElement,reliefObj), "raised" }, - { "-sliderborderwidth", TK_OPTION_PIXELS, - Tk_Offset(SliderElement,borderWidthObj), DEFAULT_BORDERWIDTH }, - { "-background", TK_OPTION_BORDER, - Tk_Offset(SliderElement,borderObj), DEFAULT_BACKGROUND }, - { "-orient", TK_OPTION_ANY, - Tk_Offset(SliderElement,orientObj), "horizontal" }, - { NULL, 0, 0, NULL } +static const Ttk_ElementOptionSpec SliderElementOptions[] = { + { "-innercolor", TK_OPTION_COLOR, offsetof(SliderElement,innerColorObj), + "#4a6984" }, + { "-outercolor", TK_OPTION_COLOR, offsetof(SliderElement,outerColorObj), + "#ffffff" }, + { "-bordercolor", TK_OPTION_COLOR, offsetof(SliderElement,borderColorObj), + "#c3c3c3" }, + { "-orient", TK_OPTION_ANY, offsetof(SliderElement,orientObj), + "horizontal" }, + { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; static void SliderElementSize( - void *clientData, void *elementRecord, Tk_Window tkwin, - int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) + TCL_UNUSED(void *), /* clientData */ + TCL_UNUSED(void *), /* elementRecord */ + Tk_Window tkwin, + int *widthPtr, int *heightPtr, + TCL_UNUSED(Ttk_Padding *)) { - SliderElement *slider = elementRecord; - int orient, length, thickness; + double scalingLevel = TkScalingLevel(tkwin); + *widthPtr = *heightPtr = SLIDER_DIM * scalingLevel; +} - Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient); - Tk_GetPixelsFromObj(NULL, tkwin, slider->lengthObj, &length); - Tk_GetPixelsFromObj(NULL, tkwin, slider->thicknessObj, &thickness); +static void SliderElementDraw( + TCL_UNUSED(void *), /* clientData */ + void *elementRecord, Tk_Window tkwin, + Drawable d, Ttk_Box b, + TCL_UNUSED(Ttk_State)) +{ + double scalingLevel = TkScalingLevel(tkwin); + int dim = SLIDER_DIM * scalingLevel; + TkMainInfo *mainInfoPtr = ((TkWindow *) tkwin)->mainPtr; - switch (orient) { - case TTK_ORIENT_VERTICAL: - *widthPtr = thickness; - *heightPtr = length; - break; + SliderElement *slider = (SliderElement *)elementRecord; + Ttk_Orient orient; + Display *disp = Tk_Display(tkwin); + XColor *innerColor = Tk_GetColorFromObj(tkwin, slider->innerColorObj); + XColor *outerColor = Tk_GetColorFromObj(tkwin, slider->outerColorObj); + XColor *borderColor = Tk_GetColorFromObj(tkwin, slider->borderColorObj); + GC gc = Tk_GCForColor(innerColor, d); + + char innerColorStr[7], outerColorStr[7], borderColorStr[7]; + Tcl_Interp *interp = Tk_Interp(tkwin); + char imgName[50]; + Tk_Image img; + + const char *svgDataPtr = sliderData; + size_t svgDataLen; + char *svgDataCopy; + char *innerColorPtr, *outerColorPtr, *borderColorPtr; + const char *cmdFmt; + size_t scriptSize; + char *script; + int code; - case TTK_ORIENT_HORIZONTAL: - *widthPtr = length; - *heightPtr = thickness; - break; + /* + * Sanity check + */ + if ( b.x < 0 + || b.y < 0 + || Tk_Width(tkwin) < b.x + dim + || Tk_Height(tkwin) < b.y + dim) + { + /* Oops! Not enough room to display the image. + * Don't draw anything. + */ + return; } -} -static void SliderElementDraw( - void *clientData, void *elementRecord, Tk_Window tkwin, - Drawable d, Ttk_Box b, unsigned int state) -{ - SliderElement *slider = elementRecord; - Tk_3DBorder border = NULL; - int relief = TK_RELIEF_RAISED, borderWidth = 2, orient; + /* + * Fill the thin trough area preceding the + * slider's center with the inner color + */ + if (mainInfoPtr != NULL) { + TtkGetOrientFromObj(NULL, slider->orientObj, &orient); + switch (orient) { + case TTK_ORIENT_HORIZONTAL: + XFillRectangle(disp, d, gc, + mainInfoPtr->troughInnerX, mainInfoPtr->troughInnerY, + b.x + dim/2 - 1, mainInfoPtr->troughInnerHeight); + break; + case TTK_ORIENT_VERTICAL: + XFillRectangle(disp, d, gc, + mainInfoPtr->troughInnerX, mainInfoPtr->troughInnerY, + mainInfoPtr->troughInnerWidth, b.y + dim/2 - 1); + break; + } + } - border = Tk_Get3DBorderFromObj(tkwin, slider->borderObj); - Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient); - Tk_GetPixelsFromObj(NULL, tkwin, slider->borderWidthObj, &borderWidth); - Tk_GetReliefFromObj(NULL, slider->reliefObj, &relief); + /* + * Construct the color strings innerColorStr, + * outerColorStr, and borderColorStr + */ + ColorToStr(innerColor, innerColorStr); + ColorToStr(outerColor, outerColorStr); + ColorToStr(borderColor, borderColorStr); - Tk_Fill3DRectangle(tkwin, d, border, - b.x, b.y, b.width, b.height, - borderWidth, relief); + /* + * Check whether there is an SVG image of this size for these color strings + */ + snprintf(imgName, sizeof(imgName), + "::tk::icons::slider_default%d_%s_%s_%s", + dim, innerColorStr, outerColorStr, borderColorStr); + img = Tk_GetImage(interp, tkwin, imgName, ImageChanged, NULL); + if (img == NULL) { + /* + * Copy the string pointed to by svgDataPtr to + * a newly allocated memory area svgDataCopy + */ + svgDataLen = strlen(svgDataPtr); + svgDataCopy = (char *)attemptckalloc(svgDataLen + 1); + if (svgDataCopy == NULL) { + return; + } + memcpy(svgDataCopy, svgDataPtr, svgDataLen); + svgDataCopy[svgDataLen] = '\0'; - if (relief != TK_RELIEF_FLAT) { - if (orient == TTK_ORIENT_HORIZONTAL) { - if (b.width > 4) { - b.x += b.width/2; - XDrawLine(Tk_Display(tkwin), d, - Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC), - b.x-1, b.y+borderWidth, b.x-1, b.y+b.height-borderWidth); - XDrawLine(Tk_Display(tkwin), d, - Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC), - b.x, b.y+borderWidth, b.x, b.y+b.height-borderWidth); - } - } else { - if (b.height > 4) { - b.y += b.height/2; - XDrawLine(Tk_Display(tkwin), d, - Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC), - b.x+borderWidth, b.y-1, b.x+b.width-borderWidth, b.y-1); - XDrawLine(Tk_Display(tkwin), d, - Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC), - b.x+borderWidth, b.y, b.x+b.width-borderWidth, b.y); - } + /* + * Update the colors within svgDataCopy + */ + innerColorPtr = strstr(svgDataCopy, "4a6984"); + outerColorPtr = strstr(svgDataCopy, "ffffff"); + borderColorPtr = strstr(svgDataCopy, "c3c3c3"); + assert(innerColorPtr); + assert(outerColorPtr); + assert(borderColorPtr); + memcpy(innerColorPtr, innerColorStr, 6); + memcpy(outerColorPtr, outerColorStr, 6); + memcpy(borderColorPtr, borderColorStr, 6); + + /* + * Create an SVG photo image from svgDataCopy + */ + cmdFmt = "image create photo %s -format $::tk::svgFmt -data {%s}"; + scriptSize = strlen(cmdFmt) + strlen(imgName) + svgDataLen; + script = (char *)attemptckalloc(scriptSize); + if (script == NULL) { + ckfree(svgDataCopy); + return; } + snprintf(script, scriptSize, cmdFmt, imgName, svgDataCopy); + ckfree(svgDataCopy); + code = Tcl_EvalEx(interp, script, -1, TCL_EVAL_GLOBAL); + ckfree(script); + if (code != TCL_OK) { + Tcl_BackgroundException(interp, code); + return; + } + img = Tk_GetImage(interp, tkwin, imgName, ImageChanged, NULL); } + + /* + * Display the image + */ + Tk_RedrawImage(img, 0, 0, dim, dim, d, b.x, b.y); + Tk_FreeImage(img); } -static Ttk_ElementSpec SliderElementSpec = { +static const Ttk_ElementSpec SliderElementSpec = { TK_STYLE_VERSION_2, sizeof(SliderElement), SliderElementOptions, @@ -1273,18 +1553,18 @@ typedef struct { Tcl_Obj *borderWidthObj; /* thickness of the border */ } PbarElement; -static Ttk_ElementOptionSpec PbarElementOptions[] = { - { "-orient", TK_OPTION_ANY, Tk_Offset(PbarElement,orientObj), +static const Ttk_ElementOptionSpec PbarElementOptions[] = { + { "-orient", TK_OPTION_ANY, offsetof(PbarElement,orientObj), "horizontal" }, - { "-thickness", TK_OPTION_PIXELS, Tk_Offset(PbarElement,thicknessObj), + { "-thickness", TK_OPTION_PIXELS, offsetof(PbarElement,thicknessObj), DEFAULT_PBAR_THICKNESS }, - { "-barsize", TK_OPTION_PIXELS, Tk_Offset(PbarElement,lengthObj), + { "-barsize", TK_OPTION_PIXELS, offsetof(PbarElement,lengthObj), DEFAULT_PBAR_LENGTH }, - { "-pbarrelief", TK_OPTION_RELIEF, Tk_Offset(PbarElement,reliefObj), + { "-pbarrelief", TK_OPTION_RELIEF, offsetof(PbarElement,reliefObj), "raised" }, - { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(PbarElement,borderWidthObj), + { "-borderwidth", TK_OPTION_PIXELS, offsetof(PbarElement,borderWidthObj), DEFAULT_BORDERWIDTH }, - { "-background", TK_OPTION_BORDER, Tk_Offset(PbarElement,borderObj), + { "-background", TK_OPTION_BORDER, offsetof(PbarElement,borderObj), DEFAULT_BACKGROUND }, { NULL, TK_OPTION_BOOLEAN, 0, NULL } }; @@ -1296,10 +1576,10 @@ static void PbarElementSize( TCL_UNUSED(Ttk_Padding *)) { PbarElement *pbar = (PbarElement *)elementRecord; - int orient; + Ttk_Orient orient; int thickness = 15, length = 30, borderWidth = 2; - Ttk_GetOrientFromObj(NULL, pbar->orientObj, &orient); + TtkGetOrientFromObj(NULL, pbar->orientObj, &orient); Tk_GetPixelsFromObj(NULL, tkwin, pbar->thicknessObj, &thickness); Tk_GetPixelsFromObj(NULL, tkwin, pbar->lengthObj, &length); Tk_GetPixelsFromObj(NULL, tkwin, pbar->borderWidthObj, &borderWidth); @@ -1334,7 +1614,7 @@ static void PbarElementDraw( borderWidth, relief); } -static Ttk_ElementSpec PbarElementSpec = { +static const Ttk_ElementSpec PbarElementSpec = { TK_STYLE_VERSION_2, sizeof(PbarElement), PbarElementOptions, @@ -1353,15 +1633,15 @@ typedef struct { Tcl_Obj *highlightColorObj; } TabElement; -static Ttk_ElementOptionSpec TabElementOptions[] = { +static const Ttk_ElementOptionSpec TabElementOptions[] = { { "-borderwidth", TK_OPTION_PIXELS, - Tk_Offset(TabElement,borderWidthObj), "1" }, + offsetof(TabElement,borderWidthObj), "1" }, { "-background", TK_OPTION_BORDER, - Tk_Offset(TabElement,backgroundObj), DEFAULT_BACKGROUND }, + offsetof(TabElement,backgroundObj), DEFAULT_BACKGROUND }, { "-highlight", TK_OPTION_BOOLEAN, - Tk_Offset(TabElement,highlightObj), "0" }, + offsetof(TabElement,highlightObj), "0" }, { "-highlightcolor", TK_OPTION_COLOR, - Tk_Offset(TabElement,highlightColorObj), "#4a6984" }, + offsetof(TabElement,highlightColorObj), "#4a6984" }, {0, TK_OPTION_BOOLEAN, 0, 0} }; @@ -1413,7 +1693,8 @@ static void TabElementDraw( int highlight = 0; XColor *hlColor = NULL; XPoint pts[6]; - int cut = 2; + double scalingLevel = TkScalingLevel(tkwin); + int cut = round(2 * scalingLevel); Display *disp = Tk_Display(tkwin); int borderWidth = 1; @@ -1554,7 +1835,7 @@ static void TabElementDraw( } } -static Ttk_ElementSpec TabElementSpec = { +static const Ttk_ElementSpec TabElementSpec = { TK_STYLE_VERSION_2, sizeof(TabElement), TabElementOptions, @@ -1599,7 +1880,7 @@ static void ClientElementDraw( b.x, b.y, b.width, b.height, borderWidth, TK_RELIEF_RAISED); } -static Ttk_ElementSpec ClientElementSpec = { +static const Ttk_ElementSpec ClientElementSpec = { TK_STYLE_VERSION_2, sizeof(ClientElement), ClientElementOptions, @@ -1631,30 +1912,30 @@ TtkElements_Init(Tcl_Interp *interp) Ttk_RegisterElement(interp, theme, "padding", &PaddingElementSpec, NULL); Ttk_RegisterElement(interp, theme, "Checkbutton.indicator", - &CheckbuttonIndicatorElementSpec, NULL); + &IndicatorElementSpec, (void *)&checkbutton_spec); Ttk_RegisterElement(interp, theme, "Radiobutton.indicator", - &RadiobuttonIndicatorElementSpec, NULL); + &IndicatorElementSpec, (void *)&radiobutton_spec); Ttk_RegisterElement(interp, theme, "Menubutton.indicator", &MenuIndicatorElementSpec, NULL); Ttk_RegisterElement(interp, theme, "indicator", &ttkNullElementSpec, NULL); Ttk_RegisterElement(interp, theme, "uparrow", - &ArrowElementSpec, &ArrowElements[0]); + &ArrowElementSpec, INT2PTR(ARROW_UP)); Ttk_RegisterElement(interp, theme, "Spinbox.uparrow", - &BoxArrowElementSpec, &ArrowElements[0]); + &BoxArrowElementSpec, INT2PTR(ARROW_UP)); Ttk_RegisterElement(interp, theme, "downarrow", - &ArrowElementSpec, &ArrowElements[1]); + &ArrowElementSpec, INT2PTR(ARROW_DOWN)); Ttk_RegisterElement(interp, theme, "Spinbox.downarrow", - &BoxArrowElementSpec, &ArrowElements[1]); + &BoxArrowElementSpec, INT2PTR(ARROW_DOWN)); Ttk_RegisterElement(interp, theme, "Combobox.downarrow", - &BoxArrowElementSpec, &ArrowElements[1]); + &BoxArrowElementSpec, INT2PTR(ARROW_DOWN)); Ttk_RegisterElement(interp, theme, "leftarrow", - &ArrowElementSpec, &ArrowElements[2]); + &ArrowElementSpec, INT2PTR(ARROW_LEFT)); Ttk_RegisterElement(interp, theme, "rightarrow", - &ArrowElementSpec, &ArrowElements[3]); + &ArrowElementSpec, INT2PTR(ARROW_RIGHT)); Ttk_RegisterElement(interp, theme, "arrow", - &ArrowElementSpec, &ArrowElements[0]); + &ArrowElementSpec, INT2PTR(ARROW_UP)); Ttk_RegisterElement(interp, theme, "trough", &TroughElementSpec, NULL); Ttk_RegisterElement(interp, theme, "thumb", &ThumbElementSpec, NULL); |