(Circle) Buddy UI Sample Overview

Wearable native

The (Circle) Buddy UI sample application demonstrates how you can create a buddy and draw a UI for the buddy.

For information on creating the sample application project in the IDE, see Creating Sample Applications.

The following figure illustrates the main screen of the Buddy UI.

Figure: (Circle) Buddy UI screens

(Circle) Buddy UI screens

The application opens with the main view where the user can view all buddies in a circular list. To view the details of a specific buddy, click the buddy in the main view.

Source Files

You can create and view the sample application project including the source files in the IDE.

Table: Source files
File name Description
edje/images This file contains the image files used in the main.edc file.
inc/buddyui.h This file contains information and definition of the variables and functions used in the C files, especially in the buddyui.c file.
inc/data.h This file contains information and definition of the variables and functions used in the C files, especially in the data.c file.
inc/view.h This file contains information and definition of the variables and functions used in the C files, especially in the view.c file.
res/edje/main.edc This file is for the UI and contains style, image, and position of the sample application.
res/images This directory contains the image files used in the C files.
src/buddyui.c This file contains the functions related to the application life-cycle, callback functions, and view control.
src/data.c This file contains the functions for retrieving and creating data for the application.
src/view.c This file contains the functions for implementing the views and handling events.

Implementation

Application Layout

To create the basic layout, use the view_create() function. The window and conformant components are essential parts of the application layout.

void
view_create(void)
{
   // Create a window
   s_info.win = view_create_win(PACKAGE);
   if (s_info.win == NULL)
{
      dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a window.");

      return;
   }

   // Create a conformant
   s_info.conform = view_create_conformant_without_indicator(s_info.win);
   if (s_info.conform == NULL)
{
      dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a conformant");

      return;
   }

   // Show the window after the main view is set up
   evas_object_show(s_info.win);
}

To manage multiple views efficiently, you need a naviframe component. To create the naviframe and a circular layout, use the view_buddy_create() function:

void view_buddy_create(void)
{
   // Create the Eext circle surface
   s_info.circle_surface = eext_circle_surface_conformant_add(s_info.conform);
   // Create a circular layout
   s_info.layout = view_create_layout_for_conformant_by_theme(s_info.conform);

   // Create the naviframe
   s_info.nf = view_create_naviframe(s_info.layout);
   if (s_info.nf == NULL)
   {
      dlog_print(DLOG_ERROR, LOG_TAG, "failed to create a naviframe.");
      evas_object_del(s_info.win);
      s_info.win = NULL;

      return;
   }
}

Main View

The application opens with the main view.

Figure: Main view

Main view

To create the main view, use the view_buddy_create() function:

main_view_layout = view_create_layout(win, edj_path, GRP_MAIN, NULL, NULL);

The following figure shows the view frame created by the above code.

Figure: Main view frame

Main view frame

To fill out each part of the view, use the _init_view() function:

  • The view_set_label() function creates a label and sets it to the sw.focus.txt object.
  • The third parameter of the view_set_label_text() function determines the focus of this view.
view_set_label(main_view_layout, "sw.focus.txt");
view_set_label_text(main_view_layout, "sw.focus.txt", item_info->name);

You can customize the _naviframe_main_view_pop_cb() callback to do something when you press the back key in the main view.

To manage the buddy list in the main view:

  • Create the buddy item list in main the view with the following information structure:
    typedef struct
    _item_info_s
    {
       int position;
       char *name;
       char *number;
       char *img_path;
       float w;
       float h;
    }
    item_info_s;
  • When the application is launched, the buddy items are created and appended to the item list.
    item_count = data_get_item_total_count();
    for (i = 0; i < item_count; i++)
    {
       Evas_Object *item_layout = NULL;
       item_info_s *item_info = malloc(sizeof(item_info_s));
    
       item_info->name = data_get_item_name(i);
       item_info->number = data_get_item_number(i);
       item_info->img_path = data_get_item_image(i);
       item_info->w = 20;
       item_info->h = 20;
    
       item_layout = view_buddy_create_item_layout(main_view_layout, item_info->name, edj_path,
                                                   item_info->img_path, default_img_path, NULL);
       evas_object_data_set(item_layout, "__ITEM_INFO__", item_info);
    
       data_push_item_to_list(&item_list, item_layout);
    }
    data_set_item_list(item_list);
  • If the application is terminated, the buddy items are destroyed:
    item_list = data_get_item_list();
    EINA_LIST_FREE(item_list, item)
    {
       item_info_s *item_info = evas_object_data_del(item, "__ITEM_INFO__");
       if (item_info == NULL)
       {
          continue;
       }
    
       free(item_info->name);
       free(item_info->number);
       free(item_info->img_path);
       free(item_info);
    }

The position of the buddy on the screen is determined by a position index that a buddy item has.

Figure: Position index in the main view

Position index in the main view

