1 /**
2  * Widget module.
3  *
4  * License:
5  *     MIT. See LICENSE for full details.
6  */
7 module tkd.widget.spinbox;
8 
9 /**
10  * Imports.
11  */
12 import std..string;
13 import tkd.element.uielement;
14 import tkd.widget.common.boundingbox;
15 import tkd.widget.common.color;
16 import tkd.widget.common.command;
17 import tkd.widget.common.cursor;
18 import tkd.widget.common.data;
19 import tkd.widget.common.delete_;
20 import tkd.widget.common.exportselection;
21 import tkd.widget.common.font;
22 import tkd.widget.common.index;
23 import tkd.widget.common.insert;
24 import tkd.widget.common.justify;
25 import tkd.widget.common.range;
26 import tkd.widget.common.selection;
27 import tkd.widget.common.show;
28 import tkd.widget.common.value;
29 import tkd.widget.common.width;
30 import tkd.widget.common.xscrollcommand;
31 import tkd.widget.common.xview;
32 import tkd.widget.widget;
33 
34 /**
35  * A spinbox widget is an entry widget with built-in up and down buttons that 
36  * are used to either modify a numeric value or to select among a set of 
37  * values. The widget implements all the features of the entry widget.
38  *
39  * If a list of string values are set to be controlled by this widget it will 
40  * override any numeric range or step set. The widget will instead use the 
41  * values specified beginning with the first value.
42  *
43  * Example:
44  * ---
45  * auto spinBox = new SpinBox()
46  * 	.setCommand(delegate(CommandArgs arg){ ... })
47  * 	.setFromValue(0.0)
48  * 	.setToValue(100.0)
49  * 	.setStep(0.5)
50  * 	.setValue(0.0)
51  * 	.pack();
52  * ---
53  *
54  * Common_Commands:
55  *     These are injected common commands that can also be used with this widget.
56  *     $(P
57  *         $(LINK2 ./common/boundingbox.html, BoundingBox) $(BR)
58  *         $(LINK2 ./common/color.html, Color) $(BR)
59  *         $(LINK2 ./common/command.html, Command) $(BR)
60  *         $(LINK2 ./common/cursor.html, Cursor) $(BR)
61  *         $(LINK2 ./common/data.html, Data) $(BR)
62  *         $(LINK2 ./common/delete_.html, Delete) $(BR)
63  *         $(LINK2 ./common/exportselection.html, Exportselection) $(BR)
64  *         $(LINK2 ./common/font.html, Font) $(BR)
65  *         $(LINK2 ./common/index.html, Index) $(BR)
66  *         $(LINK2 ./common/insert.html, Insert) $(BR)
67  *         $(LINK2 ./common/justify.html, Justify) $(BR)
68  *         $(LINK2 ./common/range.html, Range) $(BR)
69  *         $(LINK2 ./common/selection.html, Selection) $(BR)
70  *         $(LINK2 ./common/show.html, Show) $(BR)
71  *         $(LINK2 ./common/value.html, Value) $(BR)
72  *         $(LINK2 ./common/width.html, Width) $(BR)
73  *         $(LINK2 ./common/xscrollcommand.html, XScrollCommand) $(BR)
74  *         $(LINK2 ./common/xview.html, XView) $(BR)
75  *     )
76  *
77  * Additional_Events:
78  *     Additional events that can also be bound to using the $(LINK2 ../element/uielement.html#UiElement.bind, bind) method.
79  *     $(P
80  *         <<Clear>>,
81  *         <<Copy>>,
82  *         <<Cut>>,
83  *         <<Decrement>>,
84  *         <<Increment>>,
85  *         <<Paste>>,
86  *         <<PasteSelection>>,
87  *         <<PrevWindow>>,
88  *         <<TraverseIn>>,
89  *         <Alt-Key>,
90  *         <B1-Enter>,
91  *         <B1-Leave>,
92  *         <B1-Motion>,
93  *         <B2-Motion>,
94  *         <Button-1>,
95  *         <Button-2>,
96  *         <ButtonRelease-1>,
97  *         <Control-Button-1>,
98  *         <Control-Key>,
99  *         <Control-Key-Left>,
100  *         <Control-Key-Right>,
101  *         <Control-Key-a>,
102  *         <Control-Key-b>,
103  *         <Control-Key-backslash>,
104  *         <Control-Key-d>,
105  *         <Control-Key-e>,
106  *         <Control-Key-f>,
107  *         <Control-Key-h>,
108  *         <Control-Key-k>,
109  *         <Control-Key-slash>,
110  *         <Control-Key-space>,
111  *         <Control-Key-t>,
112  *         <Control-Shift-Key-Left>,
113  *         <Control-Shift-Key-Right>,
114  *         <Control-Shift-Key-space>,
115  *         <Double-Button-1>,
116  *         <Double-Shift-Button-1>,
117  *         <Key>,
118  *         <Key-BackSpace>,
119  *         <Key-Delete>,
120  *         <Key-Down>,
121  *         <Key-End>,
122  *         <Key-Escape>,
123  *         <Key-F10>,
124  *         <Key-Home>,
125  *         <Key-Insert>,
126  *         <Key-KP_Enter>,
127  *         <Key-Left>,
128  *         <Key-Return>,
129  *         <Key-Right>,
130  *         <Key-Select>,
131  *         <Key-Tab>,
132  *         <Key-Up>,
133  *         <Meta-Key>,
134  *         <Meta-Key-BackSpace>,
135  *         <Meta-Key-Delete>,
136  *         <Meta-Key-b>,
137  *         <Meta-Key-d>,
138  *         <Meta-Key-f>,
139  *         <Shift-Button-1>,
140  *         <Shift-Key-End>,
141  *         <Shift-Key-Home>,
142  *         <Shift-Key-Left>,
143  *         <Shift-Key-Right>,
144  *         <Shift-Key-Select>,
145  *         <Triple-Button-1>,
146  *         <Triple-Shift-Button-1>,
147  *     )
148  *
149  * See_Also:
150  *     $(LINK2 ./widget.html, tkd.widget.widget)
151  */
152 class SpinBox : Widget, IXScrollable!(SpinBox)
153 {
154 	/**
155 	 * The name of the variable that contains the widget's value.
156 	 */
157 	private string _valueVariable;
158 
159 	/**
160 	 * Construct the widget.
161 	 *
162 	 * Params:
163 	 *     parent = The parent of this widget.
164 	 *
165 	 * See_Also:
166 	 *     $(LINK2 ../element/uielement.html, tkd.element.uielement) $(BR)
167 	 */
168 	this(UiElement parent = null)
169 	{
170 		super(parent);
171 		this._elementId = "spinbox";
172 		this._valueVariable = format("variable-%s", this.generateHash(this.id));
173 
174 		this._tk.eval("ttk::spinbox %s -textvariable %s", this.id, this._valueVariable);
175 
176 		this.setFromValue(int.min);
177 		this.setToValue(int.max);
178 		this.setValue("0");
179 	}
180 
181 	/**
182 	 * For widgets using a numeric range, this method sets the step value of 
183 	 * each increment or decrement.
184 	 *
185 	 * Params:
186 	 *     stepValue = The step value to increment and decrement by.
187 	 *
188 	 * Returns:
189 	 *     This widget to aid method chaining.
190 	 */
191 	public auto setStep(this T)(double stepValue)
192 	{
193 		assert(stepValue > 0, "Step value should be greater than zero.");
194 
195 		this._tk.eval("%s configure -increment %s", this.id, stepValue);
196 
197 		return cast(T) this;
198 	}
199 
200 	/**
201 	 * Set whether the values wrap when the limit is reached during increment 
202 	 * or decrement.
203 	 *
204 	 * Params:
205 	 *     wrapValue = Value specifing whether the value wraps.
206 	 *
207 	 * Returns:
208 	 *     This widget to aid method chaining.
209 	 */
210 	public auto setWrap(this T)(bool wrapValue)
211 	{
212 		this._tk.eval("%s configure -wrap %s", this.id, wrapValue);
213 
214 		return cast(T) this;
215 	}
216 
217 	/**
218 	 * Specifies an alternate format to use when using a numerical range. This 
219 	 * must be a format specifier of the form '%5.2f', as it will format a 
220 	 * floating-point number.
221 	 *
222 	 * Params:
223 	 *     digitsBefore = The amount of digits to show before a decimal point.
224 	 *     digitsAfter = The amount of digits to show after a decimal point.
225 	 *
226 	 * Returns:
227 	 *     This widget to aid method chaining.
228 	 */
229 	public auto setNumericFormat(this T)(int digitsBefore, int digitsAfter)
230 	{
231 		this._tk.eval("%s configure -format %%%s.%sf", this.id, digitsBefore, digitsAfter);
232 
233 		return cast(T) this;
234 	}
235 
236 	/**
237 	 * Mixin common commands.
238 	 */
239 	mixin BoundingBox;
240 	mixin Color;
241 	mixin Command;
242 	mixin Cursor;
243 	mixin Data;
244 	mixin Delete_;
245 	mixin ExportSelection;
246 	mixin Font;
247 	mixin Index;
248 	mixin Insert;
249 	mixin Justify;
250 	mixin Range;
251 	mixin Selection;
252 	mixin Show;
253 	mixin Value!(this._valueVariable, string);
254 	mixin Width;
255 	mixin XScrollCommand!(SpinBox);
256 	mixin XView;
257 }