Creating a Form for a Basic Application Layout
This tutorial explains how to create a basic application that has a single window and multiple views: contact list view and contact details form view (displaying and editing contact information when an item is selected on the contact list).
Creating a Single-window Application
To create an elementary application with a single window, use the following code:
static bool app_create(void *data) { appdata_s *ad = data; create_gui(ad); return true; } int main(int argc, char **argv) { appdata_s ad = { 0 }; ui_app_lifecycle_callback_s event_callback = { 0 }; event_callback.create = app_create; // Zero out the structure memset(&ad, 0x0, sizeof(struct appdata)); // Run the mainloop return ui_app_main(&argc, &argv, &event_callback, &ad); }
Creating a Naviframe for Switching Views
Use a naviframe in this application to switch between different views. The first displayed view is the contact list. When an item is selected in this list, information on the contact is displayed in a contact details form. Both the list and form views are opened in a naviframe, which handles the transition between the views. It also creates a back button in the title area, and when the button is clicked, launches the transition, deletes the form view, and shows the contact list again.
Figure: Views (list and form)
To create a back button in the title area automatically, call the elm_naviframe_prev_btn_auto_pushed_set() function with EINA_TRUE (second parameter). This function decides whether a back button is automatically created in the views pushed later.
Since the naviframe is the main layout of the window, it takes all the available space. To configure the naviframe size, use the elm_win_resize_object_add() function to add the naviframe object (second parameter) to the main window (first parameter). To ensure that the naviframe covers the entire window area, call the evas_object_resize_hint_weight_set() function on the naviframe object to force the naviframe to fill its parent (the main window). The naviframe object expands in both X and Y directions.
In the end, show the naviframe object on the screen.
// Create the naviframe naviframe = elm_naviframe_add(win); elm_naviframe_prev_btn_auto_pushed_set(naviframe, EINA_TRUE); evas_object_size_hint_weight_set(naviframe, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); elm_win_resize_object_add(win, naviframe); evas_object_show(naviframe);
Creating a Contact List
To create a contact list:
-
Handle the contact list with the _create_contact_list() function. This function takes the parent object (naviframe) as the parameter and returns the genlist. To create the genlist, use the following code:
static Evas_Object * _create_contact_list(Evas_Object *parent) { Evas_Object *list; int i; // Create a new genlist list = elm_genlist_add(parent); evas_object_show(list); // Create a new item class for the genlist itc = elm_genlist_item_class_new(); itc->item_style = "default"; // Set the callback used when the genlist text is created itc->func.text_get = _genlist_text_get; // Set the callback be used when the content of the item is created itc->func.content_get = _genlist_content_get; itc->func.state_get = NULL; itc->func.del = NULL; }
The itc static variable contains the item class. The item class contains all functions that are called back when an item is created. In this case, create the _genlist_text_get() (for labels) and _genlist_content_get() (for icons) callbacks. These functions are called when labels and icons of the genlist item are created.
The contact list is contained in an array of Contacts.
typedef struct _Contact Contact; struct _Contact { const char *name; const char *mobile; const char *address; const char *email; const char *icon; }; static Contact contacts[] = { {"Alexander Holmes", "+1234567896", "", "alexander_holmes@tizen.org", "c1.png"}, {"Lara Alvaréz", "+9876543216", "", "lara_alvares@tizen.org", "c2.png"}, {"Aksel Møller", "+1679432846", "", "aksel_moller@tizen.org", "c3.png"}, {"Anir Amghar", "+1679432846", "", "anir_amghar@tizen.org", "c4.png"}, {"Noémie Cordier", "+1679432846", "", "noemie_cordier@tizen.org", "c5.png"}, {"Henry Thompson", "+1679432846", "", "henry_thompson@tizen.org", "c6.png"}, {"Mai Phan", "+1679432846", "", "mai_phan@tizen.org", "c7.png"}, };
-
Create a genlist item for each item of the array with the following code:
// Create a genlist item for each item in the contacts array for (i = 0; i < EINA_C_ARRAY_LENGTH(contacts); i++) { // Append the item, add a callback when the item is selected, and use the // current contact item as data pointer for the callbacks elm_genlist_item_append(list, itc, &contacts[i], NULL, ELM_GENLIST_ITEM_NONE, _contact_selected_cb, &contacts[i]); }
Attach the _contact_selected_cb() callback function to the genlist item. When an item is selected in the list, the data pointer passed as the parameter calls this function. In this example, it is a pointer on the contact. Pass the contact in the array to all the item class callbacks.
-
Push the list at the top of the naviframe:
// Create the list of contacts list = _create_contact_list(win); // Push the list on top of the naviframe elm_naviframe_item_push(naviframe, "Contact List", NULL, NULL, list, NULL);
-
Call the item class functions, the _genlist_text_get() function first:
static char * _genlist_text_get(void *data, Evas_Object *obj EINA_UNUSED, const char *part) { Contact *contact = data; // Return a new allocated string for the contact name return strdup(contact->name); }
These functions show the index of the contact in the array and return a freshly allocated string with the name of the contact.
When an item in the list is selected, a callback registers on the select signal and calls the corresponding function; in this case, _contact_selected_cb(). The index of the array passed in the data is retrieved and the form on contact information based on this index is created.
The _genlist_content_get function is called several times depending on the style of the created item. In this case, with the default style for the genlist item, there are 2 different swallow parts. A swallow part is a container in the edje file of the genlist item, which can contain an Evas object. The following figure shows the layout of different parts in the theme.
Figure: Genlist item
There are 2 elm.swallow parts. When the callback function for the icon creation is called, the part name is passed through the part variable. Compare this variable to elm.swallow.icon for the first object and to elm.swallow.end for the icon at the end.
Creating the Icon
Create the icon when the callback is recognized. This example uses an elm_icon object.
static Evas_Object * _genlist_content_get(void *data, Evas_Object *obj, const char *part) { Contact *contact = data; // Test which part is being created if (!strcmp(part, "elm.swallow.icon")) { char filename[PATH_MAX]; // Create a new icon Evas_Object *ic = elm_icon_add(obj); // Set the filename of the file which is to be loaded snprintf(filename, sizeof(filename), "%s%s", ICON_PATH, contact->icon); elm_image_file_set(ic, filename, NULL); // Keep the ratio squared evas_object_size_hint_aspect_set(ic, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1); // Return the icon return ic; } return NULL; }
In case the part is elm.swallow.end, the return is NULL and no icon is added.
A genlist can seem like an unnecessarily complex structure with its separate callbacks for creating items. However, in a list with thousands of elements, it is quite efficient not to create the graphical items for all list elements at once. Instead only the elements currently displayed on the screen are created through the callbacks. And when the list is scrolled, further callbacks create new elements as they are needed.
Note |
---|
When the genlist is first created, the Elementary needs to know the height of the list. All elements in the list are not necessarily the same size due to different kind of styles. Thus, the Elementary creates all elements once to know the size, and display the scroll bars correctly. If all your items have the same height, you can save CPU time by using the elm_genlist_homogeneous_set() function to impose the same height to all items. In this case, the Elementary does not create the complete list, as the global size is a multiple of the height of the first item. |
Creating a Contact Details Form
The contact details form is created inside the _create_contact_form() function. This function takes a parent Evas_Object and a contact item as parameters, and returns an Evas_Object. The parent is the naviframe object, and the contact item contains the information on the contact.
To display the various information about the contact, this example uses boxes.
Figure: Contact form layout
To create a contact form:
-
Create a vertical box:
vbox = elm_box_add(parent); elm_box_align_set(vbox, 0, 0); evas_object_show(vbox);
The elm_box_align_set() function keeps the box element aligned to the top left corner.
-
Create an icon in the genlist item with the _genlist_content_get() function. For a bigger icon, set the minimum size of the icon object to 96 x 96 px.
-
Add the icon object at the end of the vertical box with the elm_box_pack_end() function. As the icon is the first object added, it is displayed at the top of the box.
ic = elm_icon_add(vbox); snprintf(filename, sizeof(filename), "%s%s", ICON_PATH, contact->icon); elm_image_file_set(ic, filename, NULL); evas_object_size_hint_min_set(ic, 96, 96); evas_object_show(ic); elm_box_pack_end(vbox, ic);
-
Add the information on the contact: the name, the mobile phone number, the postal address, and the email address. For each information item, create a label and an edit line. The label defines the information type, and the edit box contains the actual information. To set the UI components in a horizontal layout, use a horizontal box.
-
Change the orientation of the box with the elm_box_horizontal_set() function. To add space between the elements of the vertical box, set padding to 32 px. To set the item of the box not to expand vertically, use the evas_object_size_hint_weight_set() function.
hbox = elm_box_add(vbox); elm_box_horizontal_set(hbox, EINA_TRUE); elm_box_padding_set(hbox, 32, 32); evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, 0); evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, 0); evas_object_show(hbox);
-
Create the label object, which is an elm_label. Set its text, and do not align or expand it.
label = elm_label_add(hbox); elm_object_text_set(label, form_items[i]); evas_object_size_hint_weight_set(label, 0, 0); evas_object_size_hint_align_set(label, 0, 0); evas_object_show(label);
-
Create the edit line, which is an elm_entry:
edit = elm_entry_add(hbox); evas_object_size_hint_weight_set(edit, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); evas_object_size_hint_align_set(edit, EVAS_HINT_FILL, EVAS_HINT_FILL); evas_object_show(edit);
-
Add the label and the edit inside the horizontal box and add the horizontal box to the vertical box:
elm_box_pack_end(hbox, label); elm_box_pack_end(hbox, edit); elm_box_pack_end(vbox, hbox);