Published on 25th of October 2017
Popup. Toast Style. Types of Scroller Events

In this tutorial we will continue writing second demo application. Moreover, we will look at events that can be caught in the scroller and show how they can be used. Next, we will consider how to create a popup (Toast) window with a displayed message to notify users. And at the end of this lesson, we will turn the application into a simple game.

Scroller Events

The scroller is a container of Elementary library and implements its own smart callbacks. This can be handy in some situations, for example, we can find out when the scroll bar has reached the content boundary, or the scrolling animation is completed.

Wearable devices support following types of signals that can be used like a feedback to the containers:

“edge,left” - event when the content is scrolled to the left border.

“edge,right” - event when the content is scrolled to the right border.

“edge,top” - event when content is scrolled to the top.

“edge,bottom” - event when content is scrolled to the bottom of the content.

“scroll” - event is called during the scrolling of the content, it is called a lot of times.

“scroll,anim,start” - event with this signal will be called in two cases. The first one - when the user makes a fast swipe in the scrolling area, the scroller will continue its movement and gradually stop. In this case, the signal will occur when the user stop touching the scroller. The second case is when one of the following functions is called for the scroller in the code. It will smoothly move the scroll area along the specified parameters.

void elm_scroller_region_bring_in(Evas_Object *obj,
                                  Evas_Coord x,
                                  Evas_Coord y,
                                  Evas_Coord w,
                                  Evas_Coord h);

void elm_scroller_page_bring_in(Evas_Object *obj,
                                int h_pagenumber,
                                int v_pagenumber);

“scroll,anim,stop” - event that the animation, described in the previous signal, is completed.

“scroll,drag,start” - event that is called, when the user starts moving content in the scroll area.

“scroll,drag,stop” - event that is called, when the user stops moving content in the scroll area.

Toast Style for Popup Window

Sometimes in the application there is a situation when some text information, for example, a small hint or an error message needs to be outputted to the user. For this in Tizen, there is Toast popup window, which is the same popup widget that was described in lesson 16, but it has different style. Let's add to the application a popup message, which is saying that the user can move the image with his finger across the screen. Expand the widgets structure with a pointer to a new popup widget that will be created further.

Evas_Object *toast_help;

The structure with widgets will have following content:

typedef struct _UIData {	
   Evas_Object *win;
   Evas_Object *conform;
   Evas_Object *toast_help;
   Evas_Object *scroller;
   Evas_Object *image;
} UIData;

To create and run a popup window, do two things:

static void
_toast_click_cb(void *data, Evas_Object *toast, void *event_info)
{
   evas_object_del(toast);
}

static void
_toast_create(UIData *ui)
{
   ui->toast_help = elm_popup_add(ui->conform);

   elm_object_style_set(ui->toast_help, "toast/circle");

   const float TIMEOUT_TIME = 5.0; // Seconds
   elm_popup_timeout_set(ui->toast_help, TIMEOUT_TIME);

   const char *MESSAGE = " Slide your finger across the screen to move...";
   elm_object_part_text_set(ui->toast_help, "elm.text", MESSAGE);

   evas_object_smart_callback_add(ui->toast_help, "block,clicked", _toast_click_cb, NULL);

   evas_object_show(ui->toast_help);
}

Let's analyze what you should do to create a Toast.

To create a widget object, use the following call:

ui->toast_help = elm_popup_add(ui->conform);

To set a style for any widget, or Elementary container, call the following function. The Toast style for a wearable device with a round display is called "toast/circle". As for the other widgets, the first parameter is a pointer to the widget object, and the second is style name that needs to be set:

elm_object_style_set(ui->toast_help, "toast/circle");

If the window is already displayed, the delay timer starts during the call of the function, otherwise the timer will trigger only when the function for displaying object is invoked. Let’s make a 5-second delay for the auxiliary window.

const float TIMEOUT_TIME = 5.0; // Seconds
elm_popup_timeout_set(ui->toast_help, TIMEOUT_TIME);

Set the text for the popup message. If the message is too long, then the widget will automatically display the maximum number of characters and add an ellipsis at the end of the message.

const char *MESSAGE = " Slide your finger across the screen to move...";
elm_object_part_text_set(ui->toast_help, "elm.text", MESSAGE);

