GTK+ / Gnome Application Development | |||
---|---|---|---|
<<< Previous | Home | Next >>> |
It's tedious to create large menus, especially if they have features such as icons and keyboard accelerators. Gnome provides a simple solution. You assemble a GnomeUIInfo struct as a template for each menu item, simply listing its characteristics: name, icon, accelerator, and so on. The Gnome libraries can automatically create menus from arrays of GnomeUIInfo templates. The same method works with toolbars.
Here's the declaration of struct GnomeUIInfo.
typedef struct { GnomeUIInfoType type; gchar* label; gchar* hint; gpointer moreinfo; gpointer user_data; gpointer unused_data; GnomeUIPixmapType pixmap_type; gpointer pixmap_info; guint accelerator_key; GdkModifierType ac_mods; GtkWidget* widget; } GnomeUIInfo; |
A static initializer is the most convenient way to fill in the struct (but of course you can create it dynamically if you prefer). Gnome's routines accept an array of GnomeUIInfo, and macros are provided to simplify and standardize the most common static initializers. Here's a typical example, a File menu:
static GnomeUIInfo file_menu[] = { GNOMEUIINFO_MENU_NEW_ITEM(N_("_New Window"), N_("Create a new text viewer window"), new_app_cb, NULL), GNOMEUIINFO_MENU_OPEN_ITEM(open_cb,NULL), GNOMEUIINFO_MENU_SAVE_AS_ITEM(save_as_cb,NULL), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_MENU_CLOSE_ITEM(close_cb,NULL), GNOMEUIINFO_MENU_EXIT_ITEM(exit_cb,NULL), GNOMEUIINFO_END }; |
There isn't always a nice macro for the menu item you want, so sometimes you must manually specify each element of the struct:
{ GNOME_APP_UI_ITEM, N_("_Select All"), N_("Select all cells in the spreadsheet"), select_all_cb, NULL, NULL, 0, 0, 'a', GDK_CONTROL_MASK } |
By now you're probably wondering what the struct members mean. Simple enough. Here's a breakdown:
type is a type marker from the GnomeUIInfoType enumeration. See Table 1.
label is the text of the menu or toolbar button. It should be marked for internationalization with the N_() macro.
hint is a long description of the item's function. For toolbar buttons, it will appear in a tooltip; for menus, it can be made to appear in the statusbar.
moreinfo depends on the type of the item. See Table 1.
user_data will be passed to your callback function, if this item type has a callback.
unused_data should be set to NULL, and is not used yet. It may be used in future versions of Gnome.
pixmap_type is a value from the GnomeUIPixmapType enumeration; its purpose is to specify the type of the next member, pixmap_info.
pixmap_info can be raw pixmap data, a filename, or the name of a Gnome stock pixmap.
accelerator_key is the key to be used as an accelerator for this item . You can use a character such as 'a', or a value from gdk/gdkkeysyms.h.
ac_mods is a modifier mask to be used with the accelerator.
widget should be NULL; Gnome fills it in when it creates the menu item or toolbar button. You can then retrieve it, if you need to manipulate the widget in some way.
You might also be wondering why the menu item names contain an underscore. The underscore is used to mark the key shortcut for the menu item; translators can move it around as needed to make it intuitive in their language. Gnome will parse the menu item name to obtain the accelerator, then remove the underscore.
Table 1 summarizes the possible values for the type field of a GnomeUIInfo struct. See libgnomeui/gnome-app-helper.h for more details. There are actually a few more possible values, but the others are used internally by the library. The values in Table 1 should be sufficient for application code.
Table 1. GnomeUIInfoType Values
GnomeUIInfoType | Description | moreinfo Field |
---|---|---|
GNOME_APP_UI_ENDOFINFO | Terminates a table of GnomeUIInfo | None |
GNOME_APP_UI_ITEM | Normal item (or radio item inside radio group) | Callback function |
GNOME_APP_UI_TOGGLEITEM | Toggle/check item | Callback function |
GNOME_APP_UI_RADIOITEMS | Radio item group | Array of radio items in the group |
GNOME_APP_UI_SUBTREE | Submenu | Array of GnomeUIInfo in the subtree |
GNOME_APP_UI_SEPARATOR | Separator | None |
GNOME_APP_UI_HELP | Help item | Help node to load |
To create an entire menu tree, you include pointers to previous menu tables using the GNOMEUIINFO_SUBTREE() macro:
static GnomeUIInfo main_menu[] = { GNOMEUIINFO_SUBTREE(N_("_File"), file_menu), GNOMEUIINFO_END }; |
In this particular case, there is a better macro to use, however:
static GnomeUIInfo main_menu[] = { GNOMEUIINFO_MENU_FILE_TREE(file_menu), GNOMEUIINFO_END }; |
The main advantage of this macro is standardization; it ensures that all Gnome file menus use the same key shortcut and have the same name. There are quite a few analagous macros; see libgnomeui/gnome-app-helper.h for the complete list.
Once you have a menu table, Gnome will process it and convert it to a widget. The functions are listed in Figure 4
#include <libgnomeui/gnome-app-helper.h> |
void
gnome_app_create_menus
(GnomeApp* app, GnomeUIInfo* uiinfo);
void
gnome_app_create_menus_with_data
(GnomeApp*
app, GnomeUIInfo*
uiinfo, gpointer
user_data);
void
gnome_app_create_toolbar
(GnomeApp* app, GnomeUIInfo* uiinfo);
void
gnome_app_create_toolbar_with_data
(GnomeApp*
app, GnomeUIInfo*
uiinfo, gpointer
user_data);
void
gnome_app_fill_toolbar
(GtkToolbar* toolbar, GnomeUIInfo*
uiinfo,
GtkAccelGroup*
accel_group);
void
gnome_app_fill_toolbar_with_data
(GtkToolbar*
toolbar,
GnomeUIInfo*
uiinfo, GtkAccelGroup* accel_group, gpointer data);
void
gnome_app_fill_menu
(GtkMenuShell* menushell, GnomeUIInfo*
uiinfo,
GtkAccelGroup*
accel_group, gboolean
uline_accels, gint
pos);
void
gnome_app_fill_menu_with_data
(GtkMenuShell*
menushell,
GnomeUIInfo*
uiinfo, GtkAccelGroup* accel_group, gboolean uline_accels, gint pos, gpointer user_data);
Figure 4. Creating Widgets from GnomeUIInfo
If you are using the GnomeApp widget, gnome_app_create_menus() and gnome_app_create_toolbar() create a menubar or toolbar from the GnomeUIInfo table you provide, then attach that to the GnomeApp. Most of the time these are the functions you want to use; they do everything automatically. There is a _with_data() variant of each function which overrides the user_data field of GnomeUIInfo.
If you have more specialized needs, you can manually fill a menubar or toolbar and then add it to the container of your choice. The fill functions require you to specify an accelerator group to add accelerators to; for GnomeApp, an accelerator group already exists in the widget struct (the accel_group member). The fill functions for menus take two additional arguments: you can toggle whether to parse the underscores in menu item labels to extract accelerators, and you can specify at which position in the GtkMenuShell the function will begin inserting menu items.
(GtkMenuShell is simply the base class for GtkMenuBar and GtkMenu, i.e. it is a widget that contains menu items. An accelerator group is just a collection of accelerators, normally attached to a GtkWindow; use GNOME_APP(widget)->accel_group in this case.)
When you use a GnomeUIInfo table to create a menubar or toolbar, pointers to the individual menu item or toolbar button widgets are placed in the widget member of each GnomeUIInfo struct. You can use these pointers to access the individual widgets; for example, if you create a check menu item you might want to set the state of the check. The pointer is also useful if you want to manually create some part of the menu; you can create an empty subtree item, for example, and manually build the contents of the subtree.
The GnomeHello application has menus and a toolbar created using the GnomeUIInfo method; the relevant code is in a separate file, menus.c. Appendix E lists this file in its entirety.