/* $Id: ttkElements.c,v 1.10.2.2 2010/08/26 02:06:09 hobbs Exp $ * * Copyright (c) 2003, Joe English * * Default implementation for themed elements. * */ #include #include #include #include "ttkTheme.h" #include "ttkWidget.h" #define DEFAULT_BORDERWIDTH "2" #define DEFAULT_ARROW_SIZE "15" #define MIN_THUMB_SIZE 10 /*---------------------------------------------------------------------- * +++ Null element. Does nothing; used as a stub. * Null element methods, option table and element spec are public, * and may be used in other engines. */ /* public */ Ttk_ElementOptionSpec TtkNullElementOptions[] = { { NULL, 0, 0, NULL } }; /* public */ void TtkNullElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { } /* public */ void TtkNullElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { } /* public */ Ttk_ElementSpec ttkNullElementSpec = { TK_STYLE_VERSION_2, sizeof(NullElement), TtkNullElementOptions, TtkNullElementSize, TtkNullElementDraw }; /*---------------------------------------------------------------------- * +++ Background and fill elements. * * The fill element fills its parcel with the background color. * The background element ignores the parcel, and fills the entire window. * * Ttk_GetLayout() automatically includes a background element. */ typedef struct { Tcl_Obj *backgroundObj; } BackgroundElement; static Ttk_ElementOptionSpec BackgroundElementOptions[] = { { "-background", TK_OPTION_BORDER, Tk_Offset(BackgroundElement,backgroundObj), DEFAULT_BACKGROUND }, { NULL, 0, 0, NULL } }; static void FillElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { BackgroundElement *bg = elementRecord; Tk_3DBorder backgroundPtr = Tk_Get3DBorderFromObj(tkwin,bg->backgroundObj); XFillRectangle(Tk_Display(tkwin), d, Tk_3DBorderGC(tkwin, backgroundPtr, TK_3D_FLAT_GC), b.x, b.y, b.width, b.height); } static void BackgroundElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { FillElementDraw( clientData, elementRecord, tkwin, d, Ttk_WinBox(tkwin), state); } static Ttk_ElementSpec FillElementSpec = { TK_STYLE_VERSION_2, sizeof(BackgroundElement), BackgroundElementOptions, TtkNullElementSize, FillElementDraw }; static Ttk_ElementSpec BackgroundElementSpec = { TK_STYLE_VERSION_2, sizeof(BackgroundElement), BackgroundElementOptions, TtkNullElementSize, BackgroundElementDraw }; /*---------------------------------------------------------------------- * +++ Border element. */ typedef struct { Tcl_Obj *borderObj; Tcl_Obj *borderWidthObj; Tcl_Obj *reliefObj; } BorderElement; static Ttk_ElementOptionSpec BorderElementOptions[] = { { "-background", TK_OPTION_BORDER, Tk_Offset(BorderElement,borderObj), DEFAULT_BACKGROUND }, { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(BorderElement,borderWidthObj), DEFAULT_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; Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &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 = NULL; int borderWidth = 1, relief = TK_RELIEF_FLAT; border = Tk_Get3DBorderFromObj(tkwin, bd->borderObj); Tcl_GetIntFromObj(NULL, bd->borderWidthObj, &borderWidth); Tk_GetReliefFromObj(NULL, bd->reliefObj, &relief); if (border && borderWidth > 0 && relief != TK_RELIEF_FLAT) { Tk_Draw3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, 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 *borderWidthObj; } FieldElement; static Ttk_ElementOptionSpec FieldElementOptions[] = { { "-fieldbackground", TK_OPTION_BORDER, Tk_Offset(FieldElement,borderObj), "white" }, { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(FieldElement,borderWidthObj), "2" }, { NULL, 0, 0, NULL } }; static void FieldElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { FieldElement *field = elementRecord; int borderWidth = 2; Tk_GetPixelsFromObj(NULL, tkwin, field->borderWidthObj, &borderWidth); *paddingPtr = Ttk_UniformPadding((short)borderWidth); } 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); int borderWidth = 2; Tk_GetPixelsFromObj(NULL, tkwin, field->borderWidthObj, &borderWidth); Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, borderWidth, TK_RELIEF_SUNKEN); } static Ttk_ElementSpec FieldElementSpec = { TK_STYLE_VERSION_2, sizeof(FieldElement), FieldElementOptions, FieldElementSize, FieldElementDraw }; /* *---------------------------------------------------------------------- * +++ Padding element. * * This element has no visual representation, only geometry. * It adds a (possibly non-uniform) internal border. * In addition, if "-shiftrelief" is specified, * adds additional pixels to shift child elements "in" or "out" * depending on the -relief. */ typedef struct { Tcl_Obj *paddingObj; Tcl_Obj *reliefObj; Tcl_Obj *shiftreliefObj; } PaddingElement; static Ttk_ElementOptionSpec PaddingElementOptions[] = { { "-padding", TK_OPTION_STRING, Tk_Offset(PaddingElement,paddingObj), "0" }, { "-relief", TK_OPTION_RELIEF, Tk_Offset(PaddingElement,reliefObj), "flat" }, { "-shiftrelief", TK_OPTION_INT, Tk_Offset(PaddingElement,shiftreliefObj), "0" }, { NULL, 0, 0, NULL } }; static void PaddingElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { PaddingElement *padding = elementRecord; int shiftRelief = 0; int relief = TK_RELIEF_FLAT; Ttk_Padding pad; Tk_GetReliefFromObj(NULL, padding->reliefObj, &relief); Tcl_GetIntFromObj(NULL, padding->shiftreliefObj, &shiftRelief); Ttk_GetPaddingFromObj(NULL,tkwin,padding->paddingObj,&pad); *paddingPtr = Ttk_RelievePadding(pad, relief, shiftRelief); } static Ttk_ElementSpec PaddingElementSpec = { TK_STYLE_VERSION_2, sizeof(PaddingElement), PaddingElementOptions, PaddingElementSize, TtkNullElementDraw }; /*---------------------------------------------------------------------- * +++ Focus ring element. * Draws a dashed focus ring, if the widget has keyboard focus. */ typedef struct { Tcl_Obj *focusColorObj; Tcl_Obj *focusThicknessObj; } FocusElement; /* * DrawFocusRing -- * Draw a dotted rectangle to indicate focus. */ static void DrawFocusRing( Tk_Window tkwin, Drawable d, Tcl_Obj *colorObj, Ttk_Box b) { XColor *color = Tk_GetColorFromObj(tkwin, colorObj); unsigned long mask = 0UL; XGCValues gcvalues; GC gc; gcvalues.foreground = color->pixel; gcvalues.line_style = LineOnOffDash; gcvalues.line_width = 1; gcvalues.dashes = 1; gcvalues.dash_offset = 1; mask = GCForeground | GCLineStyle | GCDashList | GCDashOffset | GCLineWidth; gc = Tk_GetGC(tkwin, mask, &gcvalues); XDrawRectangle(Tk_Display(tkwin), d, gc, b.x, b.y, b.width-1, b.height-1); Tk_FreeGC(Tk_Display(tkwin), gc); } static Ttk_ElementOptionSpec FocusElementOptions[] = { { "-focuscolor",TK_OPTION_COLOR, Tk_Offset(FocusElement,focusColorObj), "black" }, { "-focusthickness",TK_OPTION_PIXELS, Tk_Offset(FocusElement,focusThicknessObj), "1" }, { NULL, 0, 0, NULL } }; static void FocusElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { FocusElement *focus = elementRecord; int focusThickness = 0; Tcl_GetIntFromObj(NULL, focus->focusThicknessObj, &focusThickness); *paddingPtr = Ttk_UniformPadding((short)focusThickness); } static void FocusElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { FocusElement *focus = elementRecord; int focusThickness = 0; if (state & TTK_STATE_FOCUS) { Tcl_GetIntFromObj(NULL,focus->focusThicknessObj,&focusThickness); DrawFocusRing(tkwin, d, focus->focusColorObj, b); } } static Ttk_ElementSpec FocusElementSpec = { TK_STYLE_VERSION_2, sizeof(FocusElement), FocusElementOptions, FocusElementSize, FocusElementDraw }; /*---------------------------------------------------------------------- * +++ Separator element. * Just draws a horizontal or vertical bar. * Three elements are defined: horizontal, vertical, and general; * the general separator checks the "-orient" option. */ typedef struct { Tcl_Obj *orientObj; Tcl_Obj *borderObj; } SeparatorElement; static Ttk_ElementOptionSpec SeparatorElementOptions[] = { { "-orient", TK_OPTION_ANY, Tk_Offset(SeparatorElement, orientObj), "horizontal" }, { "-background", TK_OPTION_BORDER, Tk_Offset(SeparatorElement,borderObj), DEFAULT_BACKGROUND }, { NULL, 0, 0, NULL } }; static void SeparatorElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { *widthPtr = *heightPtr = 2; } static void HorizontalSeparatorElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { SeparatorElement *separator = elementRecord; Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, separator->borderObj); GC lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC); GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC); XDrawLine(Tk_Display(tkwin), d, darkGC, b.x, b.y, b.x + b.width, b.y); XDrawLine(Tk_Display(tkwin), d, lightGC, b.x, b.y+1, b.x + b.width, b.y+1); } static void VerticalSeparatorElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { SeparatorElement *separator = elementRecord; Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, separator->borderObj); GC lightGC = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC); GC darkGC = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC); XDrawLine(Tk_Display(tkwin), d, darkGC, b.x, b.y, b.x, b.y + b.height); XDrawLine(Tk_Display(tkwin), d, lightGC, b.x+1, b.y, b.x+1, b.y+b.height); } static void GeneralSeparatorElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { SeparatorElement *separator = elementRecord; int orient; Ttk_GetOrientFromObj(NULL, separator->orientObj, &orient); switch (orient) { case TTK_ORIENT_HORIZONTAL: HorizontalSeparatorElementDraw( clientData, elementRecord, tkwin, d, b, state); break; case TTK_ORIENT_VERTICAL: VerticalSeparatorElementDraw( clientData, elementRecord, tkwin, d, b, state); break; } } static Ttk_ElementSpec HorizontalSeparatorElementSpec = { TK_STYLE_VERSION_2, sizeof(SeparatorElement), SeparatorElementOptions, SeparatorElementSize, HorizontalSeparatorElementDraw }; static Ttk_ElementSpec VerticalSeparatorElementSpec = { TK_STYLE_VERSION_2, sizeof(SeparatorElement), SeparatorElementOptions, SeparatorElementSize, HorizontalSeparatorElementDraw }; static Ttk_ElementSpec SeparatorElementSpec = { TK_STYLE_VERSION_2, sizeof(SeparatorElement), SeparatorElementOptions, SeparatorElementSize, GeneralSeparatorElementDraw }; /*---------------------------------------------------------------------- * +++ Sizegrip: lower-right corner grip handle for resizing window. */ typedef struct { Tcl_Obj *backgroundObj; } SizegripElement; static Ttk_ElementOptionSpec SizegripOptions[] = { { "-background", TK_OPTION_BORDER, Tk_Offset(SizegripElement,backgroundObj), DEFAULT_BACKGROUND }, {0,0,0,0} }; static void SizegripSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { int gripCount = 3, gripSpace = 2, gripThickness = 3; *widthPtr = *heightPtr = gripCount * (gripSpace + gripThickness); } static void SizegripDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { SizegripElement *grip = elementRecord; int gripCount = 3, gripSpace = 2; 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; 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; } } static Ttk_ElementSpec SizegripElementSpec = { TK_STYLE_VERSION_2, sizeof(SizegripElement), SizegripOptions, SizegripSize, SizegripDraw }; /*---------------------------------------------------------------------- * +++ 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. */ typedef struct { Tcl_Obj *backgroundObj; Tcl_Obj *reliefObj; Tcl_Obj *colorObj; Tcl_Obj *diameterObj; 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" }, { "-indicatormargin", TK_OPTION_STRING, Tk_Offset(IndicatorElement,marginObj), "0 2 4 2" }, { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(IndicatorElement,borderWidthObj), DEFAULT_BORDERWIDTH }, { NULL, 0, 0, NULL } }; /* * Checkbutton indicators (default): 3-D square. */ static void SquareIndicatorElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { IndicatorElement *indicator = elementRecord; Ttk_Padding margins; int diameter = 0; 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 SquareIndicatorElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { 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); Tcl_GetIntFromObj(NULL,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); } /* * Radiobutton indicators: 3-D diamond. */ static void DiamondIndicatorElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { IndicatorElement *indicator = 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( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { IndicatorElement *indicator = elementRecord; Tk_3DBorder border = 0, interior = 0; int borderWidth = 2; int relief = TK_RELIEF_RAISED; int diameter, radius; XPoint points[4]; Ttk_Padding padding; interior = Tk_Get3DBorderFromObj(tkwin, indicator->colorObj); border = Tk_Get3DBorderFromObj(tkwin, indicator->backgroundObj); Tcl_GetIntFromObj(NULL,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; 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; Tk_Fill3DPolygon(tkwin,d,interior,points,4,borderWidth,TK_RELIEF_FLAT); Tk_Draw3DPolygon(tkwin,d,border,points,4,borderWidth,relief); } static Ttk_ElementSpec CheckbuttonIndicatorElementSpec = { TK_STYLE_VERSION_2, sizeof(IndicatorElement), IndicatorElementOptions, SquareIndicatorElementSize, SquareIndicatorElementDraw }; static Ttk_ElementSpec RadiobuttonIndicatorElementSpec = { TK_STYLE_VERSION_2, sizeof(IndicatorElement), IndicatorElementOptions, DiamondIndicatorElementSize, DiamondIndicatorElementDraw }; /* *---------------------------------------------------------------------- * +++ 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. */ typedef struct { Tcl_Obj *backgroundObj; Tcl_Obj *widthObj; Tcl_Obj *heightObj; Tcl_Obj *borderWidthObj; Tcl_Obj *reliefObj; Tcl_Obj *marginObj; } MenuIndicatorElement; 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" }, { "-borderwidth", 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 } }; 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); } 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; 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); } static Ttk_ElementSpec MenuIndicatorElementSpec = { TK_STYLE_VERSION_2, sizeof(MenuIndicatorElement), MenuIndicatorElementOptions, MenuIndicatorElementSize, MenuIndicatorElementDraw }; /*---------------------------------------------------------------------- * +++ Arrow elements. * * 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 *borderObj; Tcl_Obj *borderWidthObj; Tcl_Obj *reliefObj; Tcl_Obj *sizeObj; Tcl_Obj *colorObj; } ArrowElement; static Ttk_ElementOptionSpec ArrowElementOptions[] = { { "-background", TK_OPTION_BORDER, Tk_Offset(ArrowElement,borderObj), DEFAULT_BACKGROUND }, { "-relief",TK_OPTION_RELIEF, Tk_Offset(ArrowElement,reliefObj),"raised"}, { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(ArrowElement,borderWidthObj), "1" }, { "-arrowcolor",TK_OPTION_COLOR, Tk_Offset(ArrowElement,colorObj),"black"}, { "-arrowsize", TK_OPTION_PIXELS, Tk_Offset(ArrowElement,sizeObj), "14" }, { NULL, 0, 0, NULL } }; static Ttk_Padding ArrowMargins = { 3,3,3,3 }; 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 = 14; Tk_GetPixelsFromObj(NULL, tkwin, arrow->sizeObj, &width); width -= Ttk_PaddingWidth(ArrowMargins); TtkArrowSize(width/2, direction, widthPtr, heightPtr); *widthPtr += Ttk_PaddingWidth(ArrowMargins); *heightPtr += Ttk_PaddingWidth(ArrowMargins); } 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 *arrowColor = Tk_GetColorFromObj(tkwin, arrow->colorObj); int relief = TK_RELIEF_RAISED; int borderWidth = 1; Tk_GetReliefFromObj(NULL, arrow->reliefObj, &relief); Tk_Fill3DRectangle( tkwin, d, border, b.x, b.y, b.width, b.height, borderWidth, relief); TtkFillArrow(Tk_Display(tkwin), d, Tk_GCForColor(arrowColor, d), Ttk_PadBox(b, ArrowMargins), direction); } static Ttk_ElementSpec ArrowElementSpec = { TK_STYLE_VERSION_2, sizeof(ArrowElement), ArrowElementOptions, ArrowElementSize, ArrowElementDraw }; /*---------------------------------------------------------------------- * +++ Trough element. * * Used in scrollbars and scales in place of "border". */ typedef struct { Tcl_Obj *colorObj; Tcl_Obj *borderWidthObj; Tcl_Obj *reliefObj; } TroughElement; static Ttk_ElementOptionSpec TroughElementOptions[] = { { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(TroughElement,borderWidthObj), DEFAULT_BORDERWIDTH }, { "-troughcolor", TK_OPTION_BORDER, Tk_Offset(TroughElement,colorObj), DEFAULT_BACKGROUND }, { "-troughrelief",TK_OPTION_RELIEF, Tk_Offset(TroughElement,reliefObj), "sunken" }, { 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; Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth); *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; border = Tk_Get3DBorderFromObj(tkwin, troughPtr->colorObj); Tk_GetReliefFromObj(NULL, troughPtr->reliefObj, &relief); Tk_GetPixelsFromObj(NULL, tkwin, troughPtr->borderWidthObj, &borderWidth); 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. * * Used in scrollbars. */ typedef struct { Tcl_Obj *orientObj; Tcl_Obj *thicknessObj; Tcl_Obj *reliefObj; Tcl_Obj *borderObj; Tcl_Obj *borderWidthObj; } ThumbElement; static Ttk_ElementOptionSpec ThumbElementOptions[] = { { "-orient", TK_OPTION_ANY, Tk_Offset(ThumbElement, orientObj), "horizontal" }, { "-width", TK_OPTION_PIXELS, Tk_Offset(ThumbElement,thicknessObj), DEFAULT_ARROW_SIZE }, { "-relief", TK_OPTION_RELIEF, Tk_Offset(ThumbElement,reliefObj), "raised" }, { "-background", TK_OPTION_BORDER, Tk_Offset(ThumbElement,borderObj), DEFAULT_BACKGROUND }, { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(ThumbElement,borderWidthObj), DEFAULT_BORDERWIDTH }, { 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, thickness; Tk_GetPixelsFromObj(NULL, tkwin, thumb->thicknessObj, &thickness); Ttk_GetOrientFromObj(NULL, thumb->orientObj, &orient); if (orient == TTK_ORIENT_VERTICAL) { *widthPtr = thickness; *heightPtr = MIN_THUMB_SIZE; } else { *widthPtr = MIN_THUMB_SIZE; *heightPtr = thickness; } } 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); int borderWidth = 2, relief = TK_RELIEF_RAISED; Tk_GetPixelsFromObj(NULL, tkwin, thumb->borderWidthObj, &borderWidth); Tk_GetReliefFromObj(NULL, thumb->reliefObj, &relief); Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, 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. Drawn as a raised box. */ 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 */ } 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" }, { "-borderwidth", 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 void SliderElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { SliderElement *slider = elementRecord; int orient, length, thickness; Ttk_GetOrientFromObj(NULL, slider->orientObj, &orient); Tk_GetPixelsFromObj(NULL, tkwin, slider->lengthObj, &length); Tk_GetPixelsFromObj(NULL, tkwin, slider->thicknessObj, &thickness); switch (orient) { case TTK_ORIENT_VERTICAL: *widthPtr = thickness; *heightPtr = length; break; case TTK_ORIENT_HORIZONTAL: *widthPtr = length; *heightPtr = thickness; 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 = NULL; int relief = TK_RELIEF_RAISED, borderWidth = 2, orient; 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); Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, borderWidth, relief); 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); } } } } static Ttk_ElementSpec SliderElementSpec = { TK_STYLE_VERSION_2, sizeof(SliderElement), SliderElementOptions, SliderElementSize, SliderElementDraw }; /*------------------------------------------------------------------------ * +++ Progress bar element: * Draws the moving part of the progress bar. * * -thickness specifies the size along the short axis of the bar. * -length specifies the default size along the long axis; * the bar will be this long in indeterminate mode. */ #define DEFAULT_PBAR_THICKNESS "15" #define DEFAULT_PBAR_LENGTH "30" typedef struct { Tcl_Obj *orientObj; /* widget orientation */ Tcl_Obj *thicknessObj; /* the height/width of the bar */ Tcl_Obj *lengthObj; /* default width/height of the bar */ Tcl_Obj *reliefObj; /* border relief for this object */ Tcl_Obj *borderObj; /* background color */ Tcl_Obj *borderWidthObj; /* thickness of the border */ } PbarElement; static Ttk_ElementOptionSpec PbarElementOptions[] = { { "-orient", TK_OPTION_ANY, Tk_Offset(PbarElement,orientObj), "horizontal" }, { "-thickness", TK_OPTION_PIXELS, Tk_Offset(PbarElement,thicknessObj), DEFAULT_PBAR_THICKNESS }, { "-barsize", TK_OPTION_PIXELS, Tk_Offset(PbarElement,lengthObj), DEFAULT_PBAR_LENGTH }, { "-pbarrelief", TK_OPTION_RELIEF, Tk_Offset(PbarElement,reliefObj), "raised" }, { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(PbarElement,borderWidthObj), DEFAULT_BORDERWIDTH }, { "-background", TK_OPTION_BORDER, Tk_Offset(PbarElement,borderObj), DEFAULT_BACKGROUND }, { NULL, 0, 0, NULL } }; static void PbarElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { PbarElement *pbar = elementRecord; int orient, thickness = 15, length = 30, borderWidth = 2; Ttk_GetOrientFromObj(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); switch (orient) { case TTK_ORIENT_HORIZONTAL: *widthPtr = length + 2 * borderWidth; *heightPtr = thickness + 2 * borderWidth; break; case TTK_ORIENT_VERTICAL: *widthPtr = thickness + 2 * borderWidth; *heightPtr = length + 2 * borderWidth; break; } } static void PbarElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, Ttk_State state) { PbarElement *pbar = elementRecord; Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, pbar->borderObj); int relief = TK_RELIEF_RAISED, borderWidth = 2; Tk_GetPixelsFromObj(NULL, tkwin, pbar->borderWidthObj, &borderWidth); Tk_GetReliefFromObj(NULL, pbar->reliefObj, &relief); Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, borderWidth, relief); } static Ttk_ElementSpec PbarElementSpec = { TK_STYLE_VERSION_2, sizeof(PbarElement), PbarElementOptions, PbarElementSize, PbarElementDraw }; /*------------------------------------------------------------------------ * +++ Notebook tabs and client area. */ typedef struct { Tcl_Obj *borderWidthObj; Tcl_Obj *backgroundObj; } TabElement; static Ttk_ElementOptionSpec TabElementOptions[] = { { "-borderwidth", TK_OPTION_PIXELS, Tk_Offset(TabElement,borderWidthObj),"1" }, { "-background", TK_OPTION_BORDER, Tk_Offset(TabElement,backgroundObj), DEFAULT_BACKGROUND }, {0,0,0,0} }; static void TabElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { TabElement *tab = elementRecord; int borderWidth = 1; Tk_GetPixelsFromObj(0, tkwin, tab->borderWidthObj, &borderWidth); paddingPtr->top = paddingPtr->left = paddingPtr->right = borderWidth; paddingPtr->bottom = 0; } static void TabElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { TabElement *tab = elementRecord; Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, tab->backgroundObj); int borderWidth = 1; int cut = 2; XPoint pts[6]; int n = 0; Tcl_GetIntFromObj(NULL, tab->borderWidthObj, &borderWidth); if (state & TTK_STATE_SELECTED) { /* * Draw slightly outside of the allocated parcel, * to overwrite the client area border. */ b.height += borderWidth; } pts[n].x = b.x; pts[n].y = b.y + b.height - 1; ++n; pts[n].x = b.x; pts[n].y = b.y + cut; ++n; pts[n].x = b.x + cut; pts[n].y = b.y; ++n; pts[n].x = b.x + b.width-1-cut; pts[n].y = b.y; ++n; pts[n].x = b.x + b.width-1; pts[n].y = b.y + cut; ++n; pts[n].x = b.x + b.width-1; pts[n].y = b.y + b.height; ++n; XFillPolygon(Tk_Display(tkwin), d, Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC), pts, 6, Convex, CoordModeOrigin); #ifndef WIN32 /* * Account for whether XDrawLines draws endpoints by platform */ --pts[5].y; #endif while (borderWidth--) { XDrawLines(Tk_Display(tkwin), d, Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC), pts, 4, CoordModeOrigin); XDrawLines(Tk_Display(tkwin), d, Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC), pts+3, 3, CoordModeOrigin); ++pts[0].x; ++pts[1].x; ++pts[2].x; --pts[4].x; --pts[5].x; ++pts[2].y; ++pts[3].y; } } static Ttk_ElementSpec TabElementSpec = { TK_STYLE_VERSION_2, sizeof(TabElement), TabElementOptions, TabElementSize, TabElementDraw }; /* * Client area element: * Uses same resources as tab element. */ typedef TabElement ClientElement; #define ClientElementOptions TabElementOptions static void ClientElementDraw( void *clientData, void *elementRecord, Tk_Window tkwin, Drawable d, Ttk_Box b, unsigned int state) { ClientElement *ce = elementRecord; Tk_3DBorder border = Tk_Get3DBorderFromObj(tkwin, ce->backgroundObj); int borderWidth = 1; Tcl_GetIntFromObj(NULL, ce->borderWidthObj, &borderWidth); Tk_Fill3DRectangle(tkwin, d, border, b.x, b.y, b.width, b.height, borderWidth,TK_RELIEF_RAISED); } static void ClientElementSize( void *clientData, void *elementRecord, Tk_Window tkwin, int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr) { ClientElement *ce = elementRecord; int borderWidth = 1; Tk_GetPixelsFromObj(0, tkwin, ce->borderWidthObj, &borderWidth); *paddingPtr = Ttk_UniformPadding((short)borderWidth); } static Ttk_ElementSpec ClientElementSpec = { TK_STYLE_VERSION_2, sizeof(ClientElement), ClientElementOptions, ClientElementSize, ClientElementDraw }; /*---------------------------------------------------------------------- * TtkElements_Init -- * Register default element implementations. */ MODULE_SCOPE void TtkElements_Init(Tcl_Interp *interp) { Ttk_Theme theme = Ttk_GetDefaultTheme(interp); /* * Elements: */ Ttk_RegisterElement(interp, theme, "background", &BackgroundElementSpec,NULL); Ttk_RegisterElement(interp, theme, "fill", &FillElementSpec, NULL); Ttk_RegisterElement(interp, theme, "border", &BorderElementSpec, NULL); Ttk_RegisterElement(interp, theme, "field", &FieldElementSpec, NULL); Ttk_RegisterElement(interp, theme, "focus", &FocusElementSpec, NULL); Ttk_RegisterElement(interp, theme, "padding", &PaddingElementSpec, NULL); Ttk_RegisterElement(interp, theme, "Checkbutton.indicator", &CheckbuttonIndicatorElementSpec, NULL); Ttk_RegisterElement(interp, theme, "Radiobutton.indicator", &RadiobuttonIndicatorElementSpec, NULL); Ttk_RegisterElement(interp, theme, "Menubutton.indicator", &MenuIndicatorElementSpec, NULL); Ttk_RegisterElement(interp, theme, "indicator", &ttkNullElementSpec,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, "trough", &TroughElementSpec, NULL); Ttk_RegisterElement(interp, theme, "thumb", &ThumbElementSpec, NULL); Ttk_RegisterElement(interp, theme, "slider", &SliderElementSpec, NULL); Ttk_RegisterElement(interp, theme, "pbar", &PbarElementSpec, NULL); Ttk_RegisterElement(interp, theme, "separator", &SeparatorElementSpec, NULL); Ttk_RegisterElement(interp, theme, "hseparator", &HorizontalSeparatorElementSpec, NULL); Ttk_RegisterElement(interp, theme, "vseparator", &VerticalSeparatorElementSpec, NULL); Ttk_RegisterElement(interp, theme, "sizegrip", &SizegripElementSpec, NULL); Ttk_RegisterElement(interp, theme, "tab", &TabElementSpec, NULL); Ttk_RegisterElement(interp, theme, "client", &ClientElementSpec, NULL); /* * Register "default" as a user-loadable theme (for now): */ Tcl_PkgProvide(interp, "ttk::theme::default", TTK_VERSION); } /*EOF*/