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 }