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