Tizen Native API  9.0
Layout - Content, Table and Box

This example shows how one can use the Layout widget to create a customized distribution of widgets on the screen, controlled by an Edje theme. The full source code for this example can be found at layout_example_01.c.

Our custom layout is defined by a file, An example of layout theme file, which is an Edje theme file. Look for the Edje documentation to understand it. For now, it's enough to know that we describe some specific parts on this layout theme:

  • a title text field;
  • a box container;
  • a table container;
  • and a content container.

Going straight to the code, the following snippet instantiates the layout widget:

   layout = elm_layout_add(win);
   evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   elm_win_resize_object_add(win, layout);
   snprintf(buf, sizeof(buf), "%s/examples/layout_example.edj", elm_app_data_dir_get());
   elm_layout_file_set(layout, buf, "example/mylayout");
   evas_object_show(layout);

As any other widget, we set some properties for the size calculation. But notice on this piece of code the call to the function elm_layout_file_set(). Here is where the theme file is loaded, and particularly the specific group from this theme file. Also notice that the theme file here is referenced as an .edj, which is a .edc theme file compiled to its binary form. Again, look for the Edje documentation for more information about theme files.

Next, we fetch from our theme a data string referenced by the key "title". This data was defined in the theme, and can be used as parameters which the program get from the specific theme that it is using. In this case, we store the title of this window and program in the theme, as a "data" entry, just for demonstration purposes:

   // Setting title
   const char *title = elm_layout_data_get(layout, "title");
   if (title)
     {
        elm_win_title_set(win, title);
        elm_object_part_text_set(layout, TITLE, title);
     }

This call elm_layout_data_get() is used to fetch the string based on the key, and elm_object_part_text_set() will set the part defined in the theme as "example/title" to contain this string. This key "example/title" has nothing special. It's just an arbitrary convention that we are using in this example. Every string in this example referencing a part of this theme will be of the form "example/<something>".

Now let's start using our layout to distribute things on the window space. Since the layout was added as a resize object to the elementary window, it will always occupy the entire space available for this window.

