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