By default, a popup window can not be closed if you did not install a timer to it or without explicit indication that you want to delete it after an event has triggered. The popup widget implements the smart event of pressing on it (the "block, clicked" signal). The signature of the function is the same as in the standard smart callback: the first parameter is a pointer to the user data, the second is the smart object, for which the event is called (in our case, a popup window), and the third is a pointer to the data with the event parameters.

static void
_toast_click_cb(void *data, Evas_Object *toast, void *event_info)
{
   evas_object_del(toast);
}

static void
_toast_create(UIData *ui)
{
   ...
   
   evas_object_smart_callback_add(ui->toast_help, "block,clicked", _toast_click_cb, NULL);

   ...
}

After all the preparations, display the Toast. Then the 5-second timer that you have set to close the popup message will be launched.

evas_object_show(ui->toast_help);

After scroller creation and placing its contents to the conformant, add call of the Toast widget creation function.

static void
_conformant_create(UIData *ui)
{
   ...

   _scroller_create(ui);
   elm_object_content_set(ui->conform, ui->scroller);

   _toast_create(ui);

   ...
}

Since currently the application minimizes the main window when clicking on the hardware Back button, and the popup window, as well as all other widgets, is created only once during the first launching, so popup will be displayed only once. In the Toast, in order to make the prompt constantly visible, you should replace the window minimization with the application close. To do so, change the contents of the callback, registered for event of pressing the Back button.

static void
_win_back_cb(void *data, Evas_Object *obj, void *event_info)
{
   ui_app_exit();
}

Another option is to move Toast creation to the application lifecycle loop, into callback for resume event. But we will not do this in current example.

Now let’s look at the result.

This video shows how the application works on the emulator.

Now if you need to inform the user about something in the application, you can do it easily.

Making a Mini-Game from the Demo Application

As we’ve agreed, we will show you how to turn the demo application into a mini game, based on the material of this lesson.

Game description: the user is on a large map, and he or she by moving the map across the screen, should find a treasure. On the map there will be a line, helping the user to navigate on the map.

First of all, you should use a map image instead of the current image. We have drawn this kind of map for using it in this game.

nw_019_02_en

The image of the map is large enough. One cell has a size: 360x360.

Place it in the project using the following path: res/images/map.jpg.

Now indicate the way to this image for the widget. For this replace “images/image_big.png” with “images/map.jpg”

static void
_image_create(UIData *ui)
{
   ...
   
   char abs_path_to_image[PATH_MAX] = {0,};
   _file_abs_resource_path_get("images/map.jpg", abs_path_to_image, PATH_MAX);
   
   ...
}

On the map determine the coordinates where the treasure is located (horizontally and vertically):

nw_019_03

It turned out that X = 3908, and Y = 943.

As long as each time the scrolling area moves, it should be checked, whether the point with the treasure has entered the scroller's area, we have to register the callback for the scroll event. For this, add to the scroller creation function the following call:

static void
_scroller_create(UIData *ui)
{
   ...

   evas_object_smart_callback_add(ui->scroller, "scroll", _scroll_cb, ui);

   ...
}

As with any smart callback registration, the first parameter is a pointer to the widget's object, the second is the signal/event name, the third is the pointer to the smart function that should be called, and the fourth is our data which further will be used inside the callback function during its call. Next, create the function itself:

static void
_scroll_cb(void *data, Evas_Object *scroller, void *event_info)
{
   UIData *ui = data;
}

The first argument was converted to the type that you have used during the registration of the callback as its additional data.

As it was mentioned before, you should check whether a treasure is found or not.

First, determine where the scroll zone is in relation to the content. To obtain this data, scroller has the following function:

Evas_Coord x = 0;
Evas_Coord y = 0;
Evas_Coord w = 0;
Evas_Coord h = 0;
elm_scroller_region_get(ui->scroller, &x, &y, &w, &h);

The function as 4 last parameters takes 4 pointer to the objects with Evas_Coord type, but in fact, it's just a redefined int. Arguments are indicated in the following order: the position of the upper left corner horizontally, the position of the upper left corner vertically, the width of the area and the last one goes the height.

Define the center of this area on the content by the following actions:

int center_x = x + w / 2;
int center_y = y + h / 2;

Add the constants for the received coordinates of the treasure:

const int TREASURE_X = 3908;
const int TREASURE_Y = 943;
const int AREA_RADIUS = 150;

The third constant will be used as the radius of the circular zone in which you will be looking for the desired point. Since the scroller is stretched to the whole screen, and its size is 360x360, then the radius of the round screen is 180. Take a slightly smaller circle so in the beginning the cross on the map fully enters on the screen, after which it will be signaled that the treasure is found.

To determine whether the point is in the circle, write the following function:

static Eina_Bool
_is_point_in_circle(double area_center_x,
                    double area_center_y,
                    double area_radius,
                    double checking_point_x,
                    double checking_point_y)
{
   double delta_x = fabs(area_center_x - checking_point_x);
   double delta_y = fabs(area_center_y - checking_point_y);

   double distance = sqrt(delta_x * delta_x + delta_y * delta_y);

   Eina_Bool is_in_circle = EINA_FALSE;

   if (distance < area_radius)
     {
        is_in_circle = EINA_TRUE;
     }

   return is_in_circle;
}

The first three parameters of the function are the coordinates of the center of the circle and the radius, the last two are the coordinates of the point that you are checking. In another words, you should find the distance between the center of the circle and the point that is currently checking. If the distance is less than the radius of the circle, then the point enters the circle.

In order to notify the user that the treasure is found, use Toast widget. Write a function for creating this popup window.

static void
_win_toast_create(UIData *ui)
{
   Evas_Object *toast_win = elm_popup_add(ui->conform);

   elm_object_style_set(toast_win, "toast/circle");

   const char *MESSAGE = " Congratulations! You’ve found the treasure! ";
   elm_object_part_text_set(toast_win, "elm.text", MESSAGE);

   evas_object_smart_callback_add(toast_win, "block,clicked", _toast_click_cb, NULL);

   evas_object_show(toast_win);
}

The callback function that will be used by user for clicking on Toast window is the same as for the popup help window, so to avoid errors, make sure that _toast_click_cb() is declared above in the code than newly created _win_toast_create().

Additional functions have been done, now let's use them.

Check if the point with the treasure entered the scroll area and if so, create and display the popup window with congratulation. Do this in the same scroller callback on the scrolling event.

static void
_scroll_cb(void *data, Evas_Object *scroller, void *event_info)
{
   ...
   	
   if (_is_point_in_circle(center_x, center_y, AREA_RADIUS, TREASURE_X, TREASURE_Y))
     {
        _win_toast_create(ui);
     }
}

The scroller behavior allows you to move sharply the scrolling area and for some time it will continue to scroll in the specified direction. It may happen that you have simultaneously created a lot of popup windows, so you have to explicitly stop the scroller if the target area is found.

In the library there is no special function to just stop scrolling, but there is a function that sets the region that scroller should show, it will done without animations, and no scroller callbacks will be invoked, this is exactly what is needed here. For this, call the following function immediately after the winning popup window creation.

elm_scroller_region_show(ui->scroller, x, y, w, h);

Sometimes in the application, there is a need to prevent moving of content in the scroller.

Specify to the widget or to the container, which is the main contents of the scroller, that scrolling is not available for these elements, it can be done separately for horizontal scrolling or for vertical scrolling.

elm_object_scroll_lock_x_set(ui->image, EINA_TRUE);
elm_object_scroll_lock_y_set(ui->image, EINA_TRUE);

If you want to "unfreeze" the widget scrolling, you should call these functions with the second parameter - EINA_FALSE.

In addition, let's remove the built-in scroller indicator widgets (blue stripes on the left and below), by using the following function:

elm_scroller_policy_set(ui->scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);

In this function, the 2nd and 3rd parameters refer to the horizontal and vertical widgets respectively. As such, you can pass the following values:

ELM_SCROLLER_POLICY_AUTO – automatically shows the indicator only during the scrolling, and hide in another time.

ELM_SCROLLER_POLICY_ON – always shows the indicator.

ELM_SCROLLER_POLICY_OFF – never shows the indicator.

That would be all for this lesson. Now you may see what kind of game you supposed to get.

The complete source code of this tutorial is available here WearLesson019.

Leave a Reply

Your email address will not be published. Required fields are marked *