The theme already has a title, and it also defines a table element which is positioned approximately between 50% and 70% of the height of this window, and has 100% of the width. We create some widgets (two icons, a clock and a button) and pack them inside the table, in a distribution similar to a HTML table:

   // Add icon, clock and button to the table
   icon = elm_icon_add(win);
   elm_icon_standard_set(icon, "home");
   evas_object_size_hint_weight_set(icon, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(icon, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_layout_table_pack(layout, TABLE, icon, 0, 0, 1, 1);
   evas_object_show(icon);

   icon2 = elm_icon_add(win);
   elm_icon_standard_set(icon2, "close");
   evas_object_size_hint_weight_set(icon2, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(icon2, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_layout_table_pack(layout, TABLE, icon2, 1, 0, 1, 1);
   evas_object_show(icon2);

   clk = elm_clock_add(win);
   evas_object_size_hint_weight_set(clk, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(clk, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_layout_table_pack(layout, TABLE, clk, 2, 0, 1, 1);
   evas_object_show(clk);

   bt = elm_button_add(win);
   elm_object_text_set(bt, "Click me!");
   evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_layout_table_pack(layout, TABLE, bt, 0, 1, 3, 1);
   evas_object_smart_callback_add(bt, "clicked", _tbl_btn_cb, layout);
   evas_object_show(bt);

Notice that we just set size hints for every object, and call the function elm_layout_table_pack(), which does all the work. It will place the elements in the specified row/column, with row and column span if required, and then the object's size and position will be controlled by the layout widget. It will also respect size hints, alignments and weight properties set to these widgets. The resulting distribution on the screen depends on the table properties (described in the theme), the size hints set on each widget, and on the cells of the table that are being used.

For instance, we add the two icons and the clock on the first, second and third cells of the first row, and add the button the second row, making it span for 3 columns (thus having the size of the entire table width). This will result in a table that has 2 rows and 3 columns.

Now let's add some widgets to the box area of our layout. This box is around 20% and 50% of the vertical size of the layout, and 100% of its width. The theme defines that it will use an "horizontal flow" distribution to its elements. Unlike the table, a box will distribute elements without knowing about rows and columns, and the distribution function selected will take care of putting them in row, column, both, or any other available layout. This is also described in the Edje documentation.

This box area is similar to the Elm_Box widget of elementary, with the difference that its position and properties are controlled by the theme of the layout. It also contains more than one API to add items to it, since the items position now is defined in terms of a list of items, not a matrix. There's the first position (can have items added to it with elm_layout_box_prepend()), the last position (elm_layout_box_append()), the nth position (elm_layout_box_insert_at()) and the position right before an element (elm_layout_box_insert_before()). We use insert_at and prepend functions to add the first two buttons to this box, and insert_before on the callback of each button. The callback code will be shown later, but it basically adds a button just before the clicked button using the elm_layout_box_insert_before() function. Here's the code for adding the first 2 buttons:

   item = elm_button_add(win);
   elm_object_text_set(item, "Position 0");
   evas_object_size_hint_weight_set(item, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(item, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_layout_box_insert_at(layout, BOX, item, 0);
   evas_object_smart_callback_add(item, "clicked", _box_btn_cb, layout);
   evas_object_show(item);

   item = elm_button_add(win);
   elm_object_text_set(item, "Prepended");
   evas_object_size_hint_weight_set(item, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(item, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_layout_box_prepend(layout, BOX, item);
   evas_object_smart_callback_add(item, "clicked", _box_btn_cb, layout);
   evas_object_show(item);

Finally, we have an area in this layout theme, in the bottom part of it, reserved for adding an specific widget. Differently from the 2 parts described until now, this one can only receive one widget with the call elm_object_part_content_set() for the layout. If there was already an item on this specific part, it will be deleted (one can use elm_object_part_content_unset() in order to remove it without deleting). An example of removing it without deleting, but manually deleting this widget just after that, can be seen on the callback for this button. Actually, the callback defined for this button will clean the two other parts (deleting all of their elements) and then remove and delete this button.

   bt2 = elm_button_add(win);
   elm_object_text_set(bt2, "Delete All");
   elm_object_part_content_set(layout, SWALLOW, bt2);
   evas_object_smart_callback_add(bt2, "clicked", _swallow_btn_cb, layout);

Also notice that, for this last added button, we don't have to call evas_object_show() on it. This is a particularity of the theme for layouts, that will have total control over the properties like size, position, visibility and clipping of a widget added with elm_object_part_content_set(). Again, read the Edje documentation to understand this better.

Now we just put the code for the different callbacks specified for each kind of button and make simple comments about them:

static void
_tbl_btn_cb(void *data, Evas_Object *btn, void *event_info EINA_UNUSED)
{
   Evas_Object *layout = data;

   elm_layout_table_unpack(layout, TABLE, btn);
   evas_object_del(btn);
}

static void
_box_btn_cb(void *data, Evas_Object *btn, void *event_info EINA_UNUSED)
{
   Evas_Object *layout = data;
   Evas_Object *item;
   char buf[30];

   snprintf(buf, sizeof(buf), "Button %02d", _box_buttons++);

   item = elm_button_add(elm_object_parent_widget_get(layout));
   elm_object_text_set(item, buf);
   evas_object_size_hint_weight_set(item, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(item, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_layout_box_insert_before(layout, BOX, item, btn);
   evas_object_smart_callback_add(item, "clicked", _box_btn_cb, layout);
   evas_object_show(item);
}

static void
_swallow_btn_cb(void *data, Evas_Object *btn EINA_UNUSED, void *event_info EINA_UNUSED)
{
   Evas_Object *layout = data;
   Evas_Object *item;

   elm_layout_table_clear(layout, TABLE, EINA_TRUE);
   elm_layout_box_remove_all(layout, BOX, EINA_TRUE);
   item = elm_object_part_content_unset(layout, SWALLOW);
   evas_object_del(item);
}

The first callback is used for the button in the table, and will just remove itself from the table with elm_layout_table_unpack(), which remove items without deleting them, and then calling evas_object_del() on itself.

The second callback is for buttons added to the box. When clicked, these buttons will create a new button, and add them to the same box, in the position just before the clicked button.

And the last callback is for the button added to the "content" area. It will clear both the table and the box, passing EINA_TRUE to their respective clear parameters, which will imply on the items of these containers being deleted.