/* eggtoolbutton.c * * Copyright (C) 2002 Anders Carlsson * Copyright (C) 2002 James Henstridge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 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. */ #include "eggtoolbutton.h" #include #include #include #include #include #include #include #include #include #ifndef _ # define _(s) (s) #endif enum { PROP_0, PROP_LABEL, PROP_USE_UNDERLINE, PROP_STOCK_ID, PROP_ICON_SET, PROP_ICON_WIDGET, }; static void egg_tool_button_init (EggToolButton *button, EggToolButtonClass *klass); static void egg_tool_button_class_init (EggToolButtonClass *klass); static void egg_tool_button_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void egg_tool_button_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void egg_tool_button_finalize (GObject *object); static void egg_tool_button_show_all (GtkWidget *widget); static GtkWidget *egg_tool_button_create_menu_proxy (EggToolItem *item); static void egg_tool_button_set_orientation (EggToolItem *tool_item, GtkOrientation orientation); static void egg_tool_button_set_icon_size (EggToolItem *tool_item, GtkIconSize icon_size); static void egg_tool_button_set_toolbar_style (EggToolItem *tool_item, GtkToolbarStyle style); static void egg_tool_button_set_relief_style (EggToolItem *tool_item, GtkReliefStyle style); static void egg_tool_button_set_tooltip (EggToolItem *tool_item, GtkTooltips *tooltips, const gchar *tip_text, const gchar *tip_private); static void button_clicked (GtkWidget *widget, EggToolButton *button); static GObjectClass *parent_class = NULL; GType egg_tool_button_get_type (void) { static GtkType type = 0; if (!type) { static const GTypeInfo type_info = { sizeof (EggToolButtonClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) egg_tool_button_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (EggToolButton), 0, /* n_preallocs */ (GInstanceInitFunc) egg_tool_button_init, }; type = g_type_register_static (EGG_TYPE_TOOL_ITEM, "EggToolButton", &type_info, 0); } return type; } static void egg_tool_button_class_init (EggToolButtonClass *klass) { GObjectClass *object_class; GtkWidgetClass *widget_class; EggToolItemClass *tool_item_class; parent_class = g_type_class_peek_parent (klass); object_class = (GObjectClass *)klass; widget_class = (GtkWidgetClass *)klass; tool_item_class = (EggToolItemClass *)klass; object_class->set_property = egg_tool_button_set_property; object_class->get_property = egg_tool_button_get_property; object_class->finalize = egg_tool_button_finalize; widget_class->show_all = egg_tool_button_show_all; tool_item_class->create_menu_proxy = egg_tool_button_create_menu_proxy; tool_item_class->set_orientation = egg_tool_button_set_orientation; tool_item_class->set_icon_size = egg_tool_button_set_icon_size; tool_item_class->set_toolbar_style = egg_tool_button_set_toolbar_style; tool_item_class->set_relief_style = egg_tool_button_set_relief_style; tool_item_class->set_tooltip = egg_tool_button_set_tooltip; klass->button_type = GTK_TYPE_BUTTON; g_object_class_install_property (object_class, PROP_LABEL, g_param_spec_string ("label", _("Label"), _("Text to show in the item."), NULL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_USE_UNDERLINE, g_param_spec_boolean ("use_underline", _("Use underline"), _("Interpret underlines in the item label."), FALSE, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_STOCK_ID, g_param_spec_string ("stock_id", _("Stock Id"), _("The stock icon displayed on the item."), NULL, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_ICON_SET, g_param_spec_boxed ("icon_set", _("Icon set"), _("Icon set to use to draw the item's icon."), GTK_TYPE_ICON_SET, G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_ICON_WIDGET, g_param_spec_object ("icon_widget", _("Icon widget"), _("Icon widget to display in the item."), GTK_TYPE_WIDGET, G_PARAM_READWRITE)); } static void egg_tool_button_init (EggToolButton *button, EggToolButtonClass *klass) { EggToolItem *toolitem = EGG_TOOL_ITEM (button); toolitem->homogeneous = TRUE; /* create button */ button->button = g_object_new (klass->button_type, NULL); #if 0 /* FIXME: enable this when we can depend on gtk+ 2.3.0 */ gtk_button_set_focus_on_click (button->button, FALSE); #endif g_signal_connect_object (button->button, "clicked", G_CALLBACK (button_clicked), button, 0); button->box = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (button->button), button->box); gtk_widget_show (button->box); #if 0 button->icon = gtk_image_new(); gtk_box_pack_start (GTK_BOX (button->box), button->icon, TRUE, TRUE, 0); gtk_widget_show (button->icon); #endif button->label = gtk_label_new (NULL); gtk_label_set_use_underline (GTK_LABEL (button->label), TRUE); gtk_box_pack_start (GTK_BOX (button->box), button->label, FALSE, TRUE, 0); gtk_widget_show (button->label); gtk_container_add (GTK_CONTAINER (button), button->button); gtk_widget_show (button->button); } static gchar * elide_underscores (const gchar *original) { gchar *q, *result; const gchar *p; gboolean last_underscore; q = result = g_malloc (strlen (original) + 1); last_underscore = FALSE; for (p = original; *p; p++) { if (!last_underscore && *p == '_') last_underscore = TRUE; else { last_underscore = FALSE; *q++ = *p; } } *q = '\0'; return result; } static void egg_tool_button_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { EggToolButton *button = EGG_TOOL_BUTTON (object); GtkStockItem stock_item; GtkIconSet *icon_set; gchar *label_no_mnemonic = NULL; switch (prop_id) { case PROP_LABEL: egg_tool_button_set_label (button, g_value_get_string (value)); break; case PROP_USE_UNDERLINE: gtk_label_set_use_underline (GTK_LABEL (button->label), g_value_get_boolean (value)); break; case PROP_STOCK_ID: g_free (button->stock_id); button->stock_id = g_value_dup_string (value); if (!button->label_set) { if (gtk_stock_lookup (button->stock_id, &stock_item)) { label_no_mnemonic = elide_underscores (stock_item.label); gtk_label_set_label (GTK_LABEL (button->label), label_no_mnemonic); g_free (label_no_mnemonic); } } if (!button->icon_set) { if (button->icon && !GTK_IS_IMAGE (button->icon)) { gtk_container_remove (GTK_CONTAINER (button->box), button->icon); button->icon = NULL; } if (!button->icon) { button->icon = gtk_image_new (); gtk_box_pack_start (GTK_BOX (button->box), button->icon, TRUE, TRUE, 0); gtk_box_reorder_child (GTK_BOX (button->box), button->icon, 0); } gtk_image_set_from_stock (GTK_IMAGE (button->icon), button->stock_id, EGG_TOOL_ITEM (button)->icon_size); if (EGG_TOOL_ITEM (button)->style != GTK_TOOLBAR_TEXT) gtk_widget_show (button->icon); } break; case PROP_ICON_SET: if (button->icon && !GTK_IS_IMAGE (button->icon)) { gtk_container_remove (GTK_CONTAINER (button->box), button->icon); button->icon = NULL; } if (!button->icon) { button->icon = gtk_image_new (); gtk_box_pack_start (GTK_BOX (button->box), button->icon, TRUE, TRUE, 0); gtk_box_reorder_child (GTK_BOX (button->box), button->icon, 0); } icon_set = g_value_get_boxed (value); button->icon_set = (icon_set != NULL); if (!button->icon_set && button->stock_id) gtk_image_set_from_stock (GTK_IMAGE (button->icon), button->stock_id, EGG_TOOL_ITEM (button)->icon_size); else gtk_image_set_from_icon_set (GTK_IMAGE (button->icon), icon_set, EGG_TOOL_ITEM (button)->icon_size); break; case PROP_ICON_WIDGET: egg_tool_button_set_icon_widget (button, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void egg_tool_button_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { EggToolButton *button = EGG_TOOL_BUTTON (object); switch (prop_id) { case PROP_LABEL: if (button->label_set) g_value_set_string (value, gtk_label_get_label (GTK_LABEL (button->label))); break; case PROP_USE_UNDERLINE: g_value_set_boolean (value, gtk_label_get_use_underline (GTK_LABEL (button->label))); break; case PROP_STOCK_ID: g_value_set_string (value, button->stock_id); break; case PROP_ICON_SET: if (GTK_IS_IMAGE (button->icon) && GTK_IMAGE (button->icon)->storage_type == GTK_IMAGE_ICON_SET) { GtkIconSet *icon_set; gtk_image_get_icon_set (GTK_IMAGE (button->icon), &icon_set, NULL); g_value_set_boxed (value, icon_set); } else g_value_set_boxed (value, NULL); break; case PROP_ICON_WIDGET: g_value_set_object (value, button->icon); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void egg_tool_button_finalize (GObject *object) { EggToolButton *button = EGG_TOOL_BUTTON (object); g_free (button->stock_id); button->stock_id = NULL; parent_class->finalize (object); } static void egg_tool_button_show_all (GtkWidget *widget) { EggToolButton *button = EGG_TOOL_BUTTON (widget); switch (EGG_TOOL_ITEM (widget)->style) { case GTK_TOOLBAR_ICONS: if (button->icon) gtk_widget_show_all (button->icon); gtk_widget_hide (button->label); gtk_widget_show (button->box); gtk_widget_show (button->button); break; case GTK_TOOLBAR_TEXT: if (button->icon) gtk_widget_hide (button->icon); gtk_widget_show_all (button->label); gtk_widget_show (button->box); gtk_widget_show (button->button); break; case GTK_TOOLBAR_BOTH: case GTK_TOOLBAR_BOTH_HORIZ: gtk_widget_show_all (button->button); } gtk_widget_show (GTK_WIDGET (button)); } static GtkWidget * egg_tool_button_create_menu_proxy (EggToolItem *item) { EggToolButton *button = EGG_TOOL_BUTTON (item); GtkWidget *menu_item; GtkWidget *image; const char *label; label = gtk_label_get_text (GTK_LABEL (button->label)); menu_item = gtk_image_menu_item_new_with_label (label); if (GTK_IS_IMAGE (button->icon)) { image = gtk_image_new (); if (GTK_IMAGE (button->icon)->storage_type == GTK_IMAGE_STOCK) { gchar *stock_id; gtk_image_get_stock (GTK_IMAGE (button->icon), &stock_id, NULL); gtk_image_set_from_stock (GTK_IMAGE (image), stock_id, GTK_ICON_SIZE_MENU); } else if (GTK_IMAGE (button->icon)->storage_type == GTK_IMAGE_ICON_SET) { GtkIconSet *icon_set; gtk_image_get_icon_set (GTK_IMAGE (button->icon), &icon_set, NULL); gtk_image_set_from_icon_set (GTK_IMAGE (image), icon_set, GTK_ICON_SIZE_MENU); } else { g_warning ("FIXME: Add more cases here"); } gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image); } g_signal_connect_object (menu_item, "activate", G_CALLBACK (gtk_button_clicked), EGG_TOOL_BUTTON (button)->button, G_CONNECT_SWAPPED); return menu_item; } static void egg_tool_button_set_orientation (EggToolItem *tool_item, GtkOrientation orientation) { if (tool_item->orientation != orientation) { tool_item->orientation = orientation; } } static void egg_tool_button_set_icon_size (EggToolItem *tool_item, GtkIconSize icon_size) { if (tool_item->icon_size != icon_size) { EggToolButton *button = EGG_TOOL_BUTTON (tool_item); char *stock_id; if (button->icon && GTK_IS_IMAGE (button->icon) && gtk_image_get_storage_type (GTK_IMAGE (button->icon)) == GTK_IMAGE_STOCK) { gtk_image_get_stock (GTK_IMAGE (button->icon), &stock_id, NULL); stock_id = g_strdup (stock_id); gtk_image_set_from_stock (GTK_IMAGE (button->icon), stock_id, icon_size); g_free (stock_id); } tool_item->icon_size = icon_size; } } static void egg_tool_button_set_toolbar_style (EggToolItem *tool_item, GtkToolbarStyle style) { EggToolButton *button = EGG_TOOL_BUTTON (tool_item); if (tool_item->style != style) { tool_item->style = style; switch (tool_item->style) { case GTK_TOOLBAR_ICONS: gtk_widget_hide (button->label); if (button->icon) { gtk_box_set_child_packing (GTK_BOX (button->box), button->icon, TRUE, TRUE, 0, GTK_PACK_START); gtk_widget_show (button->icon); } break; case GTK_TOOLBAR_TEXT: gtk_box_set_child_packing (GTK_BOX (button->box), button->label, TRUE, TRUE, 0, GTK_PACK_START); gtk_widget_show (button->label); if (button->icon) gtk_widget_hide (button->icon); break; case GTK_TOOLBAR_BOTH: if (GTK_IS_HBOX (button->box)) { GtkWidget *vbox; vbox = gtk_vbox_new (FALSE, 0); gtk_widget_show (vbox); if (button->icon) { g_object_ref (button->icon); gtk_container_remove (GTK_CONTAINER (button->box), button->icon); gtk_box_pack_start (GTK_BOX (vbox), button->icon, TRUE, TRUE, 0); g_object_unref (button->icon); } g_object_ref (button->label); gtk_container_remove (GTK_CONTAINER (button->box), button->label); gtk_box_pack_start (GTK_BOX (vbox), button->label, FALSE, TRUE, 0); g_object_unref (button->label); gtk_container_remove (GTK_CONTAINER (button->button), button->box); button->box = vbox; gtk_container_add (GTK_CONTAINER (button->button), button->box); } gtk_box_set_child_packing (GTK_BOX (button->box), button->label, FALSE, TRUE, 0, GTK_PACK_START); gtk_widget_show (button->label); if (button->icon) { gtk_box_set_child_packing (GTK_BOX (button->box), button->icon, TRUE, TRUE, 0, GTK_PACK_START); gtk_widget_show (button->icon); } break; case GTK_TOOLBAR_BOTH_HORIZ: if (GTK_IS_VBOX (button->box)) { GtkWidget *hbox; hbox = gtk_hbox_new (FALSE, 0); gtk_widget_show (hbox); if (button->icon) { g_object_ref (button->icon); gtk_container_remove (GTK_CONTAINER (button->box), button->icon); gtk_box_pack_start (GTK_BOX (hbox), button->icon, TRUE, TRUE, 0); g_object_unref (button->icon); } g_object_ref (button->label); gtk_container_remove (GTK_CONTAINER (button->box), button->label); gtk_box_pack_start (GTK_BOX (hbox), button->label, FALSE, TRUE, 0); g_object_unref (button->label); gtk_container_remove (GTK_CONTAINER (button->button), button->box); button->box = hbox; gtk_container_add (GTK_CONTAINER (button->button), button->box); } gtk_box_set_child_packing (GTK_BOX (button->box), button->label, TRUE, TRUE, 0, GTK_PACK_START); gtk_widget_show (button->label); if (button->icon) { gtk_box_set_child_packing (GTK_BOX (button->box), button->icon, FALSE, TRUE, 0, GTK_PACK_START); gtk_widget_show (button->icon); } break; } } } static void egg_tool_button_set_relief_style (EggToolItem *tool_item, GtkReliefStyle style) { gtk_button_set_relief (GTK_BUTTON (EGG_TOOL_BUTTON (tool_item)->button), style); } static void egg_tool_button_set_tooltip (EggToolItem *tool_item, GtkTooltips *tooltips, const gchar *tip_text, const gchar *tip_private) { gtk_tooltips_set_tip (tooltips, EGG_TOOL_BUTTON (tool_item)->button, tip_text, tip_private); } static void button_clicked (GtkWidget *widget, EggToolButton *button) { g_signal_emit_by_name (button, "clicked"); } EggToolItem * egg_tool_button_new_from_stock (const gchar *stock_id) { EggToolButton *button; g_return_val_if_fail (stock_id != NULL, NULL); button = g_object_new (EGG_TYPE_TOOL_BUTTON, "stock_id", stock_id, "use_underline", TRUE, NULL); return EGG_TOOL_ITEM (button); } EggToolItem * egg_tool_button_new (void) { EggToolButton *button; button = g_object_new (EGG_TYPE_TOOL_BUTTON, NULL); return EGG_TOOL_ITEM (button); } void egg_tool_button_set_icon_widget (EggToolButton *button, GtkWidget *icon) { g_return_if_fail (EGG_IS_TOOL_BUTTON (button)); g_return_if_fail (GTK_IS_WIDGET (icon)); if (button->icon) gtk_container_remove (GTK_CONTAINER (button->box), button->icon); button->icon = NULL; button->icon_set = (icon != NULL); if (icon) { button->icon = icon; gtk_box_pack_start (GTK_BOX (button->box), button->icon, TRUE, TRUE, 0); gtk_box_reorder_child (GTK_BOX (button->box), button->icon, 0); } else if (button->stock_id) { button->icon = gtk_image_new_from_stock (button->stock_id, EGG_TOOL_ITEM (button)->icon_size); gtk_box_pack_start (GTK_BOX (button->box), button->icon, TRUE, TRUE, 0); } } void egg_tool_button_set_label (EggToolButton *button, const gchar *label) { gchar *label_no_mnemonic = NULL; GtkStockItem stock_item; g_return_if_fail (EGG_IS_TOOL_BUTTON (button)); g_return_if_fail (label != NULL); button->label_set = (label != NULL); if (label) label_no_mnemonic = elide_underscores (label); else if (button->stock_id && gtk_stock_lookup (button->stock_id, &stock_item)) label_no_mnemonic = elide_underscores (stock_item.label); gtk_label_set_label (GTK_LABEL (button->label), label_no_mnemonic); g_free (label_no_mnemonic); }