1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gtk.SpinButton;
26 
27 private import glib.ConstructionException;
28 private import gobject.ObjectG;
29 private import gobject.Signals;
30 private import gtk.Adjustment;
31 private import gtk.Entry;
32 private import gtk.OrientableIF;
33 private import gtk.OrientableT;
34 private import gtk.Widget;
35 public  import gtkc.gdktypes;
36 private import gtkc.gtk;
37 public  import gtkc.gtktypes;
38 private import std.algorithm;
39 
40 
41 /**
42  * A #GtkSpinButton is an ideal way to allow the user to set the value of
43  * some attribute. Rather than having to directly type a number into a
44  * #GtkEntry, GtkSpinButton allows the user to click on one of two arrows
45  * to increment or decrement the displayed value. A value can still be
46  * typed in, with the bonus that it can be checked to ensure it is in a
47  * given range.
48  * 
49  * The main properties of a GtkSpinButton are through an adjustment.
50  * See the #GtkAdjustment section for more details about an adjustment's
51  * properties. Note that GtkSpinButton will by default make its entry
52  * large enough to accomodate the lower and upper bounds of the adjustment,
53  * which can lead to surprising results. Best practice is to set both
54  * the #GtkEntry:width-chars and #GtkEntry:max-width-chars poperties
55  * to the desired number of characters to display in the entry.
56  * 
57  * # CSS nodes
58  * 
59  * |[<!-- language="plain" -->
60  * spinbutton.horizontal
61  * ├── entry
62  * │   ╰── ...
63  * ├── button.down
64  * ╰── button.up
65  * ]|
66  * 
67  * |[<!-- language="plain" -->
68  * spinbutton.vertical
69  * ├── button.up
70  * ├── entry
71  * │   ╰── ...
72  * ╰── button.down
73  * ]|
74  * 
75  * GtkSpinButtons main CSS node has the name spinbutton. It creates subnodes
76  * for the entry and the two buttons, with these names. The button nodes have
77  * the style classes .up and .down. The GtkEntry subnodes (if present) are put
78  * below the entry node. The orientation of the spin button is reflected in
79  * the .vertical or .horizontal style class on the main node.
80  * 
81  * ## Using a GtkSpinButton to get an integer
82  * 
83  * |[<!-- language="C" -->
84  * // Provides a function to retrieve an integer value from a GtkSpinButton
85  * // and creates a spin button to model percentage values.
86  * 
87  * gint
88  * grab_int_value (GtkSpinButton *button,
89  * gpointer       user_data)
90  * {
91  * return gtk_spin_button_get_value_as_int (button);
92  * }
93  * 
94  * void
95  * create_integer_spin_button (void)
96  * {
97  * 
98  * GtkWidget *window, *button;
99  * GtkAdjustment *adjustment;
100  * 
101  * adjustment = gtk_adjustment_new (50.0, 0.0, 100.0, 1.0, 5.0, 0.0);
102  * 
103  * window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
104  * gtk_container_set_border_width (GTK_CONTAINER (window), 5);
105  * 
106  * // creates the spinbutton, with no decimal places
107  * button = gtk_spin_button_new (adjustment, 1.0, 0);
108  * gtk_container_add (GTK_CONTAINER (window), button);
109  * 
110  * gtk_widget_show_all (window);
111  * }
112  * ]|
113  * 
114  * ## Using a GtkSpinButton to get a floating point value
115  * 
116  * |[<!-- language="C" -->
117  * // Provides a function to retrieve a floating point value from a
118  * // GtkSpinButton, and creates a high precision spin button.
119  * 
120  * gfloat
121  * grab_float_value (GtkSpinButton *button,
122  * gpointer       user_data)
123  * {
124  * return gtk_spin_button_get_value (button);
125  * }
126  * 
127  * void
128  * create_floating_spin_button (void)
129  * {
130  * GtkWidget *window, *button;
131  * GtkAdjustment *adjustment;
132  * 
133  * adjustment = gtk_adjustment_new (2.500, 0.0, 5.0, 0.001, 0.1, 0.0);
134  * 
135  * window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
136  * gtk_container_set_border_width (GTK_CONTAINER (window), 5);
137  * 
138  * // creates the spinbutton, with three decimal places
139  * button = gtk_spin_button_new (adjustment, 0.001, 3);
140  * gtk_container_add (GTK_CONTAINER (window), button);
141  * 
142  * gtk_widget_show_all (window);
143  * }
144  * ]|
145  */
146 public class SpinButton : Entry, OrientableIF
147 {
148 	/** the main Gtk struct */
149 	protected GtkSpinButton* gtkSpinButton;
150 
151 	/** Get the main Gtk struct */
152 	public GtkSpinButton* getSpinButtonStruct()
153 	{
154 		return gtkSpinButton;
155 	}
156 
157 	/** the main Gtk struct as a void* */
158 	protected override void* getStruct()
159 	{
160 		return cast(void*)gtkSpinButton;
161 	}
162 
163 	protected override void setStruct(GObject* obj)
164 	{
165 		gtkSpinButton = cast(GtkSpinButton*)obj;
166 		super.setStruct(obj);
167 	}
168 
169 	/**
170 	 * Sets our main struct and passes it to the parent class.
171 	 */
172 	public this (GtkSpinButton* gtkSpinButton, bool ownedRef = false)
173 	{
174 		this.gtkSpinButton = gtkSpinButton;
175 		super(cast(GtkEntry*)gtkSpinButton, ownedRef);
176 	}
177 
178 	// add the Orientable capabilities
179 	mixin OrientableT!(GtkSpinButton);
180 
181 
182 	/** */
183 	public static GType getType()
184 	{
185 		return gtk_spin_button_get_type();
186 	}
187 
188 	/**
189 	 * Creates a new #GtkSpinButton.
190 	 *
191 	 * Params:
192 	 *     adjustment = the #GtkAdjustment object that this spin
193 	 *         button should use, or %NULL
194 	 *     climbRate = specifies how much the spin button changes when an arrow
195 	 *         is clicked on
196 	 *     digits = the number of decimal places to display
197 	 *
198 	 * Return: The new spin button as a #GtkWidget
199 	 *
200 	 * Throws: ConstructionException GTK+ fails to create the object.
201 	 */
202 	public this(Adjustment adjustment, double climbRate, uint digits)
203 	{
204 		auto p = gtk_spin_button_new((adjustment is null) ? null : adjustment.getAdjustmentStruct(), climbRate, digits);
205 		
206 		if(p is null)
207 		{
208 			throw new ConstructionException("null returned by new");
209 		}
210 		
211 		this(cast(GtkSpinButton*) p);
212 	}
213 
214 	/**
215 	 * This is a convenience constructor that allows creation of a numeric
216 	 * #GtkSpinButton without manually creating an adjustment. The value is
217 	 * initially set to the minimum value and a page increment of 10 * @step
218 	 * is the default. The precision of the spin button is equivalent to the
219 	 * precision of @step.
220 	 *
221 	 * Note that the way in which the precision is derived works best if @step
222 	 * is a power of ten. If the resulting precision is not suitable for your
223 	 * needs, use gtk_spin_button_set_digits() to correct it.
224 	 *
225 	 * Params:
226 	 *     min = Minimum allowable value
227 	 *     max = Maximum allowable value
228 	 *     step = Increment added or subtracted by spinning the widget
229 	 *
230 	 * Return: The new spin button as a #GtkWidget
231 	 *
232 	 * Throws: ConstructionException GTK+ fails to create the object.
233 	 */
234 	public this(double min, double max, double step)
235 	{
236 		auto p = gtk_spin_button_new_with_range(min, max, step);
237 		
238 		if(p is null)
239 		{
240 			throw new ConstructionException("null returned by new_with_range");
241 		}
242 		
243 		this(cast(GtkSpinButton*) p);
244 	}
245 
246 	/**
247 	 * Changes the properties of an existing spin button. The adjustment,
248 	 * climb rate, and number of decimal places are all changed accordingly,
249 	 * after this function call.
250 	 *
251 	 * Params:
252 	 *     adjustment = a #GtkAdjustment
253 	 *     climbRate = the new climb rate
254 	 *     digits = the number of decimal places to display in the spin button
255 	 */
256 	public void configure(Adjustment adjustment, double climbRate, uint digits)
257 	{
258 		gtk_spin_button_configure(gtkSpinButton, (adjustment is null) ? null : adjustment.getAdjustmentStruct(), climbRate, digits);
259 	}
260 
261 	/**
262 	 * Get the adjustment associated with a #GtkSpinButton
263 	 *
264 	 * Return: the #GtkAdjustment of @spin_button
265 	 */
266 	public Adjustment getAdjustment()
267 	{
268 		auto p = gtk_spin_button_get_adjustment(gtkSpinButton);
269 		
270 		if(p is null)
271 		{
272 			return null;
273 		}
274 		
275 		return ObjectG.getDObject!(Adjustment)(cast(GtkAdjustment*) p);
276 	}
277 
278 	/**
279 	 * Fetches the precision of @spin_button. See gtk_spin_button_set_digits().
280 	 *
281 	 * Return: the current precision
282 	 */
283 	public uint getDigits()
284 	{
285 		return gtk_spin_button_get_digits(gtkSpinButton);
286 	}
287 
288 	/**
289 	 * Gets the current step and page the increments used by @spin_button. See
290 	 * gtk_spin_button_set_increments().
291 	 *
292 	 * Params:
293 	 *     step = location to store step increment, or %NULL
294 	 *     page = location to store page increment, or %NULL
295 	 */
296 	public void getIncrements(out double step, out double page)
297 	{
298 		gtk_spin_button_get_increments(gtkSpinButton, &step, &page);
299 	}
300 
301 	/**
302 	 * Returns whether non-numeric text can be typed into the spin button.
303 	 * See gtk_spin_button_set_numeric().
304 	 *
305 	 * Return: %TRUE if only numeric text can be entered
306 	 */
307 	public bool getNumeric()
308 	{
309 		return gtk_spin_button_get_numeric(gtkSpinButton) != 0;
310 	}
311 
312 	/**
313 	 * Gets the range allowed for @spin_button.
314 	 * See gtk_spin_button_set_range().
315 	 *
316 	 * Params:
317 	 *     min = location to store minimum allowed value, or %NULL
318 	 *     max = location to store maximum allowed value, or %NULL
319 	 */
320 	public void getRange(out double min, out double max)
321 	{
322 		gtk_spin_button_get_range(gtkSpinButton, &min, &max);
323 	}
324 
325 	/**
326 	 * Returns whether the values are corrected to the nearest step.
327 	 * See gtk_spin_button_set_snap_to_ticks().
328 	 *
329 	 * Return: %TRUE if values are snapped to the nearest step
330 	 */
331 	public bool getSnapToTicks()
332 	{
333 		return gtk_spin_button_get_snap_to_ticks(gtkSpinButton) != 0;
334 	}
335 
336 	/**
337 	 * Gets the update behavior of a spin button.
338 	 * See gtk_spin_button_set_update_policy().
339 	 *
340 	 * Return: the current update policy
341 	 */
342 	public GtkSpinButtonUpdatePolicy getUpdatePolicy()
343 	{
344 		return gtk_spin_button_get_update_policy(gtkSpinButton);
345 	}
346 
347 	/**
348 	 * Get the value in the @spin_button.
349 	 *
350 	 * Return: the value of @spin_button
351 	 */
352 	public double getValue()
353 	{
354 		return gtk_spin_button_get_value(gtkSpinButton);
355 	}
356 
357 	/**
358 	 * Get the value @spin_button represented as an integer.
359 	 *
360 	 * Return: the value of @spin_button
361 	 */
362 	public int getValueAsInt()
363 	{
364 		return gtk_spin_button_get_value_as_int(gtkSpinButton);
365 	}
366 
367 	/**
368 	 * Returns whether the spin button’s value wraps around to the
369 	 * opposite limit when the upper or lower limit of the range is
370 	 * exceeded. See gtk_spin_button_set_wrap().
371 	 *
372 	 * Return: %TRUE if the spin button wraps around
373 	 */
374 	public bool getWrap()
375 	{
376 		return gtk_spin_button_get_wrap(gtkSpinButton) != 0;
377 	}
378 
379 	/**
380 	 * Replaces the #GtkAdjustment associated with @spin_button.
381 	 *
382 	 * Params:
383 	 *     adjustment = a #GtkAdjustment to replace the existing adjustment
384 	 */
385 	public void setAdjustment(Adjustment adjustment)
386 	{
387 		gtk_spin_button_set_adjustment(gtkSpinButton, (adjustment is null) ? null : adjustment.getAdjustmentStruct());
388 	}
389 
390 	/**
391 	 * Set the precision to be displayed by @spin_button. Up to 20 digit precision
392 	 * is allowed.
393 	 *
394 	 * Params:
395 	 *     digits = the number of digits after the decimal point to be displayed for the spin button’s value
396 	 */
397 	public void setDigits(uint digits)
398 	{
399 		gtk_spin_button_set_digits(gtkSpinButton, digits);
400 	}
401 
402 	/**
403 	 * Sets the step and page increments for spin_button.  This affects how
404 	 * quickly the value changes when the spin button’s arrows are activated.
405 	 *
406 	 * Params:
407 	 *     step = increment applied for a button 1 press.
408 	 *     page = increment applied for a button 2 press.
409 	 */
410 	public void setIncrements(double step, double page)
411 	{
412 		gtk_spin_button_set_increments(gtkSpinButton, step, page);
413 	}
414 
415 	/**
416 	 * Sets the flag that determines if non-numeric text can be typed
417 	 * into the spin button.
418 	 *
419 	 * Params:
420 	 *     numeric = flag indicating if only numeric entry is allowed
421 	 */
422 	public void setNumeric(bool numeric)
423 	{
424 		gtk_spin_button_set_numeric(gtkSpinButton, numeric);
425 	}
426 
427 	/**
428 	 * Sets the minimum and maximum allowable values for @spin_button.
429 	 *
430 	 * If the current value is outside this range, it will be adjusted
431 	 * to fit within the range, otherwise it will remain unchanged.
432 	 *
433 	 * Params:
434 	 *     min = minimum allowable value
435 	 *     max = maximum allowable value
436 	 */
437 	public void setRange(double min, double max)
438 	{
439 		gtk_spin_button_set_range(gtkSpinButton, min, max);
440 	}
441 
442 	/**
443 	 * Sets the policy as to whether values are corrected to the
444 	 * nearest step increment when a spin button is activated after
445 	 * providing an invalid value.
446 	 *
447 	 * Params:
448 	 *     snapToTicks = a flag indicating if invalid values should be corrected
449 	 */
450 	public void setSnapToTicks(bool snapToTicks)
451 	{
452 		gtk_spin_button_set_snap_to_ticks(gtkSpinButton, snapToTicks);
453 	}
454 
455 	/**
456 	 * Sets the update behavior of a spin button.
457 	 * This determines whether the spin button is always updated
458 	 * or only when a valid value is set.
459 	 *
460 	 * Params:
461 	 *     policy = a #GtkSpinButtonUpdatePolicy value
462 	 */
463 	public void setUpdatePolicy(GtkSpinButtonUpdatePolicy policy)
464 	{
465 		gtk_spin_button_set_update_policy(gtkSpinButton, policy);
466 	}
467 
468 	/**
469 	 * Sets the value of @spin_button.
470 	 *
471 	 * Params:
472 	 *     value = the new value
473 	 */
474 	public void setValue(double value)
475 	{
476 		gtk_spin_button_set_value(gtkSpinButton, value);
477 	}
478 
479 	/**
480 	 * Sets the flag that determines if a spin button value wraps
481 	 * around to the opposite limit when the upper or lower limit
482 	 * of the range is exceeded.
483 	 *
484 	 * Params:
485 	 *     wrap = a flag indicating if wrapping behavior is performed
486 	 */
487 	public void setWrap(bool wrap)
488 	{
489 		gtk_spin_button_set_wrap(gtkSpinButton, wrap);
490 	}
491 
492 	/**
493 	 * Increment or decrement a spin button’s value in a specified
494 	 * direction by a specified amount.
495 	 *
496 	 * Params:
497 	 *     direction = a #GtkSpinType indicating the direction to spin
498 	 *     increment = step increment to apply in the specified direction
499 	 */
500 	public void spin(GtkSpinType direction, double increment)
501 	{
502 		gtk_spin_button_spin(gtkSpinButton, direction, increment);
503 	}
504 
505 	/**
506 	 * Manually force an update of the spin button.
507 	 */
508 	public void update()
509 	{
510 		gtk_spin_button_update(gtkSpinButton);
511 	}
512 
513 	protected class OnChangeValueDelegateWrapper
514 	{
515 		void delegate(GtkScrollType, SpinButton) dlg;
516 		gulong handlerId;
517 		ConnectFlags flags;
518 		this(void delegate(GtkScrollType, SpinButton) dlg, gulong handlerId, ConnectFlags flags)
519 		{
520 			this.dlg = dlg;
521 			this.handlerId = handlerId;
522 			this.flags = flags;
523 		}
524 	}
525 	protected OnChangeValueDelegateWrapper[] onChangeValueListeners;
526 
527 	/**
528 	 * The ::change-value signal is a [keybinding signal][GtkBindingSignal]
529 	 * which gets emitted when the user initiates a value change.
530 	 *
531 	 * Applications should not connect to it, but may emit it with
532 	 * g_signal_emit_by_name() if they need to control the cursor
533 	 * programmatically.
534 	 *
535 	 * The default bindings for this signal are Up/Down and PageUp and/PageDown.
536 	 *
537 	 * Params:
538 	 *     scroll = a #GtkScrollType to specify the speed and amount of change
539 	 */
540 	gulong addOnChangeValue(void delegate(GtkScrollType, SpinButton) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
541 	{
542 		onChangeValueListeners ~= new OnChangeValueDelegateWrapper(dlg, 0, connectFlags);
543 		onChangeValueListeners[onChangeValueListeners.length - 1].handlerId = Signals.connectData(
544 			this,
545 			"change-value",
546 			cast(GCallback)&callBackChangeValue,
547 			cast(void*)onChangeValueListeners[onChangeValueListeners.length - 1],
548 			cast(GClosureNotify)&callBackChangeValueDestroy,
549 			connectFlags);
550 		return onChangeValueListeners[onChangeValueListeners.length - 1].handlerId;
551 	}
552 	
553 	extern(C) static void callBackChangeValue(GtkSpinButton* spinbuttonStruct, GtkScrollType scroll,OnChangeValueDelegateWrapper wrapper)
554 	{
555 		wrapper.dlg(scroll, wrapper.outer);
556 	}
557 	
558 	extern(C) static void callBackChangeValueDestroy(OnChangeValueDelegateWrapper wrapper, GClosure* closure)
559 	{
560 		wrapper.outer.internalRemoveOnChangeValue(wrapper);
561 	}
562 
563 	protected void internalRemoveOnChangeValue(OnChangeValueDelegateWrapper source)
564 	{
565 		foreach(index, wrapper; onChangeValueListeners)
566 		{
567 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
568 			{
569 				onChangeValueListeners[index] = null;
570 				onChangeValueListeners = std.algorithm.remove(onChangeValueListeners, index);
571 				break;
572 			}
573 		}
574 	}
575 	
576 
577 	protected class OnInputDelegateWrapper
578 	{
579 		int delegate(void*, SpinButton) dlg;
580 		gulong handlerId;
581 		ConnectFlags flags;
582 		this(int delegate(void*, SpinButton) dlg, gulong handlerId, ConnectFlags flags)
583 		{
584 			this.dlg = dlg;
585 			this.handlerId = handlerId;
586 			this.flags = flags;
587 		}
588 	}
589 	protected OnInputDelegateWrapper[] onInputListeners;
590 
591 	/**
592 	 * The ::input signal can be used to influence the conversion of
593 	 * the users input into a double value. The signal handler is
594 	 * expected to use gtk_entry_get_text() to retrieve the text of
595 	 * the entry and set @new_value to the new value.
596 	 *
597 	 * The default conversion uses g_strtod().
598 	 *
599 	 * Params:
600 	 *     newValue = return location for the new value
601 	 *
602 	 * Return: %TRUE for a successful conversion, %FALSE if the input
603 	 *     was not handled, and %GTK_INPUT_ERROR if the conversion failed.
604 	 */
605 	gulong addOnInput(int delegate(void*, SpinButton) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
606 	{
607 		onInputListeners ~= new OnInputDelegateWrapper(dlg, 0, connectFlags);
608 		onInputListeners[onInputListeners.length - 1].handlerId = Signals.connectData(
609 			this,
610 			"input",
611 			cast(GCallback)&callBackInput,
612 			cast(void*)onInputListeners[onInputListeners.length - 1],
613 			cast(GClosureNotify)&callBackInputDestroy,
614 			connectFlags);
615 		return onInputListeners[onInputListeners.length - 1].handlerId;
616 	}
617 	
618 	extern(C) static int callBackInput(GtkSpinButton* spinbuttonStruct, void* newValue,OnInputDelegateWrapper wrapper)
619 	{
620 		return wrapper.dlg(newValue, wrapper.outer);
621 	}
622 	
623 	extern(C) static void callBackInputDestroy(OnInputDelegateWrapper wrapper, GClosure* closure)
624 	{
625 		wrapper.outer.internalRemoveOnInput(wrapper);
626 	}
627 
628 	protected void internalRemoveOnInput(OnInputDelegateWrapper source)
629 	{
630 		foreach(index, wrapper; onInputListeners)
631 		{
632 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
633 			{
634 				onInputListeners[index] = null;
635 				onInputListeners = std.algorithm.remove(onInputListeners, index);
636 				break;
637 			}
638 		}
639 	}
640 	
641 
642 	protected class OnOutputDelegateWrapper
643 	{
644 		bool delegate(SpinButton) dlg;
645 		gulong handlerId;
646 		ConnectFlags flags;
647 		this(bool delegate(SpinButton) dlg, gulong handlerId, ConnectFlags flags)
648 		{
649 			this.dlg = dlg;
650 			this.handlerId = handlerId;
651 			this.flags = flags;
652 		}
653 	}
654 	protected OnOutputDelegateWrapper[] onOutputListeners;
655 
656 	/**
657 	 * The ::output signal can be used to change to formatting
658 	 * of the value that is displayed in the spin buttons entry.
659 	 * |[<!-- language="C" -->
660 	 * // show leading zeros
661 	 * static gboolean
662 	 * on_output (GtkSpinButton *spin,
663 	 * gpointer       data)
664 	 * {
665 	 * GtkAdjustment *adjustment;
666 	 * gchar *text;
667 	 * int value;
668 	 *
669 	 * adjustment = gtk_spin_button_get_adjustment (spin);
670 	 * value = (int)gtk_adjustment_get_value (adjustment);
671 	 * text = g_strdup_printf ("%02d", value);
672 	 * gtk_entry_set_text (GTK_ENTRY (spin), text);
673 	 * g_free (text);
674 	 *
675 	 * return TRUE;
676 	 * }
677 	 * ]|
678 	 *
679 	 * Return: %TRUE if the value has been displayed
680 	 */
681 	gulong addOnOutput(bool delegate(SpinButton) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
682 	{
683 		onOutputListeners ~= new OnOutputDelegateWrapper(dlg, 0, connectFlags);
684 		onOutputListeners[onOutputListeners.length - 1].handlerId = Signals.connectData(
685 			this,
686 			"output",
687 			cast(GCallback)&callBackOutput,
688 			cast(void*)onOutputListeners[onOutputListeners.length - 1],
689 			cast(GClosureNotify)&callBackOutputDestroy,
690 			connectFlags);
691 		return onOutputListeners[onOutputListeners.length - 1].handlerId;
692 	}
693 	
694 	extern(C) static int callBackOutput(GtkSpinButton* spinbuttonStruct,OnOutputDelegateWrapper wrapper)
695 	{
696 		return wrapper.dlg(wrapper.outer);
697 	}
698 	
699 	extern(C) static void callBackOutputDestroy(OnOutputDelegateWrapper wrapper, GClosure* closure)
700 	{
701 		wrapper.outer.internalRemoveOnOutput(wrapper);
702 	}
703 
704 	protected void internalRemoveOnOutput(OnOutputDelegateWrapper source)
705 	{
706 		foreach(index, wrapper; onOutputListeners)
707 		{
708 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
709 			{
710 				onOutputListeners[index] = null;
711 				onOutputListeners = std.algorithm.remove(onOutputListeners, index);
712 				break;
713 			}
714 		}
715 	}
716 	
717 
718 	protected class OnValueChangedDelegateWrapper
719 	{
720 		void delegate(SpinButton) dlg;
721 		gulong handlerId;
722 		ConnectFlags flags;
723 		this(void delegate(SpinButton) dlg, gulong handlerId, ConnectFlags flags)
724 		{
725 			this.dlg = dlg;
726 			this.handlerId = handlerId;
727 			this.flags = flags;
728 		}
729 	}
730 	protected OnValueChangedDelegateWrapper[] onValueChangedListeners;
731 
732 	/**
733 	 * The ::value-changed signal is emitted when the value represented by
734 	 * @spinbutton changes. Also see the #GtkSpinButton::output signal.
735 	 */
736 	gulong addOnValueChanged(void delegate(SpinButton) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
737 	{
738 		onValueChangedListeners ~= new OnValueChangedDelegateWrapper(dlg, 0, connectFlags);
739 		onValueChangedListeners[onValueChangedListeners.length - 1].handlerId = Signals.connectData(
740 			this,
741 			"value-changed",
742 			cast(GCallback)&callBackValueChanged,
743 			cast(void*)onValueChangedListeners[onValueChangedListeners.length - 1],
744 			cast(GClosureNotify)&callBackValueChangedDestroy,
745 			connectFlags);
746 		return onValueChangedListeners[onValueChangedListeners.length - 1].handlerId;
747 	}
748 	
749 	extern(C) static void callBackValueChanged(GtkSpinButton* spinbuttonStruct,OnValueChangedDelegateWrapper wrapper)
750 	{
751 		wrapper.dlg(wrapper.outer);
752 	}
753 	
754 	extern(C) static void callBackValueChangedDestroy(OnValueChangedDelegateWrapper wrapper, GClosure* closure)
755 	{
756 		wrapper.outer.internalRemoveOnValueChanged(wrapper);
757 	}
758 
759 	protected void internalRemoveOnValueChanged(OnValueChangedDelegateWrapper source)
760 	{
761 		foreach(index, wrapper; onValueChangedListeners)
762 		{
763 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
764 			{
765 				onValueChangedListeners[index] = null;
766 				onValueChangedListeners = std.algorithm.remove(onValueChangedListeners, index);
767 				break;
768 			}
769 		}
770 	}
771 	
772 
773 	protected class OnWrappedDelegateWrapper
774 	{
775 		void delegate(SpinButton) dlg;
776 		gulong handlerId;
777 		ConnectFlags flags;
778 		this(void delegate(SpinButton) dlg, gulong handlerId, ConnectFlags flags)
779 		{
780 			this.dlg = dlg;
781 			this.handlerId = handlerId;
782 			this.flags = flags;
783 		}
784 	}
785 	protected OnWrappedDelegateWrapper[] onWrappedListeners;
786 
787 	/**
788 	 * The ::wrapped signal is emitted right after the spinbutton wraps
789 	 * from its maximum to minimum value or vice-versa.
790 	 *
791 	 * Since: 2.10
792 	 */
793 	gulong addOnWrapped(void delegate(SpinButton) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
794 	{
795 		onWrappedListeners ~= new OnWrappedDelegateWrapper(dlg, 0, connectFlags);
796 		onWrappedListeners[onWrappedListeners.length - 1].handlerId = Signals.connectData(
797 			this,
798 			"wrapped",
799 			cast(GCallback)&callBackWrapped,
800 			cast(void*)onWrappedListeners[onWrappedListeners.length - 1],
801 			cast(GClosureNotify)&callBackWrappedDestroy,
802 			connectFlags);
803 		return onWrappedListeners[onWrappedListeners.length - 1].handlerId;
804 	}
805 	
806 	extern(C) static void callBackWrapped(GtkSpinButton* spinbuttonStruct,OnWrappedDelegateWrapper wrapper)
807 	{
808 		wrapper.dlg(wrapper.outer);
809 	}
810 	
811 	extern(C) static void callBackWrappedDestroy(OnWrappedDelegateWrapper wrapper, GClosure* closure)
812 	{
813 		wrapper.outer.internalRemoveOnWrapped(wrapper);
814 	}
815 
816 	protected void internalRemoveOnWrapped(OnWrappedDelegateWrapper source)
817 	{
818 		foreach(index, wrapper; onWrappedListeners)
819 		{
820 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
821 			{
822 				onWrappedListeners[index] = null;
823 				onWrappedListeners = std.algorithm.remove(onWrappedListeners, index);
824 				break;
825 			}
826 		}
827 	}
828 	
829 }