summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjenglish <jenglish@flightlab.com>2008-12-07 18:42:55 (GMT)
committerjenglish <jenglish@flightlab.com>2008-12-07 18:42:55 (GMT)
commit65e8ffb61167e8855e39549a9e4233b41cfa2344 (patch)
treeaf361229e7aa628bf203e9d8d95182c4c0774371
parent229640003624b9acf35b7559855fc8e418596943 (diff)
downloadtk-65e8ffb61167e8855e39549a9e4233b41cfa2344.zip
tk-65e8ffb61167e8855e39549a9e4233b41cfa2344.tar.gz
tk-65e8ffb61167e8855e39549a9e4233b41cfa2344.tar.bz2
Add native aqua elements for ttk::spinbox [Bug 2219588].
Moved most spinbox "business logic" out of ttkEntry.c into Tcl bindings. Minor spinbox appearance improvements in clam theme.
-rw-r--r--ChangeLog9
-rw-r--r--generic/ttk/ttkEntry.c417
-rw-r--r--library/ttk/clamTheme.tcl5
-rw-r--r--library/ttk/spinbox.tcl197
-rw-r--r--macosx/ttkMacOSXTheme.c62
-rw-r--r--tests/ttk/spinbox.test139
6 files changed, 396 insertions, 433 deletions
diff --git a/ChangeLog b/ChangeLog
index 3ead46a..c246a74 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2008-12-07 Joe English <jenglish@users.sourceforge.net>
+
+ * macosx/ttkMacOSXTheme.c: Add native aqua elements for
+ ttk::spinbox [Bug 2219588]
+ * generic/ttk/ttkEntry.c, library/ttk/spinbox.tcl,
+ tests/ttk/spinbox.test: Moved most spinbox "business logic"
+ out of ttkEntry.c into Tcl bindings.
+ * library/ttk/clamTheme.tcl: Minor spinbox appearance improvements.
+
2008-12-06 Donal K. Fellows <dkf@users.sf.net>
TIP #197 IMPLEMENTATION
diff --git a/generic/ttk/ttkEntry.c b/generic/ttk/ttkEntry.c
index edf49a0..38133bb 100644
--- a/generic/ttk/ttkEntry.c
+++ b/generic/ttk/ttkEntry.c
@@ -1,5 +1,5 @@
/*
- * $Id: ttkEntry.c,v 1.13 2008/11/16 17:14:16 jenglish Exp $
+ * $Id: ttkEntry.c,v 1.14 2008/12/07 18:42:55 jenglish Exp $
*
* DERIVED FROM: tk/generic/tkEntry.c r1.35.
*
@@ -13,7 +13,6 @@
#include <string.h>
#include <tk.h>
#include <X11/Xatom.h>
-#include <math.h>
#include "ttkTheme.h"
#include "ttkWidget.h"
@@ -27,12 +26,6 @@
#define VALIDATION_SET_VALUE (WIDGET_USER_FLAG<<4)
/*
- * inline equality test for doubles
- */
-#define MIN_DBL_VAL 1E-9
-#define DOUBLES_EQ(d1, d2) (fabs((d1) - (d2)) < MIN_DBL_VAL)
-
-/*
* Definitions for -validate option values:
*/
typedef enum validateMode {
@@ -80,8 +73,7 @@ static const char *validateReasonStrings[] = {
/* Style parameters:
*/
-typedef struct
-{
+typedef struct {
Tcl_Obj *foregroundObj; /* Foreground color for normal text */
Tcl_Obj *backgroundObj; /* Entry widget background color */
Tcl_Obj *selBorderObj; /* Border and background for selection */
@@ -91,8 +83,7 @@ typedef struct
Tcl_Obj *insertWidthObj; /* Insert cursor width */
} EntryStyleData;
-typedef struct
-{
+typedef struct {
/*
* Internal state:
*/
@@ -142,8 +133,7 @@ typedef struct
} EntryPart;
-typedef struct
-{
+typedef struct {
WidgetCore core;
EntryPart entry;
} Entry;
@@ -151,12 +141,9 @@ typedef struct
/*
* Extra mask bits for Tk_SetOptions()
*/
-#define STATE_CHANGED (0x0100) /* -state option changed */
-#define TEXTVAR_CHANGED (0x0200) /* -textvariable option changed */
-#define SCROLLCMD_CHANGED (0x0400) /* -xscrollcommand option changed */
-#define VALUES_CHANGED (0x0800) /* -values option changed */
-#define FORMAT_CHANGED (0x1000) /* -format option changed (spinbox) */
-#define RANGE_CHANGED (0x2000) /* -from or -to option changed */
+#define STATE_CHANGED (0x100) /* -state option changed */
+#define TEXTVAR_CHANGED (0x200) /* -textvariable option changed */
+#define SCROLLCMD_CHANGED (0x400) /* -xscrollcommand option changed */
/*
* Default option values:
@@ -168,8 +155,7 @@ typedef struct
#define DEF_ENTRY_FONT "TkTextFont"
#define DEF_LIST_HEIGHT "10"
-static Tk_OptionSpec EntryOptionSpecs[] =
-{
+static Tk_OptionSpec EntryOptionSpecs[] = {
WIDGET_TAKES_FOCUS,
{TK_OPTION_BOOLEAN, "-exportselection", "exportSelection",
@@ -533,7 +519,7 @@ static int RunValidationScript(
ExpandPercents(entryPtr, template, new, index, count, reason, &script);
code = Tcl_EvalEx(interp,
Tcl_DStringValue(&script), Tcl_DStringLength(&script),
- TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
+ TCL_EVAL_GLOBAL);
Tcl_DStringFree(&script);
if (WidgetDestroyed(&entryPtr->core))
return TCL_ERROR;
@@ -1647,8 +1633,7 @@ static int EntryXViewCommand(
return TtkScrollviewCommand(interp, objc, objv, entryPtr->entry.xscrollHandle);
}
-static WidgetCommandSpec EntryCommands[] =
-{
+static WidgetCommandSpec EntryCommands[] = {
{ "bbox", EntryBBoxCommand },
{ "cget", TtkWidgetCgetCommand },
{ "configure", TtkWidgetConfigureCommand },
@@ -1670,8 +1655,7 @@ static WidgetCommandSpec EntryCommands[] =
* +++ Entry widget definition.
*/
-static WidgetSpec EntryWidgetSpec =
-{
+static WidgetSpec EntryWidgetSpec = {
"TEntry", /* className */
sizeof(Entry), /* recordSize */
EntryOptionSpecs, /* optionSpecs */
@@ -1687,91 +1671,105 @@ static WidgetSpec EntryWidgetSpec =
};
/*------------------------------------------------------------------------
- * +++ Values entry widget widget record.
- *
- * This record and the command function are shared by the combobox and
- * spinbox which both have support for a -values option and [current]
- * command.
+ * +++ Combobox widget record.
*/
typedef struct {
+ Tcl_Obj *postCommandObj;
Tcl_Obj *valuesObj;
- int currentIndex;
-} ValuesPart;
+ Tcl_Obj *heightObj;
+ int currentIndex;
+} ComboboxPart;
typedef struct {
WidgetCore core;
EntryPart entry;
- ValuesPart values;
-} Values;
+ ComboboxPart combobox;
+} Combobox;
-#define ENTRY_VALUES_OPTION \
- {TK_OPTION_STRING, "-values", "values", "Values", \
- "", Tk_Offset(Values, values.valuesObj), -1, 0, 0, VALUES_CHANGED}
+static Tk_OptionSpec ComboboxOptionSpecs[] = {
+ {TK_OPTION_STRING, "-height", "height", "Height",
+ DEF_LIST_HEIGHT, Tk_Offset(Combobox, combobox.heightObj), -1,
+ 0,0,0 },
+ {TK_OPTION_STRING, "-postcommand", "postCommand", "PostCommand",
+ "", Tk_Offset(Combobox, combobox.postCommandObj), -1,
+ 0,0,0 },
+ {TK_OPTION_STRING, "-values", "values", "Values",
+ "", Tk_Offset(Combobox, combobox.valuesObj), -1,
+ 0,0,0 },
+ WIDGET_INHERIT_OPTIONS(EntryOptionSpecs)
+};
+/* ComboboxInitialize --
+ * Initialization hook for combobox widgets.
+ */
static void
-ValuesInitialize(Tcl_Interp *interp, void *recordPtr)
+ComboboxInitialize(Tcl_Interp *interp, void *recordPtr)
{
- Values *valPtr = recordPtr;
- valPtr->values.currentIndex = -1;
+ Combobox *cb = recordPtr;
+
+ cb->combobox.currentIndex = -1;
+ TtkTrackElementState(&cb->core);
+ EntryInitialize(interp, recordPtr);
}
+/* ComboboxConfigure --
+ * Configuration hook for combobox widgets.
+ */
static int
-ValuesValidate(Tcl_Interp *interp, void *recordPtr, int *indexPtr)
+ComboboxConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
- Values *valPtr = recordPtr;
- int currentIndex = valPtr->values.currentIndex;
- const char *currentValue = valPtr->entry.string;
- int eltc;
- Tcl_Obj **eltv;
-
+ Combobox *cbPtr = recordPtr;
+ int unused;
- if (Tcl_ListObjLength(interp,valPtr->values.valuesObj,&eltc) != TCL_OK)
+ /* Make sure -values is a valid list:
+ */
+ if (Tcl_ListObjLength(interp,cbPtr->combobox.valuesObj,&unused) != TCL_OK)
return TCL_ERROR;
- Tcl_ListObjGetElements(interp,valPtr->values.valuesObj,&eltc,&eltv);
-
- if ( currentIndex < 0
- || currentIndex >= eltc
- || strcmp(currentValue, Tcl_GetString(eltv[currentIndex]))) {
- /*
- * Not valid. Check current value against each element in -values:
- */
- for (currentIndex = 0; currentIndex < eltc; ++currentIndex) {
- if (!strcmp(currentValue,Tcl_GetString(eltv[currentIndex]))) {
- break;
- }
- }
- if (currentIndex >= eltc) {
- /* Not found */
- currentIndex = -1;
- }
- }
- *indexPtr = currentIndex;
- return TCL_OK;
+ return EntryConfigure(interp, recordPtr, mask);
}
-/* $widget current ?newIndex? -- get or set current index.
+/* $cb current ?newIndex? -- get or set current index.
* Setting the current index updates the combobox value,
* but the value and -values may be changed independently
* of the index. Instead of trying to keep currentIndex
* in sync at all times, [$cb current] double-checks
*/
-static int ValuesCurrentCommand(
+static int ComboboxCurrentCommand(
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
{
- Values *valPtr = recordPtr;
- int currentIndex = valPtr->values.currentIndex;
+ Combobox *cbPtr = recordPtr;
+ int currentIndex = cbPtr->combobox.currentIndex;
+ const char *currentValue = cbPtr->entry.string;
int nValues;
Tcl_Obj **values;
- Tcl_ListObjGetElements(interp,valPtr->values.valuesObj,&nValues,&values);
+ Tcl_ListObjGetElements(interp,cbPtr->combobox.valuesObj,&nValues,&values);
if (objc == 2) {
- if (ValuesValidate(interp, recordPtr, &currentIndex) != TCL_OK)
- return TCL_ERROR;
- valPtr->values.currentIndex = currentIndex;
+ /* Check if currentIndex still valid:
+ */
+ if ( currentIndex < 0
+ || currentIndex >= nValues
+ || strcmp(currentValue,Tcl_GetString(values[currentIndex]))
+ )
+ {
+ /* Not valid. Check current value against each element in -values:
+ */
+ for (currentIndex = 0; currentIndex < nValues; ++currentIndex) {
+ if (!strcmp(currentValue,Tcl_GetString(values[currentIndex]))) {
+ break;
+ }
+ }
+ if (currentIndex >= nValues) {
+ /* Not found */
+ currentIndex = -1;
+ }
+ }
+ cbPtr->combobox.currentIndex = currentIndex;
Tcl_SetObjResult(interp, Tcl_NewIntObj(currentIndex));
+ return TCL_OK;
} else if (objc == 3) {
if (Tcl_GetIntFromObj(interp, objv[2], &currentIndex) != TCL_OK) {
return TCL_ERROR;
@@ -1783,7 +1781,7 @@ static int ValuesCurrentCommand(
return TCL_ERROR;
}
- valPtr->values.currentIndex = currentIndex;
+ cbPtr->combobox.currentIndex = currentIndex;
return EntrySetValue(recordPtr, Tcl_GetString(values[currentIndex]));
} else {
@@ -1794,74 +1792,13 @@ static int ValuesCurrentCommand(
}
/*------------------------------------------------------------------------
- * +++ Combobox widget record.
- */
-
-typedef struct {
- Tcl_Obj *postCommandObj;
- Tcl_Obj *heightObj;
-} ComboboxPart;
-
-typedef struct {
- WidgetCore core;
- EntryPart entry;
- ValuesPart values;
- ComboboxPart combobox;
-} Combobox;
-
-static Tk_OptionSpec ComboboxOptionSpecs[] =
-{
- {TK_OPTION_STRING, "-height", "height", "Height",
- DEF_LIST_HEIGHT, Tk_Offset(Combobox, combobox.heightObj), -1,
- 0,0,0 },
- {TK_OPTION_STRING, "-postcommand", "postCommand", "PostCommand",
- "", Tk_Offset(Combobox, combobox.postCommandObj), -1,
- 0,0,0 },
- ENTRY_VALUES_OPTION,
- WIDGET_INHERIT_OPTIONS(EntryOptionSpecs)
-};
-
-/* ComboboxInitialize --
- * Initialization hook for combobox widgets.
- */
-static void
-ComboboxInitialize(Tcl_Interp *interp, void *recordPtr)
-{
- Combobox *cb = recordPtr;
- TtkTrackElementState(&cb->core);
- ValuesInitialize(interp, recordPtr);
- EntryInitialize(interp, recordPtr);
-}
-
-/* ComboboxConfigure --
- * Configuration hook for combobox widgets.
- */
-static int
-ComboboxConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
-{
- Combobox *cbPtr = recordPtr;
- int currentIndex = 0;
-
- /* Make sure -values is a valid list:
- */
- if (mask & VALUES_CHANGED) {
- if (ValuesValidate(interp, recordPtr, &currentIndex) != TCL_OK)
- return TCL_ERROR;
- cbPtr->values.currentIndex = currentIndex;
- }
-
- return EntryConfigure(interp, recordPtr, mask);
-}
-
-/*------------------------------------------------------------------------
* +++ Combobox widget definition.
*/
-static WidgetCommandSpec ComboboxCommands[] =
-{
+static WidgetCommandSpec ComboboxCommands[] = {
{ "bbox", EntryBBoxCommand },
{ "cget", TtkWidgetCgetCommand },
{ "configure", TtkWidgetConfigureCommand },
- { "current", ValuesCurrentCommand },
+ { "current", ComboboxCurrentCommand },
{ "delete", EntryDeleteCommand },
{ "get", EntryGetCommand },
{ "icursor", EntryICursorCommand },
@@ -1876,8 +1813,7 @@ static WidgetCommandSpec ComboboxCommands[] =
{0,0}
};
-static WidgetSpec ComboboxWidgetSpec =
-{
+static WidgetSpec ComboboxWidgetSpec = {
"TCombobox", /* className */
sizeof(Combobox), /* recordSize */
ComboboxOptionSpecs, /* optionSpecs */
@@ -1893,188 +1829,88 @@ static WidgetSpec ComboboxWidgetSpec =
};
/*------------------------------------------------------------------------
- * +++ Spinbox widget record.
+ * +++ Spinbox widget.
*/
typedef struct {
- Tcl_Obj *commandObj;
- double fromValue;
- double toValue;
- int valueCount;
- Tcl_Obj *formatObj;
+ Tcl_Obj *valuesObj;
+
+ Tcl_Obj *fromObj;
+ Tcl_Obj *toObj;
Tcl_Obj *incrementObj;
+ Tcl_Obj *formatObj;
+
Tcl_Obj *wrapObj;
- char formatBuffer[TCL_INTEGER_SPACE + 4];
+ Tcl_Obj *commandObj;
} SpinboxPart;
typedef struct {
WidgetCore core;
EntryPart entry;
- ValuesPart values;
SpinboxPart spinbox;
} Spinbox;
-static Tk_OptionSpec SpinboxOptionSpecs[] =
-{
+static Tk_OptionSpec SpinboxOptionSpecs[] = {
+ {TK_OPTION_STRING, "-values", "values", "Values",
+ "", Tk_Offset(Spinbox, spinbox.valuesObj), -1,
+ 0,0,0 },
+
+ {TK_OPTION_DOUBLE, "-from", "from", "From",
+ "0", Tk_Offset(Spinbox,spinbox.fromObj), -1,
+ 0,0,0 },
+ {TK_OPTION_DOUBLE, "-to", "to", "To",
+ "0", Tk_Offset(Spinbox,spinbox.toObj), -1,
+ 0,0,0 },
+ {TK_OPTION_DOUBLE, "-increment", "increment", "Increment",
+ "1", Tk_Offset(Spinbox,spinbox.incrementObj), -1,
+ 0,0,0 },
+ {TK_OPTION_STRING, "-format", "format", "Format",
+ "", Tk_Offset(Spinbox, spinbox.formatObj), -1,
+ 0,0,0 },
+
{TK_OPTION_STRING, "-command", "command", "Command",
"", Tk_Offset(Spinbox, spinbox.commandObj), -1,
0,0,0 },
- {TK_OPTION_STRING, "-format", "format", "Format", "",
- Tk_Offset(Spinbox, spinbox.formatObj), -1, 0, 0, FORMAT_CHANGED },
- {TK_OPTION_DOUBLE, "-from", "from", "From", "0",
- -1, Tk_Offset(Spinbox,spinbox.fromValue), 0, 0, RANGE_CHANGED },
- {TK_OPTION_DOUBLE, "-to", "to", "To", "0",
- -1, Tk_Offset(Spinbox,spinbox.toValue), 0, 0, RANGE_CHANGED },
- {TK_OPTION_DOUBLE, "-increment", "increment", "Increment", "1",
- Tk_Offset(Spinbox,spinbox.incrementObj), -1, 0, 0, 0},
- {TK_OPTION_BOOLEAN, "-wrap", "wrap", "Wrap", "0",
- Tk_Offset(Spinbox,spinbox.wrapObj), -1, 0, 0, 0},
- ENTRY_VALUES_OPTION,
+ {TK_OPTION_BOOLEAN, "-wrap", "wrap", "Wrap",
+ "0", Tk_Offset(Spinbox,spinbox.wrapObj), -1,
+ 0,0,0 },
+
WIDGET_INHERIT_OPTIONS(EntryOptionSpecs)
};
-/*
- * SpinboxInitialize --
+/* SpinboxInitialize --
* Initialization hook for spinbox widgets.
*/
-
static void
SpinboxInitialize(Tcl_Interp *interp, void *recordPtr)
{
- Spinbox *sbPtr = recordPtr;
- sbPtr->spinbox.valueCount = 0;
- TtkTrackElementState(&sbPtr->core);
- ValuesInitialize(interp, recordPtr);
+ Spinbox *sb = recordPtr;
+ TtkTrackElementState(&sb->core);
EntryInitialize(interp, recordPtr);
}
-/*
- * If the format option has not been set manually then we calculate
- * an appropriate format here based upon the -from and -to options
- * If -values has been set this is not called.
- */
-
-static const char *
-SpinboxCalculateFormat(Spinbox *sbPtr)
-{
- const char *formatString = "%f";
- if (Tcl_GetCharLength(sbPtr->spinbox.formatObj) > 0) {
- formatString = Tcl_GetString(sbPtr->spinbox.formatObj);
- } else {
- double increment = 0;
- int len;
- if (Tcl_GetDoubleFromObj(NULL, sbPtr->spinbox.incrementObj, &increment) != TCL_OK)
- increment = 1;
- len = (int)floor(fabs(log10(fabs(increment))));
- sprintf(sbPtr->spinbox.formatBuffer, "%%.%df", len);
- formatString = sbPtr->spinbox.formatBuffer;
- }
- return formatString;
-}
-
/* SpinboxConfigure --
* Configuration hook for spinbox widgets.
*/
static int
SpinboxConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
- Spinbox *sbPtr = recordPtr;
- int currentIndex = 0, needsUpdate = 0;
- double d = 0;
-
- needsUpdate = (mask & FORMAT_CHANGED);
-
- if (mask & RANGE_CHANGED) {
- if (Tcl_GetDouble(NULL, sbPtr->entry.string, &d) != TCL_OK) {
- d = sbPtr->spinbox.fromValue;
- needsUpdate = 1;
- } else {
- if (d < sbPtr->spinbox.fromValue) {
- d = sbPtr->spinbox.fromValue;
- needsUpdate = 1;
- }
- if (d > sbPtr->spinbox.toValue) {
- d = sbPtr->spinbox.toValue;
- needsUpdate = 1;
- }
- }
- }
+ Spinbox *sb = recordPtr;
+ int unused;
/* Make sure -values is a valid list:
*/
- if (mask & VALUES_CHANGED) {
- if (ValuesValidate(interp, recordPtr, &currentIndex) != TCL_OK)
- return TCL_ERROR;
- if (Tcl_ListObjLength(interp,sbPtr->values.valuesObj,
- &sbPtr->spinbox.valueCount) != TCL_OK)
- return TCL_ERROR;
- if (sbPtr->spinbox.valueCount > 0) {
- if (sbPtr->values.currentIndex == -1
- || sbPtr->values.currentIndex != currentIndex) {
- Tcl_Obj *valueObj;
- if (currentIndex == -1) currentIndex = 0;
- Tcl_ListObjIndex(interp, sbPtr->values.valuesObj,
- currentIndex, &valueObj);
- EntrySetValue(recordPtr, Tcl_GetString(valueObj));
- }
- sbPtr->values.currentIndex = currentIndex;
- }
- }
-
- if (needsUpdate && sbPtr->spinbox.valueCount < 1) {
- Tcl_Obj *strObj, *valueObj = NULL;
- const char *formatString = SpinboxCalculateFormat(sbPtr);
- strObj = Tcl_NewDoubleObj(d);
- valueObj = Tcl_Format(interp, formatString, 1, &strObj);
- if (valueObj) {
- Tcl_IncrRefCount(valueObj);
- EntrySetValue(recordPtr, Tcl_GetString(valueObj));
- Tcl_DecrRefCount(valueObj);
- }
- }
+ if (Tcl_ListObjLength(interp,sb->spinbox.valuesObj,&unused) != TCL_OK)
+ return TCL_ERROR;
return EntryConfigure(interp, recordPtr, mask);
}
-/* $spinbox set $value
- * Sets the value of a spinbox widget.
- * We need to take account of any -format option.
- */
-static int SpinboxSetCommand(
- Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], void *recordPtr)
-{
- Spinbox *sbPtr = recordPtr;
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "value");
- return TCL_ERROR;
- }
- if (sbPtr->spinbox.valueCount < 1) {
- Tcl_Obj *valueObj = NULL;
- const char *formatString = SpinboxCalculateFormat(sbPtr);
- valueObj = Tcl_Format(interp, formatString, 1, &objv[2]);
- if (valueObj) {
- Tcl_IncrRefCount(valueObj);
- EntrySetValue(recordPtr, Tcl_GetString(valueObj));
- Tcl_DecrRefCount(valueObj);
- } else {
- EntrySetValue(recordPtr, Tcl_GetString(objv[2]));
- }
- } else {
- EntrySetValue(recordPtr, Tcl_GetString(objv[2]));
- }
- return TCL_OK;
-}
-
-/*------------------------------------------------------------------------
- * +++ Spinbox widget definition.
- */
-
-static WidgetCommandSpec SpinboxCommands[] =
-{
+static WidgetCommandSpec SpinboxCommands[] = {
{ "bbox", EntryBBoxCommand },
{ "cget", TtkWidgetCgetCommand },
{ "configure", TtkWidgetConfigureCommand },
- { "current", ValuesCurrentCommand },
+//X: { "current", ValuesCurrentCommand },
{ "delete", EntryDeleteCommand },
{ "get", EntryGetCommand },
{ "icursor", EntryICursorCommand },
@@ -2084,14 +1920,13 @@ static WidgetCommandSpec SpinboxCommands[] =
{ "instate", TtkWidgetInstateCommand },
{ "selection", EntrySelectionCommand },
{ "state", TtkWidgetStateCommand },
- { "set", SpinboxSetCommand },
+ { "set", EntrySetCommand },
{ "validate", EntryValidateCommand },
{ "xview", EntryXViewCommand },
{0,0}
};
-static WidgetSpec SpinboxWidgetSpec =
-{
+static WidgetSpec SpinboxWidgetSpec = {
"TSpinbox", /* className */
sizeof(Spinbox), /* recordSize */
SpinboxOptionSpecs, /* optionSpecs */
@@ -2171,18 +2006,18 @@ TTK_BEGIN_LAYOUT(ComboboxLayout)
TTK_END_LAYOUT
TTK_BEGIN_LAYOUT(SpinboxLayout)
- TTK_GROUP("Spinbox.field", TTK_FILL_BOTH,
+ TTK_GROUP("Spinbox.field", TTK_PACK_TOP|TTK_FILL_X,
+ TTK_GROUP("null", TTK_PACK_RIGHT,
+ TTK_NODE("Spinbox.uparrow", TTK_PACK_TOP|TTK_STICK_E)
+ TTK_NODE("Spinbox.downarrow", TTK_PACK_BOTTOM|TTK_STICK_E))
TTK_GROUP("Spinbox.padding", TTK_FILL_BOTH,
- TTK_NODE("Spinbox.textarea", TTK_PACK_LEFT|TTK_EXPAND))
- TTK_NODE("Spinbox.uparrow", TTK_PACK_TOP|TTK_STICK_E)
- TTK_NODE("Spinbox.downarrow", TTK_PACK_BOTTOM|TTK_STICK_E))
+ TTK_NODE("Spinbox.textarea", TTK_FILL_BOTH)))
TTK_END_LAYOUT
/*------------------------------------------------------------------------
* +++ Initialization.
*/
-MODULE_SCOPE
void TtkEntry_Init(Tcl_Interp *interp)
{
Ttk_Theme themePtr = Ttk_GetDefaultTheme(interp);
diff --git a/library/ttk/clamTheme.tcl b/library/ttk/clamTheme.tcl
index 1a07e3a..808c8a4 100644
--- a/library/ttk/clamTheme.tcl
+++ b/library/ttk/clamTheme.tcl
@@ -1,5 +1,5 @@
#
-# $Id: clamTheme.tcl,v 1.9 2008/11/29 00:43:48 patthoyts Exp $
+# $Id: clamTheme.tcl,v 1.10 2008/12/07 18:42:55 jenglish Exp $
#
# "Clam" theme.
#
@@ -111,9 +111,6 @@ namespace eval ttk::theme::clam {
ttk::style configure TSpinbox -arrowsize 10 -padding {2 0 10 0}
ttk::style map TSpinbox \
-background [list readonly $colors(-frame)] \
- -bordercolor [list focus $colors(-selectbg)] \
- -lightcolor [list focus "#6f9dc6"] \
- -darkcolor [list focus "#6f9dc6"] \
-arrowcolor [list disabled $colors(-disabledfg)]
ttk::style configure TNotebook.Tab -padding {6 2 6 2}
diff --git a/library/ttk/spinbox.tcl b/library/ttk/spinbox.tcl
index 579a22c..9464b07 100644
--- a/library/ttk/spinbox.tcl
+++ b/library/ttk/spinbox.tcl
@@ -1,16 +1,10 @@
#
-# $Id: spinbox.tcl,v 1.1 2008/11/01 15:34:24 patthoyts Exp $
+# $Id: spinbox.tcl,v 1.2 2008/12/07 18:42:55 jenglish Exp $
#
-# Tile widget set: spinbox bindings.
+# ttk::spinbox bindings
#
-#
-
-namespace eval ttk::spinbox {
- variable Values ;# Values($cb) is -listvariable of listbox widget
- variable State
- set State(entryPress) 0
-}
+namespace eval ttk::spinbox { }
### Spinbox bindings.
#
@@ -19,103 +13,132 @@ namespace eval ttk::spinbox {
ttk::copyBindings TEntry TSpinbox
-bind TSpinbox <Double-Button-1> {ttk::spinbox::Select %W %x %y word}
-bind TSpinbox <Triple-Button-1> {ttk::spinbox::Select %W %x %y line}
+bind TSpinbox <Motion> { ttk::spinbox::Motion %W %x %y }
+bind TSpinbox <ButtonPress-1> { ttk::spinbox::Press %W %x %y }
+bind TSpinbox <ButtonRelease-1> { ttk::spinbox::Release %W }
+bind TSpinbox <Double-Button-1> { ttk::spinbox::DoubleClick %W %x %y }
+bind TSpinbox <Triple-Button-1> {} ;# disable TEntry triple-click
+
+bind TSpinbox <KeyPress-Up> { ttk::spinbox::Spin %W +1 }
+bind TSpinbox <KeyPress-Down> { ttk::spinbox::Spin %W -1 }
-bind TSpinbox <ButtonPress-1> { ttk::spinbox::Press %W %x %y }
-bind TSpinbox <ButtonRelease-1> { ttk::spinbox::Release %W %x %y }
-bind TSpinbox <MouseWheel> {ttk::spinbox::Change %W [expr {%D/-120}] line}
-bind TSpinbox <Up> {ttk::spinbox::Change %W +[%W cget -increment] line}
-bind TSpinbox <Down> {ttk::spinbox::Change %W -[%W cget -increment] line}
+bind TSpinbox <<Increment>> { ttk::spinbox::Spin %W +1 }
+bind TSpinbox <<Decrement>> { ttk::spinbox::Spin %W -1 }
+# @@@ x-plat
+bind TSpinbox <MouseWheel> { ttk::spinbox::Spin %W [expr {%D/-120}] }
+
+## Motion --
+# Sets cursor.
+#
+proc ttk::spinbox::Motion {w x y} {
+ if { [$w identify $x $y] eq "textarea"
+ && [$w instate {!readonly !disabled}]
+ } {
+ ttk::setCursor $w text
+ } else {
+ ttk::setCursor $w ""
+ }
+}
+
+## Press --
+#
proc ttk::spinbox::Press {w x y} {
if {[$w instate disabled]} { return }
- variable State
- set State(xPress) $x
- set State(yPress) $y
focus $w
switch -glob -- [$w identify $x $y] {
- *uparrow {
- ttk::Repeatedly Change $w +[$w cget -increment] line
- }
- *downarrow {
- ttk::Repeatedly Change $w -[$w cget -increment] line
- }
- *textarea {
- set State(entryPress) [$w instate !readonly]
- if {$State(entryPress)} {
- ttk::entry::Press $w $x
- }
- }
+ *textarea { ttk::entry::Press $w $x }
+ *rightarrow -
+ *uparrow { ttk::Repeatedly event generate $w <<Increment>> }
+ *leftarrow -
+ *downarrow { ttk::Repeatedly event generate $w <<Decrement>> }
+ *spinbutton {
+ if {$y * 2 >= [winfo height $w]} {
+ set event <<Decrement>>
+ } else {
+ set event <<Increment>>
+ }
+ ttk::Repeatedly event generate $w $event
+ }
}
}
-proc ttk::spinbox::Release {w x y} {
- variable State
- unset -nocomplain State(xPress) State(yPress)
+## DoubleClick --
+# Select all if over the text area; otherwise same as Press.
+#
+proc ttk::spinbox::DoubleClick {w x y} {
+ if {[$w instate disabled]} { return }
+
+ switch -glob -- [$w identify $x $y] {
+ *textarea { SelectAll $w }
+ * { Press $w $x $y }
+ }
+}
+
+proc ttk::spinbox::Release {w} {
ttk::CancelRepeat
}
-proc ttk::spinbox::Change {w n units} {
- if {[set vlen [llength [$w cget -values]]] != 0} {
- set index [expr {[$w current] + $n}]
- if {[catch {$w current $index}]} {
- if {[$w cget -wrap]} {
- if {$index == -1} {
- set index [llength [$w cget -values]]
- incr index -1
- } else {
- set index 0
- }
- $w current $index
- }
- }
- } else {
- if {![catch {expr {[$w get] + $n}} v]} {
- if {$v < [$w cget -from]} {
- if {[$w cget -wrap]} {
- set v [$w cget -to]
- } else {
- set v [$w cget -from]
- }
- } elseif {$v > [$w cget -to]} {
- if {[$w cget -wrap]} {
- set v [$w cget -from]
- } else {
- set v [$w cget -to]
- }
- }
- $w set $v
- }
+proc ttk::spinbox::SelectAll {w} {
+ $w selection range 0 end
+ $w icursor end
+}
+
+proc ttk::spinbox::Limit {v min max} {
+ if {$v < $min} { return $min }
+ if {$v > $max} { return $max }
+ return $v
+}
+
+proc ttk::spinbox::Wrap {v min max} {
+ if {$v < $min} { return $max }
+ if {$v > $max} { return $min }
+ return $v
+}
+
+proc ttk::spinbox::Adjust {w v min max} {
+ if {[$w cget -wrap]} {
+ return [Wrap $v $min $max]
+ } else {
+ return [Limit $v $min $max]
}
- ::ttk::entry::Select $w 0 $units
+}
- # Run -command callback:
- #
+proc ttk::spinbox::Spin {w dir} {
+ set nvalues [llength [set values [$w cget -values]]]
+ set value [$w get]
+ if {$nvalues} {
+ set current [lsearch -exact $values $value]
+ set index [Adjust $w [expr {$current + $dir}] 0 [expr {$nvalues - 1}]]
+ $w set [lindex $values $index]
+ } else {
+ if {[catch {
+ set v [expr {[scan [$w get] %f] + $dir * [$w cget -increment]}]
+ }]} {
+ set v [$w cget -from]
+ }
+ $w set [FormatValue $w [Adjust $w $v [$w cget -from] [$w cget -to]]]
+ }
+ SelectAll $w
uplevel #0 [$w cget -command]
-
}
-# Spinbox double-click on the arrows needs interception, otherwise
-# pass to the TEntry handler
-proc ttk::spinbox::Select {w x y mode} {
- if {[$w instate disabled]} { return }
- variable State
- set State(xPress) $x
- set State(yPress) $y
- switch -glob -- [$w identify $x $y] {
- *uparrow {
- ttk::Repeatedly Change $w +[$w cget -increment] units
- }
- *downarrow {
- ttk::Repeatedly Change $w -[$w cget -increment] units
- }
- *textarea {
- return [::ttk::entry::Select $w $x $mode]
- }
+proc ttk::spinbox::FormatValue {w val} {
+ set fmt [$w cget -format]
+ if {$fmt eq ""} {
+ # Try to guess a suitable -format based on -increment.
+ set delta [expr {abs([$w cget -increment])}]
+ if {0 < $delta && $delta < 1} {
+ # NB: This guesses wrong if -increment has more than 1
+ # significant digit itself, e.g., -increment 0.25
+ set nsd [expr {int(ceil(-log10($delta)))}]
+ set fmt "%.${nsd}f"
+ } else {
+ set fmt "%.0f"
+ }
}
- return -code continue
+ return [format $fmt $val]
}
#*EOF*
diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c
index bc9fabc..598abd9 100644
--- a/macosx/ttkMacOSXTheme.c
+++ b/macosx/ttkMacOSXTheme.c
@@ -27,7 +27,7 @@
* top-level window, not to the Tk_Window. BoxToRect()
* accounts for this.
*
- * RCS: @(#) $Id: ttkMacOSXTheme.c,v 1.23 2008/12/07 16:29:38 das Exp $
+ * RCS: @(#) $Id: ttkMacOSXTheme.c,v 1.24 2008/12/07 18:42:55 jenglish Exp $
*/
#include "tkMacOSXPrivate.h"
@@ -480,6 +480,56 @@ static Ttk_ElementSpec ComboboxElementSpec = {
static Ttk_StateTable ThemeTrackEnableTable[] = {
{ kThemeTrackDisabled, TTK_STATE_DISABLED, 0 },
{ kThemeTrackInactive, TTK_STATE_BACKGROUND, 0 },
+ * +++ Spinbuttons.
+ *
+ * From Apple HIG, part III, section "Controls", "The Stepper Control":
+ * there should be 2 pixels of space between the stepper control
+ * (AKA IncDecButton, AKA "little arrows") and the text field it modifies.
+ */
+
+static Ttk_Padding SpinbuttonMargins = {2,0,2,0};
+static void SpinButtonElementSize(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ int *widthPtr, int *heightPtr, Ttk_Padding *paddingPtr)
+{
+ SInt32 s;
+ GetThemeMetric(kThemeMetricLittleArrowsWidth, &s); *widthPtr = s;
+ GetThemeMetric(kThemeMetricLittleArrowsHeight, &s); *heightPtr = s;
+ *widthPtr += Ttk_PaddingWidth(SpinbuttonMargins);
+ *heightPtr += Ttk_PaddingHeight(SpinbuttonMargins);
+}
+
+static void SpinButtonElementDraw(
+ void *clientData, void *elementRecord, Tk_Window tkwin,
+ Drawable d, Ttk_Box b, Ttk_State state)
+{
+ Rect bounds = BoxToRect(d, Ttk_PadBox(b, SpinbuttonMargins));
+ ThemeButtonDrawInfo info;
+
+ /* @@@ can't currently distinguish PressedUp (== Pressed) from PressedDown;
+ * ignore this bit for now [see #2219588]
+ */
+ info.state = Ttk_StateTableLookup(ThemeStateTable,
+ state & ~TTK_STATE_PRESSED);
+ info.value = Ttk_StateTableLookup(ButtonValueTable, state);
+ info.adornment = kThemeAdornmentNone;
+
+ BEGIN_DRAWING(d)
+ DrawThemeButton(
+ &bounds, kThemeIncDecButton, &info, NULL, NULL/*DontErase*/, NULL, 0);
+ END_DRAWING
+}
+
+static Ttk_ElementSpec SpinButtonElementSpec = {
+ TK_STYLE_VERSION_2,
+ sizeof(NullElement),
+ TtkNullElementOptions,
+ SpinButtonElementSize,
+ SpinButtonElementDraw
+};
+
+
+/*----------------------------------------------------------------------
{ kThemeTrackActive, 0, 0 }
/* { kThemeTrackNothingToScroll, ?, ? }, */
};
@@ -977,6 +1027,11 @@ TTK_LAYOUT("Tab",
TTK_NODE("Notebook.label", TTK_EXPAND|TTK_FILL_BOTH))))
/* Progress bars -- track only */
+TTK_LAYOUT("TSpinbox",
+ TTK_NODE("Spinbox.spinbutton", TTK_PACK_RIGHT|TTK_STICK_E)
+ TTK_GROUP("Spinbox.field", TTK_EXPAND|TTK_FILL_X,
+ TTK_NODE("Spinbox.textarea", TTK_EXPAND|TTK_FILL_X)))
+
TTK_LAYOUT("TProgressbar",
TTK_NODE("Progressbar.track", TTK_EXPAND|TTK_FILL_BOTH))
@@ -986,7 +1041,7 @@ TTK_LAYOUT("Heading",
TTK_NODE("Treeheading.image", TTK_PACK_RIGHT)
TTK_NODE("Treeheading.text", 0))
-/* Tree items -- omit focus ring */
+/* Tree items -- omit focus ring */
TTK_LAYOUT("Item",
TTK_GROUP("Treeitem.padding", TTK_FILL_BOTH,
TTK_NODE("Treeitem.indicator", TTK_PACK_LEFT)
@@ -1025,6 +1080,8 @@ static int AquaTheme_Init(Tcl_Interp *interp)
&ButtonElementSpec, &BevelButtonParms);
Ttk_RegisterElementSpec(themePtr, "Menubutton.button",
&ButtonElementSpec, &PopupButtonParms);
+ Ttk_RegisterElementSpec(themePtr, "Spinbox.spinbutton",
+ &SpinButtonElementSpec, 0);
Ttk_RegisterElementSpec(themePtr, "Combobox.button",
&ComboboxElementSpec, 0);
Ttk_RegisterElementSpec(themePtr, "Treeitem.indicator",
@@ -1037,6 +1094,7 @@ static int AquaTheme_Init(Tcl_Interp *interp)
Ttk_RegisterElementSpec(themePtr, "Labelframe.border",&GroupElementSpec,0);
Ttk_RegisterElementSpec(themePtr, "Entry.field",&EntryElementSpec,0);
+ Ttk_RegisterElementSpec(themePtr, "Spinbox.field",&EntryElementSpec,0);
Ttk_RegisterElementSpec(themePtr, "separator",&SeparatorElementSpec,0);
Ttk_RegisterElementSpec(themePtr, "hseparator",&SeparatorElementSpec,0);
diff --git a/tests/ttk/spinbox.test b/tests/ttk/spinbox.test
index a1b8b1f..3397e37 100644
--- a/tests/ttk/spinbox.test
+++ b/tests/ttk/spinbox.test
@@ -2,12 +2,10 @@
# ttk::spinbox widget tests
#
-package require Tk 8.5
+package require Tk
package require tcltest ; namespace import -force tcltest::*
loadTestedCommands
-set PI [expr {acos(-1)}]
-
test spinbox-1.0 "Spinbox tests -- setup" -body {
ttk::spinbox .sb
} -cleanup { destroy .sb } -result .sb
@@ -20,22 +18,6 @@ test spinbox-1.1 "Bad -values list" -setup {
destroy .sb
} -returnCodes error -result "unmatched open brace in list"
-test spinbox-1.2.1 "starts within range" -setup {
- ttk::spinbox .sb -from 0 -to 100
-} -body {
- .sb get
-} -cleanup {
- destroy .sb
-} -result 0
-
-test spinbox-1.2.2 "starts within range" -setup {
- ttk::spinbox .sb -from 100 -to 110
-} -body {
- .sb get
-} -cleanup {
- destroy .sb
-} -result 100
-
test spinbox-1.3.1 "get retrieves value" -setup {
ttk::spinbox .sb -from 0 -to 100
} -body {
@@ -48,6 +30,7 @@ test spinbox-1.3.1 "get retrieves value" -setup {
test spinbox-1.3.2 "get retrieves value" -setup {
ttk::spinbox .sb -from 0 -to 100 -values 55
} -body {
+ .sb set 55
.sb get
} -cleanup {
destroy .sb
@@ -71,23 +54,6 @@ test spinbox-1.4.2 "set changes value" -setup {
destroy .sb
} -result 33
-test spinbox-1.5.1 "format accounts for -increment" -setup {
- ttk::spinbox .sb -from 0 -to 10 -increment 0.1
-} -body {
- ::ttk::spinbox::Change .sb [expr {acos(-1)}] line
- .sb get
-} -cleanup {
- destroy .sb
-} -result 3.1
-
-test spinbox-1.5.2 "format accounts for -increment" -setup {
- ttk::spinbox .sb -from 0 -to 10 -increment 0.1
-} -body {
- .sb set $PI
- .sb get
-} -cleanup {
- destroy .sb
-} -result 3.1
test spinbox-1.6.1 "insert start" -setup {
ttk::spinbox .sb -from 0 -to 100
@@ -128,20 +94,20 @@ test spinbox-1.7.1 "-command option: set doesnt fire" -setup {
} -cleanup {
destroy .sb
} -result 0
-
+
test spinbox-1.7.2 "-command option: button handler will fire" -setup {
ttk::spinbox .sb -from 0 -to 100 -command {set ::spinbox_test 1}
} -body {
set ::spinbox_test 0
.sb set 50
- ::ttk::spinbox::Change .sb [expr {acos(-1)}] line
+ event generate .sb <<Increment>>
set ::spinbox_test
} -cleanup {
destroy .sb
} -result 1
test spinbox-1.8.1 "option -validate" -setup {
- ttk::spinbox .sb -from 0 -to 100
+ ttk::spinbox .sb -from 0 -to 100
} -body {
.sb configure -validate all
.sb cget -validate
@@ -150,7 +116,7 @@ test spinbox-1.8.1 "option -validate" -setup {
} -result {all}
test spinbox-1.8.2 "option -validate" -setup {
- ttk::spinbox .sb -from 0 -to 100
+ ttk::spinbox .sb -from 0 -to 100
} -body {
.sb configure -validate key
.sb configure -validate focus
@@ -163,7 +129,7 @@ test spinbox-1.8.2 "option -validate" -setup {
} -result {none}
test spinbox-1.8.3 "option -validate" -setup {
- ttk::spinbox .sb -from 0 -to 100
+ ttk::spinbox .sb -from 0 -to 100
} -body {
.sb configure -validate bogus
} -cleanup {
@@ -177,23 +143,24 @@ test spinbox-1.8.4 "-validate option: " -setup {
.sb configure -validate all -validatecommand {lappend ::spinbox_test %P}
pack .sb
.sb set 50
- focus -force .sb
- update
+ focus .sb
+ after 100 {set ::spinbox_wait 1} ; vwait ::spinbox_wait
set ::spinbox_test
} -cleanup {
destroy .sb
} -result {50}
-
-test spinbox-2.0 "current command -- unset should be 0" -setup {
+
+test spinbox-2.0 "current command -- unset should be 0" -constraints nyi -setup {
ttk::spinbox .sb -values [list a b c d e a]
} -body {
.sb current
} -cleanup {
destroy .sb
} -result 0
+# @@@ for combobox, this is -1.
-test spinbox-2.1 "current command -- set index" -setup {
+test spinbox-2.1 "current command -- set index" -constraints nyi -setup {
ttk::spinbox .sb -values [list a b c d e a]
} -body {
.sb current 5
@@ -202,7 +169,7 @@ test spinbox-2.1 "current command -- set index" -setup {
destroy .sb
} -result a
-test spinbox-2.2 "current command -- change -values" -setup {
+test spinbox-2.2 "current command -- change -values" -constraints nyi -setup {
ttk::spinbox .sb -values [list a b c d e a]
} -body {
.sb current 5
@@ -212,7 +179,7 @@ test spinbox-2.2 "current command -- change -values" -setup {
destroy .sb
} -result 2
-test spinbox-2.3 "current command -- change value" -setup {
+test spinbox-2.3 "current command -- change value" -constraints nyi -setup {
ttk::spinbox .sb -values [list c b a d e]
} -body {
.sb current 2
@@ -222,7 +189,7 @@ test spinbox-2.3 "current command -- change value" -setup {
destroy .sb
} -result 1
-test spinbox-2.4 "current command -- value not in list" -setup {
+test spinbox-2.4 "current command -- value not in list" -constraints nyi -setup {
ttk::spinbox .sb -values [list c b a d e]
} -body {
.sb current 2
@@ -232,6 +199,80 @@ test spinbox-2.4 "current command -- value not in list" -setup {
destroy .sb
} -result -1
+# nostomp: NB intentional difference between ttk::spinbox and tk::spinbox;
+# see also #1439266
+#
+test spinbox-nostomp-1 "don't stomp on -variable (init; -from/to)" -body {
+ set SBV 55
+ ttk::spinbox .sb -textvariable SBV -from 0 -to 100 -increment 5
+ list $SBV [.sb get]
+} -cleanup {
+ unset SBV
+ destroy .sb
+} -result [list 55 55]
+
+test spinbox-nostomp-2 "don't stomp on -variable (init; -values)" -body {
+ set SBV Apr
+ ttk::spinbox .sb -textvariable SBV -values {Jan Feb Mar Apr May Jun Jul Aug}
+ list $SBV [.sb get]
+} -cleanup {
+ unset SBV
+ destroy .sb
+} -result [list Apr Apr]
+
+test spinbox-nostomp-3 "don't stomp on -variable (configure; -from/to)" -body {
+ set SBV 55
+ ttk::spinbox .sb
+ .sb configure -textvariable SBV -from 0 -to 100 -increment 5
+ list $SBV [.sb get]
+} -cleanup {
+ unset SBV
+ destroy .sb
+} -result [list 55 55]
+
+test spinbox-nostomp-4 "don't stomp on -variable (configure; -values)" -body {
+ set SBV Apr
+ ttk::spinbox .sb
+ .sb configure -textvariable SBV -values {Jan Feb Mar Apr May Jun Jul Aug}
+ list $SBV [.sb get]
+} -cleanup {
+ unset SBV
+ destroy .sb
+} -result [list Apr Apr]
+
+test spinbox-dieoctaldie-1 "Cope with leading zeros" -body {
+ # See SF#2358545 -- ttk::spinbox also affected
+ set secs 07
+ ttk::spinbox .sb -from 0 -to 59 -format %02.0f -textvariable secs
+
+ set result [list $secs]
+ event generate .sb <<Increment>>; lappend result $secs
+ event generate .sb <<Increment>>; lappend result $secs
+ event generate .sb <<Increment>>; lappend result $secs
+ event generate .sb <<Increment>>; lappend result $secs
+
+ event generate .sb <<Decrement>>; lappend result $secs
+ event generate .sb <<Decrement>>; lappend result $secs
+ event generate .sb <<Decrement>>; lappend result $secs
+ event generate .sb <<Decrement>>; lappend result $secs
+
+ set result
+} -result [list 07 08 09 10 11 10 09 08 07] -cleanup {
+ destroy .sb
+ unset secs
+}
+
+test spinbox-dieoctaldie-2 "Cope with general bad input" -body {
+ set result [list]
+ ttk::spinbox .sb -from 0 -to 100 -format %03.0f
+ .sb set asdfasdf ; lappend result [.sb get]
+ event generate .sb <<Increment>> ; lappend result [.sb get]
+ .sb set asdfasdf ; lappend result [.sb get]
+ event generate .sb <<Decrement>> ; lappend result [.sb get]
+} -result [list asdfasdf 000 asdfasdf 000] -cleanup {
+ destroy .sb
+}
+
tcltest::cleanupTests
# Local variables: