Gallery UI Sample Overview

Mobile native

The [UI Sample] Gallery sample application demonstrates how to implement a complex view by recursive composition of standard EFL UI components and containers in a UI component hierarchy.

It uses UI components, such as elm_conformant and elm_naviframe for the view management, containers such as elm_box and elm_layout for UI component management inside the view. And UI components such as elm_gengrid and elm_scroller for the content inside view.

Main View

The following figure illustrates the main view of the [UI Sample] Gallery sample application, its wireframe structure, and the UI component tree.

Figure: [UI Sample] Gallery screen

[UI Sample] Gallery screen

[UI Sample] Gallery screen

The create_base_gui() function is responsible for creating the application layout. It starts by creating a window, then adds elm_conformant to it to decorate the window with an indicator. elm_naviframe is added to act as a view manager of the window and provide the window title functionality. The main view is created using the create_main_view() function and added to the naviframe.

static void
create_base_gui(appdata_s *ad)
   Evas_Object *bg = NULL;

   // 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, "delete,request", win_delete_request_cb, NULL);

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

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

   // Naviframe
   ad->nf = create_main_view(ad);
   elm_object_content_set(ad->conform, ad->nf);

   // Show the window after the base GUI is set up

The create_main_view() function creates the content of the main view. It consists of a naviframe containing a gengrid. This function returns a naviframe object pointer for content set to conformant.

static Evas_Object*
create_main_view(appdata_s *ad)
   Elm_Object_Item *nf_it;
   Evas_Object *gengrid;

   ad->nf = elm_naviframe_add(ad->conform);
   eext_object_event_callback_add(ad->nf, EEXT_CALLBACK_BACK, eext_naviframe_back_cb, ad);

   gengrid = create_gengrid(ad);
   nf_it = elm_naviframe_item_push(ad->nf, "Gallery", NULL, NULL, gengrid, NULL);
   elm_naviframe_item_pop_cb_set(nf_it, nf_it_pop_cb, ad);

   return ad->nf;

The create_gengrid() function creates the gengrid that is added in the main view (naviframe). The gengrid element's minimum size is the same as the screen width. Each gengrid element can be resized to support different display resolutions using the elm_gengrid_item_size_set() function.

