[UI Sample] Clock Sample Overview
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
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
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
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
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);