Also attachment "ttkClamTheme.c" to
ticket [e3069968]
added by
nemethi
2024-05-01 14:26:43.
/*
* Copyright (C) 2004 Joe English
*
* "clam" theme; inspired by the XFCE family of Gnome themes.
*/
#include "tkInt.h"
#include "ttkTheme.h"
/*
* Under windows, the Tk-provided XDrawLine and XDrawArc have an
* off-by-one error in the end point. This is especially apparent with this
* theme. Defining this macro as true handles this case.
*/
#if defined(_WIN32) && !defined(WIN32_XDRAWLINE_HACK)
#define WIN32_XDRAWLINE_HACK 1
#else
#define WIN32_XDRAWLINE_HACK 0
#endif
#define STR(x) StR(x)
#define StR(x) #x
#define SCROLLBAR_THICKNESS 14
#define FRAME_COLOR "#dcdad5"
#define LIGHT_COLOR "#ffffff"
#define DARK_COLOR "#cfcdc8"
#define DARKER_COLOR "#bab5ab"
#define DARKEST_COLOR "#9e9a91"
/*------------------------------------------------------------------------
* +++ Utilities.
*/
static GC Ttk_GCForColor(Tk_Window tkwin, Tcl_Obj* colorObj, Drawable d)
{
GC gc = Tk_GCForColor(Tk_GetColorFromObj(tkwin, colorObj), d);
#ifdef MAC_OSX_TK
/*
* Workaround for Tk bug under Aqua where the default line width is 0.
*/
Display *display = Tk_Display(tkwin);
unsigned long mask = 0ul;
XGCValues gcValues;
gcValues.line_width = 1;
mask = GCLineWidth;
XChangeGC(display, gc, mask, &gcValues);
#endif
return gc;
}
static void DrawSmoothBorder(
Tk_Window tkwin, Drawable d, Ttk_Box b,
Tcl_Obj *outerColorObj, Tcl_Obj *upperColorObj, Tcl_Obj *lowerColorObj)
{
Display *display = Tk_Display(tkwin);
int x1 = b.x, x2 = b.x + b.width - 1;
int y1 = b.y, y2 = b.y + b.height - 1;
const int w = WIN32_XDRAWLINE_HACK;
GC gc;
if ( outerColorObj
&& (gc=Ttk_GCForColor(tkwin,outerColorObj,d)))
{
XDrawLine(display,d,gc, x1+1,y1, x2-1+w,y1); /* N */
XDrawLine(display,d,gc, x1+1,y2, x2-1+w,y2); /* S */
XDrawLine(display,d,gc, x1,y1+1, x1,y2-1+w); /* E */
XDrawLine(display,d,gc, x2,y1+1, x2,y2-1+w); /* W */
}
if ( upperColorObj
&& (gc=Ttk_GCForColor(tkwin,upperColorObj,d)))
{
XDrawLine(display,d,gc, x1+1,y1+1, x2-1+w,y1+1); /* N */
XDrawLine(display,d,gc, x1+1,y1+1, x1+1,y2-1); /* E */
}
if ( lowerColorObj
&& (gc=Ttk_GCForColor(tkwin,lowerColorObj,d)))
{
XDrawLine(display,d,gc, x2-1,y2-1, x1+1-w,y2-1); /* S */
XDrawLine(display,d,gc, x2-1,y2-1, x2-1,y1+1-w); /* W */
}
}
static GC BackgroundGC(Tk_Window tkwin, Tcl_Obj *backgroundObj)
{
Tk_3DBorder bd = Tk_Get3DBorderFromObj(tkwin, backgroundObj);
return Tk_3DBorderGC(tkwin, bd, TK_3D_FLAT_GC);
}
/*------------------------------------------------------------------------
* +++ Border element.
*/
typedef struct {
Tcl_Obj *borderColorObj;
Tcl_Obj *lightColorObj;
Tcl_Obj *darkColorObj;
Tcl_Obj *reliefObj;
Tcl_Obj *borderWidthObj; /* See <<NOTE-BORDERWIDTH>> */
} BorderElement;
static Ttk_ElementOptionSpec BorderElementOptions[] = {
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(BorderElement,borderColorObj), DARKEST_COLOR },
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(BorderElement,lightColorObj), LIGHT_COLOR },
{ "-darkcolor", TK_OPTION_COLOR,
Tk_Offset(BorderElement,darkColorObj), DARK_COLOR },
{ "-relief", TK_OPTION_RELIEF,
Tk_Offset(BorderElement,reliefObj), "flat" },
{ "-borderwidth", TK_OPTION_PIXELS,
Tk_Offset(BorderElement,borderWidthObj), "2" },
{ NULL, TK_OPTION_BOOLEAN, 0, NULL }
};
/*
* <<NOTE-BORDERWIDTH>>: -borderwidth is only partially supported:
* in this theme, borders are always exactly 2 pixels thick.
* With -borderwidth 0, border is not drawn at all;
* otherwise a 2-pixel border is used. For -borderwidth > 2,
* the excess is used as padding.
*/
static void BorderElementSize(
void *dummy, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
BorderElement *border = (BorderElement*)elementRecord;
int borderWidth = 2;
(void)dummy;
(void)widthPtr;
(void)heightPtr;
Tk_GetPixelsFromObj(NULL, tkwin, border->borderWidthObj, &borderWidth);
if (borderWidth == 1) ++borderWidth;
*paddingPtr = Ttk_UniformPadding((short)borderWidth);
}
static void BorderElementDraw(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
BorderElement *border = (BorderElement *)elementRecord;
int relief = TK_RELIEF_FLAT;
int borderWidth = 2;
Tcl_Obj *outer = 0, *upper = 0, *lower = 0;
(void)dummy;
(void)state;
Tk_GetReliefFromObj(NULL, border->reliefObj, &relief);
Tk_GetPixelsFromObj(NULL, tkwin, border->borderWidthObj, &borderWidth);
if (borderWidth == 0) return;
switch (relief) {
case TK_RELIEF_GROOVE :
case TK_RELIEF_RIDGE :
case TK_RELIEF_RAISED :
outer = border->borderColorObj;
upper = border->lightColorObj;
lower = border->darkColorObj;
break;
case TK_RELIEF_SUNKEN :
outer = border->borderColorObj;
upper = border->darkColorObj;
lower = border->lightColorObj;
break;
case TK_RELIEF_FLAT :
outer = upper = lower = 0;
break;
case TK_RELIEF_SOLID :
outer = upper = lower = border->borderColorObj;
break;
}
DrawSmoothBorder(tkwin, d, b, outer, upper, lower);
}
static Ttk_ElementSpec BorderElementSpec = {
TK_STYLE_VERSION_2,
sizeof(BorderElement),
BorderElementOptions,
BorderElementSize,
BorderElementDraw
};
/*------------------------------------------------------------------------
* +++ Field element.
*/
typedef struct {
Tcl_Obj *borderColorObj;
Tcl_Obj *lightColorObj;
Tcl_Obj *backgroundObj;
} FieldElement;
static Ttk_ElementOptionSpec FieldElementOptions[] = {
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(FieldElement,borderColorObj), DARKEST_COLOR },
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(FieldElement,lightColorObj), LIGHT_COLOR },
{ "-fieldbackground", TK_OPTION_BORDER,
Tk_Offset(FieldElement,backgroundObj), "white" },
{ NULL, TK_OPTION_BOOLEAN, 0, NULL }
};
static void FieldElementSize(
void *dummy, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
(void)dummy;
(void)elementRecord;
(void)tkwin;
(void)widthPtr;
(void)heightPtr;
*paddingPtr = Ttk_UniformPadding(2);
}
static void FieldElementDraw(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
FieldElement *field = (FieldElement *)elementRecord;
Tk_3DBorder bg = Tk_Get3DBorderFromObj(tkwin, field->backgroundObj);
Ttk_Box f = Ttk_PadBox(b, Ttk_UniformPadding(2));
Tcl_Obj *outer = field->borderColorObj,
*inner = field->lightColorObj;
(void)dummy;
(void)state;
DrawSmoothBorder(tkwin, d, b, outer, inner, inner);
Tk_Fill3DRectangle(
tkwin, d, bg, f.x, f.y, f.width, f.height, 0, TK_RELIEF_SUNKEN);
}
static Ttk_ElementSpec FieldElementSpec = {
TK_STYLE_VERSION_2,
sizeof(FieldElement),
FieldElementOptions,
FieldElementSize,
FieldElementDraw
};
/*
* Modified field element for comboboxes:
* Right edge is expanded to overlap the dropdown button.
*/
static void ComboboxFieldElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
FieldElement *field = (FieldElement *)elementRecord;
GC gc = Ttk_GCForColor(tkwin,field->borderColorObj,d);
++b.width;
FieldElementDraw(clientData, elementRecord, tkwin, d, b, state);
XDrawLine(Tk_Display(tkwin), d, gc,
b.x + b.width - 1, b.y,
b.x + b.width - 1, b.y + b.height - 1 + WIN32_XDRAWLINE_HACK);
}
static Ttk_ElementSpec ComboboxFieldElementSpec = {
TK_STYLE_VERSION_2,
sizeof(FieldElement),
FieldElementOptions,
FieldElementSize,
ComboboxFieldElementDraw
};
/*------------------------------------------------------------------------
* +++ Indicator elements for check and radio buttons.
*/
typedef struct {
Tcl_Obj *sizeObj;
Tcl_Obj *marginObj;
Tcl_Obj *backgroundObj;
Tcl_Obj *foregroundObj;
Tcl_Obj *upperColorObj;
Tcl_Obj *lowerColorObj;
} IndicatorElement;
static Ttk_ElementOptionSpec IndicatorElementOptions[] = {
{ "-indicatorsize", TK_OPTION_PIXELS,
Tk_Offset(IndicatorElement,sizeObj), "10" },
{ "-indicatormargin", TK_OPTION_STRING,
Tk_Offset(IndicatorElement,marginObj), "1" },
{ "-indicatorbackground", TK_OPTION_COLOR,
Tk_Offset(IndicatorElement,backgroundObj), "white" },
{ "-indicatorforeground", TK_OPTION_COLOR,
Tk_Offset(IndicatorElement,foregroundObj), "black" },
{ "-upperbordercolor", TK_OPTION_COLOR,
Tk_Offset(IndicatorElement,upperColorObj), DARKEST_COLOR },
{ "-lowerbordercolor", TK_OPTION_COLOR,
Tk_Offset(IndicatorElement,lowerColorObj), DARK_COLOR },
{ NULL, TK_OPTION_BOOLEAN, 0, NULL }
};
static void IndicatorElementSize(
void *dummy, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
IndicatorElement *indicator = (IndicatorElement *)elementRecord;
Ttk_Padding margins;
int size = 10;
(void)dummy;
(void)paddingPtr;
Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &margins);
Tk_GetPixelsFromObj(NULL, tkwin, indicator->sizeObj, &size);
*widthPtr = size + Ttk_PaddingWidth(margins);
*heightPtr = size + Ttk_PaddingHeight(margins);
}
static void RadioIndicatorElementDraw(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
IndicatorElement *indicator = (IndicatorElement *)elementRecord;
GC gcb=Ttk_GCForColor(tkwin,indicator->backgroundObj,d);
GC gcf=Ttk_GCForColor(tkwin,indicator->foregroundObj,d);
GC gcu=Ttk_GCForColor(tkwin,indicator->upperColorObj,d);
GC gcl=Ttk_GCForColor(tkwin,indicator->lowerColorObj,d);
Ttk_Padding padding;
(void)dummy;
Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding);
b = Ttk_PadBox(b, padding);
XFillArc(Tk_Display(tkwin),d,gcb, b.x,b.y,b.width,b.height, 0,360*64);
XDrawArc(Tk_Display(tkwin),d,gcl, b.x,b.y,b.width,b.height, 225*64,180*64);
XDrawArc(Tk_Display(tkwin),d,gcu, b.x,b.y,b.width,b.height, 45*64,180*64);
if (state & TTK_STATE_SELECTED) {
b = Ttk_PadBox(b,Ttk_UniformPadding(3));
XFillArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 0,360*64);
XDrawArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 0,360*64);
#if WIN32_XDRAWLINE_HACK
XDrawArc(Tk_Display(tkwin),d,gcf, b.x,b.y,b.width,b.height, 300*64,360*64);
#endif
}
}
static void CheckIndicatorElementDraw(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
Display *display = Tk_Display(tkwin);
IndicatorElement *indicator = (IndicatorElement *)elementRecord;
GC gcb=Ttk_GCForColor(tkwin,indicator->backgroundObj,d);
GC gcf=Ttk_GCForColor(tkwin,indicator->foregroundObj,d);
GC gcu=Ttk_GCForColor(tkwin,indicator->upperColorObj,d);
GC gcl=Ttk_GCForColor(tkwin,indicator->lowerColorObj,d);
Ttk_Padding padding;
const int w = WIN32_XDRAWLINE_HACK;
(void)dummy;
Ttk_GetPaddingFromObj(NULL, tkwin, indicator->marginObj, &padding);
b = Ttk_PadBox(b, padding);
XFillRectangle(display,d,gcb, b.x,b.y,b.width,b.height);
XDrawLine(display,d,gcl,b.x,b.y+b.height,b.x+b.width+w,b.y+b.height);/*S*/
XDrawLine(display,d,gcl,b.x+b.width,b.y,b.x+b.width,b.y+b.height+w); /*E*/
XDrawLine(display,d,gcu,b.x,b.y, b.x,b.y+b.height+w); /*W*/
XDrawLine(display,d,gcu,b.x,b.y, b.x+b.width+w,b.y); /*N*/
if (state & TTK_STATE_SELECTED) {
int p,q,r,s;
b = Ttk_PadBox(b,Ttk_UniformPadding(2));
p = b.x, q = b.y, r = b.x+b.width, s = b.y+b.height;
r+=w, s+=w;
XDrawLine(display, d, gcf, p, q, r, s);
XDrawLine(display, d, gcf, p+1, q, r, s-1);
XDrawLine(display, d, gcf, p, q+1, r-1, s);
s-=w, q-=w;
XDrawLine(display, d, gcf, p, s, r, q);
XDrawLine(display, d, gcf, p+1, s, r, q+1);
XDrawLine(display, d, gcf, p, s-1, r-1, q);
}
}
static Ttk_ElementSpec RadioIndicatorElementSpec = {
TK_STYLE_VERSION_2,
sizeof(IndicatorElement),
IndicatorElementOptions,
IndicatorElementSize,
RadioIndicatorElementDraw
};
static Ttk_ElementSpec CheckIndicatorElementSpec = {
TK_STYLE_VERSION_2,
sizeof(IndicatorElement),
IndicatorElementOptions,
IndicatorElementSize,
CheckIndicatorElementDraw
};
#define MENUBUTTON_ARROW_SIZE 5
typedef struct {
Tcl_Obj *sizeObj;
Tcl_Obj *colorObj;
Tcl_Obj *paddingObj;
} MenuIndicatorElement;
static Ttk_ElementOptionSpec MenuIndicatorElementOptions[] =
{
{ "-arrowsize", TK_OPTION_PIXELS,
Tk_Offset(MenuIndicatorElement,sizeObj),
STR(MENUBUTTON_ARROW_SIZE)},
{ "-arrowcolor",TK_OPTION_COLOR,
Tk_Offset(MenuIndicatorElement,colorObj),
"black" },
{ "-arrowpadding",TK_OPTION_STRING,
Tk_Offset(MenuIndicatorElement,paddingObj),
"3" },
{ NULL, TK_OPTION_BOOLEAN, 0, NULL }
};
static void MenuIndicatorElementSize(
void *dummy, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
MenuIndicatorElement *indicator = (MenuIndicatorElement *)elementRecord;
Ttk_Padding margins;
int size = MENUBUTTON_ARROW_SIZE;
(void)dummy;
(void)paddingPtr;
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(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int 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;
(void)dummy;
(void)state;
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 Ttk_ElementSpec MenuIndicatorElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(MenuIndicatorElement),
MenuIndicatorElementOptions,
MenuIndicatorElementSize,
MenuIndicatorElementDraw
};
/*------------------------------------------------------------------------
* +++ Grips.
*
* TODO: factor this with ThumbElementDraw
*/
static Ttk_Orient GripClientData[] = {
TTK_ORIENT_HORIZONTAL, TTK_ORIENT_VERTICAL
};
typedef struct {
Tcl_Obj *lightColorObj;
Tcl_Obj *borderColorObj;
Tcl_Obj *gripCountObj;
} GripElement;
static Ttk_ElementOptionSpec GripElementOptions[] = {
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(GripElement,lightColorObj), LIGHT_COLOR },
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(GripElement,borderColorObj), DARKEST_COLOR },
{ "-gripcount", TK_OPTION_INT,
Tk_Offset(GripElement,gripCountObj), "5" },
{ NULL, TK_OPTION_BOOLEAN, 0, NULL }
};
static void GripElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL;
GripElement *grip = (GripElement *)elementRecord;
int gripCount = 0;
(void)tkwin;
(void)paddingPtr;
Tcl_GetIntFromObj(NULL, grip->gripCountObj, &gripCount);
if (horizontal) {
*widthPtr = 2*gripCount;
} else {
*heightPtr = 2*gripCount;
}
}
static void GripElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
const int w = WIN32_XDRAWLINE_HACK;
int horizontal = *((Ttk_Orient*)clientData) == TTK_ORIENT_HORIZONTAL;
GripElement *grip = (GripElement *)elementRecord;
GC lightGC = Ttk_GCForColor(tkwin,grip->lightColorObj,d);
GC darkGC = Ttk_GCForColor(tkwin,grip->borderColorObj,d);
int gripPad = 1, gripCount = 0;
int i;
Tcl_GetIntFromObj(NULL, grip->gripCountObj, &gripCount);
if (horizontal) {
int x = b.x + b.width / 2 - gripCount;
int y1 = b.y + gripPad, y2 = b.y + b.height - gripPad - 1 + w;
for (i=0; i<gripCount; ++i) {
XDrawLine(Tk_Display(tkwin), d, darkGC, x,y1, x,y2); ++x;
XDrawLine(Tk_Display(tkwin), d, lightGC, x,y1, x,y2); ++x;
}
} else {
int y = b.y + b.height / 2 - gripCount;
int x1 = b.x + gripPad, x2 = b.x + b.width - gripPad - 1 + w;
for (i=0; i<gripCount; ++i) {
XDrawLine(Tk_Display(tkwin), d, darkGC, x1,y, x2,y); ++y;
XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y, x2,y); ++y;
}
}
}
static Ttk_ElementSpec GripElementSpec = {
TK_STYLE_VERSION_2,
sizeof(GripElement),
GripElementOptions,
GripElementSize,
GripElementDraw
};
/*------------------------------------------------------------------------
* +++ Scrollbar elements: trough, arrows, thumb.
*
* Notice that the trough element has 0 internal padding;
* that way the thumb and arrow borders overlap the trough.
*/
typedef struct { /* Common element record for scrollbar elements */
Tcl_Obj *orientObj;
Tcl_Obj *backgroundObj;
Tcl_Obj *borderColorObj;
Tcl_Obj *troughColorObj;
Tcl_Obj *lightColorObj;
Tcl_Obj *darkColorObj;
Tcl_Obj *arrowColorObj;
Tcl_Obj *arrowSizeObj;
Tcl_Obj *gripCountObj;
Tcl_Obj *sliderlengthObj;
} ScrollbarElement;
static Ttk_ElementOptionSpec ScrollbarElementOptions[] = {
{ "-orient", TK_OPTION_ANY,
Tk_Offset(ScrollbarElement, orientObj), "horizontal" },
{ "-background", TK_OPTION_BORDER,
Tk_Offset(ScrollbarElement,backgroundObj), FRAME_COLOR },
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,borderColorObj), DARKEST_COLOR },
{ "-troughcolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,troughColorObj), DARKER_COLOR },
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,lightColorObj), LIGHT_COLOR },
{ "-darkcolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,darkColorObj), DARK_COLOR },
{ "-arrowcolor", TK_OPTION_COLOR,
Tk_Offset(ScrollbarElement,arrowColorObj), "#000000" },
{ "-arrowsize", TK_OPTION_PIXELS,
Tk_Offset(ScrollbarElement,arrowSizeObj), STR(SCROLLBAR_THICKNESS) },
{ "-gripcount", TK_OPTION_INT,
Tk_Offset(ScrollbarElement,gripCountObj), "5" },
{ "-sliderlength", TK_OPTION_INT,
Tk_Offset(ScrollbarElement,sliderlengthObj), "30" },
{ NULL, TK_OPTION_BOOLEAN, 0, NULL }
};
static void TroughElementDraw(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
GC gcb = Ttk_GCForColor(tkwin,sb->borderColorObj,d);
GC gct = Ttk_GCForColor(tkwin,sb->troughColorObj,d);
(void)dummy;
(void)state;
XFillRectangle(Tk_Display(tkwin), d, gct, b.x, b.y, b.width-1, b.height-1);
XDrawRectangle(Tk_Display(tkwin), d, gcb, b.x, b.y, b.width-1, b.height-1);
}
static Ttk_ElementSpec TroughElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
TtkNullElementSize,
TroughElementDraw
};
static void ThumbElementSize(
void *dummy, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
int size = SCROLLBAR_THICKNESS;
(void)dummy;
(void)tkwin;
(void)paddingPtr;
Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &size);
*widthPtr = *heightPtr = size;
}
static void ThumbElementDraw(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
int gripCount = 0;
int orient = TTK_ORIENT_HORIZONTAL;
GC lightGC, darkGC;
int x1, y1, x2, y2, dx, dy, i;
const int w = WIN32_XDRAWLINE_HACK;
(void)dummy;
(void)state;
DrawSmoothBorder(tkwin, d, b,
sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
XFillRectangle(
Tk_Display(tkwin), d, BackgroundGC(tkwin, sb->backgroundObj),
b.x+2, b.y+2, b.width-4, b.height-4);
/*
* Draw grip:
*/
Ttk_GetOrientFromObj(NULL, sb->orientObj, &orient);
Tcl_GetIntFromObj(NULL, sb->gripCountObj, &gripCount);
lightGC = Ttk_GCForColor(tkwin,sb->lightColorObj,d);
darkGC = Ttk_GCForColor(tkwin,sb->borderColorObj,d);
if (orient == TTK_ORIENT_HORIZONTAL) {
dx = 1; dy = 0;
x1 = x2 = b.x + b.width / 2 - gripCount;
y1 = b.y + 2;
y2 = b.y + b.height - 3 + w;
} else {
dx = 0; dy = 1;
y1 = y2 = b.y + b.height / 2 - gripCount;
x1 = b.x + 2;
x2 = b.x + b.width - 3 + w;
}
for (i=0; i<gripCount; ++i) {
XDrawLine(Tk_Display(tkwin), d, darkGC, x1,y1, x2,y2);
x1 += dx; x2 += dx; y1 += dy; y2 += dy;
XDrawLine(Tk_Display(tkwin), d, lightGC, x1,y1, x2,y2);
x1 += dx; x2 += dx; y1 += dy; y2 += dy;
}
}
static Ttk_ElementSpec ThumbElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
ThumbElementSize,
ThumbElementDraw
};
/*------------------------------------------------------------------------
* +++ Slider element.
*/
static void SliderElementSize(
void *dummy, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
int length, thickness;
int orient;
(void)dummy;
(void)paddingPtr;
length = thickness = SCROLLBAR_THICKNESS;
Ttk_GetOrientFromObj(NULL, sb->orientObj, &orient);
Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &thickness);
Tk_GetPixelsFromObj(NULL, tkwin, sb->sliderlengthObj, &length);
if (orient == TTK_ORIENT_VERTICAL) {
*heightPtr = length;
*widthPtr = thickness;
} else {
*heightPtr = thickness;
*widthPtr = length;
}
}
static Ttk_ElementSpec SliderElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
SliderElementSize,
ThumbElementDraw
};
/*------------------------------------------------------------------------
* +++ Progress bar element
*/
static void PbarElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
SliderElementSize(clientData, elementRecord, tkwin,
widthPtr, heightPtr, paddingPtr);
*paddingPtr = Ttk_UniformPadding(2);
*widthPtr += 4;
*heightPtr += 4;
}
static void PbarElementDraw(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
(void)dummy;
(void)state;
b = Ttk_PadBox(b, Ttk_UniformPadding(2));
if (b.width > 4 && b.height > 4) {
DrawSmoothBorder(tkwin, d, b,
sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
XFillRectangle(Tk_Display(tkwin), d,
BackgroundGC(tkwin, sb->backgroundObj),
b.x+2, b.y+2, b.width-4, b.height-4);
}
}
static Ttk_ElementSpec PbarElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
PbarElementSize,
PbarElementDraw
};
/*------------------------------------------------------------------------
* +++ Scrollbar arrows.
*/
static int ArrowElements[] = { ARROW_UP, ARROW_DOWN, ARROW_LEFT, ARROW_RIGHT };
static void ArrowElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
ArrowDirection direction = *(ArrowDirection*)clientData;
Ttk_Padding padding = Ttk_UniformPadding(3);
int size = SCROLLBAR_THICKNESS;
(void)tkwin;
(void)paddingPtr;
Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &size);
size -= Ttk_PaddingWidth(padding);
TtkArrowSize(size/2, direction, widthPtr, heightPtr);
*widthPtr += Ttk_PaddingWidth(padding);
*heightPtr += Ttk_PaddingHeight(padding);
if (*widthPtr < *heightPtr) {
*widthPtr = *heightPtr;
} else {
*heightPtr = *widthPtr;
}
}
static void ArrowElementDraw(
void *clientData, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned state)
{
ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
ArrowDirection direction = *(ArrowDirection*)clientData;
Ttk_Padding padding = Ttk_UniformPadding(3);
int cx, cy;
GC gc = Ttk_GCForColor(tkwin, sb->arrowColorObj, d);
DrawSmoothBorder(tkwin, d, b,
sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
XFillRectangle(
Tk_Display(tkwin), d, BackgroundGC(tkwin, sb->backgroundObj),
b.x+2, b.y+2, b.width-4, b.height-4);
b = Ttk_PadBox(b, padding);
switch (direction) {
case ARROW_UP:
case ARROW_DOWN:
TtkArrowSize(b.width/2, direction, &cx, &cy);
if ((b.height - cy) % 2 == 1) {
++cy;
}
break;
case ARROW_LEFT:
case ARROW_RIGHT:
TtkArrowSize(b.height/2, direction, &cx, &cy);
if ((b.width - cx) % 2 == 1) {
++cx;
}
break;
}
b = Ttk_AnchorBox(b, cx, cy, TK_ANCHOR_CENTER);
TtkFillArrow(Tk_Display(tkwin), d, gc, b, direction);
}
static Ttk_ElementSpec ArrowElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
ArrowElementSize,
ArrowElementDraw
};
/*
* Modified arrow element for spinboxes:
* The width and height are different.
*/
static void SpinboxArrowElementSize(
void *clientData, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
ScrollbarElement *sb = (ScrollbarElement *)elementRecord;
ArrowDirection direction = *(ArrowDirection*)clientData;
Ttk_Padding padding = Ttk_UniformPadding(3);
int size = 10;
(void)tkwin;
(void)paddingPtr;
Tcl_GetIntFromObj(NULL, sb->arrowSizeObj, &size);
size -= Ttk_PaddingWidth(padding);
TtkArrowSize(size/2, direction, widthPtr, heightPtr);
*widthPtr += Ttk_PaddingWidth(padding);
*heightPtr += Ttk_PaddingHeight(padding);
}
static Ttk_ElementSpec SpinboxArrowElementSpec = {
TK_STYLE_VERSION_2,
sizeof(ScrollbarElement),
ScrollbarElementOptions,
SpinboxArrowElementSize,
ArrowElementDraw
};
/*------------------------------------------------------------------------
* +++ Notebook elements.
*
* Note: Tabs, except for the rightmost, overlap the neighbor to
* their right by one pixel.
*/
typedef struct {
Tcl_Obj *backgroundObj;
Tcl_Obj *borderColorObj;
Tcl_Obj *lightColorObj;
Tcl_Obj *darkColorObj;
} NotebookElement;
static Ttk_ElementOptionSpec NotebookElementOptions[] = {
{ "-background", TK_OPTION_BORDER,
Tk_Offset(NotebookElement,backgroundObj), FRAME_COLOR },
{ "-bordercolor", TK_OPTION_COLOR,
Tk_Offset(NotebookElement,borderColorObj), DARKEST_COLOR },
{ "-lightcolor", TK_OPTION_COLOR,
Tk_Offset(NotebookElement,lightColorObj), LIGHT_COLOR },
{ "-darkcolor", TK_OPTION_COLOR,
Tk_Offset(NotebookElement,darkColorObj), DARK_COLOR },
{ NULL, TK_OPTION_BOOLEAN, 0, NULL }
};
static void TabElementSize(
void *dummy, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
Ttk_PositionSpec nbTabsStickBit = TTK_STICK_S;
TkMainInfo *mainInfoPtr = ((TkWindow *) tkwin)->mainPtr;
int borderWidth = 2;
(void)dummy;
(void)elementRecord;
(void)tkwin;
(void)widthPtr;
(void)heightPtr;
if (mainInfoPtr != NULL) {
nbTabsStickBit = (Ttk_PositionSpec) mainInfoPtr->ttkNbTabsStickBit;
}
*paddingPtr = Ttk_UniformPadding((short)borderWidth);
switch (nbTabsStickBit) {
default:
case TTK_STICK_S:
paddingPtr->bottom = 0;
break;
case TTK_STICK_N:
paddingPtr->top = 0;
break;
case TTK_STICK_E:
paddingPtr->right = 0;
break;
case TTK_STICK_W:
paddingPtr->left = 0;
break;
}
}
static void TabElementDraw(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
Ttk_PositionSpec nbTabsStickBit = TTK_STICK_S;
TkMainInfo *mainInfoPtr = ((TkWindow *) tkwin)->mainPtr;
int borderWidth = 2, delta = 0;
NotebookElement *tab = (NotebookElement *)elementRecord;
Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, tab->backgroundObj);
Display *display = Tk_Display(tkwin);
int x1, y1, x2, y2;
GC gc;
const int w = WIN32_XDRAWLINE_HACK;
(void)dummy;
if (mainInfoPtr != NULL) {
nbTabsStickBit = (Ttk_PositionSpec) mainInfoPtr->ttkNbTabsStickBit;
}
if (state & TTK_STATE_SELECTED) {
delta = borderWidth;
}
switch (nbTabsStickBit) {
default:
case TTK_STICK_S:
if (state & TTK_STATE_USER2) { /* rightmost tab */
--b.width;
}
Tk_Fill3DRectangle(tkwin, d, border,
b.x+2, b.y+2, b.width-1, b.height-2+delta,
borderWidth, TK_RELIEF_FLAT);
x1 = b.x; y1 = b.y; /* top left */
x2 = b.x + b.width; y2 = b.y + b.height-1; /* bottom right */
gc = Ttk_GCForColor(tkwin, tab->borderColorObj, d);
XDrawLine(display, d, gc, x1, y1+1, x1, y2+1+w);
XDrawLine(display, d, gc, x2, y1+1, x2, y2+1+w);
XDrawLine(display, d, gc, x1+1, y1, x2-1+w, y1);
gc = Ttk_GCForColor(tkwin, tab->lightColorObj, d);
XDrawLine(display, d, gc, x1+1, y1+1, x1+1, y2+delta+w);
XDrawLine(display, d, gc, x1+1, y1+1, x2-1+w, y1+1);
break;
case TTK_STICK_N:
if (state & TTK_STATE_USER2) { /* rightmost tab */
--b.width;
}
Tk_Fill3DRectangle(tkwin, d, border,
b.x+2, b.y-delta, b.width-1, b.height-2+delta,
borderWidth, TK_RELIEF_FLAT);
x1 = b.x; y1 = b.y + b.height-1; /* bottom left */
x2 = b.x + b.width; y2 = b.y; /* top right */
gc = Ttk_GCForColor(tkwin, tab->borderColorObj, d);
XDrawLine(display, d, gc, x1, y1-1, x1, y2-1-w);
XDrawLine(display, d, gc, x2, y1-1, x2, y2-1-w);
XDrawLine(display, d, gc, x1+1, y1, x2-1+w, y1);
gc = Ttk_GCForColor(tkwin, tab->lightColorObj, d);
XDrawLine(display, d, gc, x1+1, y1-1, x1+1, y2-delta-w);
XDrawLine(display, d, gc, x1+1, y1-1, x2-1+w, y1-1);
break;
case TTK_STICK_E:
if (state & TTK_STATE_USER2) { /* bottommost tab */
--b.height;
}
Tk_Fill3DRectangle(tkwin, d, border,
b.x+2, b.y+2, b.width-2+delta, b.height-1,
borderWidth, TK_RELIEF_FLAT);
x1 = b.x; y1 = b.y; /* top left */
x2 = b.x + b.width-1; y2 = b.y + b.height; /* bottom right */
gc = Ttk_GCForColor(tkwin, tab->borderColorObj, d);
XDrawLine(display, d, gc, x1, y1+1, x1, y2-1+w);
XDrawLine(display, d, gc, x1+1, y1, x2+1+w, y1);
XDrawLine(display, d, gc, x1+1, y2, x2+1+w, y2);
gc = Ttk_GCForColor(tkwin, tab->lightColorObj, d);
XDrawLine(display, d, gc, x1+1, y1+1, x1+1, y2-1+w);
XDrawLine(display, d, gc, x1+1, y1+1, x2+delta+w, y1+1);
break;
case TTK_STICK_W:
if (state & TTK_STATE_USER2) { /* bottommost tab */
--b.height;
}
Tk_Fill3DRectangle(tkwin, d, border,
b.x-delta, b.y+2, b.width-2+delta, b.height-1,
borderWidth, TK_RELIEF_FLAT);
x1 = b.x + b.width-1; y1 = b.y; /* top right */
x2 = b.x; y2 = b.y + b.height; /* bottom left */
gc = Ttk_GCForColor(tkwin, tab->borderColorObj, d);
XDrawLine(display, d, gc, x1, y1+1, x1, y2-1+w);
XDrawLine(display, d, gc, x1-1, y1, x2-1-w, y1);
XDrawLine(display, d, gc, x1-1, y2, x2-1-w, y2);
gc = Ttk_GCForColor(tkwin, tab->lightColorObj, d);
XDrawLine(display, d, gc, x1-1, y1+1, x1-1, y2-1+w);
XDrawLine(display, d, gc, x1-1, y1+1, x2-delta-w, y1+1);
break;
}
}
static Ttk_ElementSpec TabElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(NotebookElement),
NotebookElementOptions,
TabElementSize,
TabElementDraw
};
static void ClientElementSize(
void *dummy, void *elementRecord, Tk_Window tkwin,
int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
{
int borderWidth = 2;
(void)dummy;
(void)elementRecord;
(void)tkwin;
(void)widthPtr;
(void)heightPtr;
*paddingPtr = Ttk_UniformPadding((short)borderWidth);
}
static void ClientElementDraw(
void *dummy, void *elementRecord, Tk_Window tkwin,
Drawable d, Ttk_Box b, unsigned int state)
{
NotebookElement *ce = (NotebookElement *)elementRecord;
Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, ce->backgroundObj);
int borderWidth = 2;
(void)dummy;
(void)state;
Tk_Fill3DRectangle(tkwin, d, border,
b.x, b.y, b.width, b.height, borderWidth,TK_RELIEF_FLAT);
DrawSmoothBorder(tkwin, d, b,
ce->borderColorObj, ce->lightColorObj, ce->darkColorObj);
}
static Ttk_ElementSpec ClientElementSpec =
{
TK_STYLE_VERSION_2,
sizeof(NotebookElement),
NotebookElementOptions,
ClientElementSize,
ClientElementDraw
};
/*------------------------------------------------------------------------
* +++ Modified widget layouts.
*/
TTK_BEGIN_LAYOUT_TABLE(LayoutTable)
TTK_LAYOUT("TCombobox",
TTK_NODE("Combobox.downarrow", TTK_PACK_RIGHT|TTK_FILL_Y)
TTK_GROUP("Combobox.field", TTK_FILL_BOTH,
TTK_GROUP("Combobox.padding", TTK_FILL_BOTH,
TTK_NODE("Combobox.textarea", TTK_FILL_BOTH))))
TTK_LAYOUT("Horizontal.Sash",
TTK_GROUP("Sash.hsash", TTK_FILL_BOTH,
TTK_NODE("Sash.hgrip", TTK_FILL_BOTH)))
TTK_LAYOUT("Vertical.Sash",
TTK_GROUP("Sash.vsash", TTK_FILL_BOTH,
TTK_NODE("Sash.vgrip", TTK_FILL_BOTH)))
TTK_END_LAYOUT_TABLE
/*------------------------------------------------------------------------
* +++ Initialization.
*/
MODULE_SCOPE int
TtkClamTheme_Init(Tcl_Interp *interp)
{
Ttk_Theme theme = Ttk_CreateTheme(interp, "clam", 0);
if (!theme) {
return TCL_ERROR;
}
Ttk_RegisterElement(interp, theme, "border",
&BorderElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "field",
&FieldElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "Combobox.field",
&ComboboxFieldElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "trough",
&TroughElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "thumb",
&ThumbElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "uparrow",
&ArrowElementSpec, &ArrowElements[0]);
Ttk_RegisterElement(interp, theme, "Spinbox.uparrow",
&SpinboxArrowElementSpec, &ArrowElements[0]);
Ttk_RegisterElement(interp, theme, "downarrow",
&ArrowElementSpec, &ArrowElements[1]);
Ttk_RegisterElement(interp, theme, "Spinbox.downarrow",
&SpinboxArrowElementSpec, &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, "Checkbutton.indicator",
&CheckIndicatorElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "Radiobutton.indicator",
&RadioIndicatorElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "Menubutton.indicator",
&MenuIndicatorElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "tab", &TabElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "client", &ClientElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "bar", &PbarElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "pbar", &PbarElementSpec, NULL);
Ttk_RegisterElement(interp, theme, "hgrip",
&GripElementSpec, &GripClientData[0]);
Ttk_RegisterElement(interp, theme, "vgrip",
&GripElementSpec, &GripClientData[1]);
Ttk_RegisterLayouts(theme, LayoutTable);
Tcl_PkgProvide(interp, "ttk::theme::clam", TTK_VERSION);
return TCL_OK;
}