Page Example

Clock UI Sample Overview

Mobile native

The [UI Sample] Clock sample application demonstrates how to implement a complex view by recursive composition of standard EFL UI components and containers in a UI component hierarchy. The sample also shows how to view reconstruction in the landscape mode.

The sample uses UI components, such as elm_conformant and elm_naviframe for the view management, containers, such as elm_box, elm_grid, and elm_table for UI component management inside the view, and UI components, such as elm_button, elm_label, elm_image, and elm_genlist for the content inside the view.

Alarm View

The following figure illustrates the alarm view, its wireframe structure, and the UI component tree.

Figure: Alarm view

Alarm view

Alarm view

The create_base_gui() function creates the window, which contains an indicator (elm_conformant), a view manager (elm_naviframe), and the content created using the create_toolbar() function.

static void
create_base_gui(appdata_s *ad)
{
   Evas_Object *bg = NULL;
   Elm_Object_Item *nf_it, *tabbar_it;

   // Window
   ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
   elm_win_conformant_set(ad->win, EINA_TRUE);
   elm_win_autodel_set(ad->win, EINA_TRUE);

   if (elm_win_wm_rotation_supported_get(ad->win)) 
   {
      int rots[4] = {0, 90, 180, 270};
      elm_win_wm_rotation_available_rotations_set(ad->win, (const int *)(&rots), 4);
   }

   evas_object_smart_callback_add(ad->win, "wm,rotation,changed", rotation_cb, ad);
   evas_object_smart_callback_add(ad->win, "delete,request", win_delete_request_cb, NULL);
   eext_object_event_callback_add(ad->win, EEXT_CALLBACK_BACK, win_back_cb, ad);

   // Conformant
   ad->conform = elm_conformant_add(ad->win);
   elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW);
   elm_win_indicator_opacity_set(ad->win, ELM_WIN_INDICATOR_OPAQUE);
   evas_object_size_hint_weight_set(ad->conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   elm_win_resize_object_add(ad->win, ad->conform);
   evas_object_show(ad->conform);

   // Indicator BG
   bg = elm_bg_add(ad->conform);
   elm_object_style_set(bg, "indicator/headerbg");
   elm_object_part_content_set(ad->conform, "elm.swallow.indicator_bg", bg);
   evas_object_show(bg);

   // Naviframe
   ad->nf = elm_naviframe_add(ad->conform);
   elm_object_content_set(ad->conform, ad->nf);
   evas_object_show(ad->nf);
   nf_it = elm_naviframe_item_push(ad->nf, NULL, NULL, NULL, NULL, "tabbar/icon/notitle");

   // Tabbar
   ad->tabbar = create_toolbar(ad);
   elm_object_item_part_content_set(nf_it, "tabbar", ad->tabbar);

   // Set the first view
   tabbar_it = elm_toolbar_first_item_get(ad->tabbar);
   elm_toolbar_item_selected_set(tabbar_it, EINA_TRUE);

   // Show the window after the base GUI is set up
   evas_object_show(ad->win);
}

The create_toolbar() function creates the main view content. It first pushes a naviframe view, and then creates a toolbar and sets the toolbar options. 3 items are added in the toolbar.

static Evas_Object*
create_toolbar(appdata_s *ad)
{
   Evas_Object *tabbar;

   tabbar = elm_toolbar_add(ad->nf);
   elm_object_style_set(tabbar, "tabbar");
   elm_toolbar_shrink_mode_set(tabbar, ELM_TOOLBAR_SHRINK_NONE);
   elm_toolbar_transverse_expanded_set(tabbar, EINA_TRUE);

   elm_toolbar_item_append(tabbar, ICON_DIR"/icon_alarm.png", "Alarm", tabbar_item_cb, ad);
   elm_toolbar_item_append(tabbar, ICON_DIR"/icon_worldclock.png", "World Clock", tabbar_item_cb, ad);
   elm_toolbar_item_append(tabbar, ICON_DIR"/icon_timer.png", "Timer", tabbar_item_cb, ad);

   return tabbar;
}

When a tab bar item is selected, the tabbar_item_selected() function is called. If the Alarm tab is selected (and the device rotation degree is 0 or 180), the create_alarm_view() function is called.

The sub_view value is set as the box object to take from the create_alarm_view() function. The box object is then posted to the naviframe.

