00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <config.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <math.h>
00034 #include <string.h>
00035 #include <locale.h>
00036
00037 #include <glib.h>
00038 #include <gtk/gtk.h>
00039 #include <gdk/gdk.h>
00040 #include "gdk/gdkkeysyms.h"
00041 #include "gtk/gtkbindings.h"
00042 #include "gtk/gtkmain.h"
00043 #include "gtk/gtksettings.h"
00044
00045 #include "gtkmarshalers.h"
00046 #include "gtkintl.h"
00047
00048 #include "gtkspinbuttonsci.h"
00049
00050 #define MIN_SPIN_BUTTON_SCI_WIDTH 30
00051 #define SPIN_BUTTON_SCI_INITIAL_TIMER_DELAY 200
00052 #define SPIN_BUTTON_SCI_TIMER_DELAY 20
00053 #define MAX_TIMER_CALLS 5
00054 #define EPSILON 1e-10
00055 #define MAX_DIGITS 20
00056 #define MIN_ARROW_WIDTH 6
00057
00058 enum {
00059 PROP_0,
00060 PROP_ADJUSTMENT,
00061 PROP_CLIMB_RATE,
00062 PROP_DIGITS,
00063 PROP_SNAP_TO_TICKS,
00064 PROP_NUMERIC,
00065 PROP_WRAP,
00066 PROP_UPDATE_POLICY,
00067 PROP_VALUE
00068 };
00069
00070
00071 enum
00072 {
00073 INPUT,
00074 OUTPUT,
00075 VALUE_CHANGED,
00076 CHANGE_VALUE,
00077 LAST_SIGNAL
00078 };
00079
00080 static void gtk_spin_button_sci_class_init (GtkSpinbuttonsciClass *klass);
00081 static void gtk_spin_button_sci_editable_init (GtkEditableClass *iface);
00082 static void gtk_spin_button_sci_init (GtkSpinbuttonsci *spin_button_sci);
00083 static void gtk_spin_button_sci_finalize (GObject *object);
00084 static void gtk_spin_button_sci_destroy (GtkObject *object);
00085 static void gtk_spin_button_sci_set_property (GObject *object,
00086 guint prop_id,
00087 const GValue *value,
00088 GParamSpec *pspec);
00089 static void gtk_spin_button_sci_get_property (GObject *object,
00090 guint prop_id,
00091 GValue *value,
00092 GParamSpec *pspec);
00093 static void gtk_spin_button_sci_map (GtkWidget *widget);
00094 static void gtk_spin_button_sci_unmap (GtkWidget *widget);
00095 static void gtk_spin_button_sci_realize (GtkWidget *widget);
00096 static void gtk_spin_button_sci_unrealize (GtkWidget *widget);
00097 static void gtk_spin_button_sci_size_request (GtkWidget *widget,
00098 GtkRequisition *requisition);
00099 static void gtk_spin_button_sci_size_allocate (GtkWidget *widget,
00100 GtkAllocation *allocation);
00101 static gint gtk_spin_button_sci_expose (GtkWidget *widget,
00102 GdkEventExpose *event);
00103 static gint gtk_spin_button_sci_button_press (GtkWidget *widget,
00104 GdkEventButton *event);
00105 static gint gtk_spin_button_sci_button_release (GtkWidget *widget,
00106 GdkEventButton *event);
00107 static gint gtk_spin_button_sci_motion_notify (GtkWidget *widget,
00108 GdkEventMotion *event);
00109 static gint gtk_spin_button_sci_enter_notify (GtkWidget *widget,
00110 GdkEventCrossing *event);
00111 static gint gtk_spin_button_sci_leave_notify (GtkWidget *widget,
00112 GdkEventCrossing *event);
00113 static gint gtk_spin_button_sci_focus_out (GtkWidget *widget,
00114 GdkEventFocus *event);
00115 static void gtk_spin_button_sci_grab_notify (GtkWidget *widget,
00116 gboolean was_grabbed);
00117 static void gtk_spin_button_sci_state_changed (GtkWidget *widget,
00118 GtkStateType previous_state);
00119 static void gtk_spin_button_sci_draw_arrow (GtkSpinbuttonsci *spin_button_sci,
00120 GtkArrowType arrow_type);
00121 static gint gtk_spin_button_sci_timer (GtkSpinbuttonsci *spin_button_sci);
00122 static void gtk_spin_button_sci_stop_spinning (GtkSpinbuttonsci *spin);
00123 static void gtk_spin_button_sci_value_changed (GtkAdjustment *adjustment,
00124 GtkSpinbuttonsci *spin_button_sci);
00125 static gint gtk_spin_button_sci_key_release (GtkWidget *widget,
00126 GdkEventKey *event);
00127 static gint gtk_spin_button_sci_scroll (GtkWidget *widget,
00128 GdkEventScroll *event);
00129 static void gtk_spin_button_sci_activate (GtkEntry *entry);
00130 static void gtk_spin_button_sci_snap (GtkSpinbuttonsci *spin_button_sci,
00131 gdouble val);
00132 static void gtk_spin_button_sci_insert_text (GtkEditable *editable,
00133 const gchar *new_text,
00134 gint new_text_length,
00135 gint *position);
00136 static void gtk_spin_button_sci_real_spin (GtkSpinbuttonsci *spin_button_sci,
00137 gdouble step);
00138 static void gtk_spin_button_sci_real_change_value (GtkSpinbuttonsci *spin,
00139 GtkScrollType scroll);
00140
00141 static gint gtk_spin_button_sci_default_input (GtkSpinbuttonsci *spin_button_sci,
00142 gdouble *new_val);
00143 static gint gtk_spin_button_sci_default_output (GtkSpinbuttonsci *spin_button_sci);
00144
00145 static gint spin_button_sci_get_arrow_size (GtkSpinbuttonsci *spin_button_sci);
00146 static gint spin_button_sci_get_shadow_type (GtkSpinbuttonsci *spin_button_sci);
00147 static void spin_button_sci_redraw (GtkSpinbuttonsci *spin_button_sci);
00148
00149
00150 static GtkEntryClass *parent_class = NULL;
00151 static guint spinbuttonsci_signals[LAST_SIGNAL] = {0};
00152
00153 #define NO_ARROW 2
00154
00155 GType
00156 gtk_spin_button_sci_get_type (void)
00157 {
00158 static GType spin_button_sci_type = 0;
00159
00160 if (!spin_button_sci_type)
00161 {
00162 static const GTypeInfo spin_button_sci_info =
00163 {
00164 sizeof (GtkSpinbuttonsciClass),
00165 NULL,
00166 NULL,
00167 (GClassInitFunc) gtk_spin_button_sci_class_init,
00168 NULL,
00169 NULL,
00170 sizeof (GtkSpinbuttonsci),
00171 0,
00172 (GInstanceInitFunc) gtk_spin_button_sci_init,
00173 };
00174
00175 static const GInterfaceInfo editable_info =
00176 {
00177 (GInterfaceInitFunc) gtk_spin_button_sci_editable_init,
00178 NULL,
00179 NULL
00180 };
00181
00182 spin_button_sci_type =
00183 g_type_register_static (GTK_TYPE_ENTRY, "GtkSpinbuttonsci",
00184 &spin_button_sci_info, 0);
00185
00186 g_type_add_interface_static (spin_button_sci_type,
00187 GTK_TYPE_EDITABLE,
00188 &editable_info);
00189 }
00190 return spin_button_sci_type;
00191 }
00192
00193 #define add_spin_binding(binding_set, keyval, mask, scroll) \
00194 gtk_binding_entry_add_signal (binding_set, keyval, mask, \
00195 "change_value", 1, \
00196 GTK_TYPE_SCROLL_TYPE, scroll)
00197
00198 static void
00199 gtk_spin_button_sci_class_init (GtkSpinbuttonsciClass *class)
00200 {
00201 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
00202 GtkObjectClass *object_class;
00203 GtkWidgetClass *widget_class;
00204 GtkEntryClass *entry_class;
00205 GtkBindingSet *binding_set;
00206
00207 object_class = (GtkObjectClass*) class;
00208 widget_class = (GtkWidgetClass*) class;
00209 entry_class = (GtkEntryClass*) class;
00210
00211 parent_class = g_type_class_peek_parent (class);
00212
00213 gobject_class->finalize = gtk_spin_button_sci_finalize;
00214
00215 gobject_class->set_property = gtk_spin_button_sci_set_property;
00216 gobject_class->get_property = gtk_spin_button_sci_get_property;
00217
00218 object_class->destroy = gtk_spin_button_sci_destroy;
00219
00220 widget_class->map = gtk_spin_button_sci_map;
00221 widget_class->unmap = gtk_spin_button_sci_unmap;
00222 widget_class->realize = gtk_spin_button_sci_realize;
00223 widget_class->unrealize = gtk_spin_button_sci_unrealize;
00224 widget_class->size_request = gtk_spin_button_sci_size_request;
00225 widget_class->size_allocate = gtk_spin_button_sci_size_allocate;
00226 widget_class->expose_event = gtk_spin_button_sci_expose;
00227 widget_class->scroll_event = gtk_spin_button_sci_scroll;
00228 widget_class->button_press_event = gtk_spin_button_sci_button_press;
00229 widget_class->button_release_event = gtk_spin_button_sci_button_release;
00230 widget_class->motion_notify_event = gtk_spin_button_sci_motion_notify;
00231 widget_class->key_release_event = gtk_spin_button_sci_key_release;
00232 widget_class->enter_notify_event = gtk_spin_button_sci_enter_notify;
00233 widget_class->leave_notify_event = gtk_spin_button_sci_leave_notify;
00234 widget_class->focus_out_event = gtk_spin_button_sci_focus_out;
00235 widget_class->grab_notify = gtk_spin_button_sci_grab_notify;
00236 widget_class->state_changed = gtk_spin_button_sci_state_changed;
00237
00238 entry_class->activate = gtk_spin_button_sci_activate;
00239
00240 class->input = NULL;
00241 class->output = NULL;
00242 class->change_value = gtk_spin_button_sci_real_change_value;
00243
00244 g_object_class_install_property (gobject_class,
00245 PROP_ADJUSTMENT,
00246 g_param_spec_object ("adjustment",
00247 P_("Adjustment"),
00248 P_("The adjustment that holds the value of the spinbuttonsci"),
00249 GTK_TYPE_ADJUSTMENT,
00250 G_PARAM_READWRITE));
00251
00252 g_object_class_install_property (gobject_class,
00253 PROP_CLIMB_RATE,
00254 g_param_spec_double ("climb_rate",
00255 P_("Climb Rate"),
00256 P_("The acceleration rate when you hold down a button"),
00257 0.0,
00258 G_MAXDOUBLE,
00259 0.0,
00260 G_PARAM_READWRITE));
00261
00262 g_object_class_install_property (gobject_class,
00263 PROP_DIGITS,
00264 g_param_spec_uint ("digits",
00265 P_("Digits"),
00266 P_("The number of decimal places to display"),
00267 0,
00268 MAX_DIGITS,
00269 0,
00270 G_PARAM_READWRITE));
00271
00272 g_object_class_install_property (gobject_class,
00273 PROP_SNAP_TO_TICKS,
00274 g_param_spec_boolean ("snap_to_ticks",
00275 P_("Snap to Ticks"),
00276 P_("Whether erroneous values are automatically changed to a spin button's nearest step increment"),
00277 FALSE,
00278 G_PARAM_READWRITE));
00279
00280 g_object_class_install_property (gobject_class,
00281 PROP_NUMERIC,
00282 g_param_spec_boolean ("numeric",
00283 P_("Numeric"),
00284 P_("Whether non-numeric characters should be ignored"),
00285 FALSE,
00286 G_PARAM_READWRITE));
00287
00288 g_object_class_install_property (gobject_class,
00289 PROP_WRAP,
00290 g_param_spec_boolean ("wrap",
00291 P_("Wrap"),
00292 P_("Whether a spin button should wrap upon reaching its limits"),
00293 FALSE,
00294 G_PARAM_READWRITE));
00295
00296 g_object_class_install_property (gobject_class,
00297 PROP_UPDATE_POLICY,
00298 g_param_spec_enum ("update_policy",
00299 P_("Update Policy"),
00300 P_("Whether the spin button should update always, or only when the value is legal"),
00301 GTK_TYPE_SPIN_BUTTON_UPDATE_POLICY,
00302 GTK_UPDATE_ALWAYS,
00303 G_PARAM_READWRITE));
00304
00305 g_object_class_install_property (gobject_class,
00306 PROP_VALUE,
00307 g_param_spec_double ("value",
00308 P_("Value"),
00309 P_("Reads the current value, or sets a new value"),
00310 -G_MAXDOUBLE,
00311 G_MAXDOUBLE,
00312 0.0,
00313 G_PARAM_READWRITE));
00314
00315 gtk_widget_class_install_style_property_parser (widget_class,
00316 g_param_spec_enum ("shadow_type",
00317 "Shadow Type",
00318 P_("Style of bevel around the spin button"),
00319 GTK_TYPE_SHADOW_TYPE,
00320 GTK_SHADOW_IN,
00321 G_PARAM_READABLE),
00322 gtk_rc_property_parse_enum);
00323 spinbuttonsci_signals[INPUT] =
00324 g_signal_new ("input",
00325 G_TYPE_FROM_CLASS (gobject_class),
00326 G_SIGNAL_RUN_LAST,
00327 G_STRUCT_OFFSET (GtkSpinbuttonsciClass, input),
00328 NULL, NULL,
00329 _gtk_marshal_INT__POINTER,
00330 G_TYPE_INT, 1,
00331 G_TYPE_POINTER);
00332
00333 spinbuttonsci_signals[OUTPUT] =
00334 g_signal_new ("output",
00335 G_TYPE_FROM_CLASS (gobject_class),
00336 G_SIGNAL_RUN_LAST,
00337 G_STRUCT_OFFSET (GtkSpinbuttonsciClass, output),
00338 NULL, NULL,
00339
00340 _gtk_marshal_BOOLEAN__VOID,
00341 G_TYPE_BOOLEAN, 0);
00342
00343 spinbuttonsci_signals[VALUE_CHANGED] =
00344 g_signal_new ("value_changed",
00345 G_TYPE_FROM_CLASS (gobject_class),
00346 G_SIGNAL_RUN_LAST,
00347 G_STRUCT_OFFSET (GtkSpinbuttonsciClass, value_changed),
00348 NULL, NULL,
00349 _gtk_marshal_VOID__VOID,
00350 G_TYPE_NONE, 0);
00351
00352
00353 spinbuttonsci_signals[CHANGE_VALUE] =
00354 g_signal_new ("change_value",
00355 G_TYPE_FROM_CLASS (gobject_class),
00356 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
00357 G_STRUCT_OFFSET (GtkSpinbuttonsciClass, change_value),
00358 NULL, NULL,
00359 _gtk_marshal_VOID__ENUM,
00360 G_TYPE_NONE, 1,
00361 GTK_TYPE_SCROLL_TYPE);
00362
00363 binding_set = gtk_binding_set_by_class (class);
00364
00365 add_spin_binding (binding_set, GDK_Up, 0, GTK_SCROLL_STEP_UP);
00366 add_spin_binding (binding_set, GDK_KP_Up, 0, GTK_SCROLL_STEP_UP);
00367 add_spin_binding (binding_set, GDK_Down, 0, GTK_SCROLL_STEP_DOWN);
00368 add_spin_binding (binding_set, GDK_KP_Down, 0, GTK_SCROLL_STEP_DOWN);
00369 add_spin_binding (binding_set, GDK_Page_Up, 0, GTK_SCROLL_PAGE_UP);
00370 add_spin_binding (binding_set, GDK_Page_Down, 0, GTK_SCROLL_PAGE_DOWN);
00371 add_spin_binding (binding_set, GDK_Page_Up, GDK_CONTROL_MASK, GTK_SCROLL_END);
00372 add_spin_binding (binding_set, GDK_Page_Down, GDK_CONTROL_MASK, GTK_SCROLL_START);
00373 }
00374
00375 static void
00376 gtk_spin_button_sci_editable_init (GtkEditableClass *iface)
00377 {
00378 iface->insert_text = gtk_spin_button_sci_insert_text;
00379 }
00380
00381 static void
00382 gtk_spin_button_sci_set_property (GObject *object,
00383 guint prop_id,
00384 const GValue *value,
00385 GParamSpec *pspec)
00386 {
00387 GtkSpinbuttonsci *spin_button_sci;
00388
00389 spin_button_sci = GTK_SPIN_BUTTON_SCI (object);
00390
00391 switch (prop_id)
00392 {
00393 GtkAdjustment *adjustment;
00394
00395 case PROP_ADJUSTMENT:
00396 adjustment = GTK_ADJUSTMENT (g_value_get_object (value));
00397 if (!adjustment)
00398 adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
00399 gtk_spin_button_sci_set_adjustment (spin_button_sci, adjustment);
00400 break;
00401 case PROP_CLIMB_RATE:
00402 gtk_spin_button_sci_configure (spin_button_sci,
00403 spin_button_sci->adjustment,
00404 g_value_get_double (value),
00405 spin_button_sci->digits);
00406 break;
00407 case PROP_DIGITS:
00408 gtk_spin_button_sci_configure (spin_button_sci,
00409 spin_button_sci->adjustment,
00410 spin_button_sci->climb_rate,
00411 g_value_get_uint (value));
00412 break;
00413 case PROP_SNAP_TO_TICKS:
00414 gtk_spin_button_sci_set_snap_to_ticks (spin_button_sci, g_value_get_boolean (value));
00415 break;
00416 case PROP_NUMERIC:
00417 gtk_spin_button_sci_set_numeric (spin_button_sci, g_value_get_boolean (value));
00418 break;
00419 case PROP_WRAP:
00420 gtk_spin_button_sci_set_wrap (spin_button_sci, g_value_get_boolean (value));
00421 break;
00422 case PROP_UPDATE_POLICY:
00423 gtk_spin_button_sci_set_update_policy (spin_button_sci, g_value_get_enum (value));
00424 break;
00425 case PROP_VALUE:
00426 gtk_spin_button_sci_set_value (spin_button_sci, g_value_get_double (value));
00427 break;
00428 default:
00429 break;
00430 }
00431 }
00432
00433 static void
00434 gtk_spin_button_sci_get_property (GObject *object,
00435 guint prop_id,
00436 GValue *value,
00437 GParamSpec *pspec)
00438 {
00439 GtkSpinbuttonsci *spin_button_sci;
00440
00441 spin_button_sci = GTK_SPIN_BUTTON_SCI (object);
00442
00443 switch (prop_id)
00444 {
00445 case PROP_ADJUSTMENT:
00446 g_value_set_object (value, spin_button_sci->adjustment);
00447 break;
00448 case PROP_CLIMB_RATE:
00449 g_value_set_double (value, spin_button_sci->climb_rate);
00450 break;
00451 case PROP_DIGITS:
00452 g_value_set_uint (value, spin_button_sci->digits);
00453 break;
00454 case PROP_SNAP_TO_TICKS:
00455 g_value_set_boolean (value, spin_button_sci->snap_to_ticks);
00456 break;
00457 case PROP_NUMERIC:
00458 g_value_set_boolean (value, spin_button_sci->numeric);
00459 break;
00460 case PROP_WRAP:
00461 g_value_set_boolean (value, spin_button_sci->wrap);
00462 break;
00463 case PROP_UPDATE_POLICY:
00464 g_value_set_enum (value, spin_button_sci->update_policy);
00465 break;
00466 case PROP_VALUE:
00467 g_value_set_double (value, spin_button_sci->adjustment->value);
00468 break;
00469 default:
00470 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
00471 break;
00472 }
00473 }
00474
00475 static void
00476 gtk_spin_button_sci_init (GtkSpinbuttonsci *spin_button_sci)
00477 {
00478 spin_button_sci->adjustment = NULL;
00479 spin_button_sci->adjustment_safety = NULL;
00480 spin_button_sci->panel = NULL;
00481 spin_button_sci->timer = 0;
00482 spin_button_sci->climb_rate = 0.0;
00483 spin_button_sci->timer_step = 0.0;
00484 spin_button_sci->update_policy = GTK_UPDATE_ALWAYS;
00485 spin_button_sci->in_child = NO_ARROW;
00486 spin_button_sci->click_child = NO_ARROW;
00487 spin_button_sci->button = 0;
00488 spin_button_sci->need_timer = FALSE;
00489 spin_button_sci->timer_calls = 0;
00490 spin_button_sci->digits = 0;
00491 spin_button_sci->numeric = FALSE;
00492 spin_button_sci->wrap = FALSE;
00493 spin_button_sci->snap_to_ticks = FALSE;
00494 spin_button_sci->jump_to_limits = FALSE;
00495 spin_button_sci->sci_fixed_point_mantisse = FALSE;
00496 spin_button_sci->sci_max_left_digits = 8;
00497 spin_button_sci->sci_extension_magnitude_arrows = TRUE;
00498 spin_button_sci->sci_suffix = NULL;
00499
00500 gtk_spin_button_sci_set_adjustment (spin_button_sci,
00501 (GtkAdjustment*) gtk_adjustment_new (0, 0, 0, 0, 0, 0));
00502 }
00503
00504 static void
00505 gtk_spin_button_sci_finalize (GObject *object)
00506 {
00507 gtk_spin_button_sci_set_adjustment (GTK_SPIN_BUTTON_SCI (object), NULL);
00508
00509 G_OBJECT_CLASS (parent_class)->finalize (object);
00510 }
00511
00512 static void
00513 gtk_spin_button_sci_destroy (GtkObject *object)
00514 {
00515 gtk_spin_button_sci_stop_spinning (GTK_SPIN_BUTTON_SCI (object));
00516 gtk_spin_button_sci_set_suffix (GTK_SPIN_BUTTON_SCI (object), NULL);
00517
00518 GTK_OBJECT_CLASS (parent_class)->destroy (object);
00519 }
00520
00521 static void
00522 gtk_spin_button_sci_map (GtkWidget *widget)
00523 {
00524 if (GTK_WIDGET_REALIZED (widget) && !GTK_WIDGET_MAPPED (widget))
00525 {
00526 GTK_WIDGET_CLASS (parent_class)->map (widget);
00527 gdk_window_show (GTK_SPIN_BUTTON_SCI (widget)->panel);
00528 }
00529 }
00530
00531 static void
00532 gtk_spin_button_sci_unmap (GtkWidget *widget)
00533 {
00534 if (GTK_WIDGET_MAPPED (widget))
00535 {
00536 gdk_window_hide (GTK_SPIN_BUTTON_SCI (widget)->panel);
00537 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
00538 }
00539 }
00540
00541 static void
00542 gtk_spin_button_sci_realize (GtkWidget *widget)
00543 {
00544 GtkSpinbuttonsci *spin_button_sci;
00545 GdkWindowAttr attributes;
00546 gint attributes_mask;
00547 guint real_width;
00548 gboolean return_val;
00549 gint arrow_size;
00550
00551 spin_button_sci = GTK_SPIN_BUTTON_SCI (widget);
00552 arrow_size = spin_button_sci_get_arrow_size (spin_button_sci);
00553
00554 real_width = widget->allocation.width;
00555 widget->allocation.width -= arrow_size + 2 * widget->style->xthickness;
00556 gtk_widget_set_events (widget, gtk_widget_get_events (widget) |
00557 GDK_KEY_RELEASE_MASK);
00558 GTK_WIDGET_CLASS (parent_class)->realize (widget);
00559
00560 widget->allocation.width = real_width;
00561
00562 attributes.window_type = GDK_WINDOW_CHILD;
00563 attributes.wclass = GDK_INPUT_OUTPUT;
00564 attributes.visual = gtk_widget_get_visual (widget);
00565 attributes.colormap = gtk_widget_get_colormap (widget);
00566 attributes.event_mask = gtk_widget_get_events (widget);
00567 attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK
00568 | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK
00569 | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK;
00570
00571 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
00572
00573 attributes.x = (widget->allocation.x +
00574 widget->allocation.width - arrow_size -
00575 2 * widget->style->xthickness);
00576 attributes.y = widget->allocation.y + (widget->allocation.height -
00577 widget->requisition.height) / 2;
00578 attributes.width = arrow_size + 2 * widget->style->xthickness;
00579 attributes.height = widget->requisition.height;
00580
00581 spin_button_sci->panel = gdk_window_new (gtk_widget_get_parent_window (widget),
00582 &attributes, attributes_mask);
00583 gdk_window_set_user_data (spin_button_sci->panel, widget);
00584
00585 gtk_style_set_background (widget->style, spin_button_sci->panel, GTK_STATE_NORMAL);
00586
00587 return_val = FALSE;
00588 g_signal_emit (spin_button_sci, spinbuttonsci_signals[OUTPUT], 0, &return_val);
00589 if (return_val == FALSE)
00590 gtk_spin_button_sci_default_output (spin_button_sci);
00591
00592 gtk_widget_queue_resize (GTK_WIDGET (spin_button_sci));
00593 }
00594
00595 static void
00596 gtk_spin_button_sci_unrealize (GtkWidget *widget)
00597 {
00598 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
00599
00600 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
00601
00602 if (spin->panel)
00603 {
00604 gdk_window_set_user_data (spin->panel, NULL);
00605 gdk_window_destroy (spin->panel);
00606 spin->panel = NULL;
00607 }
00608 }
00609
00610 static int
00611 compute_double_length (double val, int digits)
00612 {
00613 int a;
00614 int extra;
00615
00616 a = 1;
00617 if (fabs (val) > 1.0)
00618 a = floor (log10 (fabs (val))) + 1;
00619
00620 extra = 0;
00621
00622
00623 if (digits > 0)
00624 extra++;
00625
00626
00627 if (val < 0)
00628 extra++;
00629
00630 return a + digits + extra;
00631 }
00632
00633
00634
00635 static void
00636 get_borders (GtkEntry *entry,
00637 gint *xborder,
00638 gint *yborder)
00639 {
00640 GtkWidget *widget = GTK_WIDGET (entry);
00641 gint focus_width;
00642 gboolean interior_focus;
00643
00644 gtk_widget_style_get (widget,
00645 "interior-focus", &interior_focus,
00646 "focus-line-width", &focus_width,
00647 NULL);
00648
00649 if (entry->has_frame)
00650 {
00651 *xborder = widget->style->xthickness;
00652 *yborder = widget->style->ythickness;
00653 }
00654 else
00655 {
00656 *xborder = 0;
00657 *yborder = 0;
00658 }
00659
00660 if (!interior_focus)
00661 {
00662 *xborder += focus_width;
00663 *yborder += focus_width;
00664 }
00665 }
00666
00667 static void
00668 gtk_spin_button_sci_size_request (GtkWidget *widget,
00669 GtkRequisition *requisition)
00670 {
00671 GtkEntry *entry;
00672 GtkSpinbuttonsci *spin_button_sci;
00673 gint arrow_size;
00674
00675 entry = GTK_ENTRY (widget);
00676 spin_button_sci = GTK_SPIN_BUTTON_SCI (widget);
00677 arrow_size = spin_button_sci_get_arrow_size (spin_button_sci);
00678
00679 GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
00680
00681 if (entry->width_chars < 0)
00682 {
00683 PangoContext *context;
00684 PangoFontMetrics *metrics;
00685 gint width;
00686 gint w;
00687 gint string_len;
00688 gint max_string_len;
00689 gint digit_width;
00690 gboolean interior_focus;
00691 gint focus_width;
00692 gint xborder, yborder;
00693
00694 gtk_widget_style_get (widget,
00695 "interior-focus", &interior_focus,
00696 "focus-line-width", &focus_width,
00697 NULL);
00698
00699 context = gtk_widget_get_pango_context (widget);
00700 metrics = pango_context_get_metrics (context,
00701 widget->style->font_desc,
00702 pango_context_get_language (context));
00703
00704 digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
00705 digit_width = PANGO_SCALE *
00706 ((digit_width + PANGO_SCALE - 1) / PANGO_SCALE);
00707
00708 pango_font_metrics_unref (metrics);
00709
00710
00711
00712 width = MIN_SPIN_BUTTON_SCI_WIDTH;
00713 max_string_len = MAX (10, compute_double_length (1e9 * spin_button_sci->adjustment->step_increment,
00714 spin_button_sci->digits));
00715
00716 string_len = compute_double_length (spin_button_sci->adjustment->upper,
00717 spin_button_sci->digits);
00718 w = PANGO_PIXELS (MIN (string_len, max_string_len) * digit_width);
00719 width = MAX (width, w);
00720 string_len = compute_double_length (spin_button_sci->adjustment->lower,
00721 spin_button_sci->digits);
00722 w = PANGO_PIXELS (MIN (string_len, max_string_len) * digit_width);
00723 width = MAX (width, w);
00724
00725 get_borders (entry, &xborder, &yborder);
00726
00727 xborder += 2;
00728
00729 requisition->width = width + xborder * 2;
00730 }
00731
00732 requisition->width += arrow_size + 2 * widget->style->xthickness;
00733 }
00734
00735 static void
00736 gtk_spin_button_sci_size_allocate (GtkWidget *widget,
00737 GtkAllocation *allocation)
00738 {
00739 GtkSpinbuttonsci *spin;
00740 GtkAllocation entry_allocation;
00741 GtkAllocation panel_allocation;
00742 gint arrow_size;
00743 gint panel_width;
00744
00745 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (widget));
00746 g_return_if_fail (allocation != NULL);
00747
00748 spin = GTK_SPIN_BUTTON_SCI (widget);
00749 arrow_size = spin_button_sci_get_arrow_size (spin);
00750 panel_width = arrow_size + 2 * widget->style->xthickness;
00751
00752 widget->allocation = *allocation;
00753
00754 entry_allocation = *allocation;
00755 entry_allocation.width -= panel_width;
00756
00757 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
00758 {
00759 entry_allocation.x += panel_width;
00760 panel_allocation.x = allocation->x;
00761 }
00762 else
00763 {
00764 panel_allocation.x = allocation->x + allocation->width - panel_width;
00765 }
00766
00767 panel_allocation.width = panel_width;
00768 panel_allocation.height = MIN (widget->requisition.height, allocation->height);
00769
00770 panel_allocation.y = allocation->y + (allocation->height -
00771 panel_allocation.height) / 2;
00772
00773 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, &entry_allocation);
00774
00775 if (GTK_WIDGET_REALIZED (widget))
00776 {
00777 gdk_window_move_resize (GTK_SPIN_BUTTON_SCI (widget)->panel,
00778 panel_allocation.x,
00779 panel_allocation.y,
00780 panel_allocation.width,
00781 panel_allocation.height);
00782 }
00783
00784 spin_button_sci_redraw (spin);
00785 }
00786
00787 static gint
00788 gtk_spin_button_sci_expose (GtkWidget *widget,
00789 GdkEventExpose *event)
00790 {
00791 GtkSpinbuttonsci *spin;
00792
00793 g_return_val_if_fail (GTK_IS_SPIN_BUTTON_SCI (widget), FALSE);
00794 g_return_val_if_fail (event != NULL, FALSE);
00795
00796 spin = GTK_SPIN_BUTTON_SCI (widget);
00797
00798 if (GTK_WIDGET_DRAWABLE (widget))
00799 {
00800 GtkShadowType shadow_type;
00801 GdkRectangle rect;
00802
00803 if (event->window != spin->panel)
00804 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
00805
00806
00807
00808
00809
00810 rect.x = 0;
00811 rect.y = 0;
00812
00813 gdk_drawable_get_size (spin->panel, &rect.width, &rect.height);
00814
00815 shadow_type = spin_button_sci_get_shadow_type (spin);
00816
00817 gdk_window_begin_paint_rect (spin->panel, &rect);
00818
00819 if (shadow_type != GTK_SHADOW_NONE)
00820 {
00821 gtk_paint_box (widget->style, spin->panel,
00822 GTK_STATE_NORMAL, shadow_type,
00823 NULL, widget, "spinbuttonsci",
00824 rect.x, rect.y, rect.width, rect.height);
00825 }
00826
00827 gtk_spin_button_sci_draw_arrow (spin, GTK_ARROW_UP);
00828 gtk_spin_button_sci_draw_arrow (spin, GTK_ARROW_DOWN);
00829
00830 gdk_window_end_paint (spin->panel);
00831 }
00832
00833 return FALSE;
00834 }
00835
00836 static gboolean
00837 spin_button_sci_at_limit (GtkSpinbuttonsci *spin_button_sci,
00838 GtkArrowType arrow)
00839 {
00840 GtkArrowType effective_arrow;
00841
00842 if (spin_button_sci->wrap)
00843 return FALSE;
00844
00845 if (spin_button_sci->adjustment->step_increment > 0)
00846 effective_arrow = arrow;
00847 else
00848 effective_arrow = arrow == GTK_ARROW_UP ? GTK_ARROW_DOWN : GTK_ARROW_UP;
00849
00850 if (effective_arrow == GTK_ARROW_UP &&
00851 (spin_button_sci->adjustment->upper - spin_button_sci->adjustment->value <= EPSILON))
00852 return TRUE;
00853
00854 if (effective_arrow == GTK_ARROW_DOWN &&
00855 (spin_button_sci->adjustment->value - spin_button_sci->adjustment->lower <= EPSILON))
00856 return TRUE;
00857
00858 return FALSE;
00859 }
00860
00861 static void
00862 gtk_spin_button_sci_draw_arrow (GtkSpinbuttonsci *spin_button_sci,
00863 GtkArrowType arrow_type)
00864 {
00865 GtkStateType state_type;
00866 GtkShadowType shadow_type;
00867 GtkWidget *widget;
00868 gint x;
00869 gint y;
00870 gint height;
00871 gint width;
00872 gint h, w;
00873
00874 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
00875 g_return_if_fail (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN);
00876
00877 widget = GTK_WIDGET (spin_button_sci);
00878
00879 if (GTK_WIDGET_DRAWABLE (widget))
00880 {
00881 width = spin_button_sci_get_arrow_size (spin_button_sci) + 2 * widget->style->xthickness;
00882
00883 if (arrow_type == GTK_ARROW_UP)
00884 {
00885 x = 0;
00886 y = 0;
00887
00888 height = widget->requisition.height / 2;
00889 }
00890 else
00891 {
00892 x = 0;
00893 y = widget->requisition.height / 2;
00894
00895 height = (widget->requisition.height + 1) / 2;
00896 }
00897
00898 if (spin_button_sci_at_limit (spin_button_sci, arrow_type))
00899 {
00900 shadow_type = GTK_SHADOW_OUT;
00901 state_type = GTK_STATE_INSENSITIVE;
00902 }
00903 else
00904 {
00905 if (spin_button_sci->click_child == arrow_type)
00906 {
00907 state_type = GTK_STATE_ACTIVE;
00908 shadow_type = GTK_SHADOW_IN;
00909 }
00910 else
00911 {
00912 if (spin_button_sci->in_child == arrow_type &&
00913 spin_button_sci->click_child == NO_ARROW)
00914 {
00915 state_type = GTK_STATE_PRELIGHT;
00916 }
00917 else
00918 {
00919 state_type = GTK_WIDGET_STATE (widget);
00920 }
00921
00922 shadow_type = GTK_SHADOW_OUT;
00923 }
00924 }
00925
00926 gtk_paint_box (widget->style, spin_button_sci->panel,
00927 state_type, shadow_type,
00928 NULL, widget,
00929 (arrow_type == GTK_ARROW_UP)? "spinbuttonsci_up" : "spinbuttonsci_down",
00930 x, y, width, height);
00931
00932 height = widget->requisition.height;
00933
00934 if (arrow_type == GTK_ARROW_DOWN)
00935 {
00936 y = height / 2;
00937 height = height - y - 2;
00938 }
00939 else
00940 {
00941 y = 2;
00942 height = height / 2 - 2;
00943 }
00944
00945 width -= 3;
00946
00947 if (widget && gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
00948 x = 2;
00949 else
00950 x = 1;
00951
00952 w = width / 2;
00953 w -= w % 2 - 1;
00954 h = (w + 1) / 2;
00955
00956 x += (width - w) / 2;
00957 y += (height - h) / 2;
00958
00959 height = h;
00960 width = w;
00961
00962 gtk_paint_arrow (widget->style, spin_button_sci->panel,
00963 state_type, shadow_type,
00964 NULL, widget, "spinbuttonsci",
00965 arrow_type, TRUE,
00966 x, y, width, height);
00967 }
00968 }
00969
00970 static gint
00971 gtk_spin_button_sci_enter_notify (GtkWidget *widget,
00972 GdkEventCrossing *event)
00973 {
00974 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
00975
00976 if (event->window == spin->panel)
00977 {
00978 gint x;
00979 gint y;
00980
00981 gdk_window_get_pointer (spin->panel, &x, &y, NULL);
00982
00983 if (y <= widget->requisition.height / 2)
00984 spin->in_child = GTK_ARROW_UP;
00985 else
00986 spin->in_child = GTK_ARROW_DOWN;
00987
00988 spin_button_sci_redraw (spin);
00989 }
00990
00991 return FALSE;
00992 }
00993
00994 static gint
00995 gtk_spin_button_sci_leave_notify (GtkWidget *widget,
00996 GdkEventCrossing *event)
00997 {
00998 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
00999
01000 spin->in_child = NO_ARROW;
01001 spin_button_sci_redraw (spin);
01002
01003 return FALSE;
01004 }
01005
01006 static gint
01007 gtk_spin_button_sci_focus_out (GtkWidget *widget,
01008 GdkEventFocus *event)
01009 {
01010 if (GTK_ENTRY (widget)->editable)
01011 gtk_spin_button_sci_update (GTK_SPIN_BUTTON_SCI (widget));
01012
01013 return GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, event);
01014 }
01015
01016 static void
01017 gtk_spin_button_sci_grab_notify (GtkWidget *widget,
01018 gboolean was_grabbed)
01019 {
01020 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
01021
01022 if (!was_grabbed)
01023 {
01024 gtk_spin_button_sci_stop_spinning (spin);
01025 spin_button_sci_redraw (spin);
01026 }
01027 }
01028
01029 static void
01030 gtk_spin_button_sci_state_changed (GtkWidget *widget,
01031 GtkStateType previous_state)
01032 {
01033 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
01034
01035 if (!GTK_WIDGET_IS_SENSITIVE (widget))
01036 {
01037 gtk_spin_button_sci_stop_spinning (spin);
01038 spin_button_sci_redraw (spin);
01039 }
01040 }
01041
01042 static gint
01043 gtk_spin_button_sci_scroll (GtkWidget *widget,
01044 GdkEventScroll *event)
01045 {
01046 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
01047
01048 if (event->direction == GDK_SCROLL_UP)
01049 {
01050 if (!GTK_WIDGET_HAS_FOCUS (widget))
01051 gtk_widget_grab_focus (widget);
01052 gtk_spin_button_sci_real_spin (spin, spin->adjustment->step_increment);
01053 }
01054 else if (event->direction == GDK_SCROLL_DOWN)
01055 {
01056 if (!GTK_WIDGET_HAS_FOCUS (widget))
01057 gtk_widget_grab_focus (widget);
01058 gtk_spin_button_sci_real_spin (spin, -spin->adjustment->step_increment);
01059 }
01060 else
01061 return FALSE;
01062
01063 return TRUE;
01064 }
01065
01066 static void
01067 gtk_spin_button_sci_stop_spinning (GtkSpinbuttonsci *spin)
01068 {
01069 if (spin->timer)
01070 {
01071 g_source_remove (spin->timer);
01072 spin->timer = 0;
01073 spin->timer_calls = 0;
01074 spin->need_timer = FALSE;
01075 }
01076
01077 spin->button = 0;
01078 spin->timer = 0;
01079 spin->timer_step = spin->adjustment->step_increment;
01080 spin->timer_calls = 0;
01081
01082 spin->click_child = NO_ARROW;
01083 spin->button = 0;
01084 }
01085
01086 static void
01087 start_spinning (GtkSpinbuttonsci *spin,
01088 GtkArrowType click_child,
01089 gdouble step)
01090 {
01091 g_return_if_fail (click_child == GTK_ARROW_UP || click_child == GTK_ARROW_DOWN);
01092
01093 spin->click_child = click_child;
01094 gtk_spin_button_sci_real_spin (spin, click_child == GTK_ARROW_UP ? step : -step);
01095
01096 if (!spin->timer)
01097 {
01098 spin->timer_step = step;
01099 spin->need_timer = TRUE;
01100 spin->timer = g_timeout_add (SPIN_BUTTON_SCI_INITIAL_TIMER_DELAY,
01101 (GSourceFunc) gtk_spin_button_sci_timer,
01102 (gpointer) spin);
01103 }
01104
01105 spin_button_sci_redraw (spin);
01106 }
01107
01108 static gint
01109 gtk_spin_button_sci_button_press (GtkWidget *widget,
01110 GdkEventButton *event)
01111 {
01112 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
01113
01114 if (!spin->button)
01115 {
01116 if (event->window == spin->panel)
01117 {
01118 if (!GTK_WIDGET_HAS_FOCUS (widget))
01119 gtk_widget_grab_focus (widget);
01120 spin->button = event->button;
01121
01122 if (GTK_ENTRY (widget)->editable)
01123 gtk_spin_button_sci_update (spin);
01124
01125 if (event->y <= widget->requisition.height / 2)
01126 {
01127 if (event->button == 1)
01128 start_spinning (spin, GTK_ARROW_UP, spin->adjustment->step_increment);
01129 else if (event->button == 2)
01130 start_spinning (spin, GTK_ARROW_UP, spin->adjustment->page_increment);
01131 else if (event->button == 3 && !spin->jump_to_limits)
01132 start_spinning (spin, GTK_ARROW_UP, 10.*spin->adjustment->page_increment);
01133 else
01134 spin->click_child = GTK_ARROW_UP;
01135 }
01136 else
01137 {
01138 if (event->button == 1)
01139 start_spinning (spin, GTK_ARROW_DOWN, spin->adjustment->step_increment);
01140 else if (event->button == 2)
01141 start_spinning (spin, GTK_ARROW_DOWN, spin->adjustment->page_increment);
01142 else if (event->button == 3 && !spin->jump_to_limits)
01143 start_spinning (spin, GTK_ARROW_DOWN, 10.*spin->adjustment->page_increment);
01144 else
01145 spin->click_child = GTK_ARROW_DOWN;
01146 }
01147 return TRUE;
01148 }
01149 else
01150 return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
01151 }
01152 return FALSE;
01153 }
01154
01155 static gint
01156 gtk_spin_button_sci_button_release (GtkWidget *widget,
01157 GdkEventButton *event)
01158 {
01159 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
01160 gint arrow_size;
01161
01162 arrow_size = spin_button_sci_get_arrow_size (spin);
01163
01164 if (event->button == spin->button)
01165 {
01166 int click_child = spin->click_child;
01167
01168 gtk_spin_button_sci_stop_spinning (spin);
01169
01170 if (event->button == 3 && spin->jump_to_limits)
01171 {
01172 if (event->y >= 0 && event->x >= 0 &&
01173 event->y <= widget->requisition.height &&
01174 event->x <= arrow_size + 2 * widget->style->xthickness)
01175 {
01176 if (click_child == GTK_ARROW_UP &&
01177 event->y <= widget->requisition.height / 2)
01178 {
01179 gdouble diff;
01180
01181 diff = spin->adjustment->upper - spin->adjustment->value;
01182 if (diff > EPSILON)
01183 gtk_spin_button_sci_real_spin (spin, diff);
01184 }
01185 else if (click_child == GTK_ARROW_DOWN &&
01186 event->y > widget->requisition.height / 2)
01187 {
01188 gdouble diff;
01189
01190 diff = spin->adjustment->value - spin->adjustment->lower;
01191 if (diff > EPSILON)
01192 gtk_spin_button_sci_real_spin (spin, -diff);
01193 }
01194 }
01195 }
01196 spin_button_sci_redraw (spin);
01197
01198 return TRUE;
01199 }
01200 else
01201 return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
01202 }
01203
01204 static gint
01205 gtk_spin_button_sci_motion_notify (GtkWidget *widget,
01206 GdkEventMotion *event)
01207 {
01208 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
01209
01210 if (spin->button)
01211 return FALSE;
01212
01213 if (event->window == spin->panel)
01214 {
01215 gint y;
01216
01217 gdk_window_get_pointer (spin->panel, NULL, &y, NULL);
01218
01219 if (y <= widget->requisition.height / 2 &&
01220 spin->in_child == GTK_ARROW_DOWN)
01221 {
01222 spin->in_child = GTK_ARROW_UP;
01223 spin_button_sci_redraw (spin);
01224 }
01225 else if (y > widget->requisition.height / 2 &&
01226 spin->in_child == GTK_ARROW_UP)
01227 {
01228 spin->in_child = GTK_ARROW_DOWN;
01229 spin_button_sci_redraw (spin);
01230 }
01231
01232 return FALSE;
01233 }
01234
01235 return GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
01236 }
01237
01238 static gint
01239 gtk_spin_button_sci_timer (GtkSpinbuttonsci *spin_button_sci)
01240 {
01241 gboolean retval = FALSE;
01242
01243 GDK_THREADS_ENTER ();
01244
01245 if (spin_button_sci->timer)
01246 {
01247 if (spin_button_sci->click_child == GTK_ARROW_UP)
01248 gtk_spin_button_sci_real_spin (spin_button_sci, spin_button_sci->timer_step);
01249 else
01250 gtk_spin_button_sci_real_spin (spin_button_sci, -spin_button_sci->timer_step);
01251
01252 if (spin_button_sci->need_timer)
01253 {
01254 spin_button_sci->need_timer = FALSE;
01255 spin_button_sci->timer = g_timeout_add (SPIN_BUTTON_SCI_TIMER_DELAY,
01256 (GSourceFunc) gtk_spin_button_sci_timer,
01257 (gpointer) spin_button_sci);
01258 }
01259 else
01260 {
01261 if (spin_button_sci->climb_rate > 0.0 && spin_button_sci->timer_step
01262 < spin_button_sci->adjustment->page_increment)
01263 {
01264 if (spin_button_sci->timer_calls < MAX_TIMER_CALLS)
01265 spin_button_sci->timer_calls++;
01266 else
01267 {
01268 spin_button_sci->timer_calls = 0;
01269 spin_button_sci->timer_step += spin_button_sci->climb_rate;
01270 }
01271 }
01272 retval = TRUE;
01273 }
01274 }
01275
01276 GDK_THREADS_LEAVE ();
01277
01278 return retval;
01279 }
01280
01281 static void
01282 gtk_spin_button_sci_value_changed (GtkAdjustment *adjustment,
01283 GtkSpinbuttonsci *spin_button_sci)
01284 {
01285 gboolean return_val;
01286
01287 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
01288
01289 return_val = FALSE;
01290 g_signal_emit (spin_button_sci, spinbuttonsci_signals[OUTPUT], 0, &return_val);
01291 if (return_val == FALSE)
01292 gtk_spin_button_sci_default_output (spin_button_sci);
01293
01294 g_signal_emit (spin_button_sci, spinbuttonsci_signals[VALUE_CHANGED], 0);
01295
01296 spin_button_sci_redraw (spin_button_sci);
01297
01298 g_object_notify (G_OBJECT (spin_button_sci), "value");
01299 }
01300
01301 static void
01302 gtk_spin_button_sci_real_change_value (GtkSpinbuttonsci *spin,
01303 GtkScrollType scroll)
01304 {
01305
01306
01307
01308
01309
01310 switch (scroll)
01311 {
01312 case GTK_SCROLL_STEP_BACKWARD:
01313 case GTK_SCROLL_STEP_DOWN:
01314 case GTK_SCROLL_STEP_LEFT:
01315 gtk_spin_button_sci_real_spin (spin, -spin->timer_step);
01316
01317 if (spin->climb_rate > 0.0 && spin->timer_step
01318 < spin->adjustment->page_increment)
01319 {
01320 if (spin->timer_calls < MAX_TIMER_CALLS)
01321 spin->timer_calls++;
01322 else
01323 {
01324 spin->timer_calls = 0;
01325 spin->timer_step += spin->climb_rate;
01326 }
01327 }
01328 break;
01329
01330 case GTK_SCROLL_STEP_FORWARD:
01331 case GTK_SCROLL_STEP_UP:
01332 case GTK_SCROLL_STEP_RIGHT:
01333 gtk_spin_button_sci_real_spin (spin, spin->timer_step);
01334
01335 if (spin->climb_rate > 0.0 && spin->timer_step
01336 < spin->adjustment->page_increment)
01337 {
01338 if (spin->timer_calls < MAX_TIMER_CALLS)
01339 spin->timer_calls++;
01340 else
01341 {
01342 spin->timer_calls = 0;
01343 spin->timer_step += spin->climb_rate;
01344 }
01345 }
01346 break;
01347
01348 case GTK_SCROLL_PAGE_BACKWARD:
01349 case GTK_SCROLL_PAGE_DOWN:
01350 case GTK_SCROLL_PAGE_LEFT:
01351 gtk_spin_button_sci_real_spin (spin, -spin->adjustment->page_increment);
01352 break;
01353
01354 case GTK_SCROLL_PAGE_FORWARD:
01355 case GTK_SCROLL_PAGE_UP:
01356 case GTK_SCROLL_PAGE_RIGHT:
01357 gtk_spin_button_sci_real_spin (spin, spin->adjustment->page_increment);
01358 break;
01359
01360 case GTK_SCROLL_START:
01361 if (spin->jump_to_limits)
01362 {
01363 gdouble diff = spin->adjustment->value - spin->adjustment->lower;
01364 if (diff > EPSILON)
01365 gtk_spin_button_sci_real_spin (spin, -diff);
01366 }
01367 break;
01368
01369 case GTK_SCROLL_END:
01370 if (spin->jump_to_limits)
01371 {
01372 gdouble diff = spin->adjustment->upper - spin->adjustment->value;
01373 if (diff > EPSILON)
01374 gtk_spin_button_sci_real_spin (spin, diff);
01375 }
01376 break;
01377
01378 default:
01379 g_warning ("Invalid scroll type %d for GtkSpinbuttonsci::change-value", scroll);
01380 break;
01381 }
01382
01383 gtk_spin_button_sci_update (spin);
01384 }
01385
01386 static gint
01387 gtk_spin_button_sci_key_release (GtkWidget *widget,
01388 GdkEventKey *event)
01389 {
01390 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (widget);
01391
01392
01393 spin->timer_step = spin->adjustment->step_increment;
01394 spin->timer_calls = 0;
01395
01396 return TRUE;
01397 }
01398
01399 static void
01400 gtk_spin_button_sci_snap (GtkSpinbuttonsci *spin_button_sci,
01401 gdouble val)
01402 {
01403 gdouble inc;
01404 gdouble tmp;
01405
01406 inc = spin_button_sci->adjustment->step_increment;
01407 if (inc == 0)
01408 return;
01409
01410 tmp = (val - spin_button_sci->adjustment->lower) / inc;
01411 if (tmp - floor (tmp) < ceil (tmp) - tmp)
01412 val = spin_button_sci->adjustment->lower + floor (tmp) * inc;
01413 else
01414 val = spin_button_sci->adjustment->lower + ceil (tmp) * inc;
01415
01416 if (fabs (val - spin_button_sci->adjustment->value) > EPSILON)
01417 gtk_adjustment_set_value (spin_button_sci->adjustment, val);
01418 else
01419 {
01420 gint return_val = FALSE;
01421 g_signal_emit (spin_button_sci, spinbuttonsci_signals[OUTPUT], 0, &return_val);
01422 if (return_val == FALSE)
01423 gtk_spin_button_sci_default_output (spin_button_sci);
01424 }
01425 }
01426
01427 static void
01428 gtk_spin_button_sci_activate (GtkEntry *entry)
01429 {
01430 if (entry->editable)
01431 gtk_spin_button_sci_update (GTK_SPIN_BUTTON_SCI (entry));
01432
01433
01434 parent_class->activate (entry);
01435 }
01436
01437 static void
01438 gtk_spin_button_sci_insert_text (GtkEditable *editable,
01439 const gchar *new_text,
01440 gint new_text_length,
01441 gint *position)
01442 {
01443 GtkEntry *entry = GTK_ENTRY (editable);
01444 GtkSpinbuttonsci *spin = GTK_SPIN_BUTTON_SCI (editable);
01445 GtkEditableClass *parent_editable_iface = g_type_interface_peek (parent_class, GTK_TYPE_EDITABLE);
01446
01447 if (spin->numeric)
01448 {
01449 struct lconv *lc;
01450 gboolean sign;
01451 gint dotpos = -1;
01452 gint i;
01453 GdkWChar pos_sign;
01454 GdkWChar neg_sign;
01455 gint entry_length;
01456
01457 entry_length = entry->text_length;
01458
01459 lc = localeconv ();
01460
01461 if (*(lc->negative_sign))
01462 neg_sign = *(lc->negative_sign);
01463 else
01464 neg_sign = '-';
01465
01466 if (*(lc->positive_sign))
01467 pos_sign = *(lc->positive_sign);
01468 else
01469 pos_sign = '+';
01470
01471 for (sign=0, i=0; i<entry_length; i++)
01472 if ((entry->text[i] == neg_sign) ||
01473 (entry->text[i] == pos_sign))
01474 {
01475 sign = 1;
01476 break;
01477 }
01478
01479 if (sign && !(*position))
01480 return;
01481
01482 for (dotpos=-1, i=0; i<entry_length; i++)
01483 if (entry->text[i] == *(lc->decimal_point))
01484 {
01485 dotpos = i;
01486 break;
01487 }
01488
01489 if (dotpos > -1 && *position > dotpos &&
01490 (gint)spin->digits - entry_length
01491 + dotpos - new_text_length + 1 < 0)
01492 return;
01493
01494 for (i = 0; i < new_text_length; i++)
01495 {
01496 if (new_text[i] == neg_sign || new_text[i] == pos_sign)
01497 {
01498 if (sign || (*position) || i)
01499 return;
01500 sign = TRUE;
01501 }
01502 else if (new_text[i] == *(lc->decimal_point))
01503 {
01504 if (!spin->digits || dotpos > -1 ||
01505 (new_text_length - 1 - i + entry_length
01506 - *position > (gint)spin->digits))
01507 return;
01508 dotpos = *position + i;
01509 }
01510 else if (new_text[i] < 0x30 || new_text[i] > 0x39)
01511 return;
01512 }
01513 }
01514
01515 parent_editable_iface->insert_text (editable, new_text,
01516 new_text_length, position);
01517 }
01518
01519 static void
01520 gtk_spin_button_sci_real_spin (GtkSpinbuttonsci *spin_button_sci,
01521 gdouble increment)
01522 {
01523 GtkAdjustment *adj;
01524 gdouble new_value = 0.0;
01525
01526 adj = spin_button_sci->adjustment;
01527
01528 new_value = adj->value + increment;
01529
01530 if (increment > 0)
01531 {
01532 if (spin_button_sci->wrap)
01533 {
01534 if (fabs (adj->value - adj->upper) < EPSILON)
01535 new_value = adj->lower;
01536 else if (new_value > adj->upper)
01537 new_value = adj->upper;
01538 }
01539 else
01540 new_value = MIN (new_value, adj->upper);
01541 }
01542 else if (increment < 0)
01543 {
01544 if (spin_button_sci->wrap)
01545 {
01546 if (fabs (adj->value - adj->lower) < EPSILON)
01547 new_value = adj->upper;
01548 else if (new_value < adj->lower)
01549 new_value = adj->lower;
01550 }
01551 else
01552 new_value = MAX (new_value, adj->lower);
01553 }
01554
01555 if (fabs (new_value - adj->value) > EPSILON)
01556 gtk_adjustment_set_value (adj, new_value);
01557
01558 spin_button_sci_redraw (spin_button_sci);
01559 }
01560
01561 static gint
01562 gtk_spin_button_sci_default_input (GtkSpinbuttonsci *spin_button_sci,
01563 gdouble *new_val)
01564 {
01565 gchar *err = NULL;
01566
01567 *new_val = g_strtod (gtk_entry_get_text (GTK_ENTRY (spin_button_sci)), &err);
01568 if (*err)
01569 return GTK_INPUT_ERROR;
01570 else
01571 return FALSE;
01572 }
01573
01574 static gint
01575 gtk_spin_button_sci_default_output (GtkSpinbuttonsci *spin_button_sci)
01576 {
01577 gchar *buf = NULL;
01578
01579 if (spin_button_sci->sci_suffix)
01580 buf = g_strdup_printf ("%0.*f %s *",
01581 spin_button_sci->digits,
01582 spin_button_sci->adjustment->value,
01583 spin_button_sci->sci_suffix);
01584 else
01585 buf = g_strdup_printf ("%0.*f",
01586 spin_button_sci->digits,
01587 spin_button_sci->adjustment->value);
01588
01589 if (strcmp (buf, gtk_entry_get_text (GTK_ENTRY (spin_button_sci))))
01590 gtk_entry_set_text (GTK_ENTRY (spin_button_sci), buf);
01591 g_free (buf);
01592 return FALSE;
01593 }
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603 void
01604 gtk_spin_button_sci_configure (GtkSpinbuttonsci *spin_button_sci,
01605 GtkAdjustment *adjustment,
01606 gdouble climb_rate,
01607 guint digits)
01608 {
01609 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
01610
01611 if (adjustment)
01612 gtk_spin_button_sci_set_adjustment (spin_button_sci, adjustment);
01613 else
01614 adjustment = spin_button_sci->adjustment;
01615
01616 g_object_freeze_notify (G_OBJECT (spin_button_sci));
01617 if (spin_button_sci->digits != digits)
01618 {
01619 spin_button_sci->digits = digits;
01620 g_object_notify (G_OBJECT (spin_button_sci), "digits");
01621 }
01622
01623 if (spin_button_sci->climb_rate != climb_rate)
01624 {
01625 spin_button_sci->climb_rate = climb_rate;
01626 g_object_notify (G_OBJECT (spin_button_sci), "climb_rate");
01627 }
01628 g_object_thaw_notify (G_OBJECT (spin_button_sci));
01629
01630 gtk_adjustment_value_changed (adjustment);
01631 }
01632
01633 GtkWidget *
01634 gtk_spin_button_sci_new (GtkAdjustment *adjustment,
01635 gdouble climb_rate,
01636 guint digits)
01637 {
01638 GtkSpinbuttonsci *spin;
01639
01640 if (adjustment)
01641 g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
01642
01643 spin = g_object_new (GTK_TYPE_SPIN_BUTTON_SCI, NULL);
01644
01645 gtk_spin_button_sci_configure (spin, adjustment, climb_rate, digits);
01646
01647 return GTK_WIDGET (spin);
01648 }
01649
01664 GtkWidget *
01665 gtk_spin_button_sci_new_with_range (gdouble min,
01666 gdouble max,
01667 gdouble step)
01668 {
01669 GtkObject *adj;
01670 GtkSpinbuttonsci *spin;
01671 gint digits;
01672
01673 g_return_val_if_fail (min < max, NULL);
01674 g_return_val_if_fail (step != 0.0, NULL);
01675
01676 spin = g_object_new (GTK_TYPE_SPIN_BUTTON_SCI, NULL);
01677
01678 adj = gtk_adjustment_new (min, min, max, step, 10 * step, 0);
01679
01680 if (fabs (step) >= 1.0 || step == 0.0)
01681 digits = 0;
01682 else {
01683 digits = abs ((gint) floor (log10 (fabs (step))));
01684 if (digits > MAX_DIGITS)
01685 digits = MAX_DIGITS;
01686 }
01687
01688 gtk_spin_button_sci_configure (spin, GTK_ADJUSTMENT (adj), step, digits);
01689
01690 gtk_spin_button_sci_set_numeric (spin, TRUE);
01691
01692 return GTK_WIDGET (spin);
01693 }
01694
01695
01696
01697
01698 static void
01699 adjustment_changed_cb (GtkAdjustment *adjustment, gpointer data)
01700 {
01701 GtkSpinbuttonsci *spin_button_sci;
01702
01703 spin_button_sci = GTK_SPIN_BUTTON_SCI (data);
01704
01705 spin_button_sci->timer_step = spin_button_sci->adjustment->step_increment;
01706 gtk_widget_queue_resize (GTK_WIDGET (spin_button_sci));
01707 }
01708
01716 void
01717 gtk_spin_button_sci_set_adjustment (GtkSpinbuttonsci *spin_button_sci,
01718 GtkAdjustment *adjustment)
01719 {
01720 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
01721
01722 if (spin_button_sci->adjustment != adjustment)
01723 {
01724 if (spin_button_sci->adjustment)
01725 {
01726 g_signal_handlers_disconnect_by_func (spin_button_sci->adjustment,
01727 gtk_spin_button_sci_value_changed,
01728 spin_button_sci);
01729 g_signal_handlers_disconnect_by_func (spin_button_sci->adjustment,
01730 adjustment_changed_cb,
01731 spin_button_sci);
01732 g_object_unref (spin_button_sci->adjustment);
01733 }
01734 spin_button_sci->adjustment = adjustment;
01735 if (adjustment)
01736 {
01737 g_object_ref (adjustment);
01738 gtk_object_sink (GTK_OBJECT (adjustment));
01739 g_signal_connect (adjustment, "value_changed",
01740 G_CALLBACK (gtk_spin_button_sci_value_changed),
01741 spin_button_sci);
01742 g_signal_connect (adjustment, "changed",
01743 G_CALLBACK (adjustment_changed_cb),
01744 spin_button_sci);
01745 spin_button_sci->timer_step = spin_button_sci->adjustment->step_increment;
01746 }
01747
01748 gtk_widget_queue_resize (GTK_WIDGET (spin_button_sci));
01749 }
01750
01751 g_object_notify (G_OBJECT (spin_button_sci), "adjustment");
01752 }
01753
01762 GtkAdjustment *
01763 gtk_spin_button_sci_get_adjustment (GtkSpinbuttonsci *spin_button_sci)
01764 {
01765 g_return_val_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci), NULL);
01766
01767 return spin_button_sci->adjustment;
01768 }
01769
01778 void
01779 gtk_spin_button_sci_set_digits (GtkSpinbuttonsci *spin_button_sci,
01780 guint digits)
01781 {
01782 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
01783
01784 if (spin_button_sci->digits != digits)
01785 {
01786 spin_button_sci->digits = digits;
01787 gtk_spin_button_sci_value_changed (spin_button_sci->adjustment, spin_button_sci);
01788 g_object_notify (G_OBJECT (spin_button_sci), "digits");
01789
01790
01791 gtk_widget_queue_resize (GTK_WIDGET (spin_button_sci));
01792 }
01793 }
01794
01803 guint
01804 gtk_spin_button_sci_get_digits (GtkSpinbuttonsci *spin_button_sci)
01805 {
01806 g_return_val_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci), 0);
01807
01808 return spin_button_sci->digits;
01809 }
01810
01820 void
01821 gtk_spin_button_sci_set_increments (GtkSpinbuttonsci *spin_button_sci,
01822 gdouble step,
01823 gdouble page)
01824 {
01825 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
01826
01827 spin_button_sci->adjustment->step_increment = step;
01828 spin_button_sci->adjustment->page_increment = page;
01829 }
01830
01840 void
01841 gtk_spin_button_sci_get_increments (GtkSpinbuttonsci *spin_button_sci,
01842 gdouble *step,
01843 gdouble *page)
01844 {
01845 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
01846
01847 if (step)
01848 *step = spin_button_sci->adjustment->step_increment;
01849 if (page)
01850 *page = spin_button_sci->adjustment->page_increment;
01851 }
01852
01861 void
01862 gtk_spin_button_sci_set_range (GtkSpinbuttonsci *spin_button_sci,
01863 gdouble min,
01864 gdouble max)
01865 {
01866 gdouble value;
01867
01868 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
01869
01870 spin_button_sci->adjustment->lower = min;
01871 spin_button_sci->adjustment->upper = max;
01872
01873 value = CLAMP (spin_button_sci->adjustment->value,
01874 spin_button_sci->adjustment->lower,
01875 (spin_button_sci->adjustment->upper - spin_button_sci->adjustment->page_size));
01876
01877 if (value != spin_button_sci->adjustment->value)
01878 gtk_spin_button_sci_set_value (spin_button_sci, value);
01879
01880 gtk_adjustment_changed (spin_button_sci->adjustment);
01881 }
01882
01892 void
01893 gtk_spin_button_sci_get_range (GtkSpinbuttonsci *spin_button_sci,
01894 gdouble *min,
01895 gdouble *max)
01896 {
01897 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
01898
01899 if (min)
01900 *min = spin_button_sci->adjustment->lower;
01901 if (max)
01902 *max = spin_button_sci->adjustment->upper;
01903 }
01904
01912 void
01913 gtk_spin_button_sci_set_suffix (GtkSpinbuttonsci *spin_button_sci,
01914 gchar *suffix)
01915 {
01916 if (spin_button_sci->sci_suffix)
01917 g_free (spin_button_sci->sci_suffix);
01918 spin_button_sci->sci_suffix = NULL;
01919 if (suffix)
01920 spin_button_sci->sci_suffix = g_strdup (suffix);
01921 }
01922
01923
01932 gdouble
01933 gtk_spin_button_sci_get_value (GtkSpinbuttonsci *spin_button_sci)
01934 {
01935 g_return_val_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci), 0.0);
01936
01937 return spin_button_sci->adjustment->value;
01938 }
01939
01948 gint
01949 gtk_spin_button_sci_get_value_as_int (GtkSpinbuttonsci *spin_button_sci)
01950 {
01951 gdouble val;
01952
01953 g_return_val_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci), 0);
01954
01955 val = spin_button_sci->adjustment->value;
01956 if (val - floor (val) < ceil (val) - val)
01957 return floor (val);
01958 else
01959 return ceil (val);
01960 }
01961
01969 void
01970 gtk_spin_button_sci_set_value (GtkSpinbuttonsci *spin_button_sci,
01971 gdouble value)
01972 {
01973 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
01974
01975 if (fabs (value - spin_button_sci->adjustment->value) > EPSILON)
01976 gtk_adjustment_set_value (spin_button_sci->adjustment, value);
01977 else
01978 {
01979 gint return_val = FALSE;
01980 g_signal_emit (spin_button_sci, spinbuttonsci_signals[OUTPUT], 0, &return_val);
01981 if (return_val == FALSE)
01982 gtk_spin_button_sci_default_output (spin_button_sci);
01983 }
01984 }
01985
01994 void
01995 gtk_spin_button_sci_set_update_policy (GtkSpinbuttonsci *spin_button_sci,
01996 GtkSpinbuttonsciUpdatePolicy policy)
01997 {
01998 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
01999
02000 if (spin_button_sci->update_policy != policy)
02001 {
02002 spin_button_sci->update_policy = policy;
02003 g_object_notify (G_OBJECT (spin_button_sci), "update_policy");
02004 }
02005 }
02006
02016 GtkSpinbuttonsciUpdatePolicy
02017 gtk_spin_button_sci_get_update_policy (GtkSpinbuttonsci *spin_button_sci)
02018 {
02019 g_return_val_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci), GTK_SPIN_SCI_UPDATE_ALWAYS);
02020
02021 return spin_button_sci->update_policy;
02022 }
02023
02032 void
02033 gtk_spin_button_sci_set_numeric (GtkSpinbuttonsci *spin_button_sci,
02034 gboolean numeric)
02035 {
02036 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
02037
02038 numeric = numeric != FALSE;
02039
02040 if (spin_button_sci->numeric != numeric)
02041 {
02042 spin_button_sci->numeric = numeric;
02043 g_object_notify (G_OBJECT (spin_button_sci), "numeric");
02044 }
02045 }
02046
02056 gboolean
02057 gtk_spin_button_sci_get_numeric (GtkSpinbuttonsci *spin_button_sci)
02058 {
02059 g_return_val_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci), FALSE);
02060
02061 return spin_button_sci->numeric;
02062 }
02063
02072 void
02073 gtk_spin_button_sci_set_wrap (GtkSpinbuttonsci *spin_button_sci,
02074 gboolean wrap)
02075 {
02076 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
02077
02078 wrap = wrap != FALSE;
02079
02080 if (spin_button_sci->wrap != wrap)
02081 {
02082 spin_button_sci->wrap = (wrap != 0);
02083
02084 g_object_notify (G_OBJECT (spin_button_sci), "wrap");
02085 }
02086 }
02087
02098 gboolean
02099 gtk_spin_button_sci_get_wrap (GtkSpinbuttonsci *spin_button_sci)
02100 {
02101 g_return_val_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci), FALSE);
02102
02103 return spin_button_sci->wrap;
02104 }
02105
02106 static gint
02107 spin_button_sci_get_arrow_size (GtkSpinbuttonsci *spin_button_sci)
02108 {
02109 gint size = pango_font_description_get_size (GTK_WIDGET (spin_button_sci)->style->font_desc);
02110 gint arrow_size;
02111
02112 arrow_size = MAX (PANGO_PIXELS (size), MIN_ARROW_WIDTH);
02113
02114 return arrow_size - arrow_size % 2;
02115 }
02116
02126 static gint
02127 spin_button_sci_get_shadow_type (GtkSpinbuttonsci *spin_button_sci)
02128 {
02129 GtkShadowType rc_shadow_type;
02130
02131 gtk_widget_style_get (GTK_WIDGET (spin_button_sci), "shadow_type", &rc_shadow_type, NULL);
02132
02133 return rc_shadow_type;
02134 }
02135
02144 void
02145 gtk_spin_button_sci_set_snap_to_ticks (GtkSpinbuttonsci *spin_button_sci,
02146 gboolean snap_to_ticks)
02147 {
02148 guint new_val;
02149
02150 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
02151
02152 new_val = (snap_to_ticks != 0);
02153
02154 if (new_val != spin_button_sci->snap_to_ticks)
02155 {
02156 spin_button_sci->snap_to_ticks = new_val;
02157 if (new_val && GTK_ENTRY (spin_button_sci)->editable)
02158 gtk_spin_button_sci_update (spin_button_sci);
02159
02160 g_object_notify (G_OBJECT (spin_button_sci), "snap_to_ticks");
02161 }
02162 }
02163
02173 gboolean
02174 gtk_spin_button_sci_get_snap_to_ticks (GtkSpinbuttonsci *spin_button_sci)
02175 {
02176 g_return_val_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci), FALSE);
02177
02178 return spin_button_sci->snap_to_ticks;
02179 }
02180
02190 void
02191 gtk_spin_button_sci_spin (GtkSpinbuttonsci *spin_button_sci,
02192 GtkSpinsciType direction,
02193 gdouble increment)
02194 {
02195 GtkAdjustment *adj;
02196 gdouble diff;
02197
02198 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
02199
02200 adj = spin_button_sci->adjustment;
02201
02202
02203 if (increment != 0 && increment != adj->step_increment &&
02204 (direction == GTK_SPIN_SCI_STEP_FORWARD ||
02205 direction == GTK_SPIN_SCI_STEP_BACKWARD))
02206 {
02207 if (direction == GTK_SPIN_SCI_STEP_BACKWARD && increment > 0)
02208 increment = -increment;
02209 direction = GTK_SPIN_SCI_USER_DEFINED;
02210 }
02211
02212 switch (direction)
02213 {
02214 case GTK_SPIN_SCI_STEP_FORWARD:
02215
02216 gtk_spin_button_sci_real_spin (spin_button_sci, adj->step_increment);
02217 break;
02218
02219 case GTK_SPIN_SCI_STEP_BACKWARD:
02220
02221 gtk_spin_button_sci_real_spin (spin_button_sci, -adj->step_increment);
02222 break;
02223
02224 case GTK_SPIN_SCI_PAGE_FORWARD:
02225
02226 gtk_spin_button_sci_real_spin (spin_button_sci, adj->page_increment);
02227 break;
02228
02229 case GTK_SPIN_SCI_PAGE_BACKWARD:
02230
02231 gtk_spin_button_sci_real_spin (spin_button_sci, -adj->page_increment);
02232 break;
02233
02234 case GTK_SPIN_SCI_HOME:
02235
02236 if (spin_button_sci->jump_to_limits)
02237 {
02238 diff = adj->value - adj->lower;
02239 if (diff > EPSILON)
02240 gtk_spin_button_sci_real_spin (spin_button_sci, -diff);
02241 }
02242 break;
02243
02244 case GTK_SPIN_SCI_END:
02245
02246 if (spin_button_sci->jump_to_limits)
02247 {
02248 diff = adj->upper - adj->value;
02249 if (diff > EPSILON)
02250 gtk_spin_button_sci_real_spin (spin_button_sci, diff);
02251 }
02252 break;
02253
02254 case GTK_SPIN_SCI_USER_DEFINED:
02255
02256 if (increment != 0)
02257 gtk_spin_button_sci_real_spin (spin_button_sci, increment);
02258 break;
02259
02260 default:
02261 break;
02262 }
02263 }
02264
02271 void
02272 gtk_spin_button_sci_update (GtkSpinbuttonsci *spin_button_sci)
02273 {
02274 gdouble val;
02275 gint error = 0;
02276 gint return_val;
02277
02278 g_return_if_fail (GTK_IS_SPIN_BUTTON_SCI (spin_button_sci));
02279
02280 return_val = FALSE;
02281 g_signal_emit (spin_button_sci, spinbuttonsci_signals[INPUT], 0, &val, &return_val);
02282 if (return_val == FALSE)
02283 {
02284 return_val = gtk_spin_button_sci_default_input (spin_button_sci, &val);
02285 error = (return_val == GTK_INPUT_ERROR);
02286 }
02287 else if (return_val == GTK_INPUT_ERROR)
02288 error = 1;
02289
02290 spin_button_sci_redraw (spin_button_sci);
02291
02292 if (spin_button_sci->update_policy == GTK_SPIN_SCI_UPDATE_ALWAYS)
02293 {
02294 if (val < spin_button_sci->adjustment->lower)
02295 val = spin_button_sci->adjustment->lower;
02296 else if (val > spin_button_sci->adjustment->upper)
02297 val = spin_button_sci->adjustment->upper;
02298 }
02299 else if ((spin_button_sci->update_policy == GTK_SPIN_SCI_UPDATE_IF_VALID) &&
02300 (error ||
02301 val < spin_button_sci->adjustment->lower ||
02302 val > spin_button_sci->adjustment->upper))
02303 {
02304 gtk_spin_button_sci_value_changed (spin_button_sci->adjustment, spin_button_sci);
02305 return;
02306 }
02307
02308 if (spin_button_sci->snap_to_ticks)
02309 gtk_spin_button_sci_snap (spin_button_sci, val);
02310 else
02311 {
02312 if (fabs (val - spin_button_sci->adjustment->value) > EPSILON)
02313 gtk_adjustment_set_value (spin_button_sci->adjustment, val);
02314 else
02315 {
02316 return_val = FALSE;
02317 g_signal_emit (spin_button_sci, spinbuttonsci_signals[OUTPUT], 0,
02318 &return_val);
02319 if (return_val == FALSE)
02320 gtk_spin_button_sci_default_output (spin_button_sci);
02321 }
02322 }
02323 }
02324
02325 static void
02326 spin_button_sci_redraw (GtkSpinbuttonsci *spin_button_sci)
02327 {
02328 GtkWidget *widget;
02329
02330 widget = GTK_WIDGET (spin_button_sci);
02331
02332 if (GTK_WIDGET_DRAWABLE (widget))
02333 {
02334 gtk_widget_queue_draw (widget);
02335
02336
02337
02338
02339 gdk_window_invalidate_rect (spin_button_sci->panel, NULL, TRUE);
02340 }
02341 }