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