X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkspinbutton.c;h=f05657cf42cc3915b68063a7aaddc6228b0c7ce4;hb=fa4878979e0a72890ca577a210ccd7cf6291dbf0;hp=1d357e38ae9664f0e733d78bbaf948d9b8acfa22;hpb=7fabfec5333c6bf8ab40082e3c5e56f1d525650c;p=~andy%2Fgtk diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c index 1d357e38a..f05657cf4 100644 --- a/gtk/gtkspinbutton.c +++ b/gtk/gtkspinbutton.c @@ -15,9 +15,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -29,21 +27,31 @@ #include "config.h" +#include "gtkspinbutton.h" + #include #include #include #include #include +#include "gtkadjustment.h" #include "gtkbindings.h" -#include "gtkspinbutton.h" #include "gtkentryprivate.h" -#include "gtkmainprivate.h" +#include "gtkiconhelperprivate.h" +#include "gtkicontheme.h" +#include "gtkintl.h" #include "gtkmarshalers.h" -#include "gtksettings.h" +#include "gtkorientable.h" +#include "gtkorientableprivate.h" #include "gtkprivate.h" -#include "gtkintl.h" +#include "gtksettings.h" +#include "gtkstock.h" #include "gtktypebuiltins.h" +#include "gtkwidgetpath.h" +#include "gtkwidgetprivate.h" + +#include "a11y/gtkspinbuttonaccessible.h" #define MIN_SPIN_BUTTON_WIDTH 30 #define MAX_TIMER_CALLS 5 @@ -143,20 +151,25 @@ struct _GtkSpinButtonPrivate { - GtkSpinButtonUpdatePolicy update_policy; GtkAdjustment *adjustment; - GdkWindow *panel; + GdkWindow *down_panel; + GdkWindow *up_panel; + + GdkWindow *click_child; + GdkWindow *in_child; guint32 timer; + GtkSpinButtonUpdatePolicy update_policy; + gdouble climb_rate; gdouble timer_step; + GtkOrientation orientation; + guint button : 2; - guint click_child : 2; /* valid: GTK_ARROW_UP=0, GTK_ARROW_DOWN=1 or 2=NONE/BOTH */ guint digits : 10; - guint in_child : 2; guint need_timer : 1; guint numeric : 1; guint snap_to_ticks : 1; @@ -173,7 +186,8 @@ enum { PROP_NUMERIC, PROP_WRAP, PROP_UPDATE_POLICY, - PROP_VALUE + PROP_VALUE, + PROP_ORIENTATION }; /* Signals */ @@ -205,7 +219,9 @@ static void gtk_spin_button_unrealize (GtkWidget *widget); static void gtk_spin_button_get_preferred_width (GtkWidget *widget, gint *minimum, gint *natural); - +static void gtk_spin_button_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural); static void gtk_spin_button_size_allocate (GtkWidget *widget, GtkAllocation *allocation); static gint gtk_spin_button_draw (GtkWidget *widget, @@ -226,13 +242,8 @@ static void gtk_spin_button_grab_notify (GtkWidget *widget, gboolean was_grabbed); static void gtk_spin_button_state_flags_changed (GtkWidget *widget, GtkStateFlags previous_state); -static void gtk_spin_button_style_updated (GtkWidget *widget); -static void gtk_spin_button_draw_arrow (GtkSpinButton *spin_button, - GtkStyleContext *context, - cairo_t *cr, - GtkArrowType arrow_type); static gboolean gtk_spin_button_timer (GtkSpinButton *spin_button); -static void gtk_spin_button_stop_spinning (GtkSpinButton *spin); +static gboolean gtk_spin_button_stop_spinning (GtkSpinButton *spin); static void gtk_spin_button_value_changed (GtkAdjustment *adjustment, GtkSpinButton *spin_button); static gint gtk_spin_button_key_release (GtkWidget *widget, @@ -245,6 +256,13 @@ static void gtk_spin_button_get_text_area_size (GtkEntry *entry, gint *y, gint *width, gint *height); +static void gtk_spin_button_get_frame_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height); +static void gtk_spin_button_set_orientation (GtkSpinButton *spin_button, + GtkOrientation orientation); static void gtk_spin_button_snap (GtkSpinButton *spin_button, gdouble val); static void gtk_spin_button_insert_text (GtkEditable *editable, @@ -258,15 +276,12 @@ static void gtk_spin_button_real_change_value (GtkSpinButton *spin, static gint gtk_spin_button_default_input (GtkSpinButton *spin_button, gdouble *new_val); -static gint gtk_spin_button_default_output (GtkSpinButton *spin_button); - -static gint spin_button_get_arrow_size (GtkSpinButton *spin_button); +static void gtk_spin_button_default_output (GtkSpinButton *spin_button); static guint spinbutton_signals[LAST_SIGNAL] = {0}; -#define NO_ARROW 2 - G_DEFINE_TYPE_WITH_CODE (GtkSpinButton, gtk_spin_button, GTK_TYPE_ENTRY, + G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE, NULL) G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE, gtk_spin_button_editable_init)) @@ -293,6 +308,7 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class) widget_class->realize = gtk_spin_button_realize; widget_class->unrealize = gtk_spin_button_unrealize; widget_class->get_preferred_width = gtk_spin_button_get_preferred_width; + widget_class->get_preferred_height = gtk_spin_button_get_preferred_height; widget_class->size_allocate = gtk_spin_button_size_allocate; widget_class->draw = gtk_spin_button_draw; widget_class->scroll_event = gtk_spin_button_scroll; @@ -305,10 +321,10 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class) widget_class->focus_out_event = gtk_spin_button_focus_out; widget_class->grab_notify = gtk_spin_button_grab_notify; widget_class->state_flags_changed = gtk_spin_button_state_flags_changed; - widget_class->style_updated = gtk_spin_button_style_updated; entry_class->activate = gtk_spin_button_activate; entry_class->get_text_area_size = gtk_spin_button_get_text_area_size; + entry_class->get_frame_size = gtk_spin_button_get_frame_size; class->input = NULL; class->output = NULL; @@ -385,6 +401,10 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class) 0.0, GTK_PARAM_READWRITE)); + g_object_class_override_property (gobject_class, + PROP_ORIENTATION, + "orientation"); + gtk_widget_class_install_style_property_parser (widget_class, g_param_spec_enum ("shadow-type", "Shadow Type", @@ -506,6 +526,8 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class) add_spin_binding (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK, GTK_SCROLL_START); g_type_class_add_private (class, sizeof (GtkSpinButtonPrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SPIN_BUTTON_ACCESSIBLE); } static void @@ -560,6 +582,9 @@ gtk_spin_button_set_property (GObject *object, case PROP_VALUE: gtk_spin_button_set_value (spin_button, g_value_get_double (value)); break; + case PROP_ORIENTATION: + gtk_spin_button_set_orientation (spin_button, g_value_get_enum (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -601,6 +626,9 @@ gtk_spin_button_get_property (GObject *object, case PROP_VALUE: g_value_set_double (value, gtk_adjustment_get_value (priv->adjustment)); break; + case PROP_ORIENTATION: + g_value_set_enum (value, priv->orientation); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -619,13 +647,14 @@ gtk_spin_button_init (GtkSpinButton *spin_button) priv = spin_button->priv; priv->adjustment = NULL; - priv->panel = NULL; + priv->down_panel = NULL; + priv->up_panel = NULL; priv->timer = 0; priv->climb_rate = 0.0; priv->timer_step = 0.0; priv->update_policy = GTK_UPDATE_ALWAYS; - priv->in_child = NO_ARROW; - priv->click_child = NO_ARROW; + priv->in_child = NULL; + priv->click_child = NULL; priv->button = 0; priv->need_timer = FALSE; priv->timer_calls = 0; @@ -634,11 +663,15 @@ gtk_spin_button_init (GtkSpinButton *spin_button) priv->wrap = FALSE; priv->snap_to_ticks = FALSE; + priv->orientation = GTK_ORIENTATION_HORIZONTAL; + gtk_spin_button_set_adjustment (spin_button, gtk_adjustment_new (0, 0, 0, 0, 0, 0)); context = gtk_widget_get_style_context (GTK_WIDGET (spin_button)); gtk_style_context_add_class (context, GTK_STYLE_CLASS_SPINBUTTON); + + gtk_widget_add_events (GTK_WIDGET (spin_button), GDK_SCROLL_MASK); } static void @@ -666,7 +699,8 @@ gtk_spin_button_map (GtkWidget *widget) if (gtk_widget_get_realized (widget) && !gtk_widget_get_mapped (widget)) { GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->map (widget); - gdk_window_show (priv->panel); + gdk_window_show (priv->down_panel); + gdk_window_show (priv->up_panel); } } @@ -680,30 +714,301 @@ gtk_spin_button_unmap (GtkWidget *widget) { gtk_spin_button_stop_spinning (GTK_SPIN_BUTTON (widget)); - gdk_window_hide (priv->panel); + gdk_window_hide (priv->down_panel); + gdk_window_hide (priv->up_panel); GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->unmap (widget); } } static void -gtk_spin_button_realize (GtkWidget *widget) +gtk_spin_button_panel_nthchildize_context (GtkSpinButton *spin_button, + GtkStyleContext *context, + GdkWindow *panel) { - GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget); GtkSpinButtonPrivate *priv = spin_button->priv; + GtkWidget *widget = GTK_WIDGET (spin_button); + GtkWidgetPath *path, *siblings_path; + GtkTextDirection direction; + gint up_pos, down_pos; + + /* We are a subclass of GtkEntry, which is not a GtkContainer, so we + * have to emulate what gtk_container_get_path_for_child() would do + * for the button panels + */ + path = _gtk_widget_create_path (widget); + siblings_path = gtk_widget_path_new (); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + direction = gtk_widget_get_direction (widget); + + /* flip children order for RTL */ + if (direction == GTK_TEXT_DIR_RTL) + { + up_pos = gtk_widget_path_append_type (siblings_path, GTK_TYPE_SPIN_BUTTON); + down_pos = gtk_widget_path_append_type (siblings_path, GTK_TYPE_SPIN_BUTTON); + gtk_widget_path_append_type (siblings_path, GTK_TYPE_ENTRY); + } + else + { + gtk_widget_path_append_type (siblings_path, GTK_TYPE_ENTRY); + down_pos = gtk_widget_path_append_type (siblings_path, GTK_TYPE_SPIN_BUTTON); + up_pos = gtk_widget_path_append_type (siblings_path, GTK_TYPE_SPIN_BUTTON); + } + } + else + { + up_pos = gtk_widget_path_append_type (siblings_path, GTK_TYPE_SPIN_BUTTON); + gtk_widget_path_append_type (siblings_path, GTK_TYPE_ENTRY); + down_pos = gtk_widget_path_append_type (siblings_path, GTK_TYPE_SPIN_BUTTON); + } + + gtk_widget_path_iter_add_class (siblings_path, up_pos, GTK_STYLE_CLASS_BUTTON); + gtk_widget_path_iter_add_class (siblings_path, down_pos, GTK_STYLE_CLASS_BUTTON); + + /* this allows compatibility for themes that use .spinbutton.button */ + gtk_widget_path_iter_add_class (siblings_path, up_pos, GTK_STYLE_CLASS_SPINBUTTON); + gtk_widget_path_iter_add_class (siblings_path, down_pos, GTK_STYLE_CLASS_SPINBUTTON); + + if (panel == priv->down_panel) + gtk_widget_path_append_with_siblings (path, siblings_path, down_pos); + else + gtk_widget_path_append_with_siblings (path, siblings_path, up_pos); + + gtk_style_context_set_path (context, path); + gtk_widget_path_unref (path); + gtk_widget_path_unref (siblings_path); +} + +static gboolean +gtk_spin_button_panel_at_limit (GtkSpinButton *spin_button, + GdkWindow *panel) +{ + GtkSpinButtonPrivate *priv = spin_button->priv; + GdkWindow *effective_panel; + + if (priv->wrap) + return FALSE; + + if (gtk_adjustment_get_step_increment (priv->adjustment) > 0) + effective_panel = panel; + else + effective_panel = panel == priv->up_panel ? priv->down_panel : priv->up_panel; + + if (effective_panel == priv->up_panel && + (gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_value (priv->adjustment) <= EPSILON)) + return TRUE; + + if (effective_panel == priv->down_panel && + (gtk_adjustment_get_value (priv->adjustment) - gtk_adjustment_get_lower (priv->adjustment) <= EPSILON)) + return TRUE; + + return FALSE; +} + +static GtkStateFlags +gtk_spin_button_panel_get_state (GtkSpinButton *spin_button, + GdkWindow *panel) +{ + GtkStateFlags state; + GtkSpinButtonPrivate *priv = spin_button->priv; + + state = gtk_widget_get_state_flags (GTK_WIDGET (spin_button)); + + state &= ~(GTK_STATE_FLAG_ACTIVE | GTK_STATE_FLAG_PRELIGHT); + + if ((state & GTK_STATE_FLAG_INSENSITIVE) || + gtk_spin_button_panel_at_limit (spin_button, panel) || + !gtk_editable_get_editable (GTK_EDITABLE (spin_button))) + { + state |= GTK_STATE_FLAG_INSENSITIVE; + } + else + { + if (priv->click_child == panel) + state |= GTK_STATE_FLAG_ACTIVE; + else if (priv->in_child == panel && + priv->click_child == NULL) + state |= GTK_STATE_FLAG_PRELIGHT; + } + + return state; +} + +static GtkStyleContext * +gtk_spin_button_panel_get_context (GtkSpinButton *spin_button, + GdkWindow *panel) +{ + GtkStyleContext *context; + + context = gtk_style_context_new (); + gtk_spin_button_panel_nthchildize_context (spin_button, context, panel); + + return context; +} + +static void +gtk_spin_button_panel_get_size (GtkSpinButton *spin_button, + GdkWindow *panel, + gint *width, + gint *height) +{ + GtkBorder button_padding, button_border; GtkStyleContext *context; GtkStateFlags state; - GtkAllocation allocation; + gint icon_size, w, h; + + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h); + icon_size = MAX (w, h); + + context = gtk_spin_button_panel_get_context (spin_button, panel); + state = gtk_spin_button_panel_get_state (spin_button, panel); + + gtk_style_context_get_padding (context, state, &button_padding); + gtk_style_context_get_border (context, state, &button_border); + + g_object_unref (context); + + if (width) + *width = icon_size + button_padding.left + button_padding.right + + button_border.left + button_border.right; + + if (height) + *height = icon_size + button_padding.top + button_padding.bottom + + button_border.top + button_border.bottom; +} + +static void +gtk_spin_button_panel_get_allocations (GtkSpinButton *spin_button, + GtkAllocation *down_allocation_out, + GtkAllocation *up_allocation_out) +{ + GtkWidget *widget = GTK_WIDGET (spin_button); + GtkSpinButtonPrivate *priv = spin_button->priv; + GtkAllocation spin_allocation, down_allocation, up_allocation, allocation; GtkRequisition requisition; + gint req_height; + gint down_panel_width, down_panel_height; + gint up_panel_width, up_panel_height; + GtkStyleContext *context; + GtkBorder border; + + gtk_widget_get_allocation (widget, &spin_allocation); + gtk_widget_get_preferred_size (widget, &requisition, NULL); + + context = gtk_widget_get_style_context (GTK_WIDGET (spin_button)); + gtk_style_context_get_border (context, GTK_STATE_FLAG_NORMAL, &border); + + gtk_spin_button_panel_get_size (spin_button, priv->down_panel, &down_panel_width, &down_panel_height); + gtk_spin_button_panel_get_size (spin_button, priv->up_panel, &up_panel_width, &up_panel_height); + + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget); + + /* both panels have the same size, and they're as tall as the entry allocation, + * excluding margins + */ + allocation.height = MIN (req_height, spin_allocation.height) - border.top - border.bottom; + allocation.y = spin_allocation.y + border.top + (spin_allocation.height - req_height) / 2; + down_allocation = up_allocation = allocation; + + down_allocation.width = down_panel_width; + up_allocation.width = up_panel_width; + + /* invert x axis allocation for RTL */ + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) + { + up_allocation.x = spin_allocation.x + border.left; + down_allocation.x = up_allocation.x + up_panel_width; + } + else + { + up_allocation.x = spin_allocation.x + spin_allocation.width - up_panel_width - border.right; + down_allocation.x = up_allocation.x - down_panel_width; + } + } + else + { + /* both panels have the same size, and they're as wide as the entry allocation */ + allocation.width = spin_allocation.width; + allocation.x = spin_allocation.x; + down_allocation = up_allocation = allocation; + + down_allocation.height = down_panel_height; + up_allocation.height = up_panel_height; + + up_allocation.y = spin_allocation.y; + down_allocation.y = spin_allocation.y + spin_allocation.height - down_allocation.height; + } + + if (down_allocation_out) + *down_allocation_out = down_allocation; + if (up_allocation_out) + *up_allocation_out = up_allocation; +} + +static void +gtk_spin_button_panel_draw (GtkSpinButton *spin_button, + cairo_t *cr, + GdkWindow *panel) +{ + GtkSpinButtonPrivate *priv = spin_button->priv; + GtkStyleContext *context; + GtkStateFlags state; + GtkWidget *widget; + gdouble width, height, x, y; + gint icon_width, icon_height; + GtkIconHelper *icon_helper; + + widget = GTK_WIDGET (spin_button); + + cairo_save (cr); + gtk_cairo_transform_to_window (cr, widget, panel); + + context = gtk_spin_button_panel_get_context (spin_button, panel); + state = gtk_spin_button_panel_get_state (spin_button, panel); + gtk_style_context_set_state (context, state); + + height = gdk_window_get_height (panel); + width = gdk_window_get_width (panel); + + icon_helper = _gtk_icon_helper_new (); + _gtk_icon_helper_set_use_fallback (icon_helper, TRUE); + + if (panel == priv->down_panel) + _gtk_icon_helper_set_icon_name (icon_helper, "list-remove-symbolic", GTK_ICON_SIZE_MENU); + else + _gtk_icon_helper_set_icon_name (icon_helper, "list-add-symbolic", GTK_ICON_SIZE_MENU); + + _gtk_icon_helper_get_size (icon_helper, context, + &icon_width, &icon_height); + + gtk_render_background (context, cr, + 0, 0, width, height); + gtk_render_frame (context, cr, + 0, 0, width, height); + + x = floor ((width - icon_width) / 2.0); + y = floor ((height - icon_height) / 2.0); + + _gtk_icon_helper_draw (icon_helper, context, cr, + x, y); + cairo_restore (cr); + + g_object_unref (icon_helper); + g_object_unref (context); +} + +static void +gtk_spin_button_realize (GtkWidget *widget) +{ + GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget); + GtkSpinButtonPrivate *priv = spin_button->priv; + GtkAllocation down_allocation, up_allocation; GdkWindowAttr attributes; gint attributes_mask; gboolean return_val; - gint arrow_size; - GtkBorder padding; - - arrow_size = spin_button_get_arrow_size (spin_button); - - gtk_widget_get_preferred_size (widget, &requisition, NULL); - gtk_widget_get_allocation (widget, &allocation); gtk_widget_set_events (widget, gtk_widget_get_events (widget) | GDK_KEY_RELEASE_MASK); @@ -719,22 +1024,36 @@ gtk_spin_button_realize (GtkWidget *widget) attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; - state = gtk_widget_get_state_flags (widget); - context = gtk_widget_get_style_context (widget); - gtk_style_context_get_padding (context, state, &padding); + gtk_spin_button_panel_get_allocations (spin_button, &down_allocation, &up_allocation); + + /* create the left panel window */ + attributes.x = down_allocation.x; + attributes.y = down_allocation.y; + attributes.width = down_allocation.width; + attributes.height = down_allocation.height; - attributes.x = allocation.x + allocation.width - arrow_size - (padding.left + padding.right); - attributes.y = allocation.y + (allocation.height - requisition.height) / 2; - attributes.width = arrow_size + padding.left + padding.right; - attributes.height = requisition.height; + priv->down_panel = gdk_window_new (gtk_widget_get_window (widget), + &attributes, attributes_mask); + gtk_widget_register_window (widget, priv->down_panel); - priv->panel = gdk_window_new (gtk_widget_get_window (widget), - &attributes, attributes_mask); - gdk_window_set_user_data (priv->panel, widget); + /* create the right panel window */ + attributes.x = up_allocation.x; + attributes.y = up_allocation.y; + attributes.width = up_allocation.width; + attributes.height = up_allocation.height; + + priv->up_panel = gdk_window_new (gtk_widget_get_window (widget), + &attributes, attributes_mask); + gtk_widget_register_window (widget, priv->up_panel); return_val = FALSE; g_signal_emit (spin_button, spinbutton_signals[OUTPUT], 0, &return_val); - if (return_val == FALSE) + + /* If output wasn't processed explicitly by the method connected to the + * 'output' signal; and if we don't have any explicit 'text' set initially, + * fallback to the default output. */ + if (!return_val && + (spin_button->priv->numeric || gtk_entry_get_text (GTK_ENTRY (spin_button)) == NULL)) gtk_spin_button_default_output (spin_button); gtk_widget_queue_resize (GTK_WIDGET (spin_button)); @@ -748,35 +1067,66 @@ gtk_spin_button_unrealize (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->unrealize (widget); - if (priv->panel) + if (priv->down_panel) + { + gtk_widget_unregister_window (widget, priv->down_panel); + gdk_window_destroy (priv->down_panel); + priv->down_panel = NULL; + } + + if (priv->up_panel) { - gdk_window_set_user_data (priv->panel, NULL); - gdk_window_destroy (priv->panel); - priv->panel = NULL; + gtk_widget_unregister_window (widget, priv->up_panel); + gdk_window_destroy (priv->up_panel); + priv->up_panel = NULL; } } -static int -compute_double_length (double val, int digits) +static void +gtk_spin_button_set_orientation (GtkSpinButton *spin, + GtkOrientation orientation) { - int a; - int extra; + GtkEntry *entry = GTK_ENTRY (spin); + GtkSpinButtonPrivate *priv = spin->priv; + + if (priv->orientation == orientation) + return; + + priv->orientation = orientation; + _gtk_orientable_set_style_classes (GTK_ORIENTABLE (spin)); + + /* change alignment if it's the default */ + if (priv->orientation == GTK_ORIENTATION_VERTICAL && + gtk_entry_get_alignment (entry) == 0.0) + gtk_entry_set_alignment (entry, 0.5); + else if (priv->orientation == GTK_ORIENTATION_HORIZONTAL && + gtk_entry_get_alignment (entry) == 0.5) + gtk_entry_set_alignment (entry, 0.0); - a = 1; - if (fabs (val) > 1.0) - a = floor (log10 (fabs (val))) + 1; + g_object_notify (G_OBJECT (spin), "orientation"); + gtk_widget_queue_resize (GTK_WIDGET (spin)); +} + +static gint +measure_string_width (PangoLayout *layout, + const gchar *string) +{ + gint width; - extra = 0; + pango_layout_set_text (layout, string, -1); + pango_layout_get_pixel_size (layout, &width, NULL); - /* The dot: */ - if (digits > 0) - extra++; + return width; +} - /* The sign: */ - if (val < 0) - extra++; +static gchar * +gtk_spin_button_format_for_value (GtkSpinButton *spin_button, + gdouble value) +{ + GtkSpinButtonPrivate *priv = spin_button->priv; + gchar *buf = g_strdup_printf ("%0.*f", priv->digits, value); - return a + digits + extra; + return buf; } static void @@ -788,122 +1138,113 @@ gtk_spin_button_get_preferred_width (GtkWidget *widget, GtkSpinButtonPrivate *priv = spin_button->priv; GtkEntry *entry = GTK_ENTRY (widget); GtkStyleContext *style_context; - GtkBorder padding; - gint arrow_size; style_context = gtk_widget_get_style_context (widget); - arrow_size = spin_button_get_arrow_size (spin_button); - GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->get_preferred_width (widget, minimum, natural); if (gtk_entry_get_width_chars (entry) < 0) { - PangoContext *context; - const PangoFontDescription *font_desc; - PangoFontMetrics *metrics; - gint width; - gint w; - gint string_len; - gint max_string_len; - gint digit_width; + gint width, w; gboolean interior_focus; gint focus_width; - gint xborder, yborder; - GtkBorder inner_border; - - gtk_widget_style_get (widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, - NULL); + GtkBorder borders; + PangoLayout *layout; + gchar *str; - font_desc = gtk_style_context_get_font (style_context, 0); + gtk_style_context_get_style (style_context, + "interior-focus", &interior_focus, + "focus-line-width", &focus_width, + NULL); - context = gtk_widget_get_pango_context (widget); - metrics = pango_context_get_metrics (context, font_desc, - pango_context_get_language (context)); - - digit_width = pango_font_metrics_get_approximate_digit_width (metrics); - digit_width = PANGO_SCALE * - ((digit_width + PANGO_SCALE - 1) / PANGO_SCALE); - - pango_font_metrics_unref (metrics); + layout = pango_layout_copy (gtk_entry_get_layout (entry)); /* Get max of MIN_SPIN_BUTTON_WIDTH, size of upper, size of lower */ width = MIN_SPIN_BUTTON_WIDTH; - max_string_len = MAX (10, compute_double_length (1e9 * gtk_adjustment_get_step_increment (priv->adjustment), - priv->digits)); - string_len = compute_double_length (gtk_adjustment_get_upper (priv->adjustment), - priv->digits); - w = PANGO_PIXELS (MIN (string_len, max_string_len) * digit_width); - width = MAX (width, w); - string_len = compute_double_length (gtk_adjustment_get_lower (priv->adjustment), priv->digits); - w = PANGO_PIXELS (MIN (string_len, max_string_len) * digit_width); + str = gtk_spin_button_format_for_value (spin_button, + gtk_adjustment_get_upper (priv->adjustment)); + w = measure_string_width (layout, str); width = MAX (width, w); + g_free (str); - _gtk_entry_get_borders (entry, &xborder, &yborder); - _gtk_entry_effective_inner_border (entry, &inner_border); + str = gtk_spin_button_format_for_value (spin_button, + gtk_adjustment_get_lower (priv->adjustment)); + w = measure_string_width (layout, str); + width = MAX (width, w); + g_free (str); - width += xborder * 2 + inner_border.left + inner_border.right; + _gtk_entry_get_borders (entry, &borders); + width += borders.left + borders.right; *minimum = width; *natural = width; + + g_object_unref (layout); } - gtk_style_context_get_padding (style_context, - gtk_widget_get_state_flags (widget), - &padding); + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gint down_panel_width; + gint up_panel_width; + + gtk_spin_button_panel_get_size (spin_button, priv->down_panel, &down_panel_width, NULL); + gtk_spin_button_panel_get_size (spin_button, priv->up_panel, &up_panel_width, NULL); - *minimum += arrow_size + padding.left + padding.right; - *natural += arrow_size + padding.left + padding.right; + *minimum += up_panel_width + down_panel_width; + *natural += up_panel_width + down_panel_width; + } } static void -gtk_spin_button_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +gtk_spin_button_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) { - GtkSpinButton *spin = GTK_SPIN_BUTTON (widget); - GtkSpinButtonPrivate *priv = spin->priv; - GtkAllocation panel_allocation; - GtkRequisition requisition; - GtkStyleContext *context; - GtkStateFlags state; - GtkBorder padding; - gint arrow_size; - gint panel_width; - - arrow_size = spin_button_get_arrow_size (spin); - context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - - gtk_style_context_get_padding (context, state, &padding); - panel_width = arrow_size + padding.left + padding.right; + GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget); + GtkSpinButtonPrivate *priv = spin_button->priv; - gtk_widget_get_preferred_size (widget, &requisition, NULL); + GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->get_preferred_height (widget, minimum, natural); - gtk_widget_set_allocation (widget, allocation); + if (priv->orientation == GTK_ORIENTATION_VERTICAL) + { + gint down_panel_height; + gint up_panel_height; - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - panel_allocation.x = allocation->x; - else - panel_allocation.x = allocation->x + allocation->width - panel_width; + gtk_spin_button_panel_get_size (spin_button, priv->down_panel, NULL, &down_panel_height); + gtk_spin_button_panel_get_size (spin_button, priv->up_panel, NULL, &up_panel_height); - panel_allocation.width = panel_width; - panel_allocation.height = MIN (requisition.height, allocation->height); + *minimum += up_panel_height + down_panel_height; + *natural += up_panel_height + down_panel_height; + } +} - panel_allocation.y = allocation->y + - (allocation->height - requisition.height) / 2; +static void +gtk_spin_button_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkSpinButton *spin = GTK_SPIN_BUTTON (widget); + GtkSpinButtonPrivate *priv = spin->priv; + GtkAllocation down_panel_allocation, up_panel_allocation; + gtk_widget_set_allocation (widget, allocation); GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->size_allocate (widget, allocation); + gtk_spin_button_panel_get_allocations (spin, &down_panel_allocation, &up_panel_allocation); + if (gtk_widget_get_realized (widget)) { - gdk_window_move_resize (priv->panel, - panel_allocation.x, - panel_allocation.y, - panel_allocation.width, - panel_allocation.height); + gdk_window_move_resize (priv->down_panel, + down_panel_allocation.x, + down_panel_allocation.y, + down_panel_allocation.width, + down_panel_allocation.height); + + gdk_window_move_resize (priv->up_panel, + up_panel_allocation.x, + up_panel_allocation.y, + up_panel_allocation.width, + up_panel_allocation.height); } gtk_widget_queue_draw (GTK_WIDGET (spin)); @@ -915,213 +1256,31 @@ gtk_spin_button_draw (GtkWidget *widget, { GtkSpinButton *spin = GTK_SPIN_BUTTON (widget); GtkSpinButtonPrivate *priv = spin->priv; - GtkStyleContext *context; - GtkStateFlags state = 0; - gboolean is_rtl; - is_rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL); - context = gtk_widget_get_style_context (widget); - - cairo_save (cr); GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->draw (widget, cr); - cairo_restore (cr); - - state = gtk_widget_get_state_flags (widget); - if (gtk_widget_has_focus (widget)) - state |= GTK_STATE_FLAG_FOCUSED; - - gtk_style_context_save (context); - gtk_style_context_set_state (context, state); - gtk_style_context_remove_class (context, GTK_STYLE_CLASS_ENTRY); - - if (is_rtl) - gtk_style_context_set_junction_sides (context, GTK_JUNCTION_RIGHT); - else - gtk_style_context_set_junction_sides (context, GTK_JUNCTION_LEFT); - - gtk_cairo_transform_to_window (cr, widget, priv->panel); - - if (gtk_entry_get_has_frame (GTK_ENTRY (widget))) - gtk_render_background (context, cr, 0, 0, - gdk_window_get_width (priv->panel), - gdk_window_get_height (priv->panel)); - - gtk_spin_button_draw_arrow (spin, context, cr, GTK_ARROW_UP); - gtk_spin_button_draw_arrow (spin, context, cr, GTK_ARROW_DOWN); - - gtk_style_context_restore (context); + /* Draw the buttons */ + gtk_spin_button_panel_draw (spin, cr, priv->down_panel); + gtk_spin_button_panel_draw (spin, cr, priv->up_panel); return FALSE; } -static gboolean -spin_button_at_limit (GtkSpinButton *spin_button, - GtkArrowType arrow) -{ - GtkSpinButtonPrivate *priv = spin_button->priv; - GtkArrowType effective_arrow; - - if (priv->wrap) - return FALSE; - - if (gtk_adjustment_get_step_increment (priv->adjustment) > 0) - effective_arrow = arrow; - else - effective_arrow = arrow == GTK_ARROW_UP ? GTK_ARROW_DOWN : GTK_ARROW_UP; - - if (effective_arrow == GTK_ARROW_UP && - (gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_value (priv->adjustment) <= EPSILON)) - return TRUE; - - if (effective_arrow == GTK_ARROW_DOWN && - (gtk_adjustment_get_value (priv->adjustment) - gtk_adjustment_get_lower (priv->adjustment) <= EPSILON)) - return TRUE; - - return FALSE; -} - -static void -gtk_spin_button_draw_arrow (GtkSpinButton *spin_button, - GtkStyleContext *context, - cairo_t *cr, - GtkArrowType arrow_type) -{ - GtkSpinButtonPrivate *priv; - GtkJunctionSides junction; - GtkStateFlags state; - GtkWidget *widget; - GtkBorder padding; - gdouble angle; - gint x; - gint y; - gint panel_height; - gint height; - gint width; - gint h, w; - - g_return_if_fail (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN); - - gtk_style_context_save (context); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON); - - priv = spin_button->priv; - widget = GTK_WIDGET (spin_button); - junction = gtk_style_context_get_junction_sides (context); - - panel_height = gdk_window_get_height (priv->panel); - - if (arrow_type == GTK_ARROW_UP) - { - x = 0; - y = 0; - - height = panel_height / 2; - angle = 0; - junction |= GTK_JUNCTION_BOTTOM; - } - else - { - x = 0; - y = panel_height / 2; - - height = (panel_height + 1) / 2; - angle = G_PI; - junction |= GTK_JUNCTION_TOP; - } - - if (spin_button_at_limit (spin_button, arrow_type)) - state = GTK_STATE_FLAG_INSENSITIVE; - else - { - if (priv->click_child == arrow_type) - state = GTK_STATE_ACTIVE; - else - { - if (priv->in_child == arrow_type && - priv->click_child == NO_ARROW) - state = GTK_STATE_FLAG_PRELIGHT; - else - state = gtk_widget_get_state_flags (widget); - } - } - - gtk_style_context_get_padding (context, state, &padding); - gtk_style_context_set_junction_sides (context, junction); - gtk_style_context_set_state (context, state); - - width = spin_button_get_arrow_size (spin_button) + padding.left + padding.right; - - gtk_render_background (context, cr, x, y, width, height); - gtk_render_frame (context, cr, x, y, width, height); - - height = panel_height; - - if (arrow_type == GTK_ARROW_DOWN) - { - y = height / 2; - height = height - y - 2; - } - else - { - y = 2; - height = height / 2 - 2; - } - - width -= 3; - - if (widget && gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - x = 2; - else - x = 1; - - w = width / 2; - w -= w % 2 - 1; /* force odd */ - h = (w + 1) / 2; - - x += (width - w) / 2; - y += (height - h) / 2; - - height = h; - width = w; - - gtk_render_arrow (context, cr, - angle, x, y, width); - - gtk_style_context_restore (context); -} - static gint gtk_spin_button_enter_notify (GtkWidget *widget, GdkEventCrossing *event) { GtkSpinButton *spin = GTK_SPIN_BUTTON (widget); GtkSpinButtonPrivate *priv = spin->priv; - GtkRequisition requisition; - if (event->window == priv->panel) + if ((event->window == priv->down_panel) || + (event->window == priv->up_panel)) { - GdkDevice *device; - gint x; - gint y; - - device = gdk_event_get_device ((GdkEvent *) event); - gdk_window_get_device_position (priv->panel, device, &x, &y, NULL); - - gtk_widget_get_preferred_size (widget, &requisition, NULL); - - if (y <= requisition.height / 2) - priv->in_child = GTK_ARROW_UP; - else - priv->in_child = GTK_ARROW_DOWN; - + priv->in_child = event->window; gtk_widget_queue_draw (GTK_WIDGET (spin)); } - if (GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->enter_notify_event) - return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->enter_notify_event (widget, event); - - return FALSE; + return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->enter_notify_event (widget, event); } static gint @@ -1131,13 +1290,13 @@ gtk_spin_button_leave_notify (GtkWidget *widget, GtkSpinButton *spin = GTK_SPIN_BUTTON (widget); GtkSpinButtonPrivate *priv = spin->priv; - priv->in_child = NO_ARROW; - gtk_widget_queue_draw (GTK_WIDGET (spin)); - - if (GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->leave_notify_event) - return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->leave_notify_event (widget, event); + if (priv->in_child != NULL) + { + priv->in_child = NULL; + gtk_widget_queue_draw (GTK_WIDGET (spin)); + } - return FALSE; + return GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->leave_notify_event (widget, event); } static gint @@ -1158,8 +1317,8 @@ gtk_spin_button_grab_notify (GtkWidget *widget, if (!was_grabbed) { - gtk_spin_button_stop_spinning (spin); - gtk_widget_queue_draw (GTK_WIDGET (spin)); + if (gtk_spin_button_stop_spinning (spin)) + gtk_widget_queue_draw (GTK_WIDGET (spin)); } } @@ -1171,29 +1330,11 @@ gtk_spin_button_state_flags_changed (GtkWidget *widget, if (!gtk_widget_is_sensitive (widget)) { - gtk_spin_button_stop_spinning (spin); - gtk_widget_queue_draw (GTK_WIDGET (spin)); - } -} - -static void -gtk_spin_button_style_updated (GtkWidget *widget) -{ - GtkSpinButton *spin = GTK_SPIN_BUTTON (widget); - GtkSpinButtonPrivate *priv = spin->priv; - - if (gtk_widget_get_realized (widget)) - { - GtkStyleContext *context; - - context = gtk_widget_get_style_context (widget); - gtk_style_context_set_background (context, priv->panel); + if (gtk_spin_button_stop_spinning (spin)) + gtk_widget_queue_draw (GTK_WIDGET (spin)); } - - GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->style_updated (widget); } - static gint gtk_spin_button_scroll (GtkWidget *widget, GdkEventScroll *event) @@ -1219,37 +1360,37 @@ gtk_spin_button_scroll (GtkWidget *widget, return TRUE; } -static void +static gboolean gtk_spin_button_stop_spinning (GtkSpinButton *spin) { GtkSpinButtonPrivate *priv = spin->priv; + gboolean did_spin = FALSE; if (priv->timer) { g_source_remove (priv->timer); priv->timer = 0; - priv->timer_calls = 0; priv->need_timer = FALSE; + + did_spin = TRUE; } priv->button = 0; - priv->timer = 0; priv->timer_step = gtk_adjustment_get_step_increment (priv->adjustment); priv->timer_calls = 0; - priv->click_child = NO_ARROW; - priv->button = 0; + priv->click_child = NULL; + + return did_spin; } static void start_spinning (GtkSpinButton *spin, - GtkArrowType click_child, + GdkWindow *click_child, gdouble step) { GtkSpinButtonPrivate *priv; - g_return_if_fail (click_child == GTK_ARROW_UP || click_child == GTK_ARROW_DOWN); - priv = spin->priv; priv->click_child = click_child; @@ -1267,7 +1408,7 @@ start_spinning (GtkSpinButton *spin, (GSourceFunc) gtk_spin_button_timer, (gpointer) spin); } - gtk_spin_button_real_spin (spin, click_child == GTK_ARROW_UP ? step : -step); + gtk_spin_button_real_spin (spin, click_child == priv->up_panel ? step : -step); gtk_widget_queue_draw (GTK_WIDGET (spin)); } @@ -1281,37 +1422,25 @@ gtk_spin_button_button_press (GtkWidget *widget, if (!priv->button) { - if (event->window == priv->panel) + if ((event->window == priv->down_panel) || + (event->window == priv->up_panel)) { - GtkRequisition requisition; - if (!gtk_widget_has_focus (widget)) gtk_widget_grab_focus (widget); priv->button = event->button; - if (gtk_editable_get_editable (GTK_EDITABLE (widget))) + if (gtk_editable_get_editable (GTK_EDITABLE (widget))) { gtk_spin_button_update (spin); - gtk_widget_get_preferred_size (widget, &requisition, NULL); + if (event->button == GDK_BUTTON_PRIMARY) + start_spinning (spin, event->window, gtk_adjustment_get_step_increment (priv->adjustment)); + else if (event->button == GDK_BUTTON_MIDDLE) + start_spinning (spin, event->window, gtk_adjustment_get_page_increment (priv->adjustment)); + else + priv->click_child = event->window; + } else + gtk_widget_error_bell (widget); - if (event->y <= requisition.height / 2) - { - if (event->button == 1) - start_spinning (spin, GTK_ARROW_UP, gtk_adjustment_get_step_increment (priv->adjustment)); - else if (event->button == 2) - start_spinning (spin, GTK_ARROW_UP, gtk_adjustment_get_page_increment (priv->adjustment)); - else - priv->click_child = GTK_ARROW_UP; - } - else - { - if (event->button == 1) - start_spinning (spin, GTK_ARROW_DOWN, gtk_adjustment_get_step_increment (priv->adjustment)); - else if (event->button == 2) - start_spinning (spin, GTK_ARROW_DOWN, gtk_adjustment_get_page_increment (priv->adjustment)); - else - priv->click_child = GTK_ARROW_DOWN; - } return TRUE; } else @@ -1326,51 +1455,30 @@ gtk_spin_button_button_release (GtkWidget *widget, { GtkSpinButton *spin = GTK_SPIN_BUTTON (widget); GtkSpinButtonPrivate *priv = spin->priv; - gint arrow_size; - - arrow_size = spin_button_get_arrow_size (spin); if (event->button == priv->button) { - int click_child = priv->click_child; + GdkWindow *click_child = priv->click_child; gtk_spin_button_stop_spinning (spin); - if (event->button == 3) + if (event->button == GDK_BUTTON_SECONDARY) { - GtkRequisition requisition; - GtkStyleContext *context; - GtkStateFlags state; - GtkBorder padding; - - gtk_widget_get_preferred_size (widget, &requisition, NULL); - - context = gtk_widget_get_style_context (widget); - state = gtk_widget_get_state_flags (widget); - gtk_style_context_get_padding (context, state, &padding); + gdouble diff; - if (event->y >= 0 && event->x >= 0 && - event->y <= requisition.height && - event->x <= arrow_size + padding.left + padding.right) + if (event->window == priv->down_panel && + click_child == event->window) { - if (click_child == GTK_ARROW_UP && - event->y <= requisition.height / 2) - { - gdouble diff; - - diff = gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_value (priv->adjustment); - if (diff > EPSILON) - gtk_spin_button_real_spin (spin, diff); - } - else if (click_child == GTK_ARROW_DOWN && - event->y > requisition.height / 2) - { - gdouble diff; - - diff = gtk_adjustment_get_value (priv->adjustment) - gtk_adjustment_get_lower (priv->adjustment); - if (diff > EPSILON) - gtk_spin_button_real_spin (spin, -diff); - } + diff = gtk_adjustment_get_value (priv->adjustment) - gtk_adjustment_get_lower (priv->adjustment); + if (diff > EPSILON) + gtk_spin_button_real_spin (spin, -diff); + } + else if (event->window == priv->up_panel && + click_child == event->window) + { + diff = gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_value (priv->adjustment); + if (diff > EPSILON) + gtk_spin_button_real_spin (spin, diff); } } gtk_widget_queue_draw (GTK_WIDGET (spin)); @@ -1391,27 +1499,13 @@ gtk_spin_button_motion_notify (GtkWidget *widget, if (priv->button) return FALSE; - if (event->window == priv->panel) + if (event->window == priv->down_panel || + event->window == priv->up_panel) { - GtkRequisition requisition; - gint y = event->y; - gdk_event_request_motions (event); - gtk_widget_get_preferred_size (widget, &requisition, NULL); - - if (y <= requisition.height / 2 && - priv->in_child == GTK_ARROW_DOWN) - { - priv->in_child = GTK_ARROW_UP; - gtk_widget_queue_draw (GTK_WIDGET (spin)); - } - else if (y > requisition.height / 2 && - priv->in_child == GTK_ARROW_UP) - { - priv->in_child = GTK_ARROW_DOWN; - gtk_widget_queue_draw (GTK_WIDGET (spin)); - } + priv->in_child = event->window; + gtk_widget_queue_draw (widget); return FALSE; } @@ -1427,7 +1521,7 @@ gtk_spin_button_timer (GtkSpinButton *spin_button) if (priv->timer) { - if (priv->click_child == GTK_ARROW_UP) + if (priv->click_child == priv->up_panel) gtk_spin_button_real_spin (spin_button, priv->timer_step); else gtk_spin_button_real_spin (spin_button, -priv->timer_step); @@ -1491,6 +1585,12 @@ gtk_spin_button_real_change_value (GtkSpinButton *spin, GtkSpinButtonPrivate *priv = spin->priv; gdouble old_value; + if (!gtk_editable_get_editable (GTK_EDITABLE (spin))) + { + gtk_widget_error_bell (GTK_WIDGET (spin)); + return; + } + /* When the key binding is activated, there may be an outstanding * value, so we first have to commit what is currently written in * the spin buttons text entry. See #106574 @@ -1499,11 +1599,6 @@ gtk_spin_button_real_change_value (GtkSpinButton *spin, old_value = gtk_adjustment_get_value (priv->adjustment); - /* We don't test whether the entry is editable, since - * this key binding conceptually corresponds to changing - * the value with the buttons using the mouse, which - * we allow for non-editable spin buttons. - */ switch (scroll) { case GTK_SCROLL_STEP_BACKWARD: @@ -1626,6 +1721,32 @@ gtk_spin_button_activate (GtkEntry *entry) GTK_ENTRY_CLASS (gtk_spin_button_parent_class)->activate (entry); } +static void +gtk_spin_button_get_frame_size (GtkEntry *entry, + gint *x, + gint *y, + gint *width, + gint *height) +{ + GtkSpinButtonPrivate *priv = GTK_SPIN_BUTTON (entry)->priv; + gint up_panel_width, up_panel_height; + gint down_panel_width, down_panel_height; + + gtk_spin_button_panel_get_size (GTK_SPIN_BUTTON (entry), priv->up_panel, &up_panel_width, &up_panel_height); + gtk_spin_button_panel_get_size (GTK_SPIN_BUTTON (entry), priv->down_panel, &down_panel_width, &down_panel_height); + + GTK_ENTRY_CLASS (gtk_spin_button_parent_class)->get_frame_size (entry, x, y, width, height); + + if (priv->orientation == GTK_ORIENTATION_VERTICAL) + { + if (y) + *y += up_panel_height; + + if (height) + *height -= up_panel_height + down_panel_height; + } +} + static void gtk_spin_button_get_text_area_size (GtkEntry *entry, gint *x, @@ -1633,28 +1754,34 @@ gtk_spin_button_get_text_area_size (GtkEntry *entry, gint *width, gint *height) { - GtkStyleContext *context; - GtkStateFlags state; - GtkWidget *widget; - GtkBorder padding; - gint arrow_size; - gint panel_width; + GtkSpinButtonPrivate *priv = GTK_SPIN_BUTTON (entry)->priv; + gint up_panel_width, up_panel_height; + gint down_panel_width, down_panel_height; - GTK_ENTRY_CLASS (gtk_spin_button_parent_class)->get_text_area_size (entry, x, y, width, height); + gtk_spin_button_panel_get_size (GTK_SPIN_BUTTON (entry), priv->up_panel, &up_panel_width, &up_panel_height); + gtk_spin_button_panel_get_size (GTK_SPIN_BUTTON (entry), priv->down_panel, &down_panel_width, &down_panel_height); - widget = GTK_WIDGET (entry); - state = gtk_widget_get_state_flags (widget); - context = gtk_widget_get_style_context (widget); - gtk_style_context_get_padding (context, state, &padding); + GTK_ENTRY_CLASS (gtk_spin_button_parent_class)->get_text_area_size (entry, x, y, width, height); - arrow_size = spin_button_get_arrow_size (GTK_SPIN_BUTTON (entry)); - panel_width = arrow_size + padding.left + padding.right; + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) + { + if (x) + *x += up_panel_width + down_panel_width; + } - if (width) - *width -= panel_width; + if (width) + *width -= up_panel_width + down_panel_width; + } + else + { + if (y) + *y += up_panel_height; - if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL && x) - *x += panel_width; + if (height) + *height -= up_panel_height + down_panel_height; + } } static void @@ -1831,17 +1958,17 @@ gtk_spin_button_default_input (GtkSpinButton *spin_button, return FALSE; } -static gint +static void gtk_spin_button_default_output (GtkSpinButton *spin_button) { GtkSpinButtonPrivate *priv = spin_button->priv; - - gchar *buf = g_strdup_printf ("%0.*f", priv->digits, gtk_adjustment_get_value (priv->adjustment)); + gchar *buf = gtk_spin_button_format_for_value (spin_button, + gtk_adjustment_get_value (priv->adjustment)); if (strcmp (buf, gtk_entry_get_text (GTK_ENTRY (spin_button)))) gtk_entry_set_text (GTK_ENTRY (spin_button), buf); + g_free (buf); - return FALSE; } @@ -2160,6 +2287,9 @@ gtk_spin_button_get_increments (GtkSpinButton *spin_button, * @max: maximum allowable value * * Sets the minimum and maximum allowable values for @spin_button. + * + * If the current value is outside this range, it will be adjusted + * to fit within the range, otherwise it will remain unchanged. */ void gtk_spin_button_set_range (GtkSpinButton *spin_button, @@ -2282,7 +2412,7 @@ gtk_spin_button_set_value (GtkSpinButton *spin_button, * @policy: a #GtkSpinButtonUpdatePolicy value * * Sets the update behavior of a spin button. - * This determines wether the spin button is always updated + * This determines whether the spin button is always updated * or only when a valid value is set. */ void @@ -2410,24 +2540,6 @@ gtk_spin_button_get_wrap (GtkSpinButton *spin_button) return spin_button->priv->wrap; } -static gint -spin_button_get_arrow_size (GtkSpinButton *spin_button) -{ - const PangoFontDescription *font_desc; - GtkStyleContext *context; - gint size; - gint arrow_size; - - /* FIXME: use getter */ - context = gtk_widget_get_style_context (GTK_WIDGET (spin_button)); - font_desc = gtk_style_context_get_font (context, 0); - - size = pango_font_description_get_size (font_desc); - arrow_size = MAX (PANGO_PIXELS (size), MIN_ARROW_WIDTH); - - return arrow_size - arrow_size % 2; /* force even */ -} - /** * gtk_spin_button_set_snap_to_ticks: * @spin_button: a #GtkSpinButton @@ -2610,8 +2722,14 @@ gtk_spin_button_update (GtkSpinButton *spin_button) gtk_spin_button_set_value (spin_button, val); } -GdkWindow * -_gtk_spin_button_get_panel (GtkSpinButton *spin_button) +void +_gtk_spin_button_get_panels (GtkSpinButton *spin_button, + GdkWindow **down_panel, + GdkWindow **up_panel) { - return spin_button->priv->panel; + if (down_panel != NULL) + *down_panel = spin_button->priv->down_panel; + + if (up_panel != NULL) + *up_panel = spin_button->priv->up_panel; }