static void
tabbar_item_selected(appdata_s *ad, Elm_Object_Item *it)
{
   Evas_Object *sub_view;
   const char *str = NULL;

   str = elm_object_item_text_get(it);

   if (str && !strcmp(str, "World Clock")) 
   {
      sub_view = create_worldclock_view(ad);
   }
   else if (str && !strcmp(str, "Timer")) 
   {
      if (ad->current_degree == 0 || ad->current_degree == 180)
         sub_view = create_timer_view(ad);
      else
         sub_view = create_landscape_timer_view(ad);
   }
   else 
   {
      if (ad->current_degree == 0 || ad->current_degree == 180)
         sub_view = create_alarm_view(ad);
      else
         sub_view = create_landscape_alarm_view(ad);
   }

   elm_object_content_set(ad->nf, sub_view);
}

The create_alarm_view() function creates the content of the main view. A box containing grid and button objects is created and added to the naviframe.

static Evas_Object *
create_alarm_view(appdata_s *ad)
{
   Evas_Object *box, *grid1, *bg1, *label1, *label2, *grid2, *bg2, *img, *label3, *btn;

   box = elm_box_add(ad->nf);
   evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_box_pack_end(box, grid1);
   elm_box_pack_end(box, grid2);
   elm_box_pack_end(box, btn);

   return box;
}

A grid containing bg and label objects is created and added to the box container. Each object in the grid has its own relative coordinates for positioning.

