summaryrefslogtreecommitdiffstats
path: root/generic/ttk/ttkElements.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/ttk/ttkElements.c')
-rw-r--r--generic/ttk/ttkElements.c1007
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);