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 }