grid1 = elm_grid_add(box);
evas_object_size_hint_weight_set(grid1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(grid1, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_show(grid1);

bg1 = create_bg(grid1, 1);
elm_grid_pack(grid1, bg1, 0, 0, 100, 100);

label1 = elm_label_add(grid1);
elm_object_text_set(label1, "<font_size=110><color=#ffffff>07:26</color></font_size>");
evas_object_show(label1);
elm_grid_pack(grid1, label1, 22, 8, 100, 100);

label2 = elm_label_add(grid1);
elm_object_text_set(label2, "<font_size=22><color=#a6a6a6>wed, January 1</color></font_size>");
evas_object_show(label2);
elm_grid_pack(grid1, label2, 35, 78, 100, 100);

grid2 = elm_grid_add(box);
evas_object_size_hint_weight_set(grid2, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(grid2, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_min_set(grid2, -1, 430);
evas_object_show(grid2);

bg2 = create_bg(grid2, 2);
elm_grid_pack(grid2, bg2, 0, 0, 100, 100);

img = create_img(grid2, "no_alarm.png");
elm_grid_pack(grid2, img, 32, 32, 36, 36);

label3 = elm_label_add(grid2);
elm_object_text_set(label3, "<b><font_size=22><color=#ffffff>No alarms</color></font_size></b>");
evas_object_show(label3);
elm_grid_pack(grid2, label3, 40, 68, 100, 100);

btn = create_btn(box, "Create alarm");

The bg, img, and btn objects are created for reusability.

static Evas_Object*
create_bg(Evas_Object *parent, int type)
{
   Evas_Object *bg;

   bg = elm_bg_add(parent);
   evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(bg, EVAS_HINT_FILL, EVAS_HINT_FILL);

   if (type == 1)
      elm_bg_color_set(bg, 0, 0, 0);
   else
      elm_bg_color_set(bg, 0, 40, 40);

   evas_object_show(bg);

   return bg;
}

static Evas_Object*
create_img(Evas_Object *parent, char *filename)
{
   Evas_Object *img;
   char buf[PATH_MAX];

   img = elm_image_add(parent);
   snprintf(buf, sizeof(buf), "%s/%s", ICON_DIR, filename);
   elm_image_file_set(img, buf, NULL);
   evas_object_show(img);

   return img;
}

static Evas_Object*
create_btn(Evas_Object *parent, char *text)
{
   Evas_Object *btn;
   char buf[PATH_MAX];

   btn = elm_button_add(parent);
   evas_object_size_hint_weight_set(btn, EVAS_HINT_EXPAND, 0.0);
   evas_object_size_hint_align_set(btn, EVAS_HINT_FILL, EVAS_HINT_FILL);
   snprintf(buf, sizeof(buf), "%s", text);
   elm_object_text_set(btn, buf);
   evas_object_show(btn);

   return btn;
}

Landscape Alarm View

The following figure illustrates the landscape Alarm view, its wireframe structure, and the UI component tree.

Figure: Landscape Alarm view

Landscape Alarm view

Landscape Alarm view

When the device is rotated, the application rearranges the UI component layout to match the view mode (portrait or landscape).

In this sample, a smart callback for device rotation in the main function is added by default.

evas_object_smart_callback_add(ad->win, "wm,rotation,changed", rotation_cb, ad);

The smart callback is called when the device is rotated.

The selected view is reconstructed according to the current device angle.

In the following snippet:

  • data is the data provided by the user during callback registration.
  • obj is the handle to the object on which the event occurred.
  • event_info is the data the object wants to pass to the callback function.
static void
rotation_cb(void *data, Evas_Object *obj, void *event_info)
{
   appdata_s *ad = data;
   Elm_Object_Item *it;
   const char *str = NULL;
   ad->current_degree = elm_win_rotation_get(obj);

   it = elm_toolbar_selected_item_get(ad->tabbar);
   str = elm_object_item_text_get(it);

   if (ad->current_degree != 0 && ad->current_degree != 180 && !strcmp(str, "World Clock")) 
   {
      elm_grid_pack_set(ad->vd->label1, 33, 16, 100, 100);
      elm_grid_pack_set(ad->vd->label2, 40, 58, 100, 100);
      elm_grid_pack_set(ad->vd->label3, 41, 69, 100, 100);
   }
   else
      tabbar_item_selected(ad, it);
}

The create_landscape_alarm_view() function creates the content of the main view.

A box containing box and button objects is created and added to the naviframe.

A box containing grid objects is created and added to the outer box container.

A grid containing label and image objects is created and added to the inner box container. Each object in the grid has its own relative coordinates for positioning.

A button is created and added to the outer box container.

static Evas_Object *
create_landscape_alarm_view(appdata_s *ad)
{
   Evas_Object *box1, *box2, *label1, *label2, *label3, *img, *bg1, *bg2, *grid1, *grid2, *btn;

   box1 = elm_box_add(ad->nf);
   evas_object_size_hint_weight_set(box1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(box1, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_box_pack_end(box1, box2);
   elm_box_pack_end(box1, btn);

   return box1;
}

World Clock View

The following figure illustrates the World clock view. The wireframe and UI component tree are similar to the normal view. In this case, no separate up function is needed for the landscape view.

Figure: World clock view

World clock view

World clock view

World clock view

The grid object minimum height value has been set. A scroller is automatically added in the list.

grid1 = elm_grid_add(box);
evas_object_size_hint_weight_set(grid1, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(grid1, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_min_set(grid1, -1, 265);
evas_object_show(grid1);

In the landscape view, the relative coordinate values of the grid items change. To ensure that the view can be maintained, rearrange the items.

if (ad->current_degree == 0 || ad->current_degree == 180) 
{
   elm_grid_pack(grid1, label1, 22, 17, 100, 100);
   elm_grid_pack(grid1, label2, 35, 62, 100, 100);
   elm_grid_pack(grid1, label3, 36, 73, 100, 100);
}
else 
{
   elm_grid_pack(grid1, label1, 33, 16, 100, 100);
   elm_grid_pack(grid1, label2, 40, 58, 100, 100);
   elm_grid_pack(grid1, label3, 41, 69, 100, 100);
}

Timer View

The following figure illustrates the Timer view, its wireframe structure, and the UI component tree.

Figure: Timer view

Timer view

Timer view

The create_timer_view() function creates the content of the main view.

A box containing grid and button objects is created and added to the naviframe.

A grid containing label and table objects is created and added to the inner box container. Each object in the grid has its own relative coordinates for positioning. A table is created and added to the grid container.

table = elm_table_add(grid2);
evas_object_show(table);
elm_table_padding_set(table, 5, 5);
elm_table_homogeneous_set(table, EINA_TRUE);

index = 0;
for (i = 0; i < 2; i++) 
{
   for (j = 0; j < 6; j++) 
   {
      index++;
      if (index == 6)
         snprintf(buf, sizeof(buf), "%s", "<font_size=50>Del</font_size>");
      else if (index == 11)
         snprintf(buf, sizeof(buf), "%s", "<font_size=50>0</font_size>");
      else if (index == 12)
         snprintf(buf, sizeof(buf), "%s", "<font_size=40>Start</font_size>");
      else 
      {
         if (index > 6)
            snprintf(buf, sizeof(buf), "%s%d%s", "<font_size=50>", index -1, "</font_size>");
         else
            snprintf(buf, sizeof(buf), "%s%d%s", "<font_size=50>", index, "</font_size>");
      }
      btn = create_btn(grid2, buf);
      elm_table_pack(table, btn, j, i, 1, 1);
   }
}

elm_grid_pack(grid2, table, 0, 0, 100, 100);