Using Fremantle widgets

THIS IS STILL WORK IN PROGRESS. TOMORROW I´LL ADD SCREENSHOTS. THAT SHOULD MAKE MANY ASPECTS CLEARER!

This document should help developers to port the user interface from Diablo to Fremantle. The official hildon documentation and the HIG are still quiet thin. Therefore the document mirrors what was discussed on the mailing lists, forum and bug reports. It is based completely on the Fremantle Beta SDK which is the most recent SDK at the moment.

Please feel totally free to add/update/change/remix this document. Many aspects are currently not discussed here but will hopefully be added by you!

Note: The casts of all code examples haven been removed for better readability.

= Toggle Buttons Vs. Radio Buttons = The use of radio buttons in Fremantle is discouraged because they don't fit the visual style quite well. Instead you should use toggle buttons.

So if you need the behavior of radio buttons (which is that only one can be selected at a time) simply create them as usually and then call. This will create a button that acts like a radio button, but is displayed as a toggle button.

Example: GtkWidget *b1 = gtk_radio_button_new_with_label("One"); GtkWidget *b2 = gtk_radio_button_new_with_label_from_widget(b1, "Two"); gtk_toggle_button_set_mode(b1, FALSE); gtk_toggle_button_set_mode(b2, FALSE);

= Window Menu = In Fremantle it is not encouraged to use  as window menu anymore. Instead you should use the. This new menu is really different from the old one so it´s worth taking a closer look. Here are the main features of the HildonAppMenu.
 * It has big / finger friendly menu items.
 * It holds a maximum of ten menu items.
 * It does not support sub menues.
 * The first row can be used for Filters. (Filters are explained in more details below.)
 * In landscape mode the menu items are displayed in two rows.
 * In portrait mode the menu items are automatically displayed in one row.
 * There are no separators, so you cannot group your menu items.
 * The menu items are GtkButtons and not GtkMenuItems.

The HildonAppMenu is meant to be displayed when the user clicks the title bar of the window, but it is possible to have several other HildonAppMenus in your application and activate them for example on button press.

As you can see the HildonAppMenu differs quite a lot from the old GtkMenu. The main difference is surely that you cannot have more then 10 menu items inside the new menu. The Hildon HIG gives an overview on how to deal with that.

Using HildonAppMenu with GtkActions
As said earlier, the menu items are no GtkMenuItems anymore but instead they are normal GtkButtons. So you´re using GtkActions in your code, you´ll probably miss a replacement for. There is no direct replacement, instead you just have to use standard gtk functions to connect the button as a proxy to the action. Here is an example: GtkButton *menu_item = gtk_button_new; gtk_action_connect_proxy(action, menu_item); This is also possible with  and. But remember that your GtkRadioButtons should look like GtkToggleButtons as mentioned above. So a complete example for a HildonAppMenu that should display three GtkRadioActions would look like this:

GSList *group = NULL; GtkAction *a1, *a2, *a3; GtkWidget *b1, *b2, *b3; GtkWidget *menu;

/* Create the actions */ a1 = gtk_radio_action_new("small", "Small", NULL, NULL, 0); a2 = gtk_radio_action_new("normal", "Normal", NULL, NULL, 1); a3 = gtk_radio_action_new("large", "Large", NULL, NULL, 2);

/* Build the radio action group */ gtk_radio_action_set_group(a1, group); group = gtk_radio_action_get_group(a1);

gtk_radio_action_set_group(a2, group); group = gtk_radio_action_get_group(a2);

gtk_radio_action_set_group(a3, group); group = gtk_radio_action_get_group(a3);

/* Create the toggle buttons */ b1 = gtk_toggle_button_new; b2 = gtk_toggle_button_new; b3 = gtk_toggle_button_new;

/* Connect the buttons and the actions */ gtk_action_connect_proxy(a1, b1); gtk_action_connect_proxy(a2, b2); gtk_action_connect_proxy(a3, b3);

/* Create the menu */ menu = hildon_app_menu_new;

/* Add the buttons to the menu */ hildon_app_menu_append(menu, b1); hildon_app_menu_append(menu, b2); hildon_app_menu_append(menu, b3);

= Finger Friendly GtkTreeView = To get a finger friendly  it´s not enough to call   instead of   but you also have to put the tree view inside a   to get finger friendly sizes. If you have your tree view inside a  it will be displayed with stylus-style (like in Diablo).

Also if you´re displaying icons in your tree view you probably should use the 40x40 pixel version for Fremantle if you used the 26x26 pixel version in Diablo.

Normal Vs. Edit Mode
There are now two different modes for the tree view. Those modes affect how the rows in a tree view react to finger taps.

You should use  if the user should only be able to activate one row of the text view. If the user taps a row in the tree view the  is emitted. In standard Gtk+ this happens only if the user double clicks the row - a single click selects the row which is not possible with.

If the user should be able to select or edit rows then you should use.

Using Filters For Sorting
Most of you probably are using the tree view with a header row that displays column labels. Often this header row can also be used to sort the columns ascending or descending. If you're designing a finger friendly UI you will usually have a very limited number of visible columns - probably only one or two. In this case the column content is often self explanatory and the header row is only there for sorting. If that's the case for your UI, you might want to remove the header column completely and replace it with so called filters on the HildonAppMenu.

According to the HIG filters are meant to change how data is presented, but it should not affect the amount of data that is displayed. Sorting a tree view would be a possible use case. To do this, just have a look at the example: /* Remove the header row */ gtk_tree_view_set_headers_visible(view, FALSE);

