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