Files
cpython-source-deps/generic/ttk/ttkDefaultTheme.c
2020-09-24 22:55:34 +01:00

1182 lines
37 KiB
C

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