Calculator UI Sample Overview

Mobile native

The [UI Sample] Calculator sample demonstrates how to implement a complex view using EFL UI components and containers.

It uses UI components, such as elm_conform and elm_panel for the view management, containers, such as elm_grid and elm_table for UI component management inside the view, and UI components, such as elm_button and elm_entry for the content inside the view.

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

Figure: [UI Sample] Calculator screen

[UI Sample] Calculator screen

[UI Sample] Calculator screen

Application Layout

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. The window contains a grid structure for the calculator entry display and its button panel. The entry display is aligned to the top of the grid and the button panel to the bottom of the grid.

static void
create_base_gui(appdata_s *ad)
{
   Evas_Object *grid, *panel;

   ad->win = elm_win_util_standard_add(PACKAGE, PACKAGE);
   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);

   ad->bg = create_bg(ad->win);
   ad->conform = create_conform(ad->win);
   elm_win_conformant_set(ad->win, EINA_TRUE);
   elm_win_indicator_mode_set(ad->win, ELM_WIN_INDICATOR_SHOW);

   // Grid 
   grid = elm_grid_add(ad->conform);
   evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_object_content_set(ad->conform, grid);

   // Entry 
   ad->entry = create_entry(grid);
   elm_grid_pack(grid, ad->entry, 5, 5, 90, 25);

   // Panel 
   panel = create_panel(grid, ad);
   elm_grid_pack(grid, panel, 0, 35, 100, 65);

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

Main View

The create_entry() function creates the calculator display. Input for the display is created with calculator buttons created in the next steps, so there is no need for the software keypad. Disable the software keypad by setting the elm_entry_editable_set() function as false. The display uses a right-aligned, 50 pt font.

static Evas_Object *
create_entry(Evas_Object *parent)
{
   Evas_Object *entry;

   entry = elm_entry_add(parent);
   elm_entry_editable_set(entry, EINA_FALSE);
   elm_entry_entry_set(entry, "<font_size=50><align=right></font_size>");
   evas_object_show(entry);

   return entry;
}

The create_panel() function creates the calculator button panel. There are 2 sets of buttons: basic buttons that are always visible, and advanced buttons that are only visible in the landscape mode.

static Evas_Object *
create_panel(Evas_Object *parent, appdata_s *ad)
{
   Evas_Object *panel, *grid, *content;

   // Panel 
   panel = elm_panel_add(parent);
   elm_panel_orient_set(panel, ELM_PANEL_ORIENT_BOTTOM);
   evas_object_show(panel);

   // Grid 
   grid = elm_grid_add(panel);
   evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_object_content_set(panel, grid);

   // Panel basic content 
   ad->basic_content = create_panel_basic_content(grid, ad);
   evas_object_size_hint_weight_set(ad->basic_content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(ad->basic_content, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_grid_pack(grid, ad->basic_content, 3, 3, 94, 94);

   // Panel advanced content 
   ad->advanced_content = create_panel_advanced_content(grid, ad);
   evas_object_size_hint_weight_set(ad->advanced_content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(ad->advanced_content, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_grid_pack(grid, ad->advanced_content, -100, -100, 94, 94);

   return panel;
}

The create_panel_basic_content() function creates the calculator buttons, such as number and sign buttons. The buttons are arranged in a table structure with a 10-pixel padding.

static Evas_Object *
create_panel_basic_content(Evas_Object *parent, appdata_s *ad)
{
   Evas_Object *table, *button;

   table = elm_table_add(parent);
   elm_table_padding_set(table, 10, 10);

   button = elm_button_add(table);
   evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(button, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_object_text_set(button, "<font_size = 50>C</font_size>");
   evas_object_smart_callback_add(button, "clicked", clicked_c_cb, ad->entry);
   evas_object_show(button);
   elm_table_pack(table, button, 0, 0, 1, 1);

   button = elm_button_add(table);
   evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
   evas_object_size_hint_align_set(button, EVAS_HINT_FILL, EVAS_HINT_FILL);
   elm_object_text_set(button, "<font_size = 50>/</font_size>");
   evas_object_smart_callback_add(button, "clicked", clicked_divide_cb, ad->entry);
   evas_object_show(button);
   elm_table_pack(table, button, 1, 0, 1, 1);
        …

   evas_object_show(table);

   return table;
}

As an example, when the user clicks the 0 button, the clicked_0_cb() function is called. The function adds the text in the entry display.

static void
clicked_0_cb(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
   Evas_Object *entry = data;
   elm_entry_entry_append(entry, "<font_size = 50>0</font_size>");
}

When the user rotates the device, the rotation_cb() function is called, which changes the layout of contents. If the new layout is in the landscape mode, the advanced content is aligned at the left side of the basic content.

static void
rotation_cb(void *data, Evas_Object *obj, void *event_info)
{
   appdata_s *ad = data;
   int current_degree = elm_win_rotation_get(obj);

   if (current_degree != 0 && current_degree != 180) 

   {
      elm_grid_pack_set(ad->basic_content, 45, 3, 52, 94);
      elm_grid_pack_set(ad->advanced_content, 3, 3, 36, 94);
   } 
   else 
   {
      elm_grid_pack_set(ad->basic_content, 3, 3, 94, 94);
      elm_grid_pack_set(ad->advanced_content, -100, -100, 94, 94);
   }
}