Legacy Maemo 5 Documentation/Graphical UI Tutorial/Menus

Revision as of 11:01, 13 July 2009



The use of menus in Hildon applications follows a very different approach from the traditional application menus.

Hildon applications have no menu bar. Each window has an attached menu which activates when the user presses the window title area. Also, unlike typical menus in desktop applications, view menus do not follow a hierarchical structure. This menu, attached to a view, is called Touch View Menu.

Additionally Hildon provides Context menus, although those should be avoided when possible.

Touch view menu

The widget which should be used as a menu in the windows of a Hildon application is HildonAppmenu.

This widget opens at the top of the screen, obscuring the topmost window, and contains several entries organized in one or two columns, depending on screen orientation. Besides entries, application menus can also contain a group of filter buttons.

The entries are GtkButtons. Assign an action to the menu item for when they are activated.

Filters are toggle buttons that can be used for presentation/sorting purposes. For example, sorting alphabetically a list of contacts or changing the size of icons in a list.

To create a HildonAppMenu, use the following command:

kWidget*  hildon_app_menu_new             (void);

Once the application menu is created, add entries to the menu by using the following functions:

	void        hildon_app_menu_append          (HildonAppMenu *menu,
        	                                     GtkButton *item);
	void        hildon_app_menu_prepend         (HildonAppMenu *menu,
                	                             GtkButton *item);
	void        hildon_app_menu_insert          (HildonAppMenu *menu,
                        	                     GtkButton *item,
                                	             gint position);

These functions allow you to append, prepend an entry or add it in a certain position (from 0 to N-1, where N is the number of menus).

It is important keep the UI simple. Try to keep the menu as short as possible and avoid adding unnecessary options. An application menu with more that 10 items is probably not displayed well.

To add filter buttons, use the following:

void        hildon_app_menu_add_filter      (HildonAppMenu *menu,
                              		               GtkButton *filter);

Again, be careful with the number of filters that you add to the application menu. More than 4 might not be well displayed, even less, depending on the length of the labels. Filters should be grouped and act as radio buttons, that is, for any filter, at least another filter with a different/opposite action should exist. Actually, GtkRadioButtons can be easily used to accomplish this by having them grouped (using gtk_radio_button_new_from_widget() like the next example shows) and by not drawing their indicator - with the function gtk_toggle_button_set_mode().

Once the menu is properly created and filled up with entries and filters, add the menu to a HildonWindow. To set and retrieve a window's menu, use the following functions:

	void        hildon_window_set_app_menu      (HildonWindow *self,
                	                             HildonAppMenu *menu);
	HildonAppMenu* hildon_window_get_app_menu   (HildonWindow *self);

The following example shows how to create and set up an application menu.

Example 3.1. Example of a Hildon application menu

#include                                        <hildon/hildon.h>

static void
menu_button_clicked                             (GtkButton *button,
                                                 GtkLabel *label)
  const char *buttontext = gtk_button_get_label (button);
  char *text = g_strdup_printf("Last option selected:\n%s", buttontext);
  gtk_label_set_text (label, text);
  g_free (text);
  g_debug ("Button clicked: %s", buttontext);

static HildonAppMenu *
create_menu                                     (GtkWidget     *label)
  int i;
  gchar *command_id;
  GtkWidget * button;
  HildonAppMenu *menu = HILDON_APP_MENU (hildon_app_menu_new ());

  for (i = 1; i < 6; i++) {
    /* Create menu entries */
    button = hildon_gtk_button_new (HILDON_SIZE_AUTO);
    command_id = g_strdup_printf ("Menu command %d", i);
    gtk_button_set_label (GTK_BUTTON (button), command_id);

    /* Attach callback to clicked signal */
    g_signal_connect_after (button, "clicked",
                            G_CALLBACK (menu_button_clicked),

    /* Add entry to the view menu */
    hildon_app_menu_append (menu, GTK_BUTTON (button));

  /* Create filters */
  button = hildon_gtk_radio_button_new (HILDON_SIZE_AUTO, NULL);
  gtk_button_set_label (GTK_BUTTON (button), "filter one");
  g_signal_connect_after (button, "clicked", G_CALLBACK (menu_button_clicked), label);
  hildon_app_menu_add_filter (menu, GTK_BUTTON (button));
  gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);

  button = hildon_gtk_radio_button_new_from_widget (HILDON_SIZE_AUTO,
                                                    GTK_RADIO_BUTTON (button));
  gtk_button_set_label (GTK_BUTTON (button), "filter two");
  g_signal_connect_after (button, "clicked", G_CALLBACK (menu_button_clicked), label);
  hildon_app_menu_add_filter (menu, GTK_BUTTON (button));
  gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);

  gtk_widget_show_all (GTK_WIDGET (menu));

  return menu;

main                                            (int argc,
                                                 char **argv)
  GtkWidget *win;
  GtkWidget *label;
  GtkWidget *label2;
  GtkBox *vbox;
  HildonAppMenu *menu;

  hildon_gtk_init (&argc, &argv);

  win = hildon_stackable_window_new ();

  /* Create and pack labels */
  label = gtk_label_new ("This is an example of the\nHildonAppMenu widget.\n\n"
                         "Click on the titlebar\nto pop up the menu.");
  label2 = gtk_label_new ("No menu option has been selected yet.");

  gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
  gtk_label_set_justify (GTK_LABEL (label2), GTK_JUSTIFY_CENTER);

  vbox = GTK_BOX (gtk_vbox_new (FALSE, 10));

  gtk_box_pack_start (vbox, label, TRUE, TRUE, 0);
  gtk_box_pack_start (vbox, label2, TRUE, TRUE, 0);

  /* Create menu */
  menu = create_menu (label2);

  /* Attach menu to the window */
  hildon_window_set_app_menu (HILDON_WINDOW (win), menu);

  /* Add label's box to window */
  gtk_container_add (GTK_CONTAINER (win), GTK_WIDGET (vbox));

  g_signal_connect (win, "delete_event", G_CALLBACK (gtk_main_quit), NULL);

  gtk_widget_show_all (win);

  gtk_main ();

  return 0;

Each entry and filter button in this example is attached to a function that simply changes a label in the main window.

Note that the function used to attach handlers to the entries is g_signal_connect_after(). So the handler are called after the default handler of the signal "clicked". The default handler for entries and filters closes the menu.

Application menus and views

The previous example had only one view. In applications with several views, you can attach a different menu to each view and add only the options that are relevant to the displayed view.

The function hildon_window_set_app_menu()allows to set a menu to an HildonWindow and its descendant HildonStackableWindow widget.

	hildon_window_set_app_menu (HILDON_STACKABLE_WINDOW (win), menu);

Note that submenus are not supported by view menus. Usually a menu item that would have suboptions in a desktop application is implemented as a new subview in a Hildon application.

A callback function for a complex menu entry could create a new HildonStackableWindow to accomplish the task that the option refers to. The new window could contain a different view menu to contain buttons to perform the action. The buttons could even reside in the window area.

Context menu

Context menu is usually invoked via long press over an item on the screen, like holding a finger over an image thumbnail. The menu should contain commands directly related to the chosen item.

Avoid using context menus, because they are a hidden and inconvenient way of interacting with the UI. Use HildonAppMenus instead.

To create a GtkMenu in a Hildon application you should use the following function instead of gtk_menu_new():

GtkWidget*  hildon_gtk_menu_new             (void);

This function creates a GtkMenu that allows Hildon specific styling.

When you use a GtkMenu in your Hildon application, consider how many menu items you are going to use, because screen space is limited. Also consider the fact that in the interests of keeping the UI clear, submenus are not allowed.