1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * GtkSpinButton widget for GTK+
5 * Copyright (C) 1998 Lars Hamann and Stefan Jeske
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
28 #include "gdk/gdkkeysyms.h"
29 #include "gtkspinbutton.h"
31 #include "gtksignal.h"
34 #define MIN_SPIN_BUTTON_WIDTH 30
36 #define SPIN_BUTTON_INITIAL_TIMER_DELAY 200
37 #define SPIN_BUTTON_TIMER_DELAY 20
38 #define MAX_TEXT_LENGTH 256
39 #define MAX_TIMER_CALLS 5
42 static void gtk_spin_button_class_init (GtkSpinButtonClass *klass);
43 static void gtk_spin_button_init (GtkSpinButton *spin_button);
44 static void gtk_spin_button_finalize (GtkObject *object);
45 static void gtk_spin_button_map (GtkWidget *widget);
46 static void gtk_spin_button_unmap (GtkWidget *widget);
47 static void gtk_spin_button_realize (GtkWidget *widget);
48 static void gtk_spin_button_unrealize (GtkWidget *widget);
49 static void gtk_spin_button_size_request (GtkWidget *widget,
50 GtkRequisition *requisition);
51 static void gtk_spin_button_size_allocate (GtkWidget *widget,
52 GtkAllocation *allocation);
53 static void gtk_spin_button_paint (GtkWidget *widget,
55 static void gtk_spin_button_draw (GtkWidget *widget,
57 static gint gtk_spin_button_expose (GtkWidget *widget,
58 GdkEventExpose *event);
59 static gint gtk_spin_button_button_press (GtkWidget *widget,
60 GdkEventButton *event);
61 static gint gtk_spin_button_button_release (GtkWidget *widget,
62 GdkEventButton *event);
63 static gint gtk_spin_button_motion_notify (GtkWidget *widget,
64 GdkEventMotion *event);
65 static gint gtk_spin_button_enter_notify (GtkWidget *widget,
66 GdkEventCrossing *event);
67 static gint gtk_spin_button_leave_notify (GtkWidget *widget,
68 GdkEventCrossing *event);
69 static gint gtk_spin_button_focus_out (GtkWidget *widget,
70 GdkEventFocus *event);
71 static void gtk_spin_button_draw_arrow (GtkSpinButton *spin_button,
73 static gint gtk_spin_button_timer (GtkSpinButton *spin_button);
74 static void gtk_spin_button_value_changed (GtkWidget *widget,
75 GtkSpinButton *spin_button);
76 static gint gtk_spin_button_key_press (GtkWidget *widget,
78 static gint gtk_spin_button_key_release (GtkWidget *widget,
80 static void gtk_spin_button_update (GtkSpinButton *spin_button);
81 static void gtk_spin_button_activate (GtkEditable *editable);
82 static void gtk_spin_button_snap (GtkSpinButton *spin_button,
84 static void gtk_spin_button_insert_text (GtkEditable *editable,
85 const gchar *new_text,
90 static GtkWidgetClass *parent_class = NULL;
94 gtk_spin_button_get_type (void)
96 static guint spin_button_type = 0;
98 if (!spin_button_type)
100 GtkTypeInfo spin_button_info =
103 sizeof (GtkSpinButton),
104 sizeof (GtkSpinButtonClass),
105 (GtkClassInitFunc) gtk_spin_button_class_init,
106 (GtkObjectInitFunc) gtk_spin_button_init,
107 (GtkArgSetFunc) NULL,
108 (GtkArgGetFunc) NULL,
111 spin_button_type = gtk_type_unique (gtk_entry_get_type (),
114 return spin_button_type;
118 gtk_spin_button_class_init (GtkSpinButtonClass *class)
120 GtkObjectClass *object_class;
121 GtkWidgetClass *widget_class;
122 GtkEditableClass *editable_class;
124 object_class = (GtkObjectClass*) class;
125 widget_class = (GtkWidgetClass*) class;
126 editable_class = (GtkEditableClass*) class;
128 parent_class = gtk_type_class (gtk_entry_get_type ());
130 object_class->finalize = gtk_spin_button_finalize;
132 widget_class->map = gtk_spin_button_map;
133 widget_class->unmap = gtk_spin_button_unmap;
134 widget_class->realize = gtk_spin_button_realize;
135 widget_class->unrealize = gtk_spin_button_unrealize;
136 widget_class->size_request = gtk_spin_button_size_request;
137 widget_class->size_allocate = gtk_spin_button_size_allocate;
138 widget_class->draw = gtk_spin_button_draw;
139 widget_class->expose_event = gtk_spin_button_expose;
140 widget_class->button_press_event = gtk_spin_button_button_press;
141 widget_class->button_release_event = gtk_spin_button_button_release;
142 widget_class->motion_notify_event = gtk_spin_button_motion_notify;
143 widget_class->key_press_event = gtk_spin_button_key_press;
144 widget_class->key_release_event = gtk_spin_button_key_release;
145 widget_class->enter_notify_event = gtk_spin_button_enter_notify;
146 widget_class->leave_notify_event = gtk_spin_button_leave_notify;
147 widget_class->focus_out_event = gtk_spin_button_focus_out;
149 editable_class->insert_text = gtk_spin_button_insert_text;
150 editable_class->activate = gtk_spin_button_activate;
154 gtk_spin_button_init (GtkSpinButton *spin_button)
156 spin_button->adjustment = NULL;
157 spin_button->panel = NULL;
158 spin_button->shadow_type = GTK_SHADOW_OUT;
159 spin_button->timer = 0;
160 spin_button->ev_time = 0;
161 spin_button->climb_rate = 0.0;
162 spin_button->timer_step = 0.0;
163 spin_button->update_policy = GTK_UPDATE_ALWAYS;
164 spin_button->in_child = 2;
165 spin_button->click_child = 2;
166 spin_button->button = 0;
167 spin_button->need_timer = 0;
168 spin_button->timer_calls = 0;
169 spin_button->digits = 0;
170 spin_button->numeric = FALSE;
171 spin_button->wrap = FALSE;
172 spin_button->snap_to_ticks = FALSE;
176 gtk_spin_button_construct (GtkSpinButton *spin_button,
177 GtkAdjustment *adjustment,
181 char buf[MAX_TEXT_LENGTH];
183 g_return_if_fail (spin_button != NULL);
184 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
185 g_return_if_fail (digits >= 0 && digits < 6);
188 adjustment = (GtkAdjustment*) gtk_adjustment_new (0, 0, 0, 0, 0, 0);
190 gtk_spin_button_set_adjustment (spin_button, adjustment);
191 spin_button->digits = digits;
192 sprintf (buf, "%0.*f", digits, adjustment->value);
193 gtk_entry_set_text (GTK_ENTRY (spin_button), buf);
194 spin_button->climb_rate = climb_rate;
198 gtk_spin_button_new (GtkAdjustment *adjustment,
204 g_return_val_if_fail (digits >= 0 && digits < 6, NULL);
206 spin = gtk_type_new (gtk_spin_button_get_type ());
208 gtk_spin_button_construct (spin, adjustment, climb_rate, digits);
210 return GTK_WIDGET (spin);
214 gtk_spin_button_finalize (GtkObject *object)
216 g_return_if_fail (object != NULL);
217 g_return_if_fail (GTK_IS_SPIN_BUTTON (object));
219 gtk_object_unref (GTK_OBJECT (GTK_SPIN_BUTTON (object)->adjustment));
221 GTK_OBJECT_CLASS (parent_class)->finalize (object);
225 gtk_spin_button_map (GtkWidget *widget)
227 g_return_if_fail (widget != NULL);
228 g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
230 if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
232 GTK_WIDGET_CLASS (parent_class)->map (widget);
233 gdk_window_show (GTK_SPIN_BUTTON (widget)->panel);
238 gtk_spin_button_unmap (GtkWidget *widget)
240 g_return_if_fail (widget != NULL);
241 g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
243 if (GTK_WIDGET_MAPPED (widget))
245 gdk_window_hide (GTK_SPIN_BUTTON (widget)->panel);
246 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
251 gtk_spin_button_realize (GtkWidget *widget)
254 GdkWindowAttr attributes;
255 gint attributes_mask;
258 g_return_if_fail (widget != NULL);
259 g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
261 spin = GTK_SPIN_BUTTON (widget);
263 real_width = widget->allocation.width;
264 widget->allocation.width -= ARROW_SIZE + 2 * widget->style->klass->xthickness;
265 gtk_widget_set_events (widget, gtk_widget_get_events (widget) |
266 GDK_KEY_RELEASE_MASK);
267 GTK_WIDGET_CLASS (parent_class)->realize (widget);
269 widget->allocation.width = real_width;
271 attributes.window_type = GDK_WINDOW_CHILD;
272 attributes.wclass = GDK_INPUT_OUTPUT;
273 attributes.visual = gtk_widget_get_visual (widget);
274 attributes.colormap = gtk_widget_get_colormap (widget);
275 attributes.event_mask = gtk_widget_get_events (widget);
276 attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
277 | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
278 | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
280 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
282 attributes.x = (widget->allocation.x + widget->allocation.width - ARROW_SIZE -
283 2 * widget->style->klass->xthickness);
284 attributes.y = widget->allocation.y + (widget->allocation.height -
285 widget->requisition.height) / 2;
286 attributes.width = ARROW_SIZE + 2 * widget->style->klass->xthickness;
287 attributes.height = widget->requisition.height;
289 spin->panel = gdk_window_new (gtk_widget_get_parent_window (widget),
290 &attributes, attributes_mask);
291 gdk_window_set_user_data (spin->panel, widget);
293 gtk_style_set_background (widget->style, spin->panel, GTK_STATE_NORMAL);
297 gtk_spin_button_unrealize (GtkWidget *widget)
301 g_return_if_fail (widget != NULL);
302 g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
304 spin = GTK_SPIN_BUTTON (widget);
306 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
310 gdk_window_set_user_data (spin->panel, NULL);
311 gdk_window_destroy (spin->panel);
317 gtk_spin_button_size_request (GtkWidget *widget,
318 GtkRequisition *requisition)
320 g_return_if_fail (widget != NULL);
321 g_return_if_fail (requisition != NULL);
322 g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
324 GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
326 requisition->width = MIN_SPIN_BUTTON_WIDTH + ARROW_SIZE
327 + 2 * widget->style->klass->xthickness;
331 gtk_spin_button_size_allocate (GtkWidget *widget,
332 GtkAllocation *allocation)
334 GtkAllocation child_allocation;
336 g_return_if_fail (widget != NULL);
337 g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
338 g_return_if_fail (allocation != NULL);
340 child_allocation = *allocation;
341 child_allocation.width -= ARROW_SIZE + 2 * widget->style->klass->xthickness;
343 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, &child_allocation);
345 widget->allocation = *allocation;
347 if (GTK_WIDGET_REALIZED (widget))
349 child_allocation.width = ARROW_SIZE + 2 * widget->style->klass->xthickness;
350 child_allocation.height = widget->requisition.height;
351 child_allocation.x = (allocation->x + allocation->width - ARROW_SIZE -
352 2 * widget->style->klass->xthickness);
353 child_allocation.y = allocation->y + (allocation->height - widget->requisition.height) / 2;
355 gdk_window_move_resize (GTK_SPIN_BUTTON (widget)->panel,
358 child_allocation.width,
359 child_allocation.height);
364 gtk_spin_button_paint (GtkWidget *widget,
369 g_return_if_fail (widget != NULL);
370 g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
372 spin = GTK_SPIN_BUTTON (widget);
374 if (GTK_WIDGET_DRAWABLE (widget))
376 if (spin->shadow_type != GTK_SHADOW_NONE)
377 gtk_draw_shadow (widget->style, spin->panel,
378 GTK_STATE_NORMAL, spin->shadow_type,
380 ARROW_SIZE + 2 * widget->style->klass->xthickness,
381 widget->requisition.height);
382 gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
383 gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
385 GTK_WIDGET_CLASS (parent_class)->draw (widget, area);
390 gtk_spin_button_draw (GtkWidget *widget,
393 g_return_if_fail (widget != NULL);
394 g_return_if_fail (GTK_IS_SPIN_BUTTON (widget));
395 g_return_if_fail (area != NULL);
397 if (GTK_WIDGET_DRAWABLE (widget))
398 gtk_spin_button_paint (widget, area);
402 gtk_spin_button_expose (GtkWidget *widget,
403 GdkEventExpose *event)
405 g_return_val_if_fail (widget != NULL, FALSE);
406 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
407 g_return_val_if_fail (event != NULL, FALSE);
409 if (GTK_WIDGET_DRAWABLE (widget))
410 gtk_spin_button_paint (widget, &event->area);
416 gtk_spin_button_draw_arrow (GtkSpinButton *spin_button,
419 GtkStateType state_type;
420 GtkShadowType shadow_type;
425 g_return_if_fail (spin_button != NULL);
426 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
428 widget = GTK_WIDGET (spin_button);
430 if (GTK_WIDGET_DRAWABLE (spin_button))
432 if (spin_button->in_child == arrow)
434 if (spin_button->click_child == arrow)
435 state_type = GTK_STATE_ACTIVE;
437 state_type = GTK_STATE_PRELIGHT;
440 state_type = GTK_STATE_NORMAL;
442 if (spin_button->click_child == arrow)
443 shadow_type = GTK_SHADOW_IN;
445 shadow_type = GTK_SHADOW_OUT;
447 if (arrow == GTK_ARROW_UP)
449 if (spin_button->shadow_type != GTK_SHADOW_NONE)
451 x = widget->style->klass->xthickness;
452 y = widget->style->klass->ythickness;
456 x = widget->style->klass->xthickness - 1;
457 y = widget->style->klass->ythickness - 1;
459 gtk_draw_arrow (widget->style, spin_button->panel,
460 state_type, shadow_type, arrow, TRUE,
461 x, y, ARROW_SIZE, widget->requisition.height / 2
462 - widget->style->klass->ythickness);
466 if (spin_button->shadow_type != GTK_SHADOW_NONE)
468 x = widget->style->klass->xthickness;
469 y = widget->requisition.height / 2;
473 x = widget->style->klass->xthickness - 1;
474 y = widget->requisition.height / 2 + 1;
476 gtk_draw_arrow (widget->style, spin_button->panel,
477 state_type, shadow_type, arrow, TRUE,
478 x, y, ARROW_SIZE, widget->requisition.height / 2
479 - widget->style->klass->ythickness);
485 gtk_spin_button_enter_notify (GtkWidget *widget,
486 GdkEventCrossing *event)
490 g_return_val_if_fail (widget != NULL, FALSE);
491 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
492 g_return_val_if_fail (event != NULL, FALSE);
494 spin = GTK_SPIN_BUTTON (widget);
496 if (event->window == spin->panel)
501 gdk_window_get_pointer (spin->panel, &x, &y, NULL);
503 if (y <= widget->requisition.height / 2)
505 spin->in_child = GTK_ARROW_UP;
506 if (spin->click_child == 2)
507 gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
511 spin->in_child = GTK_ARROW_DOWN;
512 if (spin->click_child == 2)
513 gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
520 gtk_spin_button_leave_notify (GtkWidget *widget,
521 GdkEventCrossing *event)
525 g_return_val_if_fail (widget != NULL, FALSE);
526 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
527 g_return_val_if_fail (event != NULL, FALSE);
529 spin = GTK_SPIN_BUTTON (widget);
531 if (event->window == spin->panel && spin->click_child == 2)
533 if (spin->in_child == GTK_ARROW_UP)
536 gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
541 gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
548 gtk_spin_button_focus_out (GtkWidget *widget,
549 GdkEventFocus *event)
551 g_return_val_if_fail (widget != NULL, FALSE);
552 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
553 g_return_val_if_fail (event != NULL, FALSE);
555 gtk_spin_button_update (GTK_SPIN_BUTTON (widget));
557 return GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, event);
561 gtk_spin_button_button_press (GtkWidget *widget,
562 GdkEventButton *event)
566 g_return_val_if_fail (widget != NULL, FALSE);
567 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
568 g_return_val_if_fail (event != NULL, FALSE);
570 spin = GTK_SPIN_BUTTON (widget);
574 if (event->window == spin->panel)
576 if (!GTK_WIDGET_HAS_FOCUS (widget))
577 gtk_widget_grab_focus (widget);
578 gtk_grab_add (widget);
579 spin->button = event->button;
581 gtk_spin_button_update (spin);
583 if (event->y <= widget->requisition.height / 2)
585 spin->click_child = GTK_ARROW_UP;
586 if (event->button == 1)
588 gtk_spin_button_spin (spin, spin->click_child,
589 spin->adjustment->step_increment);
592 spin->timer_step = spin->adjustment->step_increment;
593 spin->need_timer = TRUE;
594 spin->timer = gtk_timeout_add
595 (SPIN_BUTTON_INITIAL_TIMER_DELAY,
596 (GtkFunction) gtk_spin_button_timer, (gpointer) spin);
599 else if (event->button == 2)
601 gtk_spin_button_spin (spin, spin->click_child,
602 spin->adjustment->page_increment);
605 spin->timer_step = spin->adjustment->page_increment;
606 spin->need_timer = TRUE;
607 spin->timer = gtk_timeout_add
608 (SPIN_BUTTON_INITIAL_TIMER_DELAY,
609 (GtkFunction) gtk_spin_button_timer, (gpointer) spin);
612 gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
616 spin->click_child = GTK_ARROW_DOWN;
617 if (event->button == 1)
619 gtk_spin_button_spin (spin, spin->click_child,
620 spin->adjustment->step_increment);
623 spin->timer_step = spin->adjustment->step_increment;
624 spin->need_timer = TRUE;
625 spin->timer = gtk_timeout_add
626 (SPIN_BUTTON_INITIAL_TIMER_DELAY,
627 (GtkFunction) gtk_spin_button_timer, (gpointer) spin);
630 else if (event->button == 2)
632 gtk_spin_button_spin (spin, spin->click_child,
633 spin->adjustment->page_increment);
636 spin->timer_step = spin->adjustment->page_increment;
637 spin->need_timer = TRUE;
638 spin->timer = gtk_timeout_add
639 (SPIN_BUTTON_INITIAL_TIMER_DELAY,
640 (GtkFunction) gtk_spin_button_timer, (gpointer) spin);
643 gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
647 GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
653 gtk_spin_button_button_release (GtkWidget *widget,
654 GdkEventButton *event)
658 g_return_val_if_fail (widget != NULL, FALSE);
659 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
660 g_return_val_if_fail (event != NULL, FALSE);
662 spin = GTK_SPIN_BUTTON (widget);
664 if (event->button == spin->button)
670 gtk_timeout_remove (spin->timer);
672 spin->timer_calls = 0;
673 spin->need_timer = FALSE;
676 if (event->button == 3)
678 if (event->y >= 0 && event->x >= 0 &&
679 event->y <= widget->requisition.height &&
680 event->x <= ARROW_SIZE + 2 * widget->style->klass->xthickness)
682 if (spin->click_child == GTK_ARROW_UP &&
683 spin->adjustment->value < spin->adjustment->upper &&
684 event->y <= widget->requisition.height / 2)
685 gtk_adjustment_set_value (spin->adjustment,
686 spin->adjustment->upper);
687 else if (spin->click_child == GTK_ARROW_DOWN &&
688 spin->adjustment->value > spin->adjustment->lower &&
689 event->y > widget->requisition.height / 2)
690 gtk_adjustment_set_value (spin->adjustment,
691 spin->adjustment->lower);
694 gtk_grab_remove (widget);
695 click_child = spin->click_child;
696 spin->click_child = 2;
698 gtk_spin_button_draw_arrow (spin, click_child);
701 GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
707 gtk_spin_button_motion_notify (GtkWidget *widget,
708 GdkEventMotion *event)
712 g_return_val_if_fail (widget != NULL, FALSE);
713 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
714 g_return_val_if_fail (event != NULL, FALSE);
716 spin = GTK_SPIN_BUTTON (widget);
721 if (event->window == spin->panel)
727 gdk_window_get_pointer (spin->panel, NULL, &y, NULL);
729 if (y <= widget->requisition.height / 2 &&
730 spin->in_child == GTK_ARROW_DOWN)
732 spin->in_child = GTK_ARROW_UP;
733 gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
734 gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
736 else if (y > widget->requisition.height / 2 &&
737 spin->in_child == GTK_ARROW_UP)
739 spin->in_child = GTK_ARROW_DOWN;
740 gtk_spin_button_draw_arrow (spin, GTK_ARROW_UP);
741 gtk_spin_button_draw_arrow (spin, GTK_ARROW_DOWN);
746 return GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
750 gtk_spin_button_timer (GtkSpinButton *spin_button)
752 g_return_val_if_fail (spin_button != NULL, FALSE);
753 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spin_button), FALSE);
755 if (spin_button->timer)
757 gtk_spin_button_spin (spin_button, spin_button->click_child,
758 spin_button->timer_step);
760 if (spin_button->need_timer) {
761 spin_button->need_timer = FALSE;
762 spin_button->timer = gtk_timeout_add
763 (SPIN_BUTTON_TIMER_DELAY, (GtkFunction) gtk_spin_button_timer,
764 (gpointer) spin_button);
767 else if (spin_button->climb_rate > 0.0 &&
768 spin_button->timer_step < spin_button->adjustment->page_increment)
770 if (spin_button->timer_calls < MAX_TIMER_CALLS)
771 spin_button->timer_calls++;
774 spin_button->timer_calls = 0;
775 spin_button->timer_step += spin_button->climb_rate;
784 gtk_spin_button_spin (GtkSpinButton *spin_button,
788 gfloat new_value = 0.0;
790 g_return_if_fail (spin_button != NULL);
791 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
793 if (direction == GTK_ARROW_UP)
795 new_value = spin_button->adjustment->value + step;
796 if (spin_button->wrap)
798 if (spin_button->adjustment->value == spin_button->adjustment->upper)
799 new_value = spin_button->adjustment->lower;
800 else if (new_value > spin_button->adjustment->upper)
801 new_value = spin_button->adjustment->upper;
804 new_value = MIN (new_value, spin_button->adjustment->upper);
806 else if (direction == GTK_ARROW_DOWN)
808 new_value = spin_button->adjustment->value - step;
809 if (spin_button->wrap)
811 if (spin_button->adjustment->value == spin_button->adjustment->lower)
812 new_value = spin_button->adjustment->upper;
813 else if (new_value < spin_button->adjustment->lower)
814 new_value = spin_button->adjustment->lower;
817 new_value = MAX (new_value, spin_button->adjustment->lower);
820 if (new_value != spin_button->adjustment->value)
821 gtk_adjustment_set_value (spin_button->adjustment, new_value);
825 gtk_spin_button_value_changed (GtkWidget *widget,
826 GtkSpinButton *spin_button)
828 char buf[MAX_TEXT_LENGTH];
830 g_return_if_fail (widget != NULL);
831 g_return_if_fail (GTK_IS_ADJUSTMENT (widget));
833 sprintf (buf, "%0.*f", spin_button->digits, spin_button->adjustment->value);
835 gtk_entry_set_text (GTK_ENTRY (spin_button), buf);
839 gtk_spin_button_key_press (GtkWidget *widget,
844 gboolean key_repeat = FALSE;
846 g_return_val_if_fail (widget != NULL, FALSE);
847 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
849 spin = GTK_SPIN_BUTTON (widget);
852 key_repeat = (event->time == spin->ev_time);
854 if (key == GDK_Up || key == GDK_Down ||
855 key == GDK_Page_Up || key == GDK_Page_Down)
856 gtk_spin_button_update (spin);
861 if (GTK_WIDGET_HAS_FOCUS (widget))
863 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget),
866 spin->timer_step = spin->adjustment->step_increment;
868 gtk_spin_button_spin (spin, GTK_ARROW_UP, spin->timer_step);
872 if (spin->climb_rate > 0.0 && spin->timer_step
873 < spin->adjustment->page_increment)
875 if (spin->timer_calls < MAX_TIMER_CALLS)
879 spin->timer_calls = 0;
880 spin->timer_step += spin->climb_rate;
888 if (GTK_WIDGET_HAS_FOCUS (widget))
890 gtk_signal_emit_stop_by_name (GTK_OBJECT (widget),
893 spin->timer_step = spin->adjustment->step_increment;
895 gtk_spin_button_spin (spin, GTK_ARROW_DOWN, spin->timer_step);
899 if (spin->climb_rate > 0.0 && spin->timer_step
900 < spin->adjustment->page_increment)
902 if (spin->timer_calls < MAX_TIMER_CALLS)
906 spin->timer_calls = 0;
907 spin->timer_step += spin->climb_rate;
915 if (event->state & GDK_CONTROL_MASK)
916 gtk_adjustment_set_value (spin->adjustment, spin->adjustment->upper);
918 gtk_spin_button_spin (spin, GTK_ARROW_UP,
919 spin->adjustment->page_increment);
922 if (event->state & GDK_CONTROL_MASK)
923 gtk_adjustment_set_value (spin->adjustment, spin->adjustment->lower);
925 gtk_spin_button_spin (spin, GTK_ARROW_DOWN,
926 spin->adjustment->page_increment);
931 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
935 gtk_spin_button_key_release (GtkWidget *widget,
940 g_return_val_if_fail (widget != NULL, FALSE);
941 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), FALSE);
943 spin = GTK_SPIN_BUTTON (widget);
945 spin->ev_time = event->time;
950 gtk_spin_button_snap (GtkSpinButton *spin_button,
956 inc = spin_button->adjustment->step_increment;
957 tmp = (val - spin_button->adjustment->lower) / inc;
958 if (tmp - floor (tmp) < ceil (tmp) - tmp)
959 val = spin_button->adjustment->lower + floor (tmp) * inc;
961 val = spin_button->adjustment->lower + ceil (tmp) * inc;
962 gtk_adjustment_set_value (spin_button->adjustment, val);
966 gtk_spin_button_update (GtkSpinButton *spin_button)
971 g_return_if_fail (spin_button != NULL);
972 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
974 val = strtod (gtk_entry_get_text (GTK_ENTRY (spin_button)), &error);
976 if (spin_button->update_policy == GTK_UPDATE_ALWAYS)
978 if (val < spin_button->adjustment->lower)
979 val = spin_button->adjustment->lower;
980 else if (val > spin_button->adjustment->upper)
981 val = spin_button->adjustment->upper;
983 else if ((spin_button->update_policy == GTK_UPDATE_IF_VALID) &&
985 val < spin_button->adjustment->lower ||
986 val > spin_button->adjustment->upper))
988 gtk_signal_emit_by_name (GTK_OBJECT (spin_button->adjustment),
993 if (spin_button->snap_to_ticks)
994 gtk_spin_button_snap (spin_button, val);
996 gtk_adjustment_set_value (spin_button->adjustment, val);
1000 gtk_spin_button_activate (GtkEditable *editable)
1002 g_return_if_fail (editable != NULL);
1003 g_return_if_fail (GTK_IS_SPIN_BUTTON (editable));
1005 if (editable->editable)
1006 gtk_spin_button_update (GTK_SPIN_BUTTON (editable));
1010 gtk_spin_button_set_adjustment (GtkSpinButton *spin_button,
1011 GtkAdjustment *adjustment)
1013 g_return_if_fail (spin_button != NULL);
1014 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1016 if (spin_button->adjustment != adjustment)
1018 if (spin_button->adjustment)
1020 gtk_signal_disconnect_by_data (GTK_OBJECT (spin_button->adjustment),
1021 (gpointer) spin_button);
1022 gtk_object_unref (GTK_OBJECT (spin_button->adjustment));
1024 spin_button->adjustment = adjustment;
1027 gtk_object_ref (GTK_OBJECT (adjustment));
1028 gtk_object_sink (GTK_OBJECT (adjustment));
1030 (GTK_OBJECT (adjustment), "value_changed",
1031 (GtkSignalFunc) gtk_spin_button_value_changed,
1032 (gpointer) spin_button);
1038 gtk_spin_button_get_adjustment (GtkSpinButton *spin_button)
1040 g_return_val_if_fail (spin_button != NULL, NULL);
1041 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spin_button), NULL);
1043 return spin_button->adjustment;
1047 gtk_spin_button_set_digits (GtkSpinButton *spin_button,
1050 g_return_if_fail (spin_button != NULL);
1051 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1052 g_return_if_fail (digits >= 0 || digits < 6);
1054 if (spin_button->digits != digits)
1056 spin_button->digits = digits;
1057 gtk_signal_emit_by_name (GTK_OBJECT (spin_button->adjustment),
1063 gtk_spin_button_get_value_as_float (GtkSpinButton *spin_button)
1065 g_return_val_if_fail (spin_button != NULL, 0.0);
1066 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spin_button), 0.0);
1068 return spin_button->adjustment->value;
1072 gtk_spin_button_get_value_as_int (GtkSpinButton *spin_button)
1076 g_return_val_if_fail (spin_button != NULL, 0);
1077 g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spin_button), 0);
1079 val = spin_button->adjustment->value;
1080 if (val - floor (val) < ceil (val) - val)
1087 gtk_spin_button_set_value (GtkSpinButton *spin_button,
1090 g_return_if_fail (spin_button != NULL);
1091 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1093 if (spin_button->adjustment->value != value)
1094 gtk_adjustment_set_value (spin_button->adjustment, value);
1098 gtk_spin_button_set_update_policy (GtkSpinButton *spin_button,
1099 GtkSpinButtonUpdatePolicy policy)
1101 g_return_if_fail (spin_button != NULL);
1102 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1104 spin_button->update_policy = policy;
1108 gtk_spin_button_set_numeric (GtkSpinButton *spin_button,
1111 g_return_if_fail (spin_button != NULL);
1112 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1114 spin_button->numeric = (numeric != 0);
1118 gtk_spin_button_insert_text (GtkEditable *editable,
1119 const gchar *new_text,
1120 gint new_text_length,
1124 GtkSpinButton *spin;
1126 g_return_if_fail (editable != NULL);
1127 g_return_if_fail (GTK_IS_SPIN_BUTTON (editable));
1129 entry = GTK_ENTRY (editable);
1130 spin = GTK_SPIN_BUTTON (editable);
1143 if (*(lc->negative_sign))
1144 neg_sign = *(lc->negative_sign);
1148 if (*(lc->positive_sign))
1149 pos_sign = *(lc->positive_sign);
1153 sign = ((strchr (entry->text, neg_sign) != 0) ||
1154 (strchr (entry->text, pos_sign) != 0));
1156 if (sign && !(*position))
1159 dotpos = strchr (entry->text, *(lc->decimal_point)) - entry->text;
1161 if (dotpos > -1 && *position > dotpos &&
1162 spin->digits - entry->text_length + dotpos - new_text_length + 1 < 0)
1165 for (i = 0; i < new_text_length; i++)
1167 if (new_text[i] == neg_sign || new_text[i] == pos_sign)
1169 if (sign || (*position) || i)
1173 else if (new_text[i] == *(lc->decimal_point))
1175 if (!spin->digits || dotpos > -1 ||
1176 (new_text_length - 1 - i + entry->text_length - *position >
1179 dotpos = *position + i;
1181 else if (new_text[i] < 0x30 || new_text[i] > 0x39)
1186 GTK_EDITABLE_CLASS (parent_class)->insert_text (editable, new_text,
1187 new_text_length, position);
1191 gtk_spin_button_set_wrap (GtkSpinButton *spin_button,
1194 g_return_if_fail (spin_button != NULL);
1195 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1197 spin_button->wrap = (wrap != 0);
1201 gtk_spin_button_set_shadow_type (GtkSpinButton *spin_button,
1202 GtkShadowType shadow_type)
1204 g_return_if_fail (spin_button != NULL);
1205 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1207 if (shadow_type != spin_button->shadow_type)
1209 spin_button->shadow_type = shadow_type;
1210 if (GTK_WIDGET_DRAWABLE (spin_button))
1211 gdk_window_clear (spin_button->panel);
1216 gtk_spin_button_set_snap_to_ticks (GtkSpinButton *spin_button,
1221 g_return_if_fail (spin_button != NULL);
1222 g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
1224 new_val = (snap_to_ticks != 0);
1226 if (new_val != spin_button->snap_to_ticks)
1228 spin_button->snap_to_ticks = new_val;
1231 gchar *error = NULL;
1234 val = strtod (gtk_entry_get_text (GTK_ENTRY (spin_button)), &error);
1235 gtk_spin_button_snap (spin_button, val);