Mobile native Wearable native

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);
}

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)

Form tutorial: list Form tutorial: 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:

  1. 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"},
    };
    
  2. 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.

  3. 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);
    
  4. 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

    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

Contact form layout

To create a contact form:

  1. 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.

  2. 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.

  3. 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);
    
  4. 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.

  5. 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);
    
  6. 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);
    
  7. 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);
    
  8. 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);
    
Go to top