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