diff options
author | hobbs <hobbs> | 2006-10-31 01:42:25 (GMT) |
---|---|---|
committer | hobbs <hobbs> | 2006-10-31 01:42:25 (GMT) |
commit | 397a2c9832bf618f26be267501cf49ab06a562ec (patch) | |
tree | 61d5e957eccfcba57b0dd27ebc73db085385834e /generic/ttk/ttkWidget.c | |
parent | 18d330543869e240c2bd12fc9fbb8d5027f5cad6 (diff) | |
download | tk-397a2c9832bf618f26be267501cf49ab06a562ec.zip tk-397a2c9832bf618f26be267501cf49ab06a562ec.tar.gz tk-397a2c9832bf618f26be267501cf49ab06a562ec.tar.bz2 |
* doc/ttk_Geometry.3, doc/ttk_Theme.3, doc/ttk_button.n:
* doc/ttk_checkbutton.n, doc/ttk_combobox.n, doc/ttk_dialog.n:
* doc/ttk_entry.n, doc/ttk_frame.n, doc/ttk_image.n:
* doc/ttk_intro.n, doc/ttk_label.n, doc/ttk_labelframe.n:
* doc/ttk_menubutton.n, doc/ttk_notebook.n, doc/ttk_panedwindow.n:
* doc/ttk_progressbar.n, doc/ttk_radiobutton.n, doc/ttk_scrollbar.n:
* doc/ttk_separator.n, doc/ttk_sizegrip.n, doc/ttk_style.n:
* doc/ttk_treeview.n, doc/ttk_widget.n,:
* generic/ttk/ttk.decls, generic/ttk/ttkBlink.c:
* generic/ttk/ttkButton.c, generic/ttk/ttkCache.c:
* generic/ttk/ttkClamTheme.c, generic/ttk/ttkClassicTheme.c:
* generic/ttk/ttkDecls.h, generic/ttk/ttkDefaultTheme.c:
* generic/ttk/ttkElements.c, generic/ttk/ttkEntry.c:
* generic/ttk/ttkFrame.c, generic/ttk/ttkImage.c:
* generic/ttk/ttkInit.c, generic/ttk/ttkLabel.c:
* generic/ttk/ttkLayout.c, generic/ttk/ttkManager.c:
* generic/ttk/ttkManager.h, generic/ttk/ttkNotebook.c:
* generic/ttk/ttkPanedwindow.c, generic/ttk/ttkProgress.c:
* generic/ttk/ttkScale.c, generic/ttk/ttkScroll.c:
* generic/ttk/ttkScrollbar.c, generic/ttk/ttkSeparator.c:
* generic/ttk/ttkSquare.c, generic/ttk/ttkState.c:
* generic/ttk/ttkStubInit.c, generic/ttk/ttkStubLib.c:
* generic/ttk/ttkTagSet.c, generic/ttk/ttkTheme.c:
* generic/ttk/ttkTheme.h, generic/ttk/ttkThemeInt.h:
* generic/ttk/ttkTrace.c, generic/ttk/ttkTrack.c:
* generic/ttk/ttkTreeview.c, generic/ttk/ttkWidget.c:
* generic/ttk/ttkWidget.h:
* library/demos/ttk_demo.tcl, library/demos/ttk_iconlib.tcl:
* library/demos/ttk_repeater.tcl:
* library/ttk/altTheme.tcl, library/ttk/aquaTheme.tcl:
* library/ttk/button.tcl, library/ttk/clamTheme.tcl:
* library/ttk/classicTheme.tcl, library/ttk/combobox.tcl:
* library/ttk/cursors.tcl, library/ttk/defaults.tcl:
* library/ttk/dialog.tcl, library/ttk/entry.tcl:
* library/ttk/fonts.tcl, library/ttk/icons.tcl:
* library/ttk/keynav.tcl, library/ttk/menubutton.tcl:
* library/ttk/notebook.tcl, library/ttk/panedwindow.tcl:
* library/ttk/progress.tcl, library/ttk/scale.tcl:
* library/ttk/scrollbar.tcl, library/ttk/sizegrip.tcl:
* library/ttk/treeview.tcl, library/ttk/ttk.tcl:
* library/ttk/utils.tcl, library/ttk/winTheme.tcl:
* library/ttk/xpTheme.tcl:
* macosx/ttkMacOSXTheme.c:
* tests/ttk/all.tcl, tests/ttk/bwidget.test, tests/ttk/combobox.test:
* tests/ttk/entry.test, tests/ttk/image.test:
* tests/ttk/labelframe.test, tests/ttk/layout.test:
* tests/ttk/misc.test, tests/ttk/notebook.test:
* tests/ttk/panedwindow.test, tests/ttk/progressbar.test:
* tests/ttk/scrollbar.test, tests/ttk/treetags.test:
* tests/ttk/treeview.test, tests/ttk/ttk.test, tests/ttk/validate.test:
* win/ttkWinMonitor.c, win/ttkWinTheme.c, win/ttkWinXPTheme.c:
First import of Ttk themed Tk widgets as branched from tile 0.7.8
* generic/tkInt.h, generic/tkWindow.c: add Ttk_Init call, copy
tk classic widgets to ::tk namespace.
* library/tk.tcl: add source of ttk/ttk.tcl, define $::ttk::library.
* unix/Makefile.in, win/Makefile.in: add Ttk build bits
* win/configure, win/configure.in: check for uxtheme.h (XP theme).
Diffstat (limited to 'generic/ttk/ttkWidget.c')
-rw-r--r-- | generic/ttk/ttkWidget.c | 786 |
1 files changed, 786 insertions, 0 deletions
diff --git a/generic/ttk/ttkWidget.c b/generic/ttk/ttkWidget.c new file mode 100644 index 0000000..6f4e56f --- /dev/null +++ b/generic/ttk/ttkWidget.c @@ -0,0 +1,786 @@ +/* $Id: ttkWidget.c,v 1.1 2006/10/31 01:42:26 hobbs Exp $ + * Copyright (c) 2003, Joe English + * + * Ttk widget implementation, core widget utilities. + * + */ + +#include <string.h> +#include <tk.h> +#include "ttkTheme.h" +#include "ttkWidget.h" + +/*------------------------------------------------------------------------ + * Helper routines. + */ + +static void UpdateLayout(Tcl_Interp *interp, WidgetCore *corePtr) +{ + Ttk_Theme themePtr = Ttk_GetCurrentTheme(interp); + Ttk_Layout newLayout = + corePtr->widgetSpec->getLayoutProc(interp, themePtr,corePtr); + + /* TODO: @@@ Check for errors */ + if (newLayout) { + if (corePtr->layout) { + Ttk_FreeLayout(corePtr->layout); + } + corePtr->layout = newLayout; + } +} + +static void UpdateGeometry(WidgetCore *corePtr) +{ + int reqWidth = 1, reqHeight = 1; + + if (corePtr->widgetSpec->sizeProc(corePtr,&reqWidth,&reqHeight)) { + Tk_GeometryRequest(corePtr->tkwin, reqWidth, reqHeight); + } +} + +/* + * RedisplayWidget -- + * Redraw a widget. Called as an idle handler. + */ + +static void RedisplayWidget(ClientData recordPtr) +{ + WidgetCore *corePtr = (WidgetCore *)recordPtr; + Tk_Window tkwin = corePtr->tkwin; + Drawable d; + XGCValues gcValues; + GC gc; + + corePtr->flags &= ~REDISPLAY_PENDING; + if (!Tk_IsMapped(tkwin)) { + return; + } + + /* + * Get a Pixmap for drawing in the background: + */ + d = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), + Tk_Width(tkwin), Tk_Height(tkwin), + DefaultDepthOfScreen(Tk_Screen(tkwin))); + + /* + * Get a GC for blitting the pixmap to the display: + */ + gcValues.function = GXcopy; + gcValues.graphics_exposures = False; + gc = Tk_GetGC(corePtr->tkwin, GCFunction|GCGraphicsExposures, &gcValues); + + /* + * Recompute layout and draw widget contents: + */ + corePtr->widgetSpec->layoutProc(recordPtr); + corePtr->widgetSpec->displayProc(recordPtr, d); + + /* + * Copy to the screen. + */ + XCopyArea(Tk_Display(tkwin), d, Tk_WindowId(tkwin), gc, + 0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin), + 0, 0); + + /* + * Release resources + */ + Tk_FreePixmap(Tk_Display(tkwin), d); + Tk_FreeGC(Tk_Display(tkwin), gc); +} + +/* TtkRedisplayWidget -- + * Schedule redisplay as an idle handler. + */ + +void TtkRedisplayWidget(WidgetCore *corePtr) +{ + if (corePtr->flags & WIDGET_DESTROYED) { + return; + } + + if (!(corePtr->flags & REDISPLAY_PENDING)) { + Tcl_DoWhenIdle(RedisplayWidget, (ClientData) corePtr); + corePtr->flags |= REDISPLAY_PENDING; + } +} + +/* TtkResizeWidget -- + * Recompute widget size, schedule geometry propagation and redisplay. + */ + +void TtkResizeWidget(WidgetCore *corePtr) +{ + if (corePtr->flags & WIDGET_DESTROYED) { + return; + } + + UpdateGeometry(corePtr); + TtkRedisplayWidget(corePtr); +} + +/* WidgetEnsembleCommand -- + * Invoke an ensemble defined by a WidgetCommandSpec. + */ +int WidgetEnsembleCommand( + WidgetCommandSpec *commands, /* Ensemble definition */ + int cmdIndex, /* Index of command word */ + Tcl_Interp *interp, /* Interpreter to use */ + int objc, Tcl_Obj *const objv[], /* Argument vector */ + void *clientData) /* User data (widget record pointer) */ +{ + int index; + + if (objc <= cmdIndex) { + Tcl_WrongNumArgs(interp, cmdIndex, objv, "option ?arg arg...?"); + return TCL_ERROR; + } + if (Tcl_GetIndexFromObjStruct(interp, objv[cmdIndex], commands, + sizeof(commands[0]), "command", 0, &index) != TCL_OK) + { + return TCL_ERROR; + } + return commands[index].command(interp, objc, objv, clientData); +} + +/* + * WidgetInstanceObjCmd -- + * Widget instance command implementation. + */ +static int +WidgetInstanceObjCmd( + ClientData clientData, /* Widget record pointer */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj * CONST objv[]) /* Argument objects. */ +{ + WidgetCore *corePtr = (WidgetCore *)clientData; + WidgetCommandSpec *commands = corePtr->widgetSpec->commands; + int status = TCL_OK; + + Tcl_Preserve(clientData); + status = WidgetEnsembleCommand(commands, 1, interp, objc, objv, clientData); + Tcl_Release(clientData); + + return status; +} + +/* + * Command deletion callback for widget instance commands. + */ +static void +WidgetInstanceObjCmdDeleted(ClientData clientData) +{ + WidgetCore *corePtr = (WidgetCore *) clientData; + corePtr->widgetCmd = NULL; + if (corePtr->tkwin != NULL) + Tk_DestroyWindow(corePtr->tkwin); +} + +/* + * WidgetCleanup -- + * Final cleanup for widget. + * + * @@@ TODO: check all code paths leading to widget destruction, + * @@@ describe here. + * @@@ Call widget-specific cleanup routine at an appropriate point. + */ +static void +WidgetCleanup(char *memPtr) +{ + ckfree(memPtr); +} + +/* + * CoreEventProc -- + * Event handler for basic events. + * Processes Expose, Configure, FocusIn/Out, and Destroy events. + * Also handles <<ThemeChanged>> virtual events. + * + * For Expose and Configure, simply schedule the widget for redisplay. + * For Destroy events, handle the cleanup process. + * + * For Focus events, set/clear the focus bit in the state field. + * It turns out this is impossible to do correctly in a binding script, + * because Tk filters out focus events with detail == NotifyInferior. + * + * For Deactivate/Activate pseudo-events, clear/set the background state flag. + * + * <<NOTE-REALIZED>> On the first ConfigureNotify event + * (which indicates that the window has just been created), + * update the layout. This is to work around two problems: + * (1) Virtual events aren't delivered to unrealized widgets + * (see bug #835997), so any intervening <<ThemeChanged>> events + * will not have been processed. + * + * (2) Geometry calculations in the XP theme don't work + * until the widget is realized. + */ + +static const unsigned CoreEventMask + = ExposureMask + | StructureNotifyMask + | FocusChangeMask + | VirtualEventMask + | ActivateMask + ; + +static void CoreEventProc(ClientData clientData, XEvent *eventPtr) +{ + WidgetCore *corePtr = (WidgetCore *) clientData; + + switch (eventPtr->type) + { + case ConfigureNotify : + if (!(corePtr->flags & WIDGET_REALIZED)) { + /* See <<NOTE-REALIZED>> */ + UpdateLayout(corePtr->interp, corePtr); + UpdateGeometry(corePtr); + corePtr->flags |= WIDGET_REALIZED; + } + TtkRedisplayWidget(corePtr); + break; + case Expose : + if (eventPtr->xexpose.count == 0) { + TtkRedisplayWidget(corePtr); + } + break; + case DestroyNotify : + corePtr->flags |= WIDGET_DESTROYED; + + Tk_DeleteEventHandler(corePtr->tkwin, + CoreEventMask,CoreEventProc,clientData); + + if (corePtr->flags & REDISPLAY_PENDING) { + Tcl_CancelIdleCall(RedisplayWidget, clientData); + } + + corePtr->widgetSpec->cleanupProc(corePtr); + + Tk_FreeConfigOptions( + clientData, corePtr->optionTable, corePtr->tkwin); + corePtr->tkwin = NULL; + + if (corePtr->layout) { + Ttk_FreeLayout(corePtr->layout); + } + + /* NB: this can reenter the interpreter via a command traces */ + if (corePtr->widgetCmd) { + Tcl_Command cmd = corePtr->widgetCmd; + corePtr->widgetCmd = 0; + Tcl_DeleteCommandFromToken(corePtr->interp, cmd); + } + Tcl_EventuallyFree(clientData, WidgetCleanup); + break; + + case FocusIn: + case FocusOut: + /* Don't process "virtual crossing" events */ + if ( eventPtr->xfocus.detail == NotifyInferior + || eventPtr->xfocus.detail == NotifyAncestor + || eventPtr->xfocus.detail == NotifyNonlinear) + { + if (eventPtr->type == FocusIn) + corePtr->state |= TTK_STATE_FOCUS; + else + corePtr->state &= ~TTK_STATE_FOCUS; + TtkRedisplayWidget(corePtr); + } + break; + case ActivateNotify: + corePtr->state &= ~TTK_STATE_BACKGROUND; + TtkRedisplayWidget(corePtr); + break; + case DeactivateNotify: + corePtr->state |= TTK_STATE_BACKGROUND; + TtkRedisplayWidget(corePtr); + break; + case VirtualEvent: + if (!strcmp("ThemeChanged", ((XVirtualEvent *)(eventPtr))->name)) { + UpdateLayout(corePtr->interp, corePtr); + UpdateGeometry(corePtr); + TtkRedisplayWidget(corePtr); + } + default: + /* can't happen... */ + break; + } +} + +/* + * WidgetWorldChanged -- + * Default Tk_ClassWorldChangedProc() for widgets. + * Invoked whenever fonts or other system resources are changed; + * recomputes geometry. + */ +static void WidgetWorldChanged(ClientData clientData) +{ + WidgetCore *corePtr = (WidgetCore*)clientData; + UpdateGeometry(corePtr); + TtkRedisplayWidget(corePtr); +} + +static struct Tk_ClassProcs widgetClassProcs = { + sizeof(Tk_ClassProcs), + WidgetWorldChanged +}; + +/* + * WidgetConstructorObjCmd -- + * General-purpose widget constructor command implementation. + * ClientData is a WidgetSpec *. + */ +int WidgetConstructorObjCmd( + ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) +{ + WidgetSpec *widgetSpec = (WidgetSpec *)clientData; + const char *className = widgetSpec->className; + WidgetCore *corePtr; + ClientData recordPtr; + Tk_Window tkwin; + Tk_OptionTable optionTable; + int i; + + if (objc < 2 || objc % 1 == 1) { + Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?"); + return TCL_ERROR; + } + + tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp), + Tcl_GetStringFromObj(objv[1], NULL), (char *) NULL); + if (tkwin == NULL) + return TCL_ERROR; + + /* + * Check if a -class resource has been specified: + * We have to do this before the InitOptions() call, + * since InitOptions() is affected by the widget class. + */ + for (i = 2; i < objc; i += 2) { + const char *resourceName = Tcl_GetString(objv[i]); + if (!strcmp(resourceName, "-class")) { + className = Tcl_GetString(objv[i+1]); + break; + } + } + + Tk_SetClass(tkwin, className); + + /* + * Set the BackgroundPixmap to ParentRelative here, so + * subclasses don't need to worry about setting the background. + */ + Tk_SetWindowBackgroundPixmap(tkwin, ParentRelative); + + optionTable = Tk_CreateOptionTable(interp, widgetSpec->optionSpecs); + + /* + * Allocate and initialize the widget record. + */ + recordPtr = ckalloc(widgetSpec->recordSize); + memset(recordPtr, 0, widgetSpec->recordSize); + corePtr = (WidgetCore *)recordPtr; + + corePtr->tkwin = tkwin; + corePtr->interp = interp; + corePtr->widgetSpec = widgetSpec; + corePtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(tkwin), + WidgetInstanceObjCmd, recordPtr, WidgetInstanceObjCmdDeleted); + corePtr->optionTable = optionTable; + + Tk_SetClassProcs(tkwin, &widgetClassProcs, recordPtr); + + if (Tk_InitOptions(interp, recordPtr, optionTable, tkwin) != TCL_OK) + goto error; + + if (widgetSpec->initializeProc(interp, recordPtr) != TCL_OK) + goto error; + + if (Tk_SetOptions(interp, recordPtr, optionTable, objc - 2, + objv + 2, tkwin, NULL/*savePtr*/, (int *)NULL/*maskPtr*/) != TCL_OK) + goto error; + + if (widgetSpec->configureProc(interp, recordPtr, ~0) != TCL_OK) + goto error; + + if (widgetSpec->postConfigureProc(interp, recordPtr, ~0) != TCL_OK) + goto error; + + if (WidgetDestroyed(corePtr)) + goto error; + + UpdateLayout(interp, corePtr); + UpdateGeometry(corePtr); + + Tk_CreateEventHandler(tkwin, CoreEventMask, CoreEventProc, recordPtr); + + Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(tkwin), -1)); + + return TCL_OK; + +error: + if (corePtr->layout) { + Ttk_FreeLayout(corePtr->layout); + corePtr->layout = 0; + } + Tk_FreeConfigOptions(recordPtr, optionTable, tkwin); + Tk_DestroyWindow(tkwin); + corePtr->tkwin = 0; + Tcl_DeleteCommandFromToken(interp, corePtr->widgetCmd); + ckfree(recordPtr); + return TCL_ERROR; +} + +/* + * WidgetChangeState -- + * Set / clear the specified bits in the 'state' flag, + */ +void WidgetChangeState(WidgetCore *corePtr, + unsigned int setBits, unsigned int clearBits) +{ + Ttk_State oldState = corePtr->state; + corePtr->state = (oldState & ~clearBits) | setBits; + if (corePtr->state ^ oldState) { + TtkRedisplayWidget(corePtr); + } +} + +/* + * WidgetGetLayout -- + * Default getLayoutProc. + * Looks up the layout based on the -style resource (if specified), + * otherwise use the widget class. + */ +Ttk_Layout WidgetGetLayout( + Tcl_Interp *interp, Ttk_Theme themePtr, void *recordPtr) +{ + WidgetCore *corePtr = recordPtr; + const char *styleName = 0; + + if (corePtr->styleObj) + styleName = Tcl_GetString(corePtr->styleObj); + + if (!styleName || *styleName == '\0') + styleName = corePtr->widgetSpec->className; + + return Ttk_CreateLayout(interp, themePtr, styleName, + recordPtr, corePtr->optionTable, corePtr->tkwin); +} + +/* + * WidgetGetOrientedLayout -- + * Helper routine. Same as WidgetGetLayout, but prefixes + * "Horizontal." or "Vertical." to the style name, depending + * on the value of the 'orient' option. + */ +Ttk_Layout WidgetGetOrientedLayout( + Tcl_Interp *interp, Ttk_Theme themePtr, void *recordPtr, Tcl_Obj *orientObj) +{ + WidgetCore *corePtr = recordPtr; + const char *baseStyleName = 0; + Tcl_DString styleName; + int orient = TTK_ORIENT_HORIZONTAL; + Ttk_Layout layout; + + Tcl_DStringInit(&styleName); + + /* Prefix: + */ + Ttk_GetOrientFromObj(NULL, orientObj, &orient); + if (orient == TTK_ORIENT_HORIZONTAL) + Tcl_DStringAppend(&styleName, "Horizontal.", -1); + else + Tcl_DStringAppend(&styleName, "Vertical.", -1); + + + /* Add base style name: + */ + if (corePtr->styleObj) + baseStyleName = Tcl_GetString(corePtr->styleObj); + if (!baseStyleName || *baseStyleName == '\0') + baseStyleName = corePtr->widgetSpec->className; + + Tcl_DStringAppend(&styleName, baseStyleName, -1); + + /* Create layout: + */ + layout= Ttk_CreateLayout(interp, themePtr, Tcl_DStringValue(&styleName), + recordPtr, corePtr->optionTable, corePtr->tkwin); + + Tcl_DStringFree(&styleName); + + return layout; +} + +/* + * NullInitialize -- + * Default widget initializeProc (no-op) + */ +int NullInitialize(Tcl_Interp *interp, void *recordPtr) +{ + return TCL_OK; +} + +/* + * NullPostConfigure -- + * Default widget postConfigureProc (no-op) + */ +int NullPostConfigure(Tcl_Interp *interp, void *clientData, int mask) +{ + return TCL_OK; +} + +/* CoreConfigure -- + * Default widget configureProc. + */ +int CoreConfigure(Tcl_Interp *interp, void *clientData, int mask) +{ + WidgetCore *corePtr = clientData; + + if (mask & STYLE_CHANGED) { + Ttk_Theme theme = Ttk_GetCurrentTheme(interp); + Ttk_Layout newLayout = + corePtr->widgetSpec->getLayoutProc(interp,theme,corePtr); + + if (!newLayout) { + return TCL_ERROR; + } + if (corePtr->layout) { + Ttk_FreeLayout(corePtr->layout); + } + corePtr->layout = newLayout; + } + + return TCL_OK; +} + +/* + * NullCleanup -- + * Default widget cleanupProc (no-op) + */ +void NullCleanup(void *recordPtr) +{ + return; +} + +/* + * WidgetDoLayout -- + * Default widget layoutProc. + */ +void WidgetDoLayout(void *clientData) +{ + WidgetCore *corePtr = clientData; + Ttk_PlaceLayout(corePtr->layout,corePtr->state,Ttk_WinBox(corePtr->tkwin)); +} + +/* + * WidgetDisplay -- + * Default widget displayProc. + */ +void WidgetDisplay(void *recordPtr, Drawable d) +{ + WidgetCore *corePtr = recordPtr; + Ttk_DrawLayout(corePtr->layout, corePtr->state, d); +} + +/* + * WidgetSize -- + * Default widget sizeProc() + */ +int WidgetSize(void *recordPtr, int *widthPtr, int *heightPtr) +{ + WidgetCore *corePtr = recordPtr; + Ttk_LayoutSize(corePtr->layout, corePtr->state, widthPtr, heightPtr); + return 1; + +/* OR: (@@@) + return *widthPtr > Tk_Width(corePtr->tkwin) + || *heightPtr > Tk_Height(corePtr->tkwin); +*/ +} + + +/* Default implementations for widget subcommands: +*/ +int WidgetCgetCommand( +Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[], void *recordPtr) +{ + WidgetCore *corePtr = recordPtr; + Tcl_Obj *result; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "option"); + return TCL_ERROR; + } + result = Tk_GetOptionValue(interp, recordPtr, + corePtr->optionTable, objv[2], corePtr->tkwin); + if (result == NULL) + return TCL_ERROR; + Tcl_SetObjResult(interp, result); + return TCL_OK; +} + +int WidgetConfigureCommand( +Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr) +{ + WidgetCore *corePtr = recordPtr; + Tcl_Obj *result; + + if (objc == 2) { + result = Tk_GetOptionInfo(interp, recordPtr, + corePtr->optionTable, (Tcl_Obj *) NULL, corePtr->tkwin); + } else if (objc == 3) { + result = Tk_GetOptionInfo(interp, recordPtr, + corePtr->optionTable, objv[2], corePtr->tkwin); + } else { + Tk_SavedOptions savedOptions; + int status; + int mask = 0; + + status = Tk_SetOptions(interp, recordPtr, + corePtr->optionTable, objc - 2, objv + 2, + corePtr->tkwin, &savedOptions, &mask); + if (status != TCL_OK) + return status; + + if (mask & READONLY_OPTION) { + Tcl_SetResult(interp, + "Attempt to change read-only option", TCL_STATIC); + Tk_RestoreSavedOptions(&savedOptions); + return TCL_ERROR; + } + + status = corePtr->widgetSpec->configureProc(interp, recordPtr, mask); + if (status != TCL_OK) { + Tk_RestoreSavedOptions(&savedOptions); + return status; + } + Tk_FreeSavedOptions(&savedOptions); + + status = corePtr->widgetSpec->postConfigureProc(interp,recordPtr,mask); + if (status != TCL_OK) { + return status; + } + + if (mask & (STYLE_CHANGED | GEOMETRY_CHANGED)) { + UpdateGeometry(corePtr); + } + + TtkRedisplayWidget(corePtr); + result = Tcl_NewObj(); + } + + if (result == 0) { + return TCL_ERROR; + } + Tcl_SetObjResult(interp, result); + return TCL_OK; +} + +/* $w state $stateSpec + * $w state + * + * If $stateSpec is specified, modify the widget state accordingly, + * return a new stateSpec representing the changed bits. + * + * Otherwise, return a statespec matching all the currently-set bits. + */ + +int WidgetStateCommand( + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr) +{ + WidgetCore *corePtr = recordPtr; + Ttk_StateSpec spec; + int status; + Ttk_State oldState, changed; + + if (objc == 2) { + Tcl_SetObjResult(interp, + Ttk_NewStateSpecObj(corePtr->state, 0ul)); + return TCL_OK; + } + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 2, objv, "state-spec"); + return TCL_ERROR; + } + status = Ttk_GetStateSpecFromObj(interp, objv[2], &spec); + if (status != TCL_OK) + return status; + + oldState = corePtr->state; + corePtr->state = Ttk_ModifyState(corePtr->state, &spec); + changed = corePtr->state ^ oldState; + + TtkRedisplayWidget(corePtr); + + Tcl_SetObjResult(interp, + Ttk_NewStateSpecObj(oldState & changed, ~oldState & changed)); + return status; +} + +/* $w instate $stateSpec ?$script? + * + * Tests if widget state matches $stateSpec. + * If $script is specified, execute script if state matches. + * Otherwise, return true/false + */ + +int WidgetInstateCommand( + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr) +{ + WidgetCore *corePtr = recordPtr; + Ttk_State state = corePtr->state; + Ttk_StateSpec spec; + int status = TCL_OK; + + if (objc < 3 || objc > 4) { + Tcl_WrongNumArgs(interp, 2, objv, "state-spec ?script?"); + return TCL_ERROR; + } + status = Ttk_GetStateSpecFromObj(interp, objv[2], &spec); + if (status != TCL_OK) + return status; + + if (objc == 3) { + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj(Ttk_StateMatches(state,&spec))); + } else if (objc == 4) { + if (Ttk_StateMatches(state,&spec)) { + status = Tcl_EvalObjEx(interp, objv[3], 0); + } + } + return status; +} + +/* $w identify $x $y + * Returns: name of element at $x, $y + */ +int WidgetIdentifyCommand( + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr) +{ + WidgetCore *corePtr = recordPtr; + Ttk_LayoutNode *node; + int x, y; + + if (objc != 4) { + Tcl_WrongNumArgs(interp, 2, objv, "x y"); + return TCL_ERROR; + } + + if (Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK + || Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK) + return TCL_ERROR; + + node = Ttk_LayoutIdentify(corePtr->layout, x, y); + if (node) { + const char *elementName = Ttk_LayoutNodeName(node); + Tcl_SetObjResult(interp,Tcl_NewStringObj(elementName,-1)); + } + + return TCL_OK; +} + +/*EOF*/ |