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/ttkScale.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/ttkScale.c')
-rw-r--r-- | generic/ttk/ttkScale.c | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/generic/ttk/ttkScale.c b/generic/ttk/ttkScale.c new file mode 100644 index 0000000..346183a --- /dev/null +++ b/generic/ttk/ttkScale.c @@ -0,0 +1,503 @@ +/* $Id: ttkScale.c,v 1.1 2006/10/31 01:42:26 hobbs Exp $ + * Copyright (C) 2004 Pat Thoyts <patthoyts@users.sourceforge.net> + * + * Ttk widget set: scale widget. + */ + +#include <tk.h> +#include <string.h> +#include <stdio.h> +#include "ttkTheme.h" +#include "ttkWidget.h" + +#define DEF_SCALE_LENGTH "100" + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +/* + * Scale widget record + */ +typedef struct +{ + /* slider element options */ + Tcl_Obj *fromObj; /* minimum value */ + Tcl_Obj *toObj; /* maximum value */ + Tcl_Obj *valueObj; /* current value */ + Tcl_Obj *lengthObj; /* length of the long axis of the scale */ + Tcl_Obj *orientObj; /* widget orientation */ + int orient; + + /* widget options */ + Tcl_Obj *commandObj; + Tcl_Obj *variableObj; + + /* internal state */ + Ttk_TraceHandle *variableTrace; + +} ScalePart; + +typedef struct +{ + WidgetCore core; + ScalePart scale; +} Scale; + +static Tk_OptionSpec ScaleOptionSpecs[] = +{ + WIDGET_TAKES_FOCUS, + + {TK_OPTION_STRING, "-command", "command", "Command", "", + Tk_Offset(Scale,scale.commandObj), -1, + TK_OPTION_NULL_OK,0,0}, + {TK_OPTION_STRING, "-variable", "variable", "Variable", "", + Tk_Offset(Scale,scale.variableObj), -1, + 0,0,0}, + {TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", "horizontal", + Tk_Offset(Scale,scale.orientObj), + Tk_Offset(Scale,scale.orient), 0, + (ClientData)TTKOrientStrings, STYLE_CHANGED }, + + {TK_OPTION_DOUBLE, "-from", "from", "From", "0", + Tk_Offset(Scale,scale.fromObj), -1, 0, 0, 0}, + {TK_OPTION_DOUBLE, "-to", "to", "To", "1.0", + Tk_Offset(Scale,scale.toObj), -1, 0, 0, 0}, + {TK_OPTION_DOUBLE, "-value", "value", "Value", "0", + Tk_Offset(Scale,scale.valueObj), -1, 0, 0, 0}, + {TK_OPTION_PIXELS, "-length", "length", "Length", + DEF_SCALE_LENGTH, Tk_Offset(Scale,scale.lengthObj), -1, 0, 0, + GEOMETRY_CHANGED}, + + WIDGET_INHERIT_OPTIONS(CoreOptionSpecs) +}; + +static XPoint ValueToPoint(Scale *scalePtr, double value); +static double PointToValue(Scale *scalePtr, int x, int y); + +/* ScaleVariableChanged -- + * Variable trace procedure for scale -variable; + * Updates the scale's value. + * If the linked variable is not a valid double, + * sets the 'invalid' state. + */ +static void ScaleVariableChanged(void *recordPtr, const char *value) +{ + Scale *scale = recordPtr; + double v; + + if (value == NULL || Tcl_GetDouble(0, value, &v) != TCL_OK) { + WidgetChangeState(&scale->core, TTK_STATE_INVALID, 0); + } else { + Tcl_Obj *valueObj = Tcl_NewDoubleObj(v); + Tcl_IncrRefCount(valueObj); + Tcl_DecrRefCount(scale->scale.valueObj); + scale->scale.valueObj = valueObj; + WidgetChangeState(&scale->core, 0, TTK_STATE_INVALID); + } + TtkRedisplayWidget(&scale->core); +} + +/* ScaleInitialize -- + * Scale widget initialization hook. + */ +static int ScaleInitialize(Tcl_Interp *interp, void *recordPtr) +{ + Scale *scalePtr = recordPtr; + + TrackElementState(&scalePtr->core); + return TCL_OK; +} + +static void ScaleCleanup(void *recordPtr) +{ + Scale *scale = recordPtr; + + if (scale->scale.variableTrace) { + Ttk_UntraceVariable(scale->scale.variableTrace); + scale->scale.variableTrace = 0; + } +} + +/* ScaleConfigure -- + * Configuration hook. + */ +static int ScaleConfigure(Tcl_Interp *interp, void *recordPtr, int mask) +{ + Scale *scale = recordPtr; + Tcl_Obj *varName = scale->scale.variableObj; + Ttk_TraceHandle *vt = 0; + + if (varName != NULL && *Tcl_GetString(varName) != '\0') { + vt = Ttk_TraceVariable(interp,varName, ScaleVariableChanged,recordPtr); + if (!vt) return TCL_ERROR; + } + + if (CoreConfigure(interp, recordPtr, mask) != TCL_OK) { + if (vt) Ttk_UntraceVariable(vt); + return TCL_ERROR; + } + + if (scale->scale.variableTrace) { + Ttk_UntraceVariable(scale->scale.variableTrace); + } + scale->scale.variableTrace = vt; + + return TCL_OK; +} + +/* ScalePostConfigure -- + * Post-configuration hook. + */ +static int ScalePostConfigure( + Tcl_Interp *interp, void *recordPtr, int mask) +{ + Scale *scale = recordPtr; + int status = TCL_OK; + + if (scale->scale.variableTrace) { + status = Ttk_FireTrace(scale->scale.variableTrace); + if (WidgetDestroyed(&scale->core)) { + return TCL_ERROR; + } + if (status != TCL_OK) { + /* Unset -variable: */ + Ttk_UntraceVariable(scale->scale.variableTrace); + Tcl_DecrRefCount(scale->scale.variableObj); + scale->scale.variableTrace = 0; + scale->scale.variableObj = NULL; + status = TCL_ERROR; + } + } + + return status; +} + +/* ScaleGetLayout -- + * getLayout hook. + */ +static Ttk_Layout +ScaleGetLayout(Tcl_Interp *interp, Ttk_Theme theme, void *recordPtr) +{ + Scale *scalePtr = recordPtr; + return WidgetGetOrientedLayout( + interp, theme, recordPtr, scalePtr->scale.orientObj); +} + +/* + * TroughBox -- + * Returns the inner area of the trough element. + */ +static Ttk_Box TroughBox(Scale *scalePtr) +{ + WidgetCore *corePtr = &scalePtr->core; + Ttk_LayoutNode *node = Ttk_LayoutFindNode(corePtr->layout, "trough"); + + if (node) { + return Ttk_LayoutNodeInternalParcel(corePtr->layout, node); + } else { + return Ttk_MakeBox( + 0,0, Tk_Width(corePtr->tkwin), Tk_Height(corePtr->tkwin)); + } +} + +/* + * TroughRange -- + * Return the value area of the trough element, adjusted + * for slider size. + */ +static Ttk_Box TroughRange(Scale *scalePtr) +{ + Ttk_Box troughBox = TroughBox(scalePtr); + Ttk_LayoutNode *slider=Ttk_LayoutFindNode(scalePtr->core.layout,"slider"); + + /* + * If this is a scale widget, adjust range for slider: + */ + if (slider) { + Ttk_Box sliderBox = Ttk_LayoutNodeParcel(slider); + if (scalePtr->scale.orient == TTK_ORIENT_HORIZONTAL) { + troughBox.x += sliderBox.width / 2; + troughBox.width -= sliderBox.width; + } else { + troughBox.y += sliderBox.height / 2; + troughBox.height -= sliderBox.height; + } + } + + return troughBox; +} + +/* + * ScaleFraction -- + */ +static double ScaleFraction(Scale *scalePtr, double value) +{ + double from = 0, to = 1, fraction; + + Tcl_GetDoubleFromObj(NULL, scalePtr->scale.fromObj, &from); + Tcl_GetDoubleFromObj(NULL, scalePtr->scale.toObj, &to); + + if (from == to) { + return 1.0; + } + + fraction = (value - from) / (to - from); + + return fraction < 0 ? 0 : fraction > 1 ? 1 : fraction; +} + +/* $scale get ?x y? -- + * Returns the current value of the scale widget, or if $x and + * $y are specified, the value represented by point @x,y. + */ +static int +ScaleGetCommand( + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr) +{ + Scale *scalePtr = recordPtr; + int x, y, r = TCL_OK; + double value = 0; + + if ((objc != 2) && (objc != 4)) { + Tcl_WrongNumArgs(interp, 1, objv, "get ?x y?"); + return TCL_ERROR; + } + if (objc == 2) { + Tcl_SetObjResult(interp, scalePtr->scale.valueObj); + } else { + r = Tcl_GetIntFromObj(interp, objv[2], &x); + if (r == TCL_OK) + r = Tcl_GetIntFromObj(interp, objv[3], &y); + if (r == TCL_OK) { + value = PointToValue(scalePtr, x, y); + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(value)); + } + } + return r; +} + +/* $scale set $newValue + */ +static int +ScaleSetCommand( + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr) +{ + Scale *scalePtr = recordPtr; + double from = 0.0, to = 1.0, value; + int result = TCL_OK; + + if (objc != 3) { + Tcl_WrongNumArgs(interp, 1, objv, "set value"); + return TCL_ERROR; + } + + if (Tcl_GetDoubleFromObj(interp, objv[2], &value) != TCL_OK) { + return TCL_ERROR; + } + + if (scalePtr->core.state & TTK_STATE_DISABLED) { + return TCL_OK; + } + + /* ASSERT: fromObj and toObj are valid doubles. + */ + Tcl_GetDoubleFromObj(interp, scalePtr->scale.fromObj, &from); + Tcl_GetDoubleFromObj(interp, scalePtr->scale.toObj, &to); + + /* Limit new value to between 'from' and 'to': + */ + if (from < to) { + value = value < from ? from : value > to ? to : value; + } else { + value = value < to ? to : value > from ? from : value; + } + + /* + * Set value: + */ + Tcl_DecrRefCount(scalePtr->scale.valueObj); + scalePtr->scale.valueObj = Tcl_NewDoubleObj(value); + Tcl_IncrRefCount(scalePtr->scale.valueObj); + TtkRedisplayWidget(&scalePtr->core); + + /* + * Set attached variable, if any: + */ + if (scalePtr->scale.variableObj != NULL) { + Tcl_ObjSetVar2(interp, scalePtr->scale.variableObj, NULL, + scalePtr->scale.valueObj, TCL_GLOBAL_ONLY); + } + if (WidgetDestroyed(&scalePtr->core)) { + return TCL_ERROR; + } + + /* + * Invoke -command, if any: + */ + if (scalePtr->scale.commandObj != NULL) { + Tcl_Obj *cmdObj = Tcl_DuplicateObj(scalePtr->scale.commandObj); + Tcl_IncrRefCount(cmdObj); + Tcl_AppendToObj(cmdObj, " ", 1); + Tcl_AppendObjToObj(cmdObj, scalePtr->scale.valueObj); + result = Tcl_EvalObjEx(interp, cmdObj, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(cmdObj); + } + + return result; +} + +static int +ScaleCoordsCommand( + Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr) +{ + Scale *scalePtr = recordPtr; + double value; + int r = TCL_OK; + + if (objc < 2 || objc > 3) { + Tcl_WrongNumArgs(interp, 1, objv, "coords ?value?"); + return TCL_ERROR; + } + + if (objc == 3) { + r = Tcl_GetDoubleFromObj(interp, objv[2], &value); + } else { + r = Tcl_GetDoubleFromObj(interp, scalePtr->scale.valueObj, &value); + } + + if (r == TCL_OK) { + Tcl_Obj *point[2]; + XPoint pt = ValueToPoint(scalePtr, value); + point[0] = Tcl_NewIntObj(pt.x); + point[1] = Tcl_NewIntObj(pt.y); + Tcl_SetObjResult(interp, Tcl_NewListObj(2, point)); + } + return r; +} + +static void ScaleDoLayout(void *clientData) +{ + WidgetCore *corePtr = clientData; + Ttk_LayoutNode *sliderNode = Ttk_LayoutFindNode(corePtr->layout, "slider"); + + Ttk_PlaceLayout(corePtr->layout,corePtr->state,Ttk_WinBox(corePtr->tkwin)); + + /* Adjust the slider position: + */ + if (sliderNode) { + Scale *scalePtr = clientData; + Ttk_Box troughBox = TroughBox(scalePtr); + Ttk_Box sliderBox = Ttk_LayoutNodeParcel(sliderNode); + double value = 0.0; + double fraction; + int range; + + Tcl_GetDoubleFromObj(NULL, scalePtr->scale.valueObj, &value); + fraction = ScaleFraction(scalePtr, value); + + if (scalePtr->scale.orient == TTK_ORIENT_HORIZONTAL) { + range = troughBox.width - sliderBox.width; + sliderBox.x += (int)(fraction * range); + } else { + range = troughBox.height - sliderBox.height; + sliderBox.y += (int)(fraction * range); + } + Ttk_PlaceLayoutNode(corePtr->layout, sliderNode, sliderBox); + } +} + +/* + * ScaleSize -- + * Compute requested size of scale. + */ +static int ScaleSize(void *clientData, int *widthPtr, int *heightPtr) +{ + WidgetCore *corePtr = clientData; + Scale *scalePtr = clientData; + int length; + + Ttk_LayoutSize(corePtr->layout, corePtr->state, widthPtr, heightPtr); + + /* Assert the -length configuration option */ + Tk_GetPixelsFromObj(NULL, corePtr->tkwin, + scalePtr->scale.lengthObj, &length); + if (scalePtr->scale.orient == TTK_ORIENT_VERTICAL) { + *heightPtr = MAX(*heightPtr, length); + } else { + *widthPtr = MAX(*widthPtr, length); + } + + return 1; +} + +static double +PointToValue(Scale *scalePtr, int x, int y) +{ + Ttk_Box troughBox = TroughRange(scalePtr); + double from = 0, to = 1, fraction; + + Tcl_GetDoubleFromObj(NULL, scalePtr->scale.fromObj, &from); + Tcl_GetDoubleFromObj(NULL, scalePtr->scale.toObj, &to); + + if (scalePtr->scale.orient == TTK_ORIENT_HORIZONTAL) { + fraction = (double)(x - troughBox.x) / (double)troughBox.width; + } else { + fraction = (double)(y - troughBox.y) / (double)troughBox.height; + } + + fraction = fraction < 0 ? 0 : fraction > 1 ? 1 : fraction; + + return from + fraction * (to-from); +} + +/* + * Return the center point in the widget corresponding to the given + * value. This point can be used to center the slider. + */ + +static XPoint +ValueToPoint(Scale *scalePtr, double value) +{ + Ttk_Box troughBox = TroughRange(scalePtr); + double fraction = ScaleFraction(scalePtr, value); + XPoint pt = {0, 0}; + + if (scalePtr->scale.orient == TTK_ORIENT_HORIZONTAL) { + pt.x = troughBox.x + (int)(fraction * troughBox.width); + pt.y = troughBox.y + troughBox.height / 2; + } else { + pt.x = troughBox.x + troughBox.width / 2; + pt.y = troughBox.y + (int)(fraction * troughBox.height); + } + return pt; +} + +static WidgetCommandSpec ScaleCommands[] = +{ + { "configure", WidgetConfigureCommand }, + { "cget", WidgetCgetCommand }, + { "state", WidgetStateCommand }, + { "instate", WidgetInstateCommand }, + { "identify", WidgetIdentifyCommand }, + { "set", ScaleSetCommand }, + { "get", ScaleGetCommand }, + { "coords", ScaleCoordsCommand }, + { 0, 0 } +}; + +WidgetSpec ScaleWidgetSpec = +{ + "TScale", /* Class name */ + sizeof(Scale), /* record size */ + ScaleOptionSpecs, /* option specs */ + ScaleCommands, /* widget commands */ + ScaleInitialize, /* initialization proc */ + ScaleCleanup, /* cleanup proc */ + ScaleConfigure, /* configure proc */ + ScalePostConfigure, /* postConfigure */ + ScaleGetLayout, /* getLayoutProc */ + ScaleSize, /* sizeProc */ + ScaleDoLayout, /* layoutProc */ + WidgetDisplay /* displayProc */ +}; + |