/* Create two radio buttons for sorting */ GtkWidget *b1, *b2; b1 = gtk_radio_button_new_with_label(NULL, "Sort By Title"); b2 = gtk_radio_button_new_with_label_from_widget(b1, "Sort By Date");

/* Draw them as toggle buttons not as radio buttons */ gtk_toggle_button_set_mode(b1, FALSE); gtk_toggle_button_set_mode(b2, FALSE);

/* Add the buttons as filters to the menu */ hildon_app_menu_add_filter(menu, b1); hildon_app_menu_add_filter(menu, b2);

That is all for showing them on the window menu. Now only a callback is needed which gets activated whenever the user selects a filter. An example implementation might look like that: void on_sort_filter_clicked(GtkToggleButton *button, GtkTreeSortable *sortable) { if (gtk_toggle_button_get_active(button)) { gtk_tree_sortable_set_sort_column_id(sortable, TITLE_COLUMN, GTK_SORT_ASCENDING); } }

= Context Menus = To display finger friendly context menues there is a hildon helper function called. Just call this instead of  and you´re done. Example: GtkWidget *menu = hildon_gtk_menu_new;

GtkWidget *item1 = gtk_menu_item_new_with_label("Bla"); GtkWidget *item2 = gtk_menu_item_new_with_label("Blablabla");

gtk_menu_shell_append(GTK_MENU_SHELL(menu), item1); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item2);

gtk_widget_show_all(menu); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time); ''Note that in the Beta SDK there is a bug. If you´re using  instead of   the menu will have stylus-style. This bug is already fixed and a work around is available here: https://bugs.maemo.org/show_bug.cgi?id=4654 .''

= Panning = Almost all of you will know the problems with scrollbars in Diablo. You can have small scrollbars which are not finger friendly or you can have large scrollbars which are using a lot of screen space and look ugly.

In Fremantle both kinds of scrollbars are still available, but there is also a third option. features kinetic panning using fingers. There is no scrollbar anymore, only a very small scroll indicator that indicates which part of the document you´re seeing right now. can be used as a replacement for  but there are things you have to keep in mind when doing so.

GtkTextView Inside HildonPannableArea
Panning does not work with a. Instead you can use a  which is a drop in replacement. The advantage is, that then panning is possible. The disadvantage is that selecting text is not possible anymore. The discussion about this is here: https://bugs.maemo.org/show_bug.cgi?id=4619

GtkHtml Inside HildonPannableArea
When using  inside a   the panning is not smooth. The problem seems to be that GtkHtml provides some build in support for panning and that it conflicts with the panning offered by Hildon. See this bug report here: https://bugs.maemo.org/show_bug.cgi?id=4631

= Portrait Mode = If your application should work in portrait mode you probably have to change the UI quite a bit. There are a couple of problems you'll might have:
 * The toolbar is not wide enough to hold all items anymore.
 * The columns of your tree view get too small.
 * You cannot enter text because there´s no onscreen keyboard.
 * Dialogs are not shown correctly (see https://bugs.maemo.org/show_bug.cgi?id=4618 ).
 * Probably more...

This means you have to listen to changes in the orientation and hide/show/change widgets to make the UI functional in portrait mode.

Listening To Orientation Changes
There is no Fremantle specific API for that (yet?), but you can do for example the following: gboolean is_portrait { GdkScreen *screen = gdk_screen_get_default; int width = gdk_screen_get_width(screen); int height = gdk_screen_get_height(screen); if (width > height) { return FALSE; } else { return TRUE; } }

void on_orientation_changed(GdkScreen *screen, GtkWidget *widget) { if (is_portrait) { gtk_widget_hide(widget); /* Hide/Show other things */ } else { gtk_widget_show(widget); /* Hide/Show other things */ } } Then inside your UI code you should listen to the  signal of. For example: g_signal_connect(screen, "size-changed", on_orientation_changed, widget);

Testing Orientation Changes In Scratchbox
For testing your code you can execute the following commands outside scratchbox: xrandr -display :2 -o left xrandr -display :2 -o normal

Marking Your App As Portrait Capable
If your application should automatically rotate when the device is rotated you have to explicitly mark your application as portrait capable. This is not yet implemented in the current beta SDK, but there will be one enum and a function as shown below: typedef enum { HILDON_PORTRAIT_MODE_REQUEST = 1 << 0, HILDON_PORTRAIT_MODE_SUPPORT = 1 << 1 } HildonPortraitFlags;

hildon_gtk_window_set_portrait_flags(GtkWindow *window, HildonPortraitFlags flags); The support flag tells Hildon that it is allowed to rotate your application. The request flag directly puts your application into portrait mode. It´s important to note that all visible windows must support portrait mode, otherwise the screen is not rotated.

= References = In no particular order


 * http://maemo.org/api_refs/5.0/beta/tutorial/html
 * http://maemo.org/api_refs/5.0/beta/hig/html


 * http://lists.maemo.org/pipermail//maemo-developers/2009-May/019368.html
 * http://lists.maemo.org/pipermail//maemo-developers/2009-May/019144.html
 * http://lists.maemo.org/pipermail//maemo-developers/2009-June/019426.html
 * http://lists.maemo.org/pipermail//maemo-developers/2009-June/019579.html


 * https://bugs.maemo.org/show_bug.cgi?id=4617
 * https://bugs.maemo.org/show_bug.cgi?id=4618
 * https://bugs.maemo.org/show_bug.cgi?id=4619
 * https://bugs.maemo.org/show_bug.cgi?id=4654
 * https://bugs.maemo.org/show_bug.cgi?id=4637
 * https://bugs.maemo.org/show_bug.cgi?id=4648