/* $Id: ttkButton.c,v 1.8.2.1 2010/08/26 02:06:09 hobbs Exp $ * Copyright (c) 2003, Joe English * * label, button, checkbutton, radiobutton, and menubutton widgets. */ #include #include #include "ttkTheme.h" #include "ttkWidget.h" /* Bit fields for OptionSpec mask field: */ #define STATE_CHANGED (0x100) /* -state option changed */ #define DEFAULTSTATE_CHANGED (0x200) /* -default option changed */ /*------------------------------------------------------------------------ * +++ Base resources for labels, buttons, checkbuttons, etc: */ typedef struct { /* * Text element resources: */ Tcl_Obj *textObj; Tcl_Obj *textVariableObj; Tcl_Obj *underlineObj; Tcl_Obj *widthObj; Ttk_TraceHandle *textVariableTrace; Ttk_ImageSpec *imageSpec; /* * Image element resources: */ Tcl_Obj *imageObj; /* * Compound label/image resources: */ Tcl_Obj *compoundObj; Tcl_Obj *paddingObj; /* * Compatibility/legacy options: */ Tcl_Obj *stateObj; } BasePart; typedef struct { WidgetCore core; BasePart base; } Base; static Tk_OptionSpec BaseOptionSpecs[] = { {TK_OPTION_STRING, "-text", "text", "Text", "", Tk_Offset(Base,base.textObj), -1, 0,0,GEOMETRY_CHANGED }, {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable", "", Tk_Offset(Base,base.textVariableObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED }, {TK_OPTION_INT, "-underline", "underline", "Underline", "-1", Tk_Offset(Base,base.underlineObj), -1, 0,0,0 }, /* SB: OPTION_INT, see <> */ {TK_OPTION_STRING, "-width", "width", "Width", NULL, Tk_Offset(Base,base.widthObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED }, /* * Image options */ {TK_OPTION_STRING, "-image", "image", "Image", NULL/*default*/, Tk_Offset(Base,base.imageObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED }, /* * Compound base/image options */ {TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound", "none", Tk_Offset(Base,base.compoundObj), -1, 0,(ClientData)ttkCompoundStrings,GEOMETRY_CHANGED }, {TK_OPTION_STRING, "-padding", "padding", "Pad", NULL, Tk_Offset(Base,base.paddingObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED}, /* * Compatibility/legacy options */ {TK_OPTION_STRING, "-state", "state", "State", "normal", Tk_Offset(Base,base.stateObj), -1, 0,0,STATE_CHANGED }, WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs) }; /* * Variable trace procedure for -textvariable option: */ static void TextVariableChanged(void *clientData, const char *value) { Base *basePtr = clientData; Tcl_Obj *newText; if (WidgetDestroyed(&basePtr->core)) { return; } newText = value ? Tcl_NewStringObj(value, -1) : Tcl_NewStringObj("", 0); Tcl_IncrRefCount(newText); Tcl_DecrRefCount(basePtr->base.textObj); basePtr->base.textObj = newText; TtkResizeWidget(&basePtr->core); } static void BaseInitialize(Tcl_Interp *interp, void *recordPtr) { Base *basePtr = recordPtr; basePtr->base.textVariableTrace = 0; basePtr->base.imageSpec = NULL; } static void BaseCleanup(void *recordPtr) { Base *basePtr = recordPtr; if (basePtr->base.textVariableTrace) Ttk_UntraceVariable(basePtr->base.textVariableTrace); if (basePtr->base.imageSpec) TtkFreeImageSpec(basePtr->base.imageSpec); } static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Base *basePtr = recordPtr; Tcl_Obj *textVarName = basePtr->base.textVariableObj; Ttk_TraceHandle *vt = 0; Ttk_ImageSpec *imageSpec = NULL; if (textVarName != NULL && *Tcl_GetString(textVarName) != '\0') { vt = Ttk_TraceVariable(interp,textVarName,TextVariableChanged,basePtr); if (!vt) return TCL_ERROR; } if (basePtr->base.imageObj) { imageSpec = TtkGetImageSpec( interp, basePtr->core.tkwin, basePtr->base.imageObj); if (!imageSpec) { goto error; } } if (TtkCoreConfigure(interp, recordPtr, mask) != TCL_OK) { error: if (imageSpec) TtkFreeImageSpec(imageSpec); if (vt) Ttk_UntraceVariable(vt); return TCL_ERROR; } if (basePtr->base.textVariableTrace) { Ttk_UntraceVariable(basePtr->base.textVariableTrace); } basePtr->base.textVariableTrace = vt; if (basePtr->base.imageSpec) { TtkFreeImageSpec(basePtr->base.imageSpec); } basePtr->base.imageSpec = imageSpec; if (mask & STATE_CHANGED) { TtkCheckStateOption(&basePtr->core, basePtr->base.stateObj); } return TCL_OK; } static int BasePostConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Base *basePtr = recordPtr; int status = TCL_OK; if (basePtr->base.textVariableTrace) { status = Ttk_FireTrace(basePtr->base.textVariableTrace); } return status; } /*------------------------------------------------------------------------ * +++ Label widget. * Just a base widget that adds a few appearance-related options */ typedef struct { Tcl_Obj *backgroundObj; Tcl_Obj *foregroundObj; Tcl_Obj *fontObj; Tcl_Obj *borderWidthObj; Tcl_Obj *reliefObj; Tcl_Obj *anchorObj; Tcl_Obj *justifyObj; Tcl_Obj *wrapLengthObj; } LabelPart; typedef struct { WidgetCore core; BasePart base; LabelPart label; } Label; static Tk_OptionSpec LabelOptionSpecs[] = { {TK_OPTION_BORDER, "-background", "frameColor", "FrameColor", NULL, Tk_Offset(Label,label.backgroundObj), -1, TK_OPTION_NULL_OK,0,0 }, {TK_OPTION_COLOR, "-foreground", "textColor", "TextColor", NULL, Tk_Offset(Label,label.foregroundObj), -1, TK_OPTION_NULL_OK,0,0 }, {TK_OPTION_FONT, "-font", "font", "Font", NULL, Tk_Offset(Label,label.fontObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED }, {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", NULL, Tk_Offset(Label,label.borderWidthObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED }, {TK_OPTION_RELIEF, "-relief", "relief", "Relief", NULL, Tk_Offset(Label,label.reliefObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED }, {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor", NULL, Tk_Offset(Label,label.anchorObj), -1, TK_OPTION_NULL_OK, 0, GEOMETRY_CHANGED}, {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify", NULL, Tk_Offset(Label, label.justifyObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED }, {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength", NULL, Tk_Offset(Label, label.wrapLengthObj), -1, TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED /*SB: SIZE_CHANGED*/ }, WIDGET_INHERIT_OPTIONS(BaseOptionSpecs) }; static const Ttk_Ensemble LabelCommands[] = { { "configure", TtkWidgetConfigureCommand,0 }, { "cget", TtkWidgetCgetCommand,0 }, { "instate", TtkWidgetInstateCommand,0 }, { "state", TtkWidgetStateCommand,0 }, { "identify", TtkWidgetIdentifyCommand,0 }, { 0,0,0 } }; static WidgetSpec LabelWidgetSpec = { "TLabel", /* className */ sizeof(Label), /* recordSize */ LabelOptionSpecs, /* optionSpecs */ LabelCommands, /* subcommands */ BaseInitialize, /* initializeProc */ BaseCleanup, /* cleanupProc */ BaseConfigure, /* configureProc */ BasePostConfigure, /* postConfigureProc */ TtkWidgetGetLayout, /* getLayoutProc */ TtkWidgetSize, /* sizeProc */ TtkWidgetDoLayout, /* layoutProc */ TtkWidgetDisplay /* displayProc */ }; TTK_BEGIN_LAYOUT(LabelLayout) TTK_GROUP("Label.border", TTK_FILL_BOTH|TTK_BORDER, TTK_GROUP("Label.padding", TTK_FILL_BOTH|TTK_BORDER, TTK_NODE("Label.label", TTK_FILL_BOTH))) TTK_END_LAYOUT /*------------------------------------------------------------------------ * +++ Button widget. * Adds a new subcommand "invoke", and options "-command" and "-default" */ typedef struct { Tcl_Obj *commandObj; Tcl_Obj *defaultStateObj; } ButtonPart; typedef struct { WidgetCore core; BasePart base; ButtonPart button; } Button; /* * Option specifications: */ static Tk_OptionSpec ButtonOptionSpecs[] = { WIDGET_TAKES_FOCUS, {TK_OPTION_STRING, "-command", "command", "Command", "", Tk_Offset(Button, button.commandObj), -1, 0,0,0}, {TK_OPTION_STRING_TABLE, "-default", "default", "Default", "normal", Tk_Offset(Button, button.defaultStateObj), -1, 0, (ClientData) ttkDefaultStrings, DEFAULTSTATE_CHANGED}, WIDGET_INHERIT_OPTIONS(BaseOptionSpecs) }; static int ButtonConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Button *buttonPtr = recordPtr; if (BaseConfigure(interp, recordPtr, mask) != TCL_OK) { return TCL_ERROR; } /* Handle "-default" option: */ if (mask & DEFAULTSTATE_CHANGED) { int defaultState = TTK_BUTTON_DEFAULT_DISABLED; Ttk_GetButtonDefaultStateFromObj( NULL, buttonPtr->button.defaultStateObj, &defaultState); if (defaultState == TTK_BUTTON_DEFAULT_ACTIVE) { TtkWidgetChangeState(&buttonPtr->core, TTK_STATE_ALTERNATE, 0); } else { TtkWidgetChangeState(&buttonPtr->core, 0, TTK_STATE_ALTERNATE); } } return TCL_OK; } /* $button invoke -- * Evaluate the button's -command. */ static int ButtonInvokeCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Button *buttonPtr = recordPtr; if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "invoke"); return TCL_ERROR; } if (buttonPtr->core.state & TTK_STATE_DISABLED) { return TCL_OK; } return Tcl_EvalObjEx(interp, buttonPtr->button.commandObj, TCL_EVAL_GLOBAL); } static const Ttk_Ensemble ButtonCommands[] = { { "configure", TtkWidgetConfigureCommand,0 }, { "cget", TtkWidgetCgetCommand,0 }, { "invoke", ButtonInvokeCommand,0 }, { "instate", TtkWidgetInstateCommand,0 }, { "state", TtkWidgetStateCommand,0 }, { "identify", TtkWidgetIdentifyCommand,0 }, { 0,0,0 } }; static WidgetSpec ButtonWidgetSpec = { "TButton", /* className */ sizeof(Button), /* recordSize */ ButtonOptionSpecs, /* optionSpecs */ ButtonCommands, /* subcommands */ BaseInitialize, /* initializeProc */ BaseCleanup, /* cleanupProc */ ButtonConfigure, /* configureProc */ BasePostConfigure, /* postConfigureProc */ TtkWidgetGetLayout, /* getLayoutProc */ TtkWidgetSize, /* sizeProc */ TtkWidgetDoLayout, /* layoutProc */ TtkWidgetDisplay /* displayProc */ }; TTK_BEGIN_LAYOUT(ButtonLayout) TTK_GROUP("Button.border", TTK_FILL_BOTH|TTK_BORDER, TTK_GROUP("Button.focus", TTK_FILL_BOTH, TTK_GROUP("Button.padding", TTK_FILL_BOTH, TTK_NODE("Button.label", TTK_FILL_BOTH)))) TTK_END_LAYOUT /*------------------------------------------------------------------------ * +++ Checkbutton widget. */ typedef struct { Tcl_Obj *variableObj; Tcl_Obj *onValueObj; Tcl_Obj *offValueObj; Tcl_Obj *commandObj; Ttk_TraceHandle *variableTrace; } CheckbuttonPart; typedef struct { WidgetCore core; BasePart base; CheckbuttonPart checkbutton; } Checkbutton; /* * Option specifications: */ static Tk_OptionSpec CheckbuttonOptionSpecs[] = { WIDGET_TAKES_FOCUS, {TK_OPTION_STRING, "-variable", "variable", "Variable", "", Tk_Offset(Checkbutton, checkbutton.variableObj), -1, TK_OPTION_DONT_SET_DEFAULT,0,0}, {TK_OPTION_STRING, "-onvalue", "onValue", "OnValue", "1", Tk_Offset(Checkbutton, checkbutton.onValueObj), -1, 0,0,0}, {TK_OPTION_STRING, "-offvalue", "offValue", "OffValue", "0", Tk_Offset(Checkbutton, checkbutton.offValueObj), -1, 0,0,0}, {TK_OPTION_STRING, "-command", "command", "Command", "", Tk_Offset(Checkbutton, checkbutton.commandObj), -1, 0,0,0}, WIDGET_INHERIT_OPTIONS(BaseOptionSpecs) }; /* * Variable trace procedure for checkbutton -variable option */ static void CheckbuttonVariableChanged(void *clientData, const char *value) { Checkbutton *checkPtr = clientData; if (WidgetDestroyed(&checkPtr->core)) { return; } if (!value) { TtkWidgetChangeState(&checkPtr->core, TTK_STATE_ALTERNATE, 0); return; } /* else */ TtkWidgetChangeState(&checkPtr->core, 0, TTK_STATE_ALTERNATE); if (!strcmp(value, Tcl_GetString(checkPtr->checkbutton.onValueObj))) { TtkWidgetChangeState(&checkPtr->core, TTK_STATE_SELECTED, 0); } else { TtkWidgetChangeState(&checkPtr->core, 0, TTK_STATE_SELECTED); } } static void CheckbuttonInitialize(Tcl_Interp *interp, void *recordPtr) { Checkbutton *checkPtr = recordPtr; Tcl_Obj *variableObj; /* default -variable is the widget name: */ variableObj = Tcl_NewStringObj(Tk_PathName(checkPtr->core.tkwin), -1); Tcl_IncrRefCount(variableObj); checkPtr->checkbutton.variableObj = variableObj; BaseInitialize(interp, recordPtr); } static void CheckbuttonCleanup(void *recordPtr) { Checkbutton *checkPtr = recordPtr; Ttk_UntraceVariable(checkPtr->checkbutton.variableTrace); checkPtr->checkbutton.variableTrace = 0; BaseCleanup(recordPtr); } static int CheckbuttonConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Checkbutton *checkPtr = recordPtr; Ttk_TraceHandle *vt = Ttk_TraceVariable( interp, checkPtr->checkbutton.variableObj, CheckbuttonVariableChanged, checkPtr); if (!vt) { return TCL_ERROR; } if (BaseConfigure(interp, recordPtr, mask) != TCL_OK){ Ttk_UntraceVariable(vt); return TCL_ERROR; } Ttk_UntraceVariable(checkPtr->checkbutton.variableTrace); checkPtr->checkbutton.variableTrace = vt; return TCL_OK; } static int CheckbuttonPostConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Checkbutton *checkPtr = recordPtr; int status = TCL_OK; if (checkPtr->checkbutton.variableTrace) status = Ttk_FireTrace(checkPtr->checkbutton.variableTrace); if (status == TCL_OK && !WidgetDestroyed(&checkPtr->core)) status = BasePostConfigure(interp, recordPtr, mask); return status; } /* * Checkbutton 'invoke' subcommand: * Toggles the checkbutton state. */ static int CheckbuttonInvokeCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Checkbutton *checkPtr = recordPtr; WidgetCore *corePtr = &checkPtr->core; Tcl_Obj *newValue; if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "invoke"); return TCL_ERROR; } if (corePtr->state & TTK_STATE_DISABLED) return TCL_OK; /* * Toggle the selected state. */ if (corePtr->state & TTK_STATE_SELECTED) newValue = checkPtr->checkbutton.offValueObj; else newValue = checkPtr->checkbutton.onValueObj; if (Tcl_ObjSetVar2(interp, checkPtr->checkbutton.variableObj, NULL, newValue, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) return TCL_ERROR; if (WidgetDestroyed(corePtr)) return TCL_ERROR; return Tcl_EvalObjEx(interp, checkPtr->checkbutton.commandObj, TCL_EVAL_GLOBAL); } static const Ttk_Ensemble CheckbuttonCommands[] = { { "configure", TtkWidgetConfigureCommand,0 }, { "cget", TtkWidgetCgetCommand,0 }, { "invoke", CheckbuttonInvokeCommand,0 }, { "instate", TtkWidgetInstateCommand,0 }, { "state", TtkWidgetStateCommand,0 }, { "identify", TtkWidgetIdentifyCommand,0 }, /* MISSING: select, deselect, toggle */ { 0,0,0 } }; static WidgetSpec CheckbuttonWidgetSpec = { "TCheckbutton", /* className */ sizeof(Checkbutton), /* recordSize */ CheckbuttonOptionSpecs, /* optionSpecs */ CheckbuttonCommands, /* subcommands */ CheckbuttonInitialize, /* initializeProc */ CheckbuttonCleanup, /* cleanupProc */ CheckbuttonConfigure, /* configureProc */ CheckbuttonPostConfigure, /* postConfigureProc */ TtkWidgetGetLayout, /* getLayoutProc */ TtkWidgetSize, /* sizeProc */ TtkWidgetDoLayout, /* layoutProc */ TtkWidgetDisplay /* displayProc */ }; TTK_BEGIN_LAYOUT(CheckbuttonLayout) TTK_GROUP("Checkbutton.padding", TTK_FILL_BOTH, TTK_NODE("Checkbutton.indicator", TTK_PACK_LEFT) TTK_GROUP("Checkbutton.focus", TTK_PACK_LEFT | TTK_STICK_W, TTK_NODE("Checkbutton.label", TTK_FILL_BOTH))) TTK_END_LAYOUT /*------------------------------------------------------------------------ * +++ Radiobutton widget. */ typedef struct { Tcl_Obj *variableObj; Tcl_Obj *valueObj; Tcl_Obj *commandObj; Ttk_TraceHandle *variableTrace; } RadiobuttonPart; typedef struct { WidgetCore core; BasePart base; RadiobuttonPart radiobutton; } Radiobutton; /* * Option specifications: */ static Tk_OptionSpec RadiobuttonOptionSpecs[] = { WIDGET_TAKES_FOCUS, {TK_OPTION_STRING, "-variable", "variable", "Variable", "::selectedButton", Tk_Offset(Radiobutton, radiobutton.variableObj),-1, 0,0,0}, {TK_OPTION_STRING, "-value", "Value", "Value", "1", Tk_Offset(Radiobutton, radiobutton.valueObj), -1, 0,0,0}, {TK_OPTION_STRING, "-command", "command", "Command", "", Tk_Offset(Radiobutton, radiobutton.commandObj), -1, 0,0,0}, WIDGET_INHERIT_OPTIONS(BaseOptionSpecs) }; /* * Variable trace procedure for radiobuttons. */ static void RadiobuttonVariableChanged(void *clientData, const char *value) { Radiobutton *radioPtr = clientData; if (WidgetDestroyed(&radioPtr->core)) { return; } if (!value) { TtkWidgetChangeState(&radioPtr->core, TTK_STATE_ALTERNATE, 0); return; } /* else */ TtkWidgetChangeState(&radioPtr->core, 0, TTK_STATE_ALTERNATE); if (!strcmp(value, Tcl_GetString(radioPtr->radiobutton.valueObj))) { TtkWidgetChangeState(&radioPtr->core, TTK_STATE_SELECTED, 0); } else { TtkWidgetChangeState(&radioPtr->core, 0, TTK_STATE_SELECTED); } } static void RadiobuttonCleanup(void *recordPtr) { Radiobutton *radioPtr = recordPtr; Ttk_UntraceVariable(radioPtr->radiobutton.variableTrace); radioPtr->radiobutton.variableTrace = 0; BaseCleanup(recordPtr); } static int RadiobuttonConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Radiobutton *radioPtr = recordPtr; Ttk_TraceHandle *vt = Ttk_TraceVariable( interp, radioPtr->radiobutton.variableObj, RadiobuttonVariableChanged, radioPtr); if (!vt) { return TCL_ERROR; } if (BaseConfigure(interp, recordPtr, mask) != TCL_OK) { Ttk_UntraceVariable(vt); return TCL_ERROR; } Ttk_UntraceVariable(radioPtr->radiobutton.variableTrace); radioPtr->radiobutton.variableTrace = vt; return TCL_OK; } static int RadiobuttonPostConfigure(Tcl_Interp *interp, void *recordPtr, int mask) { Radiobutton *radioPtr = recordPtr; int status = TCL_OK; if (radioPtr->radiobutton.variableTrace) status = Ttk_FireTrace(radioPtr->radiobutton.variableTrace); if (status == TCL_OK && !WidgetDestroyed(&radioPtr->core)) status = BasePostConfigure(interp, recordPtr, mask); return status; } /* * Radiobutton 'invoke' subcommand: * Sets the radiobutton -variable to the -value, evaluates the -command. */ static int RadiobuttonInvokeCommand( void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Radiobutton *radioPtr = recordPtr; WidgetCore *corePtr = &radioPtr->core; if (objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "invoke"); return TCL_ERROR; } if (corePtr->state & TTK_STATE_DISABLED) return TCL_OK; if (Tcl_ObjSetVar2(interp, radioPtr->radiobutton.variableObj, NULL, radioPtr->radiobutton.valueObj, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) return TCL_ERROR; if (WidgetDestroyed(corePtr)) return TCL_ERROR; return Tcl_EvalObjEx(interp, radioPtr->radiobutton.commandObj, TCL_EVAL_GLOBAL); } static const Ttk_Ensemble RadiobuttonCommands[] = { { "configure", TtkWidgetConfigureCommand,0 }, { "cget", TtkWidgetCgetCommand,0 }, { "invoke", RadiobuttonInvokeCommand,0 }, { "instate", TtkWidgetInstateCommand,0 }, { "state", TtkWidgetStateCommand,0 }, { "identify", TtkWidgetIdentifyCommand,0 }, /* MISSING: select, deselect */ { 0,0,0 } }; static WidgetSpec RadiobuttonWidgetSpec = { "TRadiobutton", /* className */ sizeof(Radiobutton), /* recordSize */ RadiobuttonOptionSpecs, /* optionSpecs */ RadiobuttonCommands, /* subcommands */ BaseInitialize, /* initializeProc */ RadiobuttonCleanup, /* cleanupProc */ RadiobuttonConfigure, /* configureProc */ RadiobuttonPostConfigure, /* postConfigureProc */ TtkWidgetGetLayout, /* getLayoutProc */ TtkWidgetSize, /* sizeProc */ TtkWidgetDoLayout, /* layoutProc */ TtkWidgetDisplay /* displayProc */ }; TTK_BEGIN_LAYOUT(RadiobuttonLayout) TTK_GROUP("Radiobutton.padding", TTK_FILL_BOTH, TTK_NODE("Radiobutton.indicator", TTK_PACK_LEFT) TTK_GROUP("Radiobutton.focus", TTK_PACK_LEFT, TTK_NODE("Radiobutton.label", TTK_FILL_BOTH))) TTK_END_LAYOUT /*------------------------------------------------------------------------ * +++ Menubutton widget. */ typedef struct { Tcl_Obj *menuObj; Tcl_Obj *directionObj; } MenubuttonPart; typedef struct { WidgetCore core; BasePart base; MenubuttonPart menubutton; } Menubutton; /* * Option specifications: */ static const char *const directionStrings[] = { "above", "below", "left", "right", "flush", NULL }; static Tk_OptionSpec MenubuttonOptionSpecs[] = { WIDGET_TAKES_FOCUS, {TK_OPTION_STRING, "-menu", "menu", "Menu", "", Tk_Offset(Menubutton, menubutton.menuObj), -1, 0,0,0}, {TK_OPTION_STRING_TABLE, "-direction", "direction", "Direction", "below", Tk_Offset(Menubutton, menubutton.directionObj), -1, 0,(ClientData)directionStrings,GEOMETRY_CHANGED}, WIDGET_INHERIT_OPTIONS(BaseOptionSpecs) }; static const Ttk_Ensemble MenubuttonCommands[] = { { "configure", TtkWidgetConfigureCommand,0 }, { "cget", TtkWidgetCgetCommand,0 }, { "instate", TtkWidgetInstateCommand,0 }, { "state", TtkWidgetStateCommand,0 }, { "identify", TtkWidgetIdentifyCommand,0 }, { 0,0,0 } }; static WidgetSpec MenubuttonWidgetSpec = { "TMenubutton", /* className */ sizeof(Menubutton), /* recordSize */ MenubuttonOptionSpecs, /* optionSpecs */ MenubuttonCommands, /* subcommands */ BaseInitialize, /* initializeProc */ BaseCleanup, /* cleanupProc */ BaseConfigure, /* configureProc */ BasePostConfigure, /* postConfigureProc */ TtkWidgetGetLayout, /* getLayoutProc */ TtkWidgetSize, /* sizeProc */ TtkWidgetDoLayout, /* layoutProc */ TtkWidgetDisplay /* displayProc */ }; TTK_BEGIN_LAYOUT(MenubuttonLayout) TTK_GROUP("Menubutton.border", TTK_FILL_BOTH, TTK_GROUP("Menubutton.focus", TTK_FILL_BOTH, TTK_NODE("Menubutton.indicator", TTK_PACK_RIGHT) TTK_GROUP("Menubutton.padding", TTK_PACK_LEFT|TTK_EXPAND|TTK_FILL_X, TTK_NODE("Menubutton.label", TTK_PACK_LEFT)))) TTK_END_LAYOUT /*------------------------------------------------------------------------ * +++ Initialization. */ MODULE_SCOPE void TtkButton_Init(Tcl_Interp *interp) { Ttk_Theme theme = Ttk_GetDefaultTheme(interp); Ttk_RegisterLayout(theme, "TLabel", LabelLayout); Ttk_RegisterLayout(theme, "TButton", ButtonLayout); Ttk_RegisterLayout(theme, "TCheckbutton", CheckbuttonLayout); Ttk_RegisterLayout(theme, "TRadiobutton", RadiobuttonLayout); Ttk_RegisterLayout(theme, "TMenubutton", MenubuttonLayout); RegisterWidget(interp, "ttk::label", &LabelWidgetSpec); RegisterWidget(interp, "ttk::button", &ButtonWidgetSpec); RegisterWidget(interp, "ttk::checkbutton", &CheckbuttonWidgetSpec); RegisterWidget(interp, "ttk::radiobutton", &RadiobuttonWidgetSpec); RegisterWidget(interp, "ttk::menubutton", &MenubuttonWidgetSpec); }