Import Tk 8.5.15 (as of svn r89086)
This commit is contained in:
853
generic/ttk/ttkButton.c
Normal file
853
generic/ttk/ttkButton.c
Normal file
@@ -0,0 +1,853 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Joe English
|
||||
*
|
||||
* label, button, checkbutton, radiobutton, and menubutton widgets.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <tk.h>
|
||||
#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 <<NOTE-NULLOPTIONS>> */
|
||||
{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_TAKEFOCUS_FALSE,
|
||||
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[] =
|
||||
{
|
||||
{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_TAKEFOCUS_TRUE,
|
||||
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[] =
|
||||
{
|
||||
{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_TAKEFOCUS_TRUE,
|
||||
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[] =
|
||||
{
|
||||
{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_TAKEFOCUS_TRUE,
|
||||
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[] =
|
||||
{
|
||||
{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_TAKEFOCUS_TRUE,
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user