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_size_request (GtkWidget *widget,
58 GtkRequisition *requisition);
59 static void gtk_tool_button_size_allocate (GtkWidget *widget,
60 GtkAllocation *allocation);
61 static void gtk_tool_button_set_property (GObject *object,
65 static void gtk_tool_button_get_property (GObject *object,
69 static void gtk_tool_button_finalize (GObject *object);
71 static void gtk_tool_button_toolbar_reconfigured (GtkToolItem *tool_item);
72 static gboolean gtk_tool_button_create_menu_proxy (GtkToolItem *item);
73 static void button_clicked (GtkWidget *widget,
74 GtkToolButton *button);
76 static void gtk_tool_button_construct_contents (GtkToolItem *tool_item);
78 static GObjectClass *parent_class = NULL;
79 static guint toolbutton_signals[LAST_SIGNAL] = { 0 };
82 gtk_tool_button_get_type (void)
84 static GtkType type = 0;
88 static const GTypeInfo type_info =
90 sizeof (GtkToolButtonClass),
92 (GBaseFinalizeFunc) NULL,
93 (GClassInitFunc) gtk_tool_button_class_init,
94 (GClassFinalizeFunc) NULL,
96 sizeof (GtkToolButton),
98 (GInstanceInitFunc) gtk_tool_button_init,
101 type = g_type_register_static (GTK_TYPE_TOOL_ITEM,
109 gtk_tool_button_class_init (GtkToolButtonClass *klass)
111 GObjectClass *object_class;
112 GtkWidgetClass *widget_class;
113 GtkToolItemClass *tool_item_class;
115 parent_class = g_type_class_peek_parent (klass);
117 object_class = (GObjectClass *)klass;
118 widget_class = (GtkWidgetClass *)klass;
119 tool_item_class = (GtkToolItemClass *)klass;
121 object_class->set_property = gtk_tool_button_set_property;
122 object_class->get_property = gtk_tool_button_get_property;
123 object_class->finalize = gtk_tool_button_finalize;
125 widget_class->size_request = gtk_tool_button_size_request;
126 widget_class->size_allocate = gtk_tool_button_size_allocate;
128 tool_item_class->create_menu_proxy = gtk_tool_button_create_menu_proxy;
129 tool_item_class->toolbar_reconfigured = gtk_tool_button_toolbar_reconfigured;
131 klass->button_type = GTK_TYPE_BUTTON;
133 /* Properties are interpreted like this:
135 * - if the tool button has an icon_widget, then that widget
136 * will be used as the icon. Otherwise, if the tool button
137 * has a stock id, the corresponding stock icon will be
138 * used. Otherwise, the tool button will not have an icon.
140 * - if the tool button has a label_widget then that widget
141 * will be used as the label. Otherwise, if the tool button
142 * has a label text, that text will be used as label. Otherwise,
143 * if the toolbutton has a stock id, the corresponding text
144 * will be used as label. Otherwise, the toolbutton will
145 * have an empty label.
147 * - The use_underline property only has an effect when the label
148 * on the toolbutton comes from the label property (ie. not from
149 * label_widget or from stock_id).
151 * In that case, if use_underline is set,
153 * - underscores are removed from the label text before
154 * the label is shown on the toolbutton unless the
155 * underscore is followed by another underscore
157 * - an underscore indicates that the next character when
158 * used in the overflow menu should be used as a mnemonic.
160 * In short: use_underline = TRUE means that the label text has
161 * the form "_Open" and the toolbar should take appropriate action.
164 g_object_class_install_property (object_class,
166 g_param_spec_string ("label",
168 _("Text to show in the item."),
171 g_object_class_install_property (object_class,
173 g_param_spec_boolean ("use_underline",
175 _("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"),
178 g_object_class_install_property (object_class,
180 g_param_spec_object ("label_widget",
182 _("Widget to use as the item label"),
185 g_object_class_install_property (object_class,
187 g_param_spec_string ("stock_id",
189 _("The stock icon displayed on the item"),
192 g_object_class_install_property (object_class,
194 g_param_spec_object ("icon_widget",
196 _("Icon widget to display in the item"),
200 toolbutton_signals[CLICKED] =
201 g_signal_new ("clicked",
202 G_OBJECT_CLASS_TYPE (klass),
204 G_STRUCT_OFFSET (GtkToolButtonClass, clicked),
206 g_cclosure_marshal_VOID__VOID,
211 gtk_tool_button_init (GtkToolButton *button,
212 GtkToolButtonClass *klass)
214 GtkToolItem *toolitem = GTK_TOOL_ITEM (button);
216 toolitem->homogeneous = TRUE;
219 button->button = g_object_new (klass->button_type, NULL);
220 gtk_button_set_focus_on_click (GTK_BUTTON (button->button), FALSE);
221 g_signal_connect_object (button->button, "clicked",
222 G_CALLBACK (button_clicked), button, 0);
224 gtk_container_add (GTK_CONTAINER (button), button->button);
225 gtk_widget_show (button->button);
229 gtk_tool_button_size_request (GtkWidget *widget,
230 GtkRequisition *requisition)
232 GtkWidget *child = GTK_BIN (widget)->child;
234 if (child && GTK_WIDGET_VISIBLE (child))
236 gtk_widget_size_request (child, requisition);
240 requisition->width = 0;
241 requisition->height = 0;
244 requisition->width += GTK_CONTAINER (widget)->border_width * 2;
245 requisition->height += GTK_CONTAINER (widget)->border_width * 2;
249 gtk_tool_button_size_allocate (GtkWidget *widget,
250 GtkAllocation *allocation)
252 GtkToolItem *toolitem = GTK_TOOL_ITEM (widget);
253 GtkAllocation child_allocation;
255 GtkWidget *child = GTK_BIN (widget)->child;
257 widget->allocation = *allocation;
258 border_width = GTK_CONTAINER (widget)->border_width;
260 if (toolitem->drag_window && GTK_WIDGET_REALIZED (widget))
261 gdk_window_move_resize (toolitem->drag_window,
262 widget->allocation.x + border_width,
263 widget->allocation.y + border_width,
264 widget->allocation.width - border_width * 2,
265 widget->allocation.height - border_width * 2);
267 if (child && GTK_WIDGET_VISIBLE (child))
269 child_allocation.x = allocation->x + border_width;
270 child_allocation.y = allocation->y + border_width;
271 child_allocation.width = allocation->width - 2 * border_width;
272 child_allocation.height = allocation->height - 2 * border_width;
274 gtk_widget_size_allocate (child, &child_allocation);
279 gtk_tool_button_construct_contents (GtkToolItem *tool_item)
281 GtkToolButton *button = GTK_TOOL_BUTTON (tool_item);
282 GtkWidget *label = NULL;
283 GtkWidget *icon = NULL;
284 GtkToolbarStyle style;
285 gboolean need_label = FALSE;
286 gboolean need_icon = FALSE;
287 GtkIconSize icon_size;
288 GtkWidget *box = NULL;
290 if (gtk_tool_item_get_proxy_menu_item (tool_item, MENU_ID))
292 /* Remove item, so it will be recreated on the next
293 * create_proxy_menu_item()
295 gtk_tool_item_set_proxy_menu_item (tool_item, MENU_ID, NULL);
298 if (button->icon_widget && button->icon_widget->parent)
300 gtk_container_remove (GTK_CONTAINER (button->icon_widget->parent),
301 button->icon_widget);
304 if (button->label_widget && button->label_widget->parent)
306 gtk_container_remove (GTK_CONTAINER (button->label_widget->parent),
307 button->label_widget);
310 if (GTK_BIN (button->button)->child)
312 /* Note: we are not destroying the label_widget or icon_widget
313 * here because they were removed from their containers above
315 gtk_widget_destroy (GTK_BIN (button->button)->child);
318 style = gtk_tool_item_get_toolbar_style (GTK_TOOL_ITEM (button));
320 if (style != GTK_TOOLBAR_TEXT)
323 if (style != GTK_TOOLBAR_ICONS)
328 if (button->label_widget)
330 label = button->label_widget;
334 GtkStockItem stock_item;
338 if (button->label_text)
340 label_text = button->label_text;
341 elide = button->use_underline;
343 else if (button->stock_id && gtk_stock_lookup (button->stock_id, &stock_item))
345 label_text = stock_item.label;
355 label_text = _gtk_toolbar_elide_underscores (label_text);
357 label_text = g_strdup (label_text);
359 label = gtk_label_new (label_text);
363 gtk_widget_show (label);
367 icon_size = gtk_tool_item_get_icon_size (GTK_TOOL_ITEM (button));
370 if (button->icon_widget)
372 icon = button->icon_widget;
374 if (GTK_IS_IMAGE (icon))
376 g_object_set (G_OBJECT (button->icon_widget),
377 "icon-size", icon_size,
381 else if (button->stock_id)
383 icon = gtk_image_new_from_stock (button->stock_id, icon_size);
384 gtk_widget_show (icon);
390 case GTK_TOOLBAR_ICONS:
392 gtk_container_add (GTK_CONTAINER (button->button), icon);
395 case GTK_TOOLBAR_BOTH:
396 box = gtk_vbox_new (FALSE, 0);
397 gtk_box_pack_start (GTK_BOX (box), icon, TRUE, TRUE, 0);
398 gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
399 gtk_container_add (GTK_CONTAINER (button->button), box);
402 case GTK_TOOLBAR_BOTH_HORIZ:
403 box = gtk_hbox_new (FALSE, 0);
404 gtk_box_pack_start (GTK_BOX (box), icon, FALSE, TRUE, 0);
405 gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
406 gtk_container_add (GTK_CONTAINER (button->button), box);
409 case GTK_TOOLBAR_TEXT:
410 gtk_container_add (GTK_CONTAINER (button->button), label);
415 gtk_widget_show (box);
417 gtk_button_set_relief (GTK_BUTTON (button->button),
418 gtk_tool_item_get_relief_style (GTK_TOOL_ITEM (button)));
420 gtk_widget_queue_resize (GTK_WIDGET (button));
424 gtk_tool_button_set_property (GObject *object,
429 GtkToolButton *button = GTK_TOOL_BUTTON (object);
434 gtk_tool_button_set_label (button, g_value_get_string (value));
436 case PROP_USE_UNDERLINE:
437 gtk_tool_button_set_use_underline (button, g_value_get_boolean (value));
439 case PROP_LABEL_WIDGET:
440 gtk_tool_button_set_label_widget (button, g_value_get_object (value));
443 gtk_tool_button_set_stock_id (button, g_value_get_string (value));
445 case PROP_ICON_WIDGET:
446 gtk_tool_button_set_icon_widget (button, g_value_get_object (value));
449 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
454 gtk_tool_button_get_property (GObject *object,
459 GtkToolButton *button = GTK_TOOL_BUTTON (object);
464 g_value_set_string (value, gtk_tool_button_get_label (button));
466 case PROP_LABEL_WIDGET:
467 g_value_set_object (value, gtk_tool_button_get_label_widget (button));
469 case PROP_USE_UNDERLINE:
470 g_value_set_boolean (value, gtk_tool_button_get_use_underline (button));
473 g_value_set_string (value, button->stock_id);
475 case PROP_ICON_WIDGET:
476 g_value_set_object (value, button->icon_widget);
479 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
484 gtk_tool_button_finalize (GObject *object)
486 GtkToolButton *button = GTK_TOOL_BUTTON (object);
488 g_free (button->stock_id);
489 button->stock_id = NULL;
491 parent_class->finalize (object);
495 clone_image_menu_size (GtkImage *image, GtkSettings *settings)
497 GtkImageType storage_type = gtk_image_get_storage_type (image);
499 if (storage_type == GTK_IMAGE_STOCK)
502 gtk_image_get_stock (image, &stock_id, NULL);
503 return gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
505 else if (storage_type == GTK_IMAGE_ICON_SET)
507 GtkIconSet *icon_set;
508 gtk_image_get_icon_set (image, &icon_set, NULL);
509 return gtk_image_new_from_icon_set (icon_set, GTK_ICON_SIZE_MENU);
511 else if (storage_type == GTK_IMAGE_PIXBUF)
516 gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
519 GdkPixbuf *src_pixbuf, *dest_pixbuf;
521 src_pixbuf = gtk_image_get_pixbuf (image);
522 dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
523 GDK_INTERP_BILINEAR);
525 return gtk_image_new_from_pixbuf (dest_pixbuf);
533 gtk_tool_button_create_menu_proxy (GtkToolItem *item)
535 GtkToolButton *button = GTK_TOOL_BUTTON (item);
536 GtkWidget *menu_item;
537 GtkWidget *menu_image = NULL;
538 GtkStockItem stock_item;
539 gboolean use_mnemonic = TRUE;
542 if (button->label_widget && GTK_IS_LABEL (button->label_widget))
544 label = gtk_label_get_label (GTK_LABEL (button->label_widget));
545 use_mnemonic = gtk_label_get_use_underline (GTK_LABEL (button->label_widget));
547 else if (button->label_text)
549 label = button->label_text;
550 use_mnemonic = button->use_underline;
552 else if (button->stock_id && gtk_stock_lookup (button->stock_id, &stock_item))
554 label = stock_item.label;
555 use_mnemonic = FALSE;
560 use_mnemonic = FALSE;
564 menu_item = gtk_image_menu_item_new_with_mnemonic (label);
566 menu_item = gtk_image_menu_item_new_with_label (label);
568 if (button->icon_widget && GTK_IS_IMAGE (button->icon_widget))
570 menu_image = clone_image_menu_size (GTK_IMAGE (button->icon_widget),
571 gtk_widget_get_settings (GTK_WIDGET (button)));
573 else if (button->stock_id)
575 menu_image = gtk_image_new_from_stock (button->stock_id, GTK_ICON_SIZE_MENU);
579 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), menu_image);
581 g_signal_connect_closure_by_id (menu_item,
582 g_signal_lookup ("activate", G_OBJECT_TYPE (menu_item)), 0,
583 g_cclosure_new_object_swap (G_CALLBACK (gtk_button_clicked),
584 G_OBJECT (GTK_TOOL_BUTTON (button)->button)),
587 gtk_tool_item_set_proxy_menu_item (GTK_TOOL_ITEM (button), MENU_ID, menu_item);
593 button_clicked (GtkWidget *widget,
594 GtkToolButton *button)
596 g_signal_emit_by_name (button, "clicked");
600 gtk_tool_button_toolbar_reconfigured (GtkToolItem *tool_item)
602 gtk_tool_button_construct_contents (tool_item);
606 gtk_tool_button_new_from_stock (const gchar *stock_id)
608 GtkToolButton *button;
610 g_return_val_if_fail (stock_id != NULL, NULL);
612 button = g_object_new (GTK_TYPE_TOOL_BUTTON,
613 "stock_id", stock_id,
616 return GTK_TOOL_ITEM (button);
620 gtk_tool_button_new (const gchar *label,
621 GtkWidget *icon_widget)
623 GtkToolButton *button;
625 button = g_object_new (GTK_TYPE_TOOL_BUTTON,
629 gtk_tool_button_set_label (button, label);
632 gtk_tool_button_set_icon_widget (button, icon_widget);
634 return GTK_TOOL_ITEM (button);
638 gtk_tool_button_set_label (GtkToolButton *button,
643 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
645 old_label = button->label_text;
647 button->label_text = g_strdup (label);
648 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
650 g_object_notify (G_OBJECT (button), "label");
656 G_CONST_RETURN gchar *
657 gtk_tool_button_get_label (GtkToolButton *button)
659 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
661 return button->label_text;
665 gtk_tool_button_set_use_underline (GtkToolButton *button,
666 gboolean use_underline)
668 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
670 use_underline = use_underline != FALSE;
672 if (use_underline != button->use_underline)
674 button->use_underline = use_underline;
676 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
678 g_object_notify (G_OBJECT (button), "use_underline");
683 gtk_tool_button_get_use_underline (GtkToolButton *button)
685 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), FALSE);
687 return button->use_underline;
691 gtk_tool_button_set_stock_id (GtkToolButton *button,
692 const gchar *stock_id)
696 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
698 old_stock_id = button->stock_id;
700 button->stock_id = g_strdup (stock_id);
701 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
703 g_object_notify (G_OBJECT (button), "stock_id");
705 g_free (old_stock_id);
708 G_CONST_RETURN gchar *
709 gtk_tool_button_get_stock_id (GtkToolButton *button)
711 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
713 return button->stock_id;
717 gtk_tool_button_set_icon_widget (GtkToolButton *button,
720 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
721 g_return_if_fail (icon == NULL || GTK_IS_WIDGET (icon));
723 if (icon != button->icon_widget)
725 if (button->icon_widget)
726 g_object_unref (G_OBJECT (button->icon_widget));
731 gtk_object_sink (GTK_OBJECT (icon));
734 button->icon_widget = icon;
736 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
738 g_object_notify (G_OBJECT (button), "icon_widget");
743 gtk_tool_button_set_label_widget (GtkToolButton *button,
744 GtkWidget *label_widget)
746 g_return_if_fail (GTK_IS_TOOL_BUTTON (button));
747 g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
749 if (label_widget != button->label_widget)
751 if (button->label_widget)
752 g_object_unref (button->label_widget);
756 g_object_ref (label_widget);
757 gtk_object_sink (GTK_OBJECT (label_widget));
760 button->label_widget = label_widget;
762 gtk_tool_button_construct_contents (GTK_TOOL_ITEM (button));
764 g_object_notify (G_OBJECT (button), "label_widget");
769 gtk_tool_button_get_label_widget (GtkToolButton *button)
771 g_return_val_if_fail (GTK_IS_TOOL_BUTTON (button), NULL);
773 return button->label_widget;
777 gtk_tool_button_get_icon_widget (GtkToolButton *button)
779 g_return_val_if_fail (GTK_IS_BUTTON (button), NULL);
781 return button->icon_widget;