X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkspinbutton.c;h=2e071d9aca310c8b528cb81a9e35254cedf047de;hb=ceeed09d0780e5a2227fcfdb3e13f7530aa5fcf2;hp=978109edae0115b4aa7bd3d8880f95b0875c50eb;hpb=1a122a43679ecf0d6d7f992668561e42f547269f;p=~andy%2Fgtk diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c index 978109eda..2e071d9ac 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,22 +27,29 @@ #include "config.h" +#include "gtkspinbutton.h" + #include #include #include #include #include +#include "gtkadjustment.h" #include "gtkbindings.h" -#include "gtkspinbutton.h" #include "gtkentryprivate.h" +#include "gtkiconhelperprivate.h" #include "gtkicontheme.h" +#include "gtkintl.h" #include "gtkmarshalers.h" +#include "gtkorientable.h" +#include "gtkorientableprivate.h" +#include "gtkprivate.h" #include "gtksettings.h" #include "gtkstock.h" -#include "gtkprivate.h" -#include "gtkintl.h" #include "gtktypebuiltins.h" +#include "gtkwidgetpath.h" +#include "gtkwidgetprivate.h" #include "a11y/gtkspinbuttonaccessible.h" @@ -161,6 +166,8 @@ struct _GtkSpinButtonPrivate gdouble climb_rate; gdouble timer_step; + GtkOrientation orientation; + guint button : 2; guint digits : 10; guint need_timer : 1; @@ -179,7 +186,8 @@ enum { PROP_NUMERIC, PROP_WRAP, PROP_UPDATE_POLICY, - PROP_VALUE + PROP_VALUE, + PROP_ORIENTATION }; /* Signals */ @@ -211,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, @@ -246,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, @@ -259,11 +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 void gtk_spin_button_default_output (GtkSpinButton *spin_button); static guint spinbutton_signals[LAST_SIGNAL] = {0}; 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)) @@ -290,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,6 +324,7 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class) 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; @@ -381,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", @@ -558,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; @@ -599,54 +626,15 @@ 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; } } -static gint -get_icon_size (void) -{ - gint width, height, icon_size; - - gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height); - icon_size = MAX (width, height); - - return icon_size; -} - -static GdkPixbuf * -create_one_pixbuf (GtkStyleContext *context, - const gchar *icon_name) -{ - GtkIconInfo *icon_info; - GdkPixbuf *pix; - gint size = get_icon_size (); - - icon_info = gtk_icon_theme_lookup_icon (gtk_icon_theme_get_default (), - icon_name, size, - GTK_ICON_LOOKUP_GENERIC_FALLBACK); - - if (icon_info != NULL) - { - pix = gtk_icon_info_load_symbolic_for_context (icon_info, context, - NULL, NULL); - gtk_icon_info_free (icon_info); - } - else - { - GtkIconSet *icon_set; - - icon_set = gtk_style_context_lookup_icon_set (context, GTK_STOCK_MISSING_IMAGE); - pix = gtk_icon_set_render_icon_pixbuf (icon_set, context, size); - - g_warning ("Unable to fetch icon %s from the icon theme", icon_name); - } - - return pix; -} - static void gtk_spin_button_init (GtkSpinButton *spin_button) { @@ -675,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 @@ -733,6 +725,7 @@ gtk_spin_button_panel_nthchildize_context (GtkSpinButton *spin_button, GtkStyleContext *context, GdkWindow *panel) { + GtkSpinButtonPrivate *priv = spin_button->priv; GtkWidget *widget = GTK_WIDGET (spin_button); GtkWidgetPath *path, *siblings_path; GtkTextDirection direction; @@ -742,22 +735,32 @@ gtk_spin_button_panel_nthchildize_context (GtkSpinButton *spin_button, * have to emulate what gtk_container_get_path_for_child() would do * for the button panels */ - path = gtk_widget_path_copy (gtk_widget_get_path (widget)); - direction = gtk_widget_get_direction (widget); + path = _gtk_widget_create_path (widget); siblings_path = gtk_widget_path_new (); - /* flip children order for RTL */ - if (direction == GTK_TEXT_DIR_RTL) + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) { - 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); + 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 { - 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); + 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); @@ -767,16 +770,10 @@ gtk_spin_button_panel_nthchildize_context (GtkSpinButton *spin_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 == spin_button->priv->down_panel) - { - gtk_widget_path_append_with_siblings (path, siblings_path, up_pos); - gtk_widget_path_append_with_siblings (path, siblings_path, down_pos); - } + 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, down_pos); - gtk_widget_path_append_with_siblings (path, siblings_path, up_pos); - } + gtk_widget_path_append_with_siblings (path, siblings_path, up_pos); gtk_style_context_set_path (context, path); gtk_widget_path_unref (path); @@ -816,20 +813,23 @@ gtk_spin_button_panel_get_state (GtkSpinButton *spin_button, GtkStateFlags state; GtkSpinButtonPrivate *priv = spin_button->priv; - if (gtk_spin_button_panel_at_limit (spin_button, panel)) - state = GTK_STATE_FLAG_INSENSITIVE; + 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_ACTIVE; - else - { - if (priv->in_child == panel && - priv->click_child == NULL) - state = GTK_STATE_FLAG_PRELIGHT; - else - state = gtk_widget_get_state_flags (GTK_WIDGET (spin_button)); - } + state |= GTK_STATE_FLAG_ACTIVE; + else if (priv->in_child == panel && + priv->click_child == NULL) + state |= GTK_STATE_FLAG_PRELIGHT; } return state; @@ -847,13 +847,19 @@ gtk_spin_button_panel_get_context (GtkSpinButton *spin_button, return context; } -static gint -gtk_spin_button_panel_get_width (GtkSpinButton *spin_button, - GdkWindow *panel) +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; + 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); @@ -863,8 +869,13 @@ gtk_spin_button_panel_get_width (GtkSpinButton *spin_button, g_object_unref (context); - return get_icon_size () + button_padding.left + button_padding.right + - button_border.left + button_border.right; + 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 @@ -877,40 +888,58 @@ gtk_spin_button_panel_get_allocations (GtkSpinButton *spin_button, GtkAllocation spin_allocation, down_allocation, up_allocation, allocation; GtkRequisition requisition; gint req_height; - gint up_panel_width, down_panel_width; + gint down_panel_width, down_panel_height; + gint up_panel_width, up_panel_height; GtkStyleContext *context; - GtkBorder space; + 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_NORMAL, &space); + gtk_style_context_get_border (context, GTK_STATE_FLAG_NORMAL, &border); - req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget); - down_panel_width = gtk_spin_button_panel_get_width (spin_button, priv->down_panel); - up_panel_width = gtk_spin_button_panel_get_width (spin_button, priv->up_panel); + 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); - /* both panels have the same size, and they're as big as the entry allocation, - * excluding margins - */ - allocation.height = MIN (req_height, spin_allocation.height) - space.top - space.bottom; - allocation.y = spin_allocation.y + space.top + (spin_allocation.height - req_height) / 2; - down_allocation = up_allocation = allocation; + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) + { + req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget); - down_allocation.width = down_panel_width; - up_allocation.width = up_panel_width; + /* 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; - /* invert x axis allocation for RTL */ - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - { - up_allocation.x = spin_allocation.x + space.left; - down_allocation.x = up_allocation.x + up_panel_width; + 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 { - up_allocation.x = spin_allocation.x + spin_allocation.width - up_panel_width - space.right; - down_allocation.x = up_allocation.x - down_panel_width; + /* 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) @@ -929,7 +958,8 @@ gtk_spin_button_panel_draw (GtkSpinButton *spin_button, GtkStateFlags state; GtkWidget *widget; gdouble width, height, x, y; - GdkPixbuf *pix; + gint icon_width, icon_height; + GtkIconHelper *icon_helper; widget = GTK_WIDGET (spin_button); @@ -943,24 +973,30 @@ gtk_spin_button_panel_draw (GtkSpinButton *spin_button, 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) - pix = create_one_pixbuf (context, "list-remove-symbolic"); + _gtk_icon_helper_set_icon_name (icon_helper, "list-remove-symbolic", GTK_ICON_SIZE_MENU); else - pix = create_one_pixbuf (context, "list-add-symbolic"); + _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 - gdk_pixbuf_get_width (pix)) / 2.0); - y = floor ((height - gdk_pixbuf_get_height (pix)) / 2.0); + x = floor ((width - icon_width) / 2.0); + y = floor ((height - icon_height) / 2.0); - gtk_render_icon (context, cr, pix, - x, y); + _gtk_icon_helper_draw (icon_helper, context, cr, + x, y); cairo_restore (cr); - g_object_unref (pix); + g_object_unref (icon_helper); g_object_unref (context); } @@ -998,7 +1034,7 @@ gtk_spin_button_realize (GtkWidget *widget) priv->down_panel = gdk_window_new (gtk_widget_get_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (priv->down_panel, widget); + gtk_widget_register_window (widget, priv->down_panel); /* create the right panel window */ attributes.x = up_allocation.x; @@ -1008,7 +1044,7 @@ gtk_spin_button_realize (GtkWidget *widget) priv->up_panel = gdk_window_new (gtk_widget_get_window (widget), &attributes, attributes_mask); - gdk_window_set_user_data (priv->up_panel, widget); + gtk_widget_register_window (widget, priv->up_panel); return_val = FALSE; g_signal_emit (spin_button, spinbutton_signals[OUTPUT], 0, &return_val); @@ -1028,40 +1064,64 @@ gtk_spin_button_unrealize (GtkWidget *widget) if (priv->down_panel) { - gdk_window_set_user_data (priv->down_panel, NULL); + 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->up_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 @@ -1073,69 +1133,85 @@ gtk_spin_button_get_preferred_width (GtkWidget *widget, GtkSpinButtonPrivate *priv = spin_button->priv; GtkEntry *entry = GTK_ENTRY (widget); GtkStyleContext *style_context; - gint up_panel_width, down_panel_width; style_context = gtk_widget_get_style_context (widget); - up_panel_width = gtk_spin_button_panel_get_width (spin_button, priv->up_panel); - down_panel_width = gtk_spin_button_panel_get_width (spin_button, priv->down_panel); 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; + GtkBorder borders; + PangoLayout *layout; + gchar *str; gtk_style_context_get_style (style_context, "interior-focus", &interior_focus, "focus-line-width", &focus_width, NULL); - font_desc = gtk_style_context_get_font (style_context, GTK_STATE_FLAG_NORMAL); - - 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); } - *minimum += up_panel_width + down_panel_width; - *natural += up_panel_width + down_panel_width; + 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 += up_panel_width + down_panel_width; + *natural += up_panel_width + down_panel_width; + } +} + +static void +gtk_spin_button_get_preferred_height (GtkWidget *widget, + gint *minimum, + gint *natural) +{ + GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget); + GtkSpinButtonPrivate *priv = spin_button->priv; + + GTK_WIDGET_CLASS (gtk_spin_button_parent_class)->get_preferred_height (widget, minimum, natural); + + if (priv->orientation == GTK_ORIENTATION_VERTICAL) + { + gint down_panel_height; + gint up_panel_height; + + 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); + + *minimum += up_panel_height + down_panel_height; + *natural += up_panel_height + down_panel_height; + } } static void @@ -1348,15 +1424,17 @@ gtk_spin_button_button_press (GtkWidget *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); - if (event->button == 1) - start_spinning (spin, event->window, gtk_adjustment_get_step_increment (priv->adjustment)); - else if (event->button == 2) - start_spinning (spin, event->window, gtk_adjustment_get_page_increment (priv->adjustment)); - else - priv->click_child = event->window; + 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); return TRUE; } @@ -1379,7 +1457,7 @@ gtk_spin_button_button_release (GtkWidget *widget, gtk_spin_button_stop_spinning (spin); - if (event->button == 3) + if (event->button == GDK_BUTTON_SECONDARY) { gdouble diff; @@ -1502,6 +1580,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 @@ -1510,11 +1594,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: @@ -1637,6 +1716,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, @@ -1645,21 +1750,33 @@ gtk_spin_button_get_text_area_size (GtkEntry *entry, gint *height) { GtkSpinButtonPrivate *priv = GTK_SPIN_BUTTON (entry)->priv; - gint up_panel_width, down_panel_width; + gint up_panel_width, up_panel_height; + gint down_panel_width, down_panel_height; - up_panel_width = gtk_spin_button_panel_get_width (GTK_SPIN_BUTTON (entry), priv->up_panel); - down_panel_width = gtk_spin_button_panel_get_width (GTK_SPIN_BUTTON (entry), priv->down_panel); + 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_text_area_size (entry, x, y, width, height); - if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) + if (priv->orientation == GTK_ORIENTATION_HORIZONTAL) { - if (x) - *x += up_panel_width + down_panel_width; + if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) + { + if (x) + *x += up_panel_width + down_panel_width; + } + + if (width) + *width -= up_panel_width + down_panel_width; } + else + { + if (y) + *y += up_panel_height; - if (width) - *width -= up_panel_width + down_panel_width; + if (height) + *height -= up_panel_height + down_panel_height; + } } static void @@ -1836,17 +1953,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; } @@ -2290,7 +2407,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