3 * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se>
4 * Copyright (C) 2002 James Henstridge <james@daa.com.au>
5 * Copyright (C) 2003 Soeren Sandmann <sandmann@daimi.au.dk>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include "gtktoolbutton.h"
24 #include "gtkbutton.h"
26 #include "gtkiconfactory.h"
28 #include "gtkimagemenuitem.h"
33 #include "gtktoolbar.h"
34 #include "gtkiconfactory.h"
38 #define MENU_ID "gtk-tool-button-menu-id"
54 static void gtk_tool_button_init (GtkToolButton *button,
55 GtkToolButtonClass *klass);
56 static void gtk_tool_button_class_init (GtkToolButtonClass *klass);
57 static void gtk_tool_button_set_property (GObject *object,
61 static void gtk_tool_button_get_property (GObject *object,
65 static void gtk_tool_button_finalize (GObject *object);
67 static void gtk_tool_button_toolbar_reconfigured (GtkToolItem *tool_item);
68 static gboolean gtk_tool_button_create_menu_proxy (GtkToolItem *item);
69 static void button_clicked (GtkWidget *widget,
70 GtkToolButton *button);
72 static void gtk_tool_button_construct_contents (GtkToolItem *tool_item);
74 static GObjectClass *parent_class = NULL;
75 static guint toolbutton_signals[LAST_SIGNAL] = { 0 };
77 struct _GtkToolButtonPrivate
83 GtkWidget *label_widget;
84 GtkWidget *icon_widget;
86 guint use_underline : 1;
90 gtk_tool_button_get_type (void)
92 static GtkType type = 0;
96 static const GTypeInfo type_info =
98 sizeof (GtkToolButtonClass),
100 (GBaseFinalizeFunc) NULL,
101 (GClassInitFunc) gtk_tool_button_class_init,
102 (GClassFinalizeFunc) NULL,
104 sizeof (GtkToolButton),
106 (GInstanceInitFunc) gtk_tool_button_init,
109 type = g_type_register_static (GTK_TYPE_TOOL_ITEM,
117 gtk_tool_button_class_init (GtkToolButtonClass *klass)
119 GObjectClass *object_class;
120 GtkWidgetClass *widget_class;
121 GtkToolItemClass *tool_item_class;
123 parent_class = g_type_class_peek_parent (klass);
125 object_class = (GObjectClass *)klass;
126 widget_class = (GtkWidgetClass *)klass;
127 tool_item_class = (GtkToolItemClass *)klass;
129 object_class->set_property = gtk_tool_button_set_property;
130 object_class->get_property = gtk_tool_button_get_property;
131 object_class->finalize = gtk_tool_button_finalize;
133 tool_item_class->create_menu_proxy = gtk_tool_button_create_menu_proxy;
134 tool_item_class->toolbar_reconfigured = gtk_tool_button_toolbar_reconfigured;
136 klass->button_type = GTK_TYPE_BUTTON;
138 /* Properties are interpreted like this:
140 * - if the tool button has an icon_widget, then that widget
141 * will be used as the icon. Otherwise, if the tool button
142 * has a stock id, the corresponding stock icon will be
143 * used. Otherwise, the tool button will not have an icon.
145 * - if the tool button has a label_widget then that widget
146 * will be used as the label. Otherwise, if the tool button
147 * has a label text, that text will be used as label. Otherwise,
148 * if the toolbutton has a stock id, the corresponding text
149 * will be used as label. Otherwise, the toolbutton will
150 * have an empty label.
152 * - The use_underline property only has an effect when the label
153 * on the toolbutton comes from the label property (ie. not from
154 * label_widget or from stock_id).
156 * In that case, if use_underline is set,
158 * - underscores are removed from the label text before
159 * the label is shown on the toolbutton unless the
160 * underscore is followed by another underscore
162 * - an underscore indicates that the next character when
163 * used in the overflow menu should be used as a mnemonic.
165 * In short: use_underline = TRUE means that the label text has
166 * the form "_Open" and the toolbar should take appropriate action.
169 g_object_class_install_property (object_class,
171 g_param_spec_string ("label",
173 _("Text to show in the item."),
176 g_object_class_install_property (object_class,
178 g_param_spec_boolean ("use_underline",
180 _("If set, an underline in the label property indicates that the next character should be used for the mnemonic accelerator key in the overflow menu"),
183 g_object_class_install_property (object_class,
185 g_param_spec_object ("label_widget",
187 _("Widget to use as the item label"),
190 g_object_class_install_property (object_class,
192 g_param_spec_string ("stock_id",
194 _("The stock icon displayed on the item"),
197 g_object_class_install_property (object_class,
199 g_param_spec_object ("icon_widget",
201 _("Icon widget to display in the item"),
205 toolbutton_signals[CLICKED] =
206 g_signal_new ("clicked",
207 G_OBJECT_CLASS_TYPE (klass),
209 G_STRUCT_OFFSET (GtkToolButtonClass, clicked),
211 g_cclosure_marshal_VOID__VOID,
214 g_type_class_add_private (object_class, sizeof (GtkToolButtonPrivate));
218 gtk_tool_button_init (GtkToolButton *button,
219 GtkToolButtonClass *klass)
221 GtkToolItem *toolitem = GTK_TOOL_ITEM (button);
223 button->priv = GTK_TOOL_BUTTON_GET_PRIVATE (button);
225 gtk_tool_item_set_homogeneous (toolitem, TRUE);
228 button->priv->button = g_object_new (klass->button_type, NULL);
229 gtk_button_set_focus_on_click (GTK_BUTTON (button->priv->button), FALSE);
230 g_signal_connect_object (button->priv->button, "clicked",
231 G_CALLBACK (button_clicked), button, 0);
233 gtk_container_add (GTK_CONTAINER (button), button->priv->button);
234 gtk_widget_show (button->priv->button);
238 gtk_tool_button_construct_contents (GtkToolItem *tool_item)
240 GtkToolButton *button = GTK_TOOL_BUTTON (tool_item);
241 GtkWidget *label = NULL;
242 GtkWidget *icon = NULL;
243 GtkToolbarStyle style;
244 gboolean need_label = FALSE;
245 gboolean need_icon = FALSE;
246 GtkIconSize icon_size;
247 GtkWidget *box = NULL;
249 if (gtk_tool_item_get_proxy_menu_item (tool_item, MENU_ID))
251 /* Remove item, so it will be recreated on the next
252 * create_proxy_menu_item()
254 gtk_tool_item_set_proxy_menu_item (tool_item, MENU_ID, NULL);
257 if (button->priv->icon_widget && button->priv->icon_widget->parent)
259 gtk_container_remove (GTK_CONTAINER (button->priv->icon_widget->parent),
260 button->priv->icon_widget);
263 if (button->priv->label_widget && button->priv->label_widget->parent)
265 gtk_container_remove (GTK_CONTAINER (button->priv->label_widget->parent),
266 button->priv->label_widget);
269 if (GTK_BIN (button->priv->button)->child)
271 /* Note: we are not destroying the label_widget or icon_widget
272 * here because they were removed from their containers above
274 gtk_widget_destroy (GTK_BIN (button->priv->button)->child);
277 style = gtk_tool_item_get_toolbar_style (GTK_TOOL_ITEM (button));
279 if (style != GTK_TOOLBAR_TEXT)
282 if (style != GTK_TOOLBAR_ICONS)
287 if (button->priv->label_widget)
289 label = button->priv->label_widget;
293 GtkStockItem stock_item;
297 if (button->priv->label_text)
299 label_text = button->priv->label_text;
300 elide = button->priv->use_underline;
302 else if (button->priv->stock_id && gtk_stock_lookup (button->priv->stock_id, &stock_item))
304 label_text = stock_item.label;
314 label_text = _gtk_toolbar_elide_underscores (label_text);
316 label_text = g_strdup (label_text);
318 label = gtk_label_new (label_text);
322 gtk_widget_show (label);
326 icon_size = gtk_tool_item_get_icon_size (GTK_TOOL_ITEM (button));
329 if (button->priv->icon_widget)
331 icon = button->priv->icon_widget;
333 if (GTK_IS_IMAGE (icon))
335 g_object_set (G_OBJECT (button->priv->icon_widget),
336 "icon-size", icon_size,
340 else if (button->priv->stock_id)
342 icon = gtk_image_new_from_stock (button->priv->stock_id, icon_size);
343 gtk_widget_show (icon);
349 case GTK_TOOLBAR_ICONS:
351 gtk_container_add (GTK_CONTAINER (button->priv->button), icon);
354 case GTK_TOOLBAR_BOTH:
355 box = gtk_vbox_new (FALSE, 0);
357 gtk_box_pack_start (GTK_BOX (box), icon, TRUE, TRUE, 0);
358 gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
359 gtk_container_add (GTK_CONTAINER (button->priv->button), box);
362 case GTK_TOOLBAR_BOTH_HORIZ:
363 box = gtk_hbox_new (FALSE, 0);
364 gtk_box_pack_start (GTK_BOX (box), icon, FALSE, TRUE, 0);
365 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
366 gtk_container_add (GTK_CONTAINER (button->priv->button), box);
369 case GTK_TOOLBAR_TEXT:
370 gtk_container_add (GTK_CONTAINER (button->priv->button), label);
375 gtk_widget_show (box);
377 gtk_button_set_relief (GTK_BUTTON (button->priv->button),
378 gtk_tool_item_get_relief_style (GTK_TOOL_ITEM (button)));
380 gtk_widget_queue_resize (GTK_WIDGET (button));
384 gtk_tool_button_set_property (GObject *object,
389 GtkToolButton *button = GTK_TOOL_BUTTON (object);
394 gtk_tool_button_set_label (button, g_value_get_string (value));
396 case PROP_USE_UNDERLINE:
397 gtk_tool_button_set_use_underline (button, g_value_get_boolean (value));
399 case PROP_LABEL_WIDGET:
400 gtk_tool_button_set_label_widget (button, g_value_get_object (value));
403 gtk_tool_button_set_stock_id (button, g_value_get_string (value));
405 case PROP_ICON_WIDGET:
406 gtk_tool_button_set_icon_widget (button, g_value_get_object (value));
409 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
414 gtk_tool_button_get_property (GObject *object,
419 GtkToolButton *button = GTK_TOOL_BUTTON (object);
424 g_value_set_string (value, gtk_tool_button_get_label (button));
426 case PROP_LABEL_WIDGET:
427 g_value_set_object (value, gtk_tool_button_get_label_widget (button));
429 case PROP_USE_UNDERLINE:
430 g_value_set_boolean (value, gtk_tool_button_get_use_underline (button));
433 g_value_set_string (value, button->priv->stock_id);
435 case PROP_ICON_WIDGET:
436 g_value_set_object (value, button->priv->icon_widget);
439 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
444 gtk_tool_button_finalize (GObject *object)
446 GtkToolButton *button = GTK_TOOL_BUTTON (object);
448 if (button->priv->stock_id)
449 g_free (button->priv->stock_id);
451 if (button->priv->label_text)
452 g_free (button->priv->label_text);
454 if (button->priv->label_widget)
455 g_object_unref (G_OBJECT (button->priv->label_widget));
457 if (button->priv->icon_widget)
458 g_object_unref (G_OBJECT (button->priv->icon_widget));
460 parent_class->finalize (object);
464 clone_image_menu_size (GtkImage *image, GtkSettings *settings)
466 GtkImageType storage_type = gtk_image_get_storage_type (image);
468 if (storage_type == GTK_IMAGE_STOCK)
471 gtk_image_get_stock (image, &stock_id, NULL);
472 return gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
474 else if (storage_type == GTK_IMAGE_ICON_SET)
476 GtkIconSet *icon_set;
477 gtk_image_get_icon_set (image, &icon_set, NULL);
478 return gtk_image_new_from_icon_set (icon_set, GTK_ICON_SIZE_MENU);
480 else if (storage_type == GTK_IMAGE_PIXBUF)
485 gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
488 GdkPixbuf *src_pixbuf, *dest_pixbuf;
490 src_pixbuf = gtk_image_get_pixbuf (image);
491 dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
492 GDK_INTERP_BILINEAR);
494 return gtk_image_new_from_pixbuf (dest_pixbuf);
502 gtk_tool_button_create_menu_proxy (GtkToolItem *item)
504 GtkToolButton *button = GTK_TOOL_BUTTON (item);
505 GtkWidget *menu_item;
506 GtkWidget *menu_image = NULL;
507 GtkStockItem stock_item;
508 gboolean use_mnemonic = TRUE;
511 if (button->priv->label_widget && GTK_IS_LABEL (button->priv->label_widget))
513 label = gtk_label_get_label (GTK_LABEL (button->priv->label_widget));
514 use_mnemonic = gtk_label_get_use_underline (GTK_LABEL (button->priv->label_widget));
516 else if (button->priv->label_text)
518 label = button->priv->label_text;
519 use_mnemonic = button->priv->use_underline;
521 else if (button->priv->stock_id && gtk_stock_lookup (button->priv->stock_id, &stock_item))
523 label = stock_item.label;
524 use_mnemonic = FALSE;
529 use_mnemonic = FALSE;
533 menu_item = gtk_image_menu_item_new_with_mnemonic (label);
535 menu_item = gtk_image_menu_item_new_with_label (label);
537 if (button->priv->icon_widget && GTK_IS_IMAGE (button->priv->icon_widget))
539 menu_image = clone_image_menu_size (GTK_IMAGE (button->priv->icon_widget),
540 gtk_widget_get_settings (GTK_WIDGET (button)));
542 else if (button->priv->stock_id)
544 menu_image = gtk_image_new_from_stock (button->priv->stock_id, GTK_ICON_SIZE_MENU);
548 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image);
550 g_signal_connect_closure_by_id (menu_item,
551 g_signal_lookup ("activate", G_OBJECT_TYPE (menu_item)), 0,
552 g_cclosure_new_object_swap (G_CALLBACK (gtk_button_clicked),
553 G_OBJECT (GTK_TOOL_BUTTON (button)->priv->button)),
556 gtk_tool_item_set_proxy_menu_item (GTK_TOOL_ITEM (button), MENU_ID, menu_item);
562 button_clicked (GtkWidget *widget,
563 GtkToolButton *button)
565 g_signal_emit_by_name (button, "clicked");
569 gtk_tool_button_toolbar_reconfigured (GtkToolItem *tool_item)
571 gtk_tool_button_construct_contents (tool_item);
575 gtk_tool_button_new_from_stock (const gchar *stock_id)
577 GtkToolButton *button;
579 g_return_val_if_fail (stock_id != NULL, NULL);
581 button = g_object_new (GTK_TYPE_TOOL_BUTTON,
582 "stock_id", stock_id,
585 return GTK_TOOL_ITEM (button);
589 gtk_tool_button_new (const gchar *label,
590 GtkWidget *icon_widget)
592 GtkToolButton *button;
594 button = g_object_new (GTK_TYPE_TOOL_BUTTON,
598 gtk_tool_button_set_label (button, label);
601 gtk_tool_button_set_icon_widget (button, icon_widget);
603 return GTK_TOOL_ITEM (button);
607 gtk_tool_button_set_label (GtkToolButton *button,
612 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
614 old_label = button->priv->label_text;
616 button->priv->label_text = g_strdup (label);
617 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
619 g_object_notify (G_OBJECT (button), "label");
625 G_CONST_RETURN gchar *
626 gtk_tool_button_get_label (GtkToolButton *button)
628 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
630 return button->priv->label_text;
634 gtk_tool_button_set_use_underline (GtkToolButton *button,
635 gboolean use_underline)
637 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
639 use_underline = use_underline != FALSE;
641 if (use_underline != button->priv->use_underline)
643 button->priv->use_underline = use_underline;
645 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
647 g_object_notify (G_OBJECT (button), "use_underline");
652 gtk_tool_button_get_use_underline (GtkToolButton *button)
654 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), FALSE);
656 return button->priv->use_underline;
660 gtk_tool_button_set_stock_id (GtkToolButton *button,
661 const gchar *stock_id)
665 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
667 old_stock_id = button->priv->stock_id;
669 button->priv->stock_id = g_strdup (stock_id);
670 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
672 g_object_notify (G_OBJECT (button), "stock_id");
674 g_free (old_stock_id);
677 G_CONST_RETURN gchar *
678 gtk_tool_button_get_stock_id (GtkToolButton *button)
680 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
682 return button->priv->stock_id;
686 gtk_tool_button_set_icon_widget (GtkToolButton *button,
689 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
690 g_return_if_fail (icon == NULL || GTK_IS_WIDGET (icon));
692 if (icon != button->priv->icon_widget)
694 if (button->priv->icon_widget)
695 g_object_unref (G_OBJECT (button->priv->icon_widget));
700 gtk_object_sink (GTK_OBJECT (icon));
703 button->priv->icon_widget = icon;
705 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
707 g_object_notify (G_OBJECT (button), "icon_widget");
712 gtk_tool_button_set_label_widget (GtkToolButton *button,
713 GtkWidget *label_widget)
715 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
716 g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
718 if (label_widget != button->priv->label_widget)
720 if (button->priv->label_widget)
721 g_object_unref (button->priv->label_widget);
725 g_object_ref (label_widget);
726 gtk_object_sink (GTK_OBJECT (label_widget));
729 button->priv->label_widget = label_widget;
731 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
733 g_object_notify (G_OBJECT (button), "label_widget");
738 gtk_tool_button_get_label_widget (GtkToolButton *button)
740 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
742 return button->priv->label_widget;
746 gtk_tool_button_get_icon_widget (GtkToolButton *button)
748 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
750 return button->priv->icon_widget;
754 _gtk_tool_button_get_button (GtkToolButton *button)
756 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
758 return button->priv->button;