When a rotary event is detected, buddy items are moved according to the direction of rotation. At this time, the buddy item position, size, transparency, and font size are set according to the location information matched with the index. The animation of the movement is implemented using the _simple_circle_animation() function of the Ecore Animator API.

static Eina_Bool
_simple_circle_path_animation(void *data)
{
   Evas_Object *main_view_layout = data;
   Eina_List *item_list = NULL;
   Eina_List *l = NULL;
   Evas_Object *item_layout = NULL;
   static int frame = 0;

   // After the last item, the circle path animation is finished
   if (_check_last_item_in_list() == EINA_TRUE)
   {
      frame = 0;
      s_info.anim = NULL;
      s_info.anim_end = EINA_TRUE;
      return ECORE_CALLBACK_CANCEL;
   }

   // If the current frame is over FRAME_MAX, circle path animation is finished
   if (frame > FRAME_MAX)
   {
      frame = 0;
      s_info.anim = NULL;
      s_info.anim_end = EINA_TRUE;
      return ECORE_CALLBACK_CANCEL;
   }
   else if (frame == 0)
   {
      _change_title_position(main_view_layout);
   }
   s_info.anim_end = EINA_FALSE;

   item_list = data_get_item_list();
   EINA_LIST_FOREACH(item_list, l, item_layout)
   {
      item_info_s *item_info = NULL;
      int to_deg, to_x, to_y, to_w, to_h, to_opacity;
      int from_deg, from_x, from_y, from_w, from_h, from_opacity;
      int cur_x, cur_y, cur_w, cur_h;
      int index, move_x, move_y, radius, opacity;
      int x_coord, y_coord;
      float deg_delta = 0.0f, angle = 0.0f;

      item_info = evas_object_data_get(item_layout, "__ITEM_INFO__");
      index = item_info->position;

      if (frame == 0)
      {
         int font_size = data_get_position_font_size(data_get_next_index(s_info.rotary_direction, index));
         view_buddy_change_item_font_size(item_layout, font_size);
      }
      else if (frame == FRAME_MAX)
      {
         _set_item_property(item_layout, data_get_next_index(s_info.rotary_direction, index));

         if (data_get_next_index(s_info.rotary_direction, index) == 5)
         {
            view_set_label_text(main_view_layout, "sw.focus.txt", item_info->name);
            dlog_print(DLOG_DEBUG, LOG_TAG, "item info : %s, %s", item_info->name, item_info->img_path);
         }
         continue;
      }

      data_get_position_info(index, &from_x, &from_y, &from_w, &from_h, &from_opacity);
      data_get_position_info(data_get_next_index(s_info.rotary_direction, index), &to_x, &to_y, &to_w, &to_h, &to_opacity);

      evas_object_geometry_get(item_layout, &cur_x, &cur_y, &cur_w, &cur_h);

      // Get the degree of the item layout
      from_deg = data_get_position_degree(index);
      to_deg = data_get_position_degree(data_get_next_index(s_info.rotary_direction, index));
      deg_delta = fabs((float) from_deg - (float) to_deg);

      // Get the size of the item layout
      if (index < 0 || index > 10)
      {
         item_info->w = 20;
         item_info->h = 20;
      }
      else
      {
         data_get_item_size(&item_info->w, &item_info->h, from_w, from_h, to_w, to_h, deg_delta);
      }
      evas_object_resize(item_layout, item_info->w, item_info->h);

      // Get the position of the item layout
      if (index < 0 || index > 10)
      {
         x_coord = 360;
         y_coord = 180;
      }
      else
      {
         // Calculate angle
         angle = data_get_item_angle(from_deg, to_deg, deg_delta, frame);
         // Calculate radius
         radius = data_get_item_radius(index, s_info.rotary_direction, frame);
         // Calculate position
         data_get_simple_circle_path(&move_x, &move_y, radius, angle);
         x_coord = move_x - (cur_w / 2);
         y_coord = move_y - (cur_h / 2);
      }
      evas_object_move(item_layout, x_coord, y_coord);

      // Get the opacity of the item layout
      opacity = data_get_item_opacity(item_layout, from_opacity, to_opacity, deg_delta);
      evas_object_color_set(item_layout, opacity, opacity, opacity, opacity);

      evas_object_show(item_layout);
   }

   frame++;

   return ECORE_CALLBACK_RENEW;
}

Detail View

To move to the detail view when the user clicks the focused buddy on the main view, register and customize the _focus_clicked_cb() callback:

view_set_customized_event_callback(main_view_layout, "mouse,clicked", "img.focus.bg", _focus_clicked_cb, main_view_layout);

In the callback, the detail view is created and shows the buddy item information.

Figure: Detail view

Detail view

To manage the view easily, add it to the naviframe:

view_push_item_to_naviframe(naviframe, detail_view_layout, _detail_view_pop_cb, main_view_layout);