Puzzle / src /
view.c
- /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd
- *
- * Licensed under the Flora License, Version 1.1 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://floralicense.org/license/
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #include <Elementary.h>
- #include <efl_extension.h>
- #include "view.h"
- #include "view_defines.h"
- #include "$(appName).h"
- #define IMG_SMILE "smile.jpg"
- #define IMG_CORRECT "correct.jpg"
- #define PUZZLE_RATIO 0.6
- #define MENU_RATIO 0.2
- #define PUZZLE_SIZE_LEVEL_4 4
- #define PUZZLE_SIZE_LEVEL_5 5
- #define IMAGE_PREVIEW_SIZE 0.5
- #define MAX_SHUFFLE_COUNT 70
- #define PIECE_COUNT PUZZLE_SIZE_LEVEL_5 * PUZZLE_SIZE_LEVEL_5 + 1
- typedef enum {NB_UP, NB_DOWN, NB_LEFT, NB_RIGHT} navi_button_e;
- static struct view_info {
- Evas_Object *win;
- Evas_Object *conform;
- Evas_Object *radio_group;
- int radio_selector;
- Evas_Object *piece[PIECE_COUNT];
- int piece_pos[PIECE_COUNT];
- Evas* e;
- int full_image_width;
- int full_image_height;
- int origin_image_width;
- int origin_image_height;
- int puzzle_start_x;
- int puzzle_start_y;
- int white_piece;
- int size;
- int screen_width;
- int screen_height;
- int r;
- int g;
- int b;
- int a;
- int start;
- bool shuffling;
- int shuffle_count;
- int level;
- } s_info = {
- .win = NULL,
- .conform = NULL,
- .radio_group = NULL,
- .radio_selector = 0,
- .piece = {NULL,},
- .piece_pos = {0,},
- .e = NULL,
- .full_image_width = 0,
- .full_image_height = 0,
- .origin_image_width = 0,
- .origin_image_height = 0,
- .puzzle_start_x = 0,
- .puzzle_start_y = 0,
- .white_piece = 0,
- .size = 0,
- .screen_width = 0,
- .screen_height = 0,
- .r = 0,
- .g = 0,
- .b = 0,
- .a = 0,
- .start = 0,
- .shuffling = 0,
- .shuffle_count = 0,
- .level = 0,
- };
- static void _delete_win_request_cb(void *data, Evas_Object *obj, void *event_info);
- static void _layout_back_cb(void *data, Evas_Object *obj, void *event_info);
- static void _popup_close_cb(void *data, Evas_Object *obj, void *event_info);
- static void _popup_level_accept_cb(void *data, Evas_Object *obj, void *event_info);
- static void _answer_icon_click_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
- static void _level_icon_click_cb(void* data, Evas *e, Evas_Object *obj, void *event_info);
- static void _shuffle_icon_click_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
- static void _navigation_button_cb(void *data, Evas_Object *obj, void *event_info);
- static Eina_Bool _shuffle_cb(void *data);
- static void _get_app_resource(const char *edj_file_in, char *edj_path_out);
- static bool _create_main_layout(void);
- static bool _create_menu(Evas_Object *parent);
- static bool _create_navigation(Evas_Object *parent);
- static void _create_puzzle(int level);
- static void _move_puzzle(int offset);
- static bool _check_puzzle_move(navi_button_e nb_type);
- static void _change_size(int level);
- static void _finished(void);
- /**
- * @brief Creates essential objects: window, conformant and layout.
- */
- Eina_Bool view_create(void *user_data)
- {
- /* Create the 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 EINA_FALSE;
- }
- elm_win_screen_size_get(s_info.win, NULL, NULL, &s_info.screen_width, &s_info.screen_height);
- /* Create the 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 EINA_FALSE;
- }
- if (!_create_main_layout())
- return EINA_FALSE;
- /* Show the window after main view is set up */
- evas_object_show(s_info.win);
- return EINA_TRUE;
- }
- /**
- * @brief Creates a basic window named package.
- * @param[in] pkg_name Name of the window
- */
- Evas_Object *view_create_win(const char *pkg_name)
- {
- Evas_Object *win = NULL;
- /*
- * Window
- * Create and initialize elm_win.
- * elm_win is mandatory to manipulate the window.
- */
- win = elm_win_util_standard_add(pkg_name, pkg_name);
- elm_win_conformant_set(win, EINA_TRUE);
- elm_win_autodel_set(win, EINA_TRUE);
- elm_win_indicator_mode_set(win, ELM_WIN_INDICATOR_HIDE);
- elm_win_indicator_opacity_set(win, ELM_WIN_INDICATOR_OPAQUE);
- evas_object_smart_callback_add(win, "delete,request", _delete_win_request_cb, NULL);
- return win;
- }
- /**
- * @brief Creates a layout object for parent object based on provided EDJE script.
- * @param[in] parent The parent object for layout object.
- * @param[in] edj_file_name The relative path to the layout EDJE script.
- * @param[in] edj_group The name of the group to be loaded from the EDJE script.
- * @param[in] part_name The EDJE part's name where the layout is to be set.
- * @return The function returns layout object if it was created successfully,
- * otherwise 'NULL' is returned.
- */
- Evas_Object *view_create_layout(Evas_Object *parent, const char *edj_file_name, const char *group_name, const char *part_name)
- {
- char edj_path[PATH_MAX] = {0, };
- Evas_Object *layout = NULL;
- _get_app_resource(edj_file_name, edj_path);
- layout = elm_layout_add(parent);
- if (!layout) {
- dlog_print(DLOG_ERROR, LOG_TAG, "elm_layout_add() failed.");
- return NULL;
- }
- if (!elm_layout_file_set(layout, edj_path, group_name)) {
- dlog_print(DLOG_ERROR, LOG_TAG, "elm_layout_file_set() failed.");
- return NULL;
- }
- evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
- eext_object_event_callback_add(layout, EEXT_CALLBACK_BACK, _layout_back_cb, NULL);
- if (!part_name)
- elm_object_content_set(parent, layout);
- else
- elm_object_part_content_set(parent, part_name, layout);
- evas_object_show(layout);
- return layout;
- }
- /**
- * @brief Creates a conformant without indicator for wearable app.
- * @param[in] win The object to which you want to set this conformant
- * Conformant is mandatory for base GUI to have proper size
- */
- Evas_Object *view_create_conformant_without_indicator(Evas_Object *win)
- {
- /*
- * Conformant
- * Create and initialize elm_conformant.
- * elm_conformant is mandatory for base GUI to have proper size
- * when indicator or virtual keypad is visible.
- */
- Evas_Object *conform = NULL;
- if (win == NULL) {
- dlog_print(DLOG_ERROR, LOG_TAG, "window is NULL.");
- return NULL;
- }
- conform = elm_conformant_add(win);
- evas_object_size_hint_weight_set(conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
- elm_win_resize_object_add(win, conform);
- evas_object_show(conform);
- return conform;
- }
- /**
- * @brief Creates an icon object and sets it to the parent object.
- * The icon displays an standard image specified by icon_type.
- * @param[in] parent The parent object for icon object.
- * @param[in] icon_type The icon type name.
- * @param[in] part_name The EDJE part's name where the icon is to be set.
- * @return The function returns icon object if it was created successfully,
- * otherwise 'NULL' is returned.
- */
- Evas_Object *view_create_icon(Evas_Object *parent, const char *icon_type, const char *part_name)
- {
- Evas_Object *icon = elm_icon_add(parent);
- if (!icon) {
- dlog_print(DLOG_ERROR, LOG_TAG, "elm_icon_add() failed.");
- return NULL;
- };
- if (!elm_icon_standard_set(icon, icon_type)) {
- dlog_print(DLOG_ERROR, LOG_TAG, "elm_icon_standard_set() failed. No '%s' icon.", icon_type);
- return NULL;
- }
- elm_object_part_content_set(parent, part_name, icon);
- evas_object_show(icon);
- return icon;
- }
- /**
- * @brief Creates an image object and sets it to the parent object.
- * @param[in] parent The parent object for image object.
- * @param[in] file_name The name of the image file to be displayed.
- * @param[in] part_name The EDJE part's name where the image is to be set.
- * @param[in] width The width of the image in pixels.
- * @param[in] height The height of the image in pixels.
- * @return The function returns image object if it was created successfully,
- * otherwise 'NULL' is returned.
- */
- Evas_Object *view_create_image(Evas_Object *parent, const char *file_name, const char *part_name, int width, int height)
- {
- char img_path[PATH_MAX] = {0, };
- Evas_Object *image = elm_image_add(parent);
- if (!image) {
- dlog_print(DLOG_ERROR, LOG_TAG, "elm_image_add() failed.");
- return NULL;
- };
- _get_app_resource(file_name, img_path);
- if (!elm_image_file_set(image, img_path, NULL)) {
- dlog_print(DLOG_ERROR, LOG_TAG, "elm_image_file_set() failed.");
- return NULL;
- }
- elm_image_aspect_fixed_set(image, EINA_TRUE);
- evas_object_size_hint_min_set(image, width, height);
- evas_object_size_hint_max_set(image, width, height);
- elm_object_part_content_set(parent, part_name, image);
- evas_object_show(image);
- return image;
- }
- /**
- * @brief Creates a button object for the parent object.
- * @param[in] parent The parent object for button object.
- * @param[in] caption The caption to be displayed on the button.
- * @param[in] part_name The part name where the button is to be set.
- * @param[in] on_click_cb The callback function's handler to be invoked on button click.
- * @param[in] data The data to be passed to the callback function.
- * @return The function returns button object if it was created successfully,
- * otherwise 'NULL' is returned.
- */
- Evas_Object *view_create_button(Evas_Object *parent, const char *caption, const char *part_name, Evas_Smart_Cb on_click_cb, void *data)
- {
- Evas_Object *button = elm_button_add(parent);
- if (!button) {
- dlog_print(DLOG_ERROR, LOG_TAG, "elm_button_add() failed.");
- return NULL;
- }
- 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, caption);
- elm_object_part_content_set(parent, part_name, button);
- evas_object_smart_callback_add(button, "clicked", on_click_cb, data);
- evas_object_show(button);
- return button;
- }
- /**
- * @brief Creates a popup window with 'OK' button set.
- * @param[in] title The popup window title.
- * @param[in] button1 The first button caption.
- * @param[in] on_click1_cb The first button's callback function invoked on click event.
- * @param[in] button2 The second button caption.
- * @param[in] on_click2_cb The second button's callback function invoked on click event.
- * @return This function returns popup window object if it was successfully created,
- * otherwise 'false' is returned.
- */
- Evas_Object *view_create_popup(const char *title, const char *button1, Evas_Smart_Cb on_click1_cb, const char *button2, Evas_Smart_Cb on_click2_cb)
- {
- Evas_Object *button;
- Evas_Object *popup = elm_popup_add(s_info.win);
- if (!popup) {
- dlog_print(DLOG_ERROR, LOG_TAG, "elm_popup_add() failed.");
- return NULL;
- }
- elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
- elm_object_part_text_set(popup, "title,text", title);
- if (button1) {
- button = view_create_button(popup, button1, "button1", on_click1_cb, (void *)popup);
- if (!button) {
- evas_object_del(popup);
- return NULL;
- }
- }
- if (button2) {
- button = view_create_button(popup, button2, "button2", on_click2_cb, (void *)popup);
- if (!button) {
- evas_object_del(popup);
- return NULL;
- }
- }
- evas_object_show(popup);
- return popup;
- }
- /**
- * @brief Creates a radio button within a group of radio buttons and sets it to the parent object.
- * @param[in] parent The parent object for radio button.
- * @param[in] part_name The part name where the radio is to be set.
- * @param[in] v_pointer The pointer to the selected item's id.
- * @return This function returns radio button object if it was successfully created,
- * otherwise 'false' is returned.
- */
- Evas_Object *view_create_radio(Evas_Object *parent, const char *part_name, int *v_pointer)
- {
- static int radio_id = 0;
- Evas_Object *radio = elm_radio_add(parent);
- if (!radio) {
- dlog_print(DLOG_ERROR, LOG_TAG, "elm_radio_add() failed.");
- return NULL;
- }
- if (!s_info.radio_group) {
- radio_id = 0;
- s_info.radio_group = radio;
- elm_radio_value_pointer_set(radio, v_pointer);
- } else {
- elm_radio_group_add(radio, s_info.radio_group);
- }
- elm_radio_state_value_set(radio, radio_id++);
- evas_object_size_hint_align_set(radio, EVAS_HINT_FILL, EVAS_HINT_FILL);
- evas_object_size_hint_weight_set(radio, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
- elm_object_part_content_set(parent, part_name, radio);
- evas_object_show(radio);
- return radio;
- }
- /**
- * @brief Destroys window and frees its resources.
- */
- void view_destroy(void)
- {
- if (s_info.win == NULL)
- return;
- evas_object_del(s_info.win);
- }
- /**
- * @brief Internal callback function invoked when the main window needs to be destroyed.
- * @param[in] data The user data passed to the evas_object_smart_callback_add() function.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- static void _delete_win_request_cb(void *data, Evas_Object *obj, void *event_info)
- {
- ui_app_exit();
- }
- /**
- * @brief Internal callback function invoked when the HW Back button is pressed.
- * @param[in] data The user data passed to the eext_object_event_callback_add() function.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- static void _layout_back_cb(void *data, Evas_Object *obj, void *event_info)
- {
- /* Let window go to hide state. */
- elm_win_lower(s_info.win);
- }
- /**
- * @brief Internal callback function invoked when the 'Close' button is pressed
- * while popup window is visible.
- * @param[in] data The user data passed to the callback attachment function.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- static void _popup_close_cb(void *data, Evas_Object *obj, void *event_info)
- {
- s_info.radio_group = NULL;
- evas_object_del((Evas_Object *)data);
- }
- /**
- * @brief Internal callback function invoked when the 'OK' button is pressed
- * while popup window is visible.
- * @param[in] data The user data passed to the callback attachment function.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- static void _popup_level_accept_cb(void *data, Evas_Object *obj, void *event_info)
- {
- if (s_info.level != s_info.radio_selector) {
- if (s_info.radio_selector == 0)
- _change_size(PUZZLE_SIZE_LEVEL_4);
- else if (s_info.radio_selector == 1)
- _change_size(PUZZLE_SIZE_LEVEL_5);
- s_info.level = s_info.radio_selector;
- }
- _popup_close_cb(data, obj, event_info);
- }
- /**
- * @brief Internal callback function invoked when the 'answer' icon is pressed.
- * @param[in] data The user data passed to the callback attachment function.
- * @param[in] e The evas surface of the object.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- static void _answer_icon_click_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
- {
- Evas_Object *popup;
- int width = 0;
- popup = view_create_popup("Answer", "Close", _popup_close_cb, NULL, NULL);
- if (!popup)
- return;
- elm_win_screen_size_get(s_info.win, NULL, NULL, &width, NULL);
- if (!view_create_image(popup, IMG_SMILE, "default", width * IMAGE_PREVIEW_SIZE, width * IMAGE_PREVIEW_SIZE)) {
- evas_object_del(popup);
- return;
- }
- evas_object_show(popup);
- }
- /**
- * @brief Internal callback function invoked when the 'level' icon is pressed.
- * @param[in] data The user data passed to the callback attachment function.
- * @param[in] e The evas surface of the object.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- static void _level_icon_click_cb(void* data, Evas *e, Evas_Object *obj, void *event_info)
- {
- Evas_Object *popup;
- Evas_Object *layout;
- popup = view_create_popup("Level", "OK", _popup_level_accept_cb, "Close", _popup_close_cb);
- if (!popup)
- return;
- layout = view_create_layout(popup, EDJ_MAIN, GRP_POPUP, "default");
- if (!layout) {
- evas_object_del(popup);
- return;
- }
- view_create_radio(layout, PART_POPUP_ITEM_1, &s_info.radio_selector);
- view_create_radio(layout, PART_POPUP_ITEM_2, &s_info.radio_selector);
- evas_object_show(popup);
- }
- /**
- * @brief Internal callback function invoked when the 'shuffle' icon is pressed.
- * @param[in] data The user data passed to the callback attachment function.
- * @param[in] e The evas surface of the object.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- static void _shuffle_icon_click_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
- {
- Ecore_Animator *animator;
- if (s_info.shuffling)
- return;
- s_info.shuffle_count = 0;
- s_info.shuffling = true;
- animator = ecore_animator_add(_shuffle_cb, NULL);
- }
- /**
- * @brief Internal callback function invoked when one of the navigation buttons is pressed.
- * @param[in] data The user data passed to the callback attachment function.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- static void _navigation_button_cb(void *data, Evas_Object *obj, void *event_info)
- {
- navi_button_e nb_type = (navi_button_e)data;
- if (!_check_puzzle_move(nb_type))
- return;
- switch (nb_type) {
- case NB_UP:
- _move_puzzle(s_info.size);
- break;
- case NB_DOWN:
- _move_puzzle(-s_info.size);
- break;
- case NB_LEFT:
- _move_puzzle(1);
- break;
- case NB_RIGHT:
- _move_puzzle(-1);
- break;
- default:
- dlog_print(DLOG_WARN, LOG_TAG, "Unknown navigation button type.");
- }
- }
- /**
- * @brief Internal callback function invoked when the mouse button is pressed
- * over the puzzle piece.
- * This function performs selected piece highlighting.
- * @param[in] data The user data passed to the callback attachment function.
- * @param[in] e The evas surface of the object.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- void _mouse_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
- {
- Evas_Object *piece = obj;
- int pos = (int)evas_object_data_get(piece, "position");
- int r, g, b, a;
- if (pos == (int)evas_object_data_get(s_info.piece[s_info.white_piece], "position"))
- return;
- evas_object_color_get(piece, &r, &g, &b, &a);
- evas_object_color_set(piece, r, g, b, 200);
- evas_object_show(piece);
- }
- /**
- * @brief Internal callback function invoked when the mouse button is released
- * from the puzzle piece.
- * This function performs selected piece movement to the white space.
- * @param[in] data The user data passed to the callback attachment function.
- * @param[in] e The evas surface of the object.
- * @param[in] obj The object invoking this callback function.
- * @param[in] event_info The structure containing the information on this event.
- */
- void _mouse_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
- {
- Evas_Object *piece = obj;
- int pos = (int)evas_object_data_get(piece, "position");
- if (pos == (int)evas_object_data_get(s_info.piece[s_info.white_piece], "position"))
- return;
- evas_object_color_set(piece, 255, 255, 255, 255);
- if (pos - s_info.size == s_info.white_piece)
- _navigation_button_cb((void *)NB_UP, NULL, NULL);
- else if (pos - 1 == s_info.white_piece && ((s_info.white_piece + 1) % s_info.size))
- _navigation_button_cb((void *)NB_LEFT, NULL, NULL);
- else if (pos + 1 == s_info.white_piece && (s_info.white_piece % s_info.size))
- _navigation_button_cb((void *)NB_RIGHT, NULL, NULL);
- else if (pos + s_info.size == s_info.white_piece)
- _navigation_button_cb((void *)NB_DOWN, NULL, NULL);
- evas_object_show(piece);
- }
- /**
- * @brief Internal callback function invoked on pieces shuffling animation.
- * @param[in] data The user data passed to the callback attachment function.
- */
- static Eina_Bool _shuffle_cb(void *data)
- {
- navi_button_e nb_type = (navi_button_e)(rand() % 4);
- s_info.shuffle_count++;
- if (!_check_puzzle_move(nb_type))
- s_info.shuffle_count--;
- else
- _navigation_button_cb((void *)nb_type, NULL, NULL);
- if (s_info.shuffle_count < MAX_SHUFFLE_COUNT) {
- return ECORE_CALLBACK_RENEW;
- } else {
- s_info.shuffling = false;
- return ECORE_CALLBACK_CANCEL;
- }
- }
- /**
- * @brief Internal function which creates fully qualified path to the provided resource file.
- * @param[in] edj_file_in The file name.
- * @param[out] edj_path_out The fully qualified path to the edj_file_in file.
- */
- static void _get_app_resource(const char *edj_file_in, char *edj_path_out)
- {
- char *res_path = app_get_resource_path();
- if (res_path) {
- snprintf(edj_path_out, PATH_MAX, "%s%s", res_path, edj_file_in);
- free(res_path);
- }
- }
- /**
- * @brief Internal function which creates the main layout.
- * @return This function returns 'true' if the main layout was created successfully,
- * otherwise 'false' is returned.
- */
- static bool _create_main_layout(void)
- {
- Evas_Object *layout = NULL;
- layout = view_create_layout(s_info.conform, EDJ_MAIN, GRP_MAIN, "elm.swallow.content");
- if (!layout)
- return false;
- s_info.e = evas_object_evas_get(layout);
- if (!s_info.e)
- return false;
- if (!_create_menu(layout))
- return false;
- if (!_create_navigation(layout))
- return false;
- _create_puzzle(PUZZLE_SIZE_LEVEL_4);
- return true;
- }
- /**
- * @brief Internal function which creates the top menu layout.
- * The menu consists of three icons (buttons): answer preview, level selection, puzzle shuffle.
- * @return This function returns 'true' if the menu layout was created successfully,
- * otherwise 'false' is returned.
- */
- static bool _create_menu(Evas_Object *parent)
- {
- Evas_Object *layout;
- Evas_Object *answer;
- Evas_Object *level;
- Evas_Object *shuffle;
- layout = view_create_layout(parent, EDJ_MAIN, GRP_MENU, PART_MAIN_MENU);
- if (!layout)
- return false;
- answer = view_create_icon(layout, "no_photo", PART_MENU_ANSWER);
- if (!answer)
- return false;
- level = view_create_icon(layout, "file", PART_MENU_LEVEL);
- if (!level)
- return false;
- shuffle = view_create_icon(layout, "refresh", PART_MENU_SHUFFLE);
- if (!shuffle)
- return false;
- evas_object_event_callback_add(answer, EVAS_CALLBACK_MOUSE_UP, _answer_icon_click_cb, NULL);
- evas_object_event_callback_add(level, EVAS_CALLBACK_MOUSE_UP, _level_icon_click_cb, NULL);
- evas_object_event_callback_add(shuffle, EVAS_CALLBACK_MOUSE_UP, _shuffle_icon_click_cb, NULL);
- return true;
- }
- /**
- * @brief Internal function which creates the navigation layout.
- * The navigation consists of four buttons for puzzle pieces moving in four directions.
- * @return This function returns 'true' if the navigation layout was created successfully,
- * otherwise 'false' is returned.
- */
- static bool _create_navigation(Evas_Object *parent)
- {
- Evas_Object *layout = view_create_layout(parent, EDJ_MAIN, GRP_NAVI, PART_MAIN_NAVI);
- if (!layout)
- return false;
- return (view_create_button(layout, "UP", PART_NAVI_UP, _navigation_button_cb, (void *)NB_UP) &&
- view_create_button(layout, "DOWN", PART_NAVI_DOWN, _navigation_button_cb, (void *)NB_DOWN) &&
- view_create_button(layout, "LEFT", PART_NAVI_LEFT, _navigation_button_cb, (void *)NB_LEFT) &&
- view_create_button(layout, "RIGHT", PART_NAVI_RIGHT, _navigation_button_cb, (void *)NB_RIGHT));
- }
- /**
- * @brief Internal function which creates the puzzle image area.
- */
- static void _create_puzzle(int level)
- {
- char file_path[PATH_MAX] = {0,};
- int x, y;
- int extract_region_width, extract_region_height;
- int puzzle_width, puzzle_height;
- int i;
- int ret;
- _get_app_resource(IMG_SMILE, file_path);
- s_info.full_image_width = s_info.screen_width - (6 + 6);
- s_info.full_image_height = (s_info.screen_height * PUZZLE_RATIO) - (6 + 6);
- s_info.puzzle_start_x = 6;
- s_info.puzzle_start_y = (s_info.screen_height * MENU_RATIO) + 6;
- for (i = 0; i < PIECE_COUNT; i++) {
- s_info.piece[i] = evas_object_image_filled_add(s_info.e);
- s_info.piece_pos[i] = i;
- evas_object_image_file_set(s_info.piece[i], file_path, NULL);
- ret = evas_object_image_load_error_get(s_info.piece[i]);
- if (ret != EVAS_LOAD_ERROR_NONE)
- dlog_print(DLOG_ERROR, LOG_TAG, "Failed to load image");
- evas_object_data_set(s_info.piece[i], "position", (void *)i);
- }
- evas_object_image_size_get(s_info.piece[PIECE_COUNT - 1], &s_info.origin_image_width, &s_info.origin_image_height);
- extract_region_width = s_info.origin_image_width / level;
- extract_region_height = s_info.origin_image_height / level;
- puzzle_width = s_info.full_image_width / level;
- puzzle_height = s_info.full_image_height / level;
- for (y = 0; y < level; y++)
- for (x = 0; x < level; x++) {
- evas_object_move(s_info.piece[y * level + x], s_info.puzzle_start_x + x * (2 + puzzle_width), s_info.puzzle_start_y + y * (2 + puzzle_height));
- evas_object_image_load_region_set(s_info.piece[y * level + x], x * extract_region_width, y * extract_region_height, extract_region_width, extract_region_height);
- evas_object_resize(s_info.piece[y * level + x], puzzle_width, puzzle_height);
- evas_object_event_callback_add(s_info.piece[y * level + x], EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, NULL);
- evas_object_event_callback_add(s_info.piece[y * level + x], EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, NULL);
- if (y == level - 1 && x == level - 1) {
- evas_object_color_get(s_info.piece[y * level + x], &s_info.r, &s_info.g, &s_info.b, &s_info.a);
- evas_object_color_set(s_info.piece[y * level + x], s_info.r, s_info.g, s_info.b, 0);
- s_info.white_piece = y * level + x;
- }
- evas_object_show(s_info.piece[y * level + x]);
- }
- s_info.size = level;
- s_info.start = 0;
- }
- /**
- * @brief Internal function which moves the puzzle piece.
- * @param[in] offset The number of cells to move the current piece. In order to
- * specify a valid value, the puzzle image must be considered as a continuous
- * list (array) of cells. To move the current cell:
- * - down/up - the offset equals to +/-row_length;
- * - right/left - the offset equals to +/-1.
- */
- static void _move_puzzle(int offset)
- {
- int x1, y1, w1, h1;
- int x2, y2, w2, h2;
- int temp;
- int white_piece = s_info.white_piece;
- evas_object_image_load_region_get(s_info.piece[white_piece + offset], &x1, &y1, &w1, &h1);
- evas_object_image_load_region_get(s_info.piece[white_piece], &x2, &y2, &w2, &h2);
- evas_object_image_load_region_set(s_info.piece[white_piece + offset], x2, y2, w2, h2);
- evas_object_image_load_region_set(s_info.piece[white_piece], x1, y1, w1, h1);
- evas_object_color_set(s_info.piece[white_piece], s_info.r, s_info.g, s_info.b, s_info.a);
- evas_object_color_set(s_info.piece[white_piece + offset], s_info.r, s_info.g, s_info.b, 0);
- evas_object_show(s_info.piece[white_piece]);
- evas_object_show(s_info.piece[white_piece + offset]);
- temp = s_info.piece_pos[white_piece];
- s_info.piece_pos[white_piece] = s_info.piece_pos[white_piece + offset];
- s_info.piece_pos[white_piece + offset] = temp;
- s_info.white_piece = white_piece + offset;
- if (s_info.piece_pos[s_info.white_piece] == s_info.size * s_info.size - 1 && s_info.start == 1)
- _finished();
- }
- /**
- * @brief Internal function which checks whether the current puzzle can be moved
- * with the provided button type.
- * @param[in] nb_type The type of the navigation button to check against.
- * @return This function returns 'true' if the current piece can be moved using
- * the provided button type, otherwise 'false' is returned.
- */
- static bool _check_puzzle_move(navi_button_e nb_type)
- {
- switch (nb_type) {
- case NB_UP:
- return (s_info.white_piece + s_info.size < s_info.size * s_info.size);
- case NB_DOWN:
- return (s_info.white_piece - s_info.size >= 0);
- case NB_LEFT:
- return ((s_info.white_piece + 1) % s_info.size > 0);
- case NB_RIGHT:
- return (s_info.white_piece % s_info.size > 0);
- default:
- return false;
- }
- }
- /**
- * @brief Internal function which changes the puzzle size and recalculates all the
- * parameters and coordinates of each puzzle piece.
- * @param[in] level The number of pieces along one edge.
- */
- static void _change_size(int level)
- {
- char file_path[PATH_MAX] = {0,};
- int x, y;
- int extract_region_width, extract_region_height;
- int puzzle_width, puzzle_height;
- int i;
- _get_app_resource(IMG_SMILE, file_path);
- for (i = 0; i < PIECE_COUNT; i++) {
- evas_object_color_set(s_info.piece[i], s_info.r, s_info.g, s_info.b, 0);
- evas_object_show(s_info.piece[i]);
- evas_object_move(s_info.piece[i], 0, 0);
- }
- extract_region_width = s_info.origin_image_width / level;
- extract_region_height = s_info.origin_image_height / level;
- puzzle_width = s_info.full_image_width / level;
- puzzle_height = s_info.full_image_height / level;
- for (y = 0; y < level; y++)
- for (x = 0; x < level; x++) {
- evas_object_color_set(s_info.piece[y * level + x], s_info.r, s_info.g, s_info.b, 255);
- evas_object_image_file_set(s_info.piece[y * level + x], file_path, NULL);
- evas_object_move(s_info.piece[y * level + x], s_info.puzzle_start_x + x * (2 + puzzle_width), s_info.puzzle_start_y + y * (2 + puzzle_height));
- evas_object_image_load_region_set(s_info.piece[y * level + x], x * extract_region_width, y * extract_region_height, extract_region_width, extract_region_height);
- evas_object_resize(s_info.piece[y * level + x], puzzle_width, puzzle_height);
- evas_object_event_callback_add(s_info.piece[y * level + x], EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, NULL);
- evas_object_event_callback_add(s_info.piece[y * level + x], EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, NULL);
- if (y == (level - 1) && x == (level - 1)) {
- evas_object_color_get(s_info.piece[y * level + x], &s_info.r, &s_info.g, &s_info.b, &s_info.a);
- evas_object_color_set(s_info.piece[y * level + x], s_info.r, s_info.g, s_info.b, 0);
- s_info.white_piece = y * level + x;
- }
- evas_object_show(s_info.piece[y * level + x]);
- }
- s_info.size = level;
- s_info.start = 0;
- }
- /**
- * @brief Internal function which validates the pieces arrangement correctness
- * and displays the final popup window if the validation is passed.
- */
- static void _finished(void)
- {
- Evas_Object *popup = NULL;
- int width = 0;
- int i;
- for (i = 0; i < s_info.size * s_info.size; i++)
- if (s_info.piece_pos[i] != i)
- return;
- popup = view_create_popup("Correct !!!", "OK", _popup_close_cb, NULL, NULL);
- if (!popup)
- return;
- elm_win_screen_size_get(s_info.win, NULL, NULL, &width, NULL);
- if (!view_create_image(popup, IMG_CORRECT, "default", width * IMAGE_PREVIEW_SIZE, width * IMAGE_PREVIEW_SIZE)) {
- evas_object_del(popup);
- return;
- }
- evas_object_show(popup);
- s_info.start = 0;
- }