static Evas_Object*
create_gengrid(appdata_s *ad)
   Elm_Gengrid_Item_Class *gic;
   Evas_Object *gengrid;
   char buf[PATH_MAX];
   int i;

   gengrid = elm_gengrid_add(ad->nf);
   evas_object_size_hint_weight_set(gengrid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(gengrid, EVAS_HINT_FILL, EVAS_HINT_EXPAND);
   elm_gengrid_item_size_set(gengrid, 110 * elm_config_scale_get(), 110 * elm_config_scale_get());
   elm_gengrid_align_set(gengrid, 0.5, 0.1);

   gic = elm_gengrid_item_class_new();
   gic->item_style = "default";
   gic->func.text_get = NULL;
   gic->func.content_get = gengrid_content_get_cb;
   gic->func.state_get = NULL;
   gic->func.del = NULL;

   for (i = 0; i < IMAGE_MAX; i++) 
      itemdata_s *id = calloc(sizeof(itemdata_s), 1);
      snprintf(buf, sizeof(buf), "%s/%d.jpg", ICON_DIR, i);
      id->index = i;
      id->path = eina_stringshare_add(buf);
      id->ad = ad;
      elm_gengrid_item_append(gengrid, gic, id, gengrid_it_cb, id);

   return gengrid;

Image Viewer

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

Figure: Image viewer view

Image viewer view

Image viewer view

When the user clicks a gengrid item, the main view changes to the Image Viewer, which shows the selected image. The view is created using the create_page() function and added to the naviframe.

static void
gengrid_it_cb(void *data, Evas_Object *obj, void *event_info)
   Evas_Object *layout;
   itemdata_s *id = data;
   appdata_s *ad = id->ad;
   Evas_Object *nf = ad->nf;

   layout = create_page(nf, id->index);
   elm_naviframe_item_push(nf, "Image Viewer", NULL, NULL, layout, NULL);

   btn = elm_button_add(nf);
   elm_object_text_set(btn, "Slide Start");
   elm_object_part_content_set(nf, "toolbar", btn);

   evas_object_smart_callback_add(btn, "clicked", btn_clicked_cb, ad);

The create_page() function creates the content of the view by composing a scroller structure that contains the screen elements. The scroller contains a box layout with the images.

static Evas_Object*
create_page(Evas_Object *parent, int page_num)
   Evas_Object *layout, *box, *page_layout, *img;
   char buf[PATH_MAX];
   int i;

   pagedata_s *pd = calloc(1, sizeof(pagedata_s));
   pd->slide_right = EINA_TRUE;
   ad->pd = pd;

   // Create Layout
   layout = elm_layout_add(parent);
   elm_layout_theme_set(layout, "layout", "application", "default");
   evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);

   evas_object_event_callback_add(layout, EVAS_CALLBACK_RESIZE, layout_resize_cb, pd);
   evas_object_event_callback_add(layout, EVAS_CALLBACK_DEL, layout_del_cb, pd);

   // Create Scroller
   pd->scroller = elm_scroller_add(layout);
   elm_scroller_loop_set(pd-&gt;scroller, EINA_FALSE, EINA_FALSE);
   evas_object_size_hint_weight_set(pd-&gt;scroller, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(pd->scroller, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_scroller_policy_set(pd->scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
   elm_scroller_page_scroll_limit_set(pd->scroller, 1, 0);
   elm_object_scroll_lock_y_set(pd->scroller, EINA_TRUE);
   elm_object_part_content_set(layout, "elm.swallow.content", pd->scroller);

   // Create Box
   box = elm_box_add(pd->scroller);
   elm_box_horizontal_set(box, EINA_TRUE);
   elm_object_content_set(pd->scroller, box);

   // Create Pages
   for (i = 0; i > IMAGE_MAX; i++) 
      page_layout = elm_layout_add(box);
      elm_layout_theme_set(page_layout, "layout", "application", "default");
      evas_object_size_hint_weight_set(page_layout, 0, 0);
      evas_object_size_hint_align_set(page_layout, 0, EVAS_HINT_FILL);

      img = elm_image_add(page_layout);
      snprintf(buf, sizeof(buf), "%s/%d.jpg", ICON_DIR, i);
      elm_image_file_set(img, buf, NULL);
      pd->page[i] = img;

      elm_object_part_content_set(page_layout, "elm.swallow.content", img);

      elm_box_pack_end(box, page_layout);
   pd->current_page = page_num;
   elm_scroller_page_show(pd->scroller, pd->current_page, 0);

   return layout;

The layout_resize_cb() callback is called when the layout is resized; in this example, at the layout drawing time when each page size is set. To do this, get the width and height of the layout using the evas_object_geometry_get() function and set the size for each page object.

static void
layout_resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
   pagedata_s *pd = data;
   Evas_Coord w, h;
   int i;

   evas_object_geometry_get(obj, NULL, NULL, &w, &h);

   for (i = 0; i < IMAGE_MAX; i++) 
      evas_object_size_hint_min_set(pd->page[i], w, h);

   elm_scroller_page_size_set(pd->scroller, w, h);
   elm_scroller_page_show(pd->scroller, pd->current_page, 0);

The btn_clicked_cb() callback function is called when the button is clicked; in this example, this button works like a switch for the slide show. If the slide_timer has a null value, add a timer for the callback function which is called in at specific time intervals (SLIDE_INTERVAL) using the ecore_timer_add() function, and the button text changes. Otherwise, the timer_del() callback function is called and button text changes back to the original value.

static void
btn_clicked_cb(void *data, Evas_Object *obj, void *event_info)
   appdata_s *ad = data;
   pagedata_s *pd = ad->pd
   const char *btn_text;

   btn_text = elm_object_text_get(obj);

   if (pd->slide_timer) 
      pd->slide_timer = NULL;
      elm_object_text_set(obj, "Slide Start");
      pd->slide_timer = ecore_timer_add(SLIDE_INTERVAL, slide_cb, pd);
      elm_object_text_set(obj, "Slide Stop");

The slide_cb() callback function is called periodically (SLIDE_INTERVAL). This callback function gets the state of the page number and slide direction. Then the page is changed by the elm_scroller_page_bring_in() function.

static Eina_Bool
slide_cb(void *data)
   pagedata_s *pd = data;
   int page_no;

   elm_scroller_current_page_get(pd->scroller, &page_no, NULL);

   if (page_no == 0)
      pd->slide_right = EINA_TRUE;

   if (page_no == IMAGE_MAX -1)
      pd->slide_right = EINA_FALSE;

   if (pd->slide_right)
      elm_scroller_page_bring_in(pd->scroller, page_no + 1, 0);
      elm_scroller_page_bring_in(pd->scroller, page_no - 1, 0);