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