diff options
Diffstat (limited to 'tools/glade/glade/gbwidgets/gbmenubar.c')
-rw-r--r-- | tools/glade/glade/gbwidgets/gbmenubar.c | 552 |
1 files changed, 552 insertions, 0 deletions
diff --git a/tools/glade/glade/gbwidgets/gbmenubar.c b/tools/glade/glade/gbwidgets/gbmenubar.c new file mode 100644 index 00000000..c756094d --- /dev/null +++ b/tools/glade/glade/gbwidgets/gbmenubar.c @@ -0,0 +1,552 @@ + +/* Gtk+ User Interface Builder + * Copyright (C) 1998 Damon Chaplin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <gtk/gtkbutton.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenubar.h> +#include <gtk/gtkimagemenuitem.h> +#include <gtk/gtkstock.h> +#include "../gb.h" +#include "../glade_gnome.h" +#include "../glade_menu_editor.h" + +/* Include the 21x21 icon pixmap for this widget, to be used in the palette */ +#include "../graphics/menubar.xpm" + +/* + * This is the GbWidget struct for this widget (see ../gbwidget.h). + * It is initialized in the init() function at the end of this file + */ +static GbWidget gbwidget; + +static gchar *PackDirection = "GtkMenuBar::pack_direction"; +static gchar *ChildPackDirection = "GtkMenuBar::child_pack_direction"; + + +static const gchar *GbPackDirectionChoices[] = +{ + "Left to Right", + "Right to Left", + "Top to Bottom", + "Bottom to Top", + NULL +}; +static const gint GbPackDirectionValues[] = +{ + GTK_PACK_DIRECTION_LTR, + GTK_PACK_DIRECTION_RTL, + GTK_PACK_DIRECTION_TTB, + GTK_PACK_DIRECTION_BTT +}; +static const gchar *GbPackDirectionSymbols[] = +{ + "GTK_PACK_DIRECTION_LTR", + "GTK_PACK_DIRECTION_RTL", + "GTK_PACK_DIRECTION_TTB", + "GTK_PACK_DIRECTION_BTT" +}; + +static void on_menu_bar_size_request (GtkWidget * widget, + GtkRequisition *requisition, + gpointer data); +static void gb_menu_bar_on_edit_menu (GtkWidget *button, + gpointer data); +static void gb_menu_bar_on_edit_menu_activate (GtkWidget *menuitem, + GtkWidget *menubar); + + + +/****** + * NOTE: To use these functions you need to uncomment them AND add a pointer + * to the function in the GbWidget struct at the end of this file. + ******/ + + +static GtkWidget* +gb_menu_bar_add_menu (GtkWidget *menu, const gchar *label) +{ + GtkWidget *menuitem, *child_menu; + + menuitem = gb_widget_new ("GtkMenuItem", NULL); + gtk_label_set_text_with_mnemonic (GTK_LABEL (GTK_BIN (menuitem)->child), + label); + gtk_widget_show (menuitem); + gtk_container_add (GTK_CONTAINER (menu), menuitem); + + child_menu = gb_widget_new ("GtkMenu", NULL); + gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem), child_menu); + + return child_menu; +} + + +/* This returns the name to use given the widget's label. Spaces are converted + to underscores, and '.' and '_' chars are ignore, e.g. '_Open...' -> 'Open'. + The returned string should be freed. */ +static char* +gb_menu_bar_generate_item_name (const gchar *label) +{ + char *name, *dest; + const char *src; + + /* We never add characters, so name is never longer than label. I think this + is OK for UTF-8. */ + name = g_malloc (strlen (label) + 1); + for (src = label, dest = name; *src; src++) + { + if (*src == ' ') + *dest++ = '_'; + else if (*src == '.') + continue; + else if (*src == '_') + continue; + else + *dest++ = *src; + } + *dest = '\0'; + + return name; +} + + +/* This adds an "activate" signal handler to the menuitem. */ +static void +gb_menu_bar_add_item_handler (GtkWidget *menuitem) +{ + GladeWidgetData *wdata; + GladeSignal *signal; + const char *name; + + wdata = (GladeWidgetData*) gtk_object_get_data (GTK_OBJECT(menuitem), + GB_WIDGET_DATA_KEY); + if (wdata == NULL) + { + g_warning ("Widget has no GladeWidgetData attached"); + return; + } + + + name = gtk_widget_get_name (menuitem); + + signal = g_new (GladeSignal, 1); + signal->name = g_strdup ("activate"); + signal->handler = g_strdup_printf ("on_%s_activate", name); + signal->object = NULL; + signal->after = FALSE; + signal->data = NULL; + signal->last_modification_time = time (NULL); + wdata->signals = g_list_append (wdata->signals, signal); +} + +static void +gb_menu_bar_add_stock_item (GtkWidget *menu, const gchar *stock_id) +{ + GtkWidget *menuitem; + char *label_text, *name; + + menuitem = gtk_image_menu_item_new_from_stock (stock_id, NULL); + label_text = glade_util_get_label_text (GTK_BIN (menuitem)->child); + name = gb_menu_bar_generate_item_name (label_text); + gb_widget_create_from (menuitem, name); + g_free (name); + g_free (label_text); + gtk_widget_show (menuitem); + gtk_container_add (GTK_CONTAINER (menu), menuitem); + + /* For stock items we also have to store the stock_id. */ + gtk_object_set_data_full (GTK_OBJECT (menuitem), GladeMenuItemStockIDKey, + g_strdup (stock_id), g_free); + + gb_menu_bar_add_item_handler (menuitem); +} + + +static void +gb_menu_bar_add_item (GtkWidget *menu, const gchar *label) +{ + GtkWidget *menuitem; + char *name; + + menuitem = gtk_menu_item_new_with_mnemonic (label); + name = gb_menu_bar_generate_item_name (label); + gb_widget_create_from (menuitem, name); + g_free (name); + gtk_widget_show (menuitem); + gtk_container_add (GTK_CONTAINER (menu), menuitem); + + gb_menu_bar_add_item_handler (menuitem); +} + + +static void +gb_menu_bar_add_separator (GtkWidget *menu) +{ + GtkWidget *menuitem; + + menuitem = gb_widget_new ("GtkSeparatorMenuItem", NULL); + gtk_widget_show (menuitem); + gtk_container_add (GTK_CONTAINER (menu), menuitem); +} + + +static void +gb_menu_bar_setup_initial_menus (GtkWidget *widget) +{ + GtkWidget *menu; + + /* FIXME: I'm not sure if we should translate the non-stock labels or not. */ + menu = gb_menu_bar_add_menu (widget, _("_File")); + gb_menu_bar_add_stock_item (menu, GTK_STOCK_NEW); + gb_menu_bar_add_stock_item (menu, GTK_STOCK_OPEN); + gb_menu_bar_add_stock_item (menu, GTK_STOCK_SAVE); + gb_menu_bar_add_stock_item (menu, GTK_STOCK_SAVE_AS); + gb_menu_bar_add_separator (menu); + gb_menu_bar_add_stock_item (menu, GTK_STOCK_QUIT); + + menu = gb_menu_bar_add_menu (widget, _("_Edit")); + gb_menu_bar_add_stock_item (menu, GTK_STOCK_CUT); + gb_menu_bar_add_stock_item (menu, GTK_STOCK_COPY); + gb_menu_bar_add_stock_item (menu, GTK_STOCK_PASTE); + gb_menu_bar_add_stock_item (menu, GTK_STOCK_DELETE); + + menu = gb_menu_bar_add_menu (widget, _("_View")); + + menu = gb_menu_bar_add_menu (widget, _("_Help")); + gb_menu_bar_add_item (menu, _("_About")); +} + + +/* + * Creates a new GtkWidget of class GtkMenuBar, performing any specialized + * initialization needed for the widget to work correctly in this environment. + * If a dialog box is used to initialize the widget, return NULL from this + * function, and call data->callback with your new widget when it is done. + * If the widget needs a special destroy handler, add a signal here. + */ +GtkWidget* +gb_menu_bar_new(GbWidgetNewData *data) +{ + GtkWidget *new_widget; + + new_widget = gtk_menu_bar_new (); + + gtk_signal_connect_after (GTK_OBJECT (new_widget), "size_request", + GTK_SIGNAL_FUNC (on_menu_bar_size_request), + NULL); + + if (data->action == GB_CREATING) + { +#ifdef USE_GNOME + if (glade_project_get_gnome_support (data->project)) + glade_gnome_setup_initial_menus (new_widget); + else + gb_menu_bar_setup_initial_menus (new_widget); +#else + gb_menu_bar_setup_initial_menus (new_widget); +#endif + } + + return new_widget; +} + + +static void +on_menu_bar_size_request (GtkWidget * widget, + GtkRequisition *requisition, + gpointer data) +{ + /* Make sure we request a decent size. If we don't do this, when a menubar + is created it appears about 3 pixels high which is not very good. */ + requisition->width = MAX (requisition->width, 32); + requisition->height = MAX (requisition->height, 24); +} + + +/* + * Creates the components needed to edit the extra properties of this widget. + */ +static void +gb_menu_bar_create_properties(GtkWidget *widget, GbWidgetCreateArgData *data) +{ + GtkWidget *property_table, *button; + gint property_table_row; + + property_add_choice (PackDirection, _("Pack Direction:"), + _("The pack direction of the menubar"), + GbPackDirectionChoices); + property_add_choice (ChildPackDirection, _("Child Direction:"), + _("The child pack direction of the menubar"), + GbPackDirectionChoices); + + /* Add a button for editing the menubar. */ + property_table = property_get_table_position (&property_table_row); + button = gtk_button_new_with_label (_("Edit Menus...")); + gtk_widget_show (button); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gb_menu_bar_on_edit_menu), NULL); + gtk_table_attach (GTK_TABLE (property_table), button, 0, 3, + property_table_row, property_table_row + 1, + GTK_FILL, GTK_FILL, 10, 10); +} + + +/* Make window behave like a dialog */ +static void +dialogize (GtkWidget *menued, GtkWidget *parent_widget) +{ + GtkWidget *transient_parent; + + gtk_signal_connect (GTK_OBJECT (menued), "key_press_event", + GTK_SIGNAL_FUNC (glade_util_check_key_is_esc), + GINT_TO_POINTER (GladeEscDestroys)); + transient_parent = glade_util_get_toplevel (parent_widget); + if (GTK_IS_WINDOW (transient_parent)) + { + gtk_window_set_transient_for (GTK_WINDOW (menued), + GTK_WINDOW (transient_parent)); + } +} + +static void +gb_menu_bar_on_edit_menu (GtkWidget *button, + gpointer data) +{ + GtkWidget *menubar, *menued; + + menubar = property_get_widget (); + g_return_if_fail (GTK_IS_MENU_BAR (menubar)); + + menued = glade_menu_editor_new (current_project, GTK_MENU_SHELL (menubar)); + dialogize (menued, button); + gtk_widget_show (GTK_WIDGET (menued)); +} + + +/* + * Gets the properties of the widget. This is used for both displaying the + * properties in the property editor, and also for saving the properties. + */ +static void +gb_menu_bar_get_properties(GtkWidget *widget, GbWidgetGetArgData *data) +{ + GtkPackDirection pack_direction, child_pack_direction; + gint i; + + pack_direction = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget)); + child_pack_direction = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget)); + + for (i = 0; i < sizeof (GbPackDirectionValues) / sizeof (GbPackDirectionValues[0]); i++) + { + if (GbPackDirectionValues[i] == pack_direction) + gb_widget_output_choice (data, PackDirection, i, GbPackDirectionSymbols[i]); + + if (GbPackDirectionValues[i] == child_pack_direction) + gb_widget_output_choice (data, ChildPackDirection, i, GbPackDirectionSymbols[i]); + } +} + + +/* + * Sets the properties of the widget. This is used for both applying the + * properties changed in the property editor, and also for loading. + */ +static void +gb_menu_bar_set_properties(GtkWidget *widget, GbWidgetSetArgData *data) +{ + gchar *pack_direction, *child_pack_direction; + gint i; + + pack_direction = gb_widget_input_choice (data, PackDirection); + if (data->apply) + { + for (i = 0; i < sizeof (GbPackDirectionValues) / sizeof (GbPackDirectionValues[0]); i++) + { + if (!strcmp (pack_direction, GbPackDirectionChoices[i]) + || !strcmp (pack_direction, GbPackDirectionSymbols[i])) + { + gtk_menu_bar_set_pack_direction (GTK_MENU_BAR (widget), + GbPackDirectionValues[i]); + break; + } + } + } + + child_pack_direction = gb_widget_input_choice (data, ChildPackDirection); + if (data->apply) + { + for (i = 0; i < sizeof (GbPackDirectionValues) / sizeof (GbPackDirectionValues[0]); i++) + { + if (!strcmp (child_pack_direction, GbPackDirectionChoices[i]) + || !strcmp (child_pack_direction, GbPackDirectionSymbols[i])) + { + gtk_menu_bar_set_child_pack_direction (GTK_MENU_BAR (widget), + GbPackDirectionValues[i]); + break; + } + } + } +} + + +/* + * Adds menu items to a context menu which is just about to appear! + * Add commands to aid in editing a GtkMenuBar, with signals pointing to + * other functions in this file. + */ +static void +gb_menu_bar_create_popup_menu(GtkWidget *widget, GbWidgetCreateMenuData *data) +{ + GtkWidget *menuitem; + + menuitem = gtk_menu_item_new_with_label (_("Edit Menus...")); + gtk_widget_show (menuitem); + gtk_container_add (GTK_CONTAINER (data->menu), menuitem); + gtk_signal_connect (GTK_OBJECT (menuitem), "activate", + GTK_SIGNAL_FUNC (gb_menu_bar_on_edit_menu_activate), + widget); +} + + +static void +gb_menu_bar_on_edit_menu_activate (GtkWidget *menuitem, + GtkWidget *menubar) +{ + GtkWidget *menued; + + menued = glade_menu_editor_new (current_project, GTK_MENU_SHELL (menubar)); + dialogize (menued, menubar); + gtk_widget_show (GTK_WIDGET (menued)); +} + + +/* + * Writes the source code needed to create this widget. + * You have to output everything necessary to create the widget here, though + * there are some convenience functions to help. + */ +static void +gb_menu_bar_write_source (GtkWidget * widget, GbWidgetWriteSourceData * data) +{ + gboolean created_menu = FALSE; + GtkPackDirection pack_direction, child_pack_direction; + gint i; + + pack_direction = gtk_menu_bar_get_pack_direction (GTK_MENU_BAR (widget)); + child_pack_direction = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (widget)); + +#ifdef USE_GNOME + /* For Gnome projects the menus are created using GnomeUIInfo structs, so + we just create the start of the struct here. In a GnomeApp dock item, + the code to add the menu to the GnomeApp is in output in gnomedockitem.c. + If the menubar is not in a GnomeApp, we have to output the code to create + it here. */ + if (data->project->gnome_support) + { + glade_gnome_start_menu_source (GTK_MENU_SHELL (widget), data); + + if (widget->parent && glade_gnome_is_app_dock_item (widget->parent)) + { + /* FIXME: should we set some standard properties? */ + gb_widget_write_add_child_source (widget, data); + return; + } + else + { + if (data->create_widget) + { + source_add (data, " %s = gtk_menu_bar_new ();\n", data->wname); + } + + gb_widget_write_standard_source (widget, data); + + data->need_accel_group = TRUE; + source_add (data, + " gnome_app_fill_menu (GTK_MENU_SHELL (%s), %s_uiinfo,\n" + " accel_group, FALSE, 0);\n", + data->wname, data->real_wname); + created_menu = TRUE; + } + } +#endif + + if (!created_menu) + { + if (data->create_widget) + { + source_add (data, " %s = gtk_menu_bar_new ();\n", data->wname); + } + + gb_widget_write_standard_source (widget, data); + } + + if (pack_direction != GTK_PACK_DIRECTION_LTR) + { + for (i = 0; i < sizeof (GbPackDirectionValues) / sizeof (GbPackDirectionValues[0]); i++) + { + if (GbPackDirectionValues[i] == pack_direction) + source_add (data, + " gtk_menu_bar_set_pack_direction (GTK_MENU_BAR (%s), %s);\n", + data->wname, GbPackDirectionSymbols[i]); + } + } + + if (child_pack_direction != GTK_PACK_DIRECTION_LTR) + { + for (i = 0; i < sizeof (GbPackDirectionValues) / sizeof (GbPackDirectionValues[0]); i++) + { + if (GbPackDirectionValues[i] == child_pack_direction) + source_add (data, + " gtk_menu_bar_set_child_pack_direction (GTK_MENU_BAR (%s), %s);\n", + data->wname, GbPackDirectionSymbols[i]); + } + } +} + + + +/* + * Initializes the GbWidget structure. + * I've placed this at the end of the file so we don't have to include + * declarations of all the functions. + */ +GbWidget * +gb_menu_bar_init () +{ + /* Initialise the GTK type */ + volatile GtkType type; + type = gtk_menu_bar_get_type (); + + /* Initialize the GbWidget structure */ + gb_widget_init_struct (&gbwidget); + + /* Fill in the pixmap struct & tooltip */ + gbwidget.pixmap_struct = menubar_xpm; + gbwidget.tooltip = _("Menu Bar"); + + /* Fill in any functions that this GbWidget has */ + gbwidget.gb_widget_new = gb_menu_bar_new; + gbwidget.gb_widget_create_properties = gb_menu_bar_create_properties; + gbwidget.gb_widget_get_properties = gb_menu_bar_get_properties; + gbwidget.gb_widget_set_properties = gb_menu_bar_set_properties; + gbwidget.gb_widget_create_popup_menu = gb_menu_bar_create_popup_menu; + gbwidget.gb_widget_write_source = gb_menu_bar_write_source; + + return &gbwidget; +} |