70808dc693682fb3b50b94bc12dc22d060bdde1b
[platform/core/security/krate.git] / tools / apps / kaskit / src / ui.c
1 /*
2  * Tizen Krate launcher application
3  *
4  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 #include "kaskit.h"
20 #include "widget.h"
21 #include "conf.h"
22
23 static uidata_s ud = {0, };
24
25 static int __num_of_apps = 0;
26 static bool __is_edit_mode = false;
27 static Ecore_Timer *__app_icon_long_press_timer = NULL;
28
29 static void __block_clicked_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
30 {
31         ui_app_exit();
32 }
33
34 static void __app_view_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
35 {
36         eina_list_free(ud.app_icon_list);
37 }
38
39 static void __set_kaskit_layout()
40 {
41         ud.panel = _create_layout(ud.layout, ud.edj_path, "popup_layout");
42
43         elm_object_part_content_set(ud.layout, "popup_window", ud.panel);
44
45         ud.scroller = elm_scroller_add(ud.panel);
46         elm_scroller_bounce_set(ud.scroller, EINA_FALSE, EINA_TRUE);
47         elm_scroller_policy_set(ud.scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
48         elm_object_part_content_set(ud.panel, "popup_content", ud.scroller);
49
50         ud.app_view = elm_table_add(ud.scroller);
51         elm_table_homogeneous_set(ud.app_view, EINA_TRUE);
52         elm_object_content_set(ud.scroller, ud.app_view);
53
54         evas_object_event_callback_add(ud.app_view, EVAS_CALLBACK_DEL, __app_view_del_cb, NULL);
55
56         return;
57 }
58
59 static char *__get_res_path(const char *file)
60 {
61         char *res_path = NULL;
62         char edj_path[PATH_MAX] = "\0";
63
64         res_path = app_get_resource_path();
65         if (res_path == NULL) {
66                 dlog_print(DLOG_ERROR, LOG_TAG, "failed get resource path");
67                 ui_app_exit();
68         }
69         snprintf(edj_path, PATH_MAX, "%s%s", res_path, file);
70
71         free(res_path);
72
73         return strdup(edj_path);
74 }
75
76 static Eina_Bool key_event_cb(void *data, int type, void *event)
77 {
78         Evas_Event_Key_Down *ev = (Evas_Event_Key_Down *)event;
79
80         if (!strcmp(ev->keyname, "XF86Back")) {
81                 Evas_Object *icon;
82                 Eina_List *i;
83
84                 if (__is_edit_mode) {
85                         __is_edit_mode = false;
86
87                         EINA_LIST_FOREACH(ud.app_icon_list, i, icon) {
88                                 elm_object_signal_emit(icon, "uninstall_button_hide", "source");
89                                 elm_object_signal_emit(icon, "icon_sub_badge_show", "source");
90                         }
91                 } else {
92                         ui_app_exit();
93                 }
94         }
95
96         return EINA_TRUE;
97 }
98
99 void _create_kaskit_window()
100 {
101         ud.edj_path = __get_res_path(PACKAGE ".edj");
102         ud.win = _create_win(PACKAGE);
103         ud.conform = _create_conformant(ud.win);
104         ud.layout = _create_layout(ud.conform, ud.edj_path, "main_window");
105         elm_object_content_set(ud.conform, ud.layout);
106
107         __set_kaskit_layout();
108
109         evas_object_show(ud.win);
110
111         return;
112 }
113
114 void _set_kaskit_window_exit_cb()
115 {
116         ecore_event_handler_add(ECORE_EVENT_KEY_DOWN, key_event_cb, NULL);
117
118         elm_object_signal_callback_add(ud.layout, "bg_clicked", "layout", __block_clicked_cb, NULL);
119 }
120
121 static Eina_Bool __app_icon_long_press_cb(void *data)
122 {
123         Evas_Object *icon;
124         Eina_List *i;
125
126         EINA_LIST_FOREACH(ud.app_icon_list, i, icon) {
127                 if (evas_object_data_get(icon, "removable")) {
128                         elm_object_signal_emit(icon, "uninstall_button_show", "source");
129                 }
130                 elm_object_signal_emit(icon, "icon_sub_badge_hide", "source");
131         }
132
133         __is_edit_mode = true;
134
135         return ECORE_CALLBACK_CANCEL;
136 }
137
138 void _set_kaskit_window_title(const char *title)
139 {
140         elm_object_part_text_set(ud.panel, "popup_title", title);
141 }
142
143 static int __icon_down_x, __icon_down_y;
144 static void __app_icon_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
145 {
146         Evas_Event_Mouse_Up *ev = event_info;
147
148         __icon_down_x = ev->output.x;
149         __icon_down_y = ev->output.y;
150
151         __app_icon_long_press_timer = ecore_timer_add(LONG_PRESS_TIME, __app_icon_long_press_cb, NULL);
152 }
153
154 static void __app_icon_move_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
155 {
156         Evas_Event_Mouse_Up *ev = event_info;
157
158         int distance_x = (ev->output.x - __icon_down_x);
159         int distance_y = (ev->output.y - __icon_down_y);
160         int distance = distance_x * distance_x + distance_y * distance_y;
161
162         if (distance > ALLOWED_ICON_DRAG_DISTANCE) {
163                 if (__app_icon_long_press_timer != NULL) {
164                         ecore_timer_del(__app_icon_long_press_timer);
165                         __app_icon_long_press_timer = NULL;
166                 }
167         }
168 }
169
170 static void __app_icon_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
171 {
172         Evas_Event_Mouse_Up *ev = event_info;
173
174         int distance_x = (ev->output.x - __icon_down_x);
175         int distance_y = (ev->output.y - __icon_down_y);
176         int distance = distance_x * distance_x + distance_y * distance_y;
177
178         if (distance <= ALLOWED_ICON_DRAG_DISTANCE && !__is_edit_mode) {
179                 _icon_clicked_cb(evas_object_data_get(obj, "id"));
180         }
181
182         if (__app_icon_long_press_timer != NULL) {
183                 ecore_timer_del(__app_icon_long_press_timer);
184                 __app_icon_long_press_timer = NULL;
185         }
186 }
187
188 static void __app_icon_del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
189 {
190         free(evas_object_data_get(obj, "id"));
191         free(evas_object_data_get(obj, "package"));
192 }
193
194 static void __app_icon_uninstall_btn_clicked_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
195 {
196         _icon_uninstalled_cb(evas_object_data_get(obj, "package"));
197 }
198
199 void _create_app_icon(const char *pkg_id, const char *app_id, const char *label, const char *icon, bool removable)
200 {
201         char string[1024] = {0, }, *default_icon;
202         Evas_Object *icon_layout;
203         Evas_Object *icon_image;
204
205         icon_layout = _create_layout(ud.app_view, ud.edj_path, "icon");
206         evas_object_size_hint_weight_set(icon_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
207         evas_object_size_hint_align_set(icon_layout, 0.0, 0.0);
208
209         icon_image = elm_image_add(icon_layout);
210         if (ecore_file_can_read(icon)) {
211                 elm_image_file_set(icon_image, icon, NULL);
212         } else {
213                 default_icon = __get_res_path("images/default_app_icon.png");
214                 elm_image_file_set(icon_image, default_icon, NULL);
215                 free(default_icon);
216         }
217         evas_object_size_hint_min_set(icon_image, ICON_IMG_SIZE, ICON_IMG_SIZE);
218         evas_object_size_hint_max_set(icon_image, ICON_IMG_SIZE, ICON_IMG_SIZE);
219
220         snprintf(string, sizeof(string), "<font_size=%d><color=#%s><shadow_color=#%s>%s</shadow_color></color></font_size>",
221                          ICON_TXT_SIZE_NORMAL, ICON_TXT_COLOR, ICON_TXT_SHADOW_COLOR,
222                          label);
223         elm_object_part_text_set(icon_layout, "icon_name", string);
224
225         elm_object_part_content_set(icon_layout, "icon_content", icon_image);
226
227         evas_object_data_set(icon_layout, "id", strdup(app_id));
228         evas_object_data_set(icon_layout, "package", strdup(pkg_id));
229         evas_object_data_set(icon_layout, "removable", (const void *)removable);
230
231         evas_object_event_callback_add(icon_layout, EVAS_CALLBACK_DEL, __app_icon_del_cb, NULL);
232         evas_object_event_callback_add(icon_layout, EVAS_CALLBACK_MOUSE_DOWN, __app_icon_down_cb, NULL);
233         evas_object_event_callback_add(icon_layout, EVAS_CALLBACK_MOUSE_MOVE, __app_icon_move_cb, NULL);
234         evas_object_event_callback_add(icon_layout, EVAS_CALLBACK_MOUSE_UP, __app_icon_up_cb, NULL);
235
236         elm_object_signal_callback_add(icon_layout, "uninstall_button_clicked", "source", __app_icon_uninstall_btn_clicked_cb, NULL);
237
238         elm_table_pack(ud.app_view, icon_layout, __num_of_apps % 3, __num_of_apps / 3, 1, 1);
239         evas_object_size_hint_min_set(ud.app_view, 0, (__num_of_apps / 3 + 1) * ICON_SIZE_H);
240
241         ud.app_icon_list = eina_list_append(ud.app_icon_list, icon_layout);
242
243         __num_of_apps++;
244
245         evas_object_show(icon_image);
246         evas_object_show(icon_layout);
247
248         if (__is_edit_mode && removable) {
249                 elm_object_signal_emit(icon_layout, "uninstall_button_show", "source");
250         }
251 }
252
253 void _destroy_app_icon(const char *pkg_id)
254 {
255         int index = 0;
256         Eina_List *i, *i_next;
257         Evas_Object *app_icon;
258         char *app_pkg_id;
259
260         EINA_LIST_FOREACH_SAFE(ud.app_icon_list, i, i_next, app_icon) {
261                 app_pkg_id = evas_object_data_get(app_icon, "package");
262                 if (strncmp(app_pkg_id, pkg_id, PATH_MAX)) {
263                         elm_table_pack(ud.app_view, app_icon, index % 3, index / 3, 1, 1);
264                         evas_object_size_hint_min_set(ud.app_view, 0, (__num_of_apps / 3 + 1) * ICON_SIZE_H);
265                         index++;
266                         continue;
267                 }
268                 elm_table_unpack(ud.app_view, app_icon);
269                 evas_object_del(app_icon);
270                 evas_object_size_hint_min_set(ud.app_view, 0, (__num_of_apps / 3 + 1) * ICON_SIZE_H);
271                 ud.app_icon_list = eina_list_remove_list(ud.app_icon_list, i);
272         }
273         __num_of_apps--;
274         evas_object_size_hint_min_set(ud.app_view, 0, (__num_of_apps / 3 + 1) * ICON_SIZE_H);
275 }
276
277 void _update_app_icon_badge(const char *app_id, unsigned int count)
278 {
279         Eina_List *i, *i_next;
280         Evas_Object *app_icon;
281         char str[8], *icon_app_id;
282
283         EINA_LIST_FOREACH_SAFE(ud.app_icon_list, i, i_next, app_icon) {
284                 icon_app_id = evas_object_data_get(app_icon, "id");
285                 if (strncmp(icon_app_id, app_id, PATH_MAX) == 0) {
286                         if (count == 0) {
287                                 elm_object_signal_emit(app_icon, "icon_badge_hide", "source");
288                                 break;
289                         }
290
291                         if (count > MAX_BADGE_DISPLAY_COUNT) {
292                                 snprintf(str, 8, "%d+", MAX_BADGE_DISPLAY_COUNT);
293                         } else {
294                                 snprintf(str, 8, "%d", count);
295                         }
296                         elm_layout_text_set(app_icon, "badge_text", str);
297                         elm_object_signal_emit(app_icon, "icon_badge_show", "source");
298                         break;
299                 }
300         }
301 }