tizen 2.4 release
[apps/home/attach-panel.git] / src / grid.c
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <aul.h>
18 #include <app_control.h>
19 #include <Elementary.h>
20 #include <rua.h>
21
22 #include "attach_panel.h"
23 #include "attach_panel_internal.h"
24 #include "attach_bundle.h"
25 #include "conf.h"
26 #include "content_list.h"
27 #include "gesture.h"
28 #include "grid.h"
29 #include "log.h"
30
31
32
33 static const char *const FILE_LAYOUT_EDJ = EDJEDIR"/layout.edj";
34 static const char *const PRIVATE_DATA_KEY_GRID_LIST = "p_g_lt";
35 static const char *const PRIVATE_DATA_KEY_GIC = "p_gic";
36 static const char *const PRIVATE_DATA_KEY_LIST_INDEX = "p_lt_ix";
37 static const char *const PRIVATE_DATA_KEY_ICON_WIDTH = "p_ic_w";
38 static const char *const PRIVATE_DATA_KEY_ICON_HEIGHT = "p_ic_h";
39 static const char *const PRIVATE_DATA_KEY_ITEM_WIDTH = "p_it_w";
40 static const char *const PRIVATE_DATA_KEY_ITEM_HEIGHT = "p_it_h";
41 static const char *const PRIVATE_DATA_KEY_ANIMATOR = "p_tm";
42 static const char *const DEFAULT_ICON = "/usr/share/icons/A01-1_icon_Menu.png";
43
44
45
46 Eina_Bool _grid_can_flick(attach_panel_h attach_panel)
47 {
48         content_s *current_content_info = NULL;
49         int content_h, grid_h;
50
51         if (attach_panel->rotate) {
52                 if (ATTACH_PANEL_STATE_FULL != attach_panel->attach_panel_land_state) {
53                         _D("panel is not full state(land mode)");
54                         return EINA_TRUE;
55                 }
56         } else {
57                 if (ATTACH_PANEL_STATE_FULL != attach_panel->attach_panel_port_state) {
58                         _D("panel is not full state(port mode)");
59                         evas_object_data_set(attach_panel->grid, DATA_KEY_EDGE_TOP, (void *) 1);
60                         return EINA_TRUE;
61                 }
62         }
63
64         current_content_info = eina_list_nth(attach_panel->content_list, attach_panel->cur_page_no);
65         retv_if(!current_content_info, EINA_TRUE);
66
67         if (attach_panel->grid != current_content_info->content) {
68                 _D("current page is ug page");
69                 return EINA_TRUE;
70         }
71
72         elm_scroller_child_size_get(attach_panel->grid, NULL, &content_h);
73         evas_object_geometry_get(attach_panel->grid, NULL, NULL, NULL, &grid_h);
74
75         if (content_h < grid_h) {
76                 _D("scrolling is not exist(grid size : %d, content size : %d", grid_h, content_h);
77                 return EINA_TRUE;
78         }
79
80         if (!evas_object_data_del(attach_panel->grid, DATA_KEY_EDGE_TOP)) {
81                 _D("grid can not reach the edge top");
82                 return EINA_FALSE;
83         }
84
85         return EINA_TRUE;
86 }
87
88
89
90 static char *__text_get(void *data, Evas_Object *obj, const char *part)
91 {
92         content_s *info = data;
93         innate_content_s *innate_content_info = NULL;
94         char *buf = NULL;
95         retv_if(!info, NULL);
96
97         innate_content_info = info->innate_content_info;
98         retv_if(!innate_content_info, NULL);
99         if (!strcmp(part, "elm.text")) {
100                 buf = elm_entry_utf8_to_markup(D_(innate_content_info->name));
101                 return buf;
102         }
103
104         return NULL;
105 }
106
107
108
109 static Evas_Object *__add_icon(Evas_Object *parent, const char *file)
110 {
111         const char *real_icon_file = NULL;
112         Evas_Object *icon = NULL;
113         Evas_Object *icon_layout = NULL;
114         int w, h;
115
116         real_icon_file = file;
117         if (access(real_icon_file, R_OK) != 0) {
118                 _E("Failed to access an icon(%s)", real_icon_file);
119                 real_icon_file = DEFAULT_ICON;
120         }
121
122         icon = elm_icon_add(parent);
123         retv_if(!icon, NULL);
124
125         if (elm_image_file_set(icon, real_icon_file, NULL) == EINA_FALSE) {
126                 _E("Icon file is not accessible (%s)", real_icon_file);
127                 evas_object_del(icon);
128                 return NULL;
129         }
130
131         w = (int) evas_object_data_get(parent, PRIVATE_DATA_KEY_ICON_WIDTH);
132         h = (int) evas_object_data_get(parent, PRIVATE_DATA_KEY_ICON_HEIGHT);
133         evas_object_size_hint_min_set(icon, w, h);
134
135         elm_image_preload_disabled_set(icon, EINA_TRUE);
136         elm_image_smooth_set(icon, EINA_TRUE);
137         elm_image_no_scale_set(icon, EINA_FALSE);
138         evas_object_show(icon);
139
140         icon_layout = elm_layout_add(parent);
141         retv_if(!icon_layout, NULL);
142
143         elm_layout_file_set(icon_layout, FILE_LAYOUT_EDJ, "grid,icon");
144         evas_object_size_hint_weight_set(icon_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
145         evas_object_size_hint_align_set(icon_layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
146         evas_object_show(icon_layout);
147
148         elm_object_part_content_set(icon_layout, "icon", icon);
149
150         return icon_layout;
151 }
152
153
154
155 static Evas_Object *__content_get(void *data, Evas_Object *obj, const char *part)
156 {
157         content_s *info = data;
158         innate_content_s *innate_content_info = NULL;
159
160         retv_if(!info, NULL);
161         innate_content_info = info->innate_content_info;
162         retv_if(!innate_content_info, NULL);
163
164         if (!strcmp(part, "elm.swallow.end")) {
165                 Evas_Object *bg = evas_object_rectangle_add(evas_object_evas_get(obj));
166                 retv_if(!bg, NULL);
167                 int w, h;
168
169                 w = (int) evas_object_data_get(obj, PRIVATE_DATA_KEY_ITEM_WIDTH);
170                 h = (int) evas_object_data_get(obj, PRIVATE_DATA_KEY_ITEM_HEIGHT);
171
172                 evas_object_size_hint_min_set(bg, w, h);
173                 evas_object_color_set(bg, 0, 0, 0, 0);
174                 evas_object_show(bg);
175                 return bg;
176         } else if (!strcmp(part, "elm.swallow.icon")) {
177                 retv_if(!innate_content_info->icon, NULL);
178                 return __add_icon(obj, innate_content_info->icon);
179         } else if (!strcmp(part, "selected")) {
180
181         }
182         return NULL;
183 }
184
185
186
187 static void __del(void *data, Evas_Object *obj)
188 {
189         ret_if(NULL == data);
190 }
191
192
193
194 static void __reply_cb(app_control_h request, app_control_h reply, app_control_result_e result, void *user_data)
195 {
196         content_s *content_info = user_data;
197         char **select = NULL;
198         int i = 0;
199         int length = 0;
200         int ret = APP_CONTROL_ERROR_NONE;
201
202         ret_if(!content_info);
203         ret_if(!content_info->attach_panel);
204
205         /* This is just for protocol log */
206         _D("relay callback is called");
207         ret = app_control_get_extra_data_array(reply, "http://tizen.org/appcontrol/data/selected", &select, &length);
208         if (APP_CONTROL_ERROR_NONE == ret && select) {
209                 for (i = 0; i < length; i++) {
210                         _D("selected is %s[%d]", select[i], i);
211                 }
212         }
213
214         ret = app_control_get_extra_data_array(reply, "http://tizen.org/appcontrol/data/path", &select, &length);
215         if (APP_CONTROL_ERROR_NONE == ret && select) {
216                 for (i = 0; i < length; i++) {
217                         _D("path is %s[%d]", select[i], i);
218                 }
219         }
220
221         if (content_info->attach_panel->result_cb) {
222                 content_info->attach_panel->result_cb(content_info->attach_panel
223                                 , content_info->innate_content_info->content_category
224                                 , reply
225                                 , result
226                                 , content_info->attach_panel->result_data);
227
228                 if (ATTACH_PANEL_STATE_FULL == _gesture_get_state()) {
229                         /* This is same with attach_panel_hide() */
230                         _content_list_set_pause(content_info->attach_panel->content_list, ATTACH_PANEL_CONTENT_CATEGORY_UG);
231                         _gesture_hide(content_info->attach_panel);
232                 }
233         } else {
234                 _D("content_info->attach_panel->result_cb is NULL");
235         }
236 }
237
238
239
240 static void __launch_app(content_s *content_info)
241 {
242         app_control_h app_control = NULL;
243         innate_content_s *innate_content_info = NULL;
244         char value[BUF_SIZE] = {0, };
245         int ret;
246
247         ret_if(!content_info);
248
249         innate_content_info = content_info->innate_content_info;
250         ret_if(!innate_content_info);
251
252         ret = app_control_create(&app_control);
253         ret_if(APP_CONTROL_ERROR_NONE != ret);
254
255         if (content_info->innate_content_info->operation) {
256                 ret = app_control_set_operation(app_control, content_info->innate_content_info->operation);
257                 if (APP_CONTROL_ERROR_NONE != ret)
258                         _E("Fail to set operation");
259         }
260
261         if (content_info->innate_content_info->mode) {
262                 snprintf(value, sizeof(value), "%d", content_info->innate_content_info->mode);
263                 ret = app_control_add_extra_data(app_control, "http://tizen.org/appcontrol/data/mode", value);
264                 if (APP_CONTROL_ERROR_NONE != ret)
265                         _E("Fail to add 'http://tizen.org/appcontrol/data/mode'");
266         }
267
268         if (content_info->innate_content_info->type) {
269                 ret = app_control_add_extra_data(app_control, "http://tizen.org/appcontrol/data/type", content_info->innate_content_info->type);
270                 if (APP_CONTROL_ERROR_NONE != ret)
271                         _E("Fail to add 'http://tizen.org/appcontrol/data/type'");
272         }
273
274         if (content_info->innate_content_info->item_type) {
275                 ret = app_control_add_extra_data(app_control, "http://tizen.org/appcontrol/data/item_type", content_info->innate_content_info->item_type);
276                 if (APP_CONTROL_ERROR_NONE != ret)
277                         _E("Fail to add 'http://tizen.org/appcontrol/data/item_type'");
278         }
279
280         if (content_info->innate_content_info->selection_mode) {
281                 ret = app_control_add_extra_data(app_control, APP_CONTROL_DATA_SELECTION_MODE, content_info->innate_content_info->selection_mode);
282                 if (APP_CONTROL_ERROR_NONE != ret)
283                         _E("Fail to add APP_CONTROL_DATA_SELECTION_MODE");
284         }
285
286         if (content_info->innate_content_info->mime) {
287                 ret = app_control_set_mime(app_control, content_info->innate_content_info->mime);
288                 if (APP_CONTROL_ERROR_NONE != ret)
289                         _E("Fail to set mime");
290         }
291
292         if (content_info->innate_content_info->max) {
293                 snprintf(value, sizeof(value), "%d", content_info->innate_content_info->max);
294                 ret = app_control_add_extra_data(app_control, "http://tizen.org/appcontrol/data/max", value);
295                 if (APP_CONTROL_ERROR_NONE != ret)
296                         _E("Fail to add 'http://tizen.org/appcontrol/data/max'");
297         }
298
299         if (content_info->extra_data) {
300                 _D("app control add the extra data for app");
301                 _bundle_add_to_app_control(content_info->extra_data, app_control);
302         }
303
304         ret = app_control_add_extra_data(app_control, AUL_SVC_K_RUA_STAT_CALLER, "attach-panel");
305         if (APP_CONTROL_ERROR_NONE != ret)
306                 _E("Fail to add 'AUL_SVC_K_RUA_STAT_CALLER'");
307
308         ret = app_control_add_extra_data(app_control, AUL_SVC_K_RUA_STAT_TAG, content_info->innate_content_info->appid);
309         if (APP_CONTROL_ERROR_NONE != ret)
310                 _E("Fail to add 'AUL_SVC_K_RUA_STAT_TAG'");
311
312         ret = app_control_add_extra_data(app_control, "__CALLER_PANEL__", "attach-panel");
313         if (APP_CONTROL_ERROR_NONE != ret)
314                 _E("Fail to add '__CALLER_PANEL__'");
315
316         ret = app_control_set_launch_mode(app_control, APP_CONTROL_LAUNCH_MODE_GROUP);
317         if (APP_CONTROL_ERROR_NONE != ret)
318                 _E("Fail to set launch mode");
319
320         ret = app_control_send_launch_request(app_control, __reply_cb, content_info);
321         if (APP_CONTROL_ERROR_NONE != ret)
322                 _E("Fail to send launch request");
323
324         app_control_destroy(app_control);
325 }
326
327
328
329 static void __item_selected(void *data, Evas_Object *obj, void *event_info)
330 {
331         content_s *info = data;
332         innate_content_s *innate_content_info = NULL;
333         Elm_Object_Item *selected_item = NULL;
334
335         ret_if(!info);
336         innate_content_info = info->innate_content_info;
337         ret_if(!innate_content_info);
338
339         selected_item = elm_gengrid_selected_item_get(obj);
340         ret_if(!selected_item);
341         elm_gengrid_item_selected_set(selected_item, EINA_FALSE);
342
343         _D("Selected an item[%s]", innate_content_info->operation);
344
345         __launch_app(info);
346 }
347
348
349
350 Eina_Bool __animator_cb(void *data)
351 {
352         Evas_Object *grid = data;
353         Elm_Gengrid_Item_Class *gic = NULL;
354         Eina_List *list = NULL;
355         content_s *info = NULL;
356
357         int index = 0;
358         int count = 0;
359
360         retv_if(!grid, ECORE_CALLBACK_CANCEL);
361
362         list = evas_object_data_get(grid, PRIVATE_DATA_KEY_GRID_LIST);
363         retv_if(!list, ECORE_CALLBACK_CANCEL);
364
365         gic = evas_object_data_get(grid, PRIVATE_DATA_KEY_GIC);
366         retv_if(!gic, ECORE_CALLBACK_CANCEL);
367
368         index = (int) evas_object_data_get(grid, PRIVATE_DATA_KEY_LIST_INDEX);
369
370         count = eina_list_count(list);
371         if (index == count) goto OUT;
372         info = eina_list_nth(list, index);
373         if (info && info->innate_content_info) {
374                 if (!info->innate_content_info->is_ug) {
375                         elm_gengrid_item_append(grid, gic, info, __item_selected, info);
376                 }
377         }
378         index++;
379         if (index == count) goto OUT;
380         evas_object_data_set(grid, PRIVATE_DATA_KEY_LIST_INDEX, (void *) index);
381
382         return ECORE_CALLBACK_RENEW;
383
384 OUT:
385         _D("Loading apps is done");
386
387         Elm_Object_Item *first_it = elm_gengrid_first_item_get(grid);
388         if (first_it) {
389                 elm_gengrid_item_bring_in(first_it, ELM_GENGRID_ITEM_SCROLLTO_TOP);
390         }
391         evas_object_data_del(grid, PRIVATE_DATA_KEY_LIST_INDEX);
392         evas_object_data_del(grid, PRIVATE_DATA_KEY_ANIMATOR);
393
394         return ECORE_CALLBACK_CANCEL;
395 }
396
397
398
399 void _grid_refresh(Evas_Object *grid)
400 {
401         Ecore_Animator *anim = NULL;
402
403         ret_if(!grid);
404
405         elm_gengrid_clear(grid);
406
407         anim = evas_object_data_del(grid, PRIVATE_DATA_KEY_ANIMATOR);
408         if (anim) {
409                 ecore_animator_del(anim);
410         }
411         anim = ecore_animator_add(__animator_cb, grid);
412         ret_if(!anim);
413
414         evas_object_data_set(grid, PRIVATE_DATA_KEY_ANIMATOR, anim);
415 }
416
417
418
419 static void __edge_top_cb(void *data, Evas_Object *grid, void *event_info)
420 {
421         ret_if(!grid);
422         _D("grid reach the edge top");
423         evas_object_data_set(grid, DATA_KEY_EDGE_TOP, (void *) 1);
424 }
425
426
427
428 static void __scroll_cb(void *data, Evas_Object *grid, void *event_info)
429 {
430         ret_if(!grid);
431         evas_object_data_del(grid, DATA_KEY_EDGE_TOP);
432 }
433
434
435
436 static void __lang_changed_cb(void *data, Evas_Object *grid, void *event_info)
437 {
438         ret_if(!grid);
439         elm_gengrid_realized_items_update(grid);
440 }
441
442
443
444 Evas_Object *_grid_create(Evas_Object *page, attach_panel_h attach_panel)
445 {
446         Evas_Object *grid = NULL;
447         Elm_Gengrid_Item_Class *gic = NULL;
448
449         int item_w = 0, item_h = 0, icon_size = 0;
450         int w, h;
451
452         retv_if(!attach_panel, NULL);
453
454         grid = elm_gengrid_add(page);
455         goto_if(!grid, ERROR);
456
457         evas_object_size_hint_weight_set(grid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
458         evas_object_size_hint_align_set(grid, EVAS_HINT_FILL, EVAS_HINT_FILL);
459
460         evas_object_geometry_get(attach_panel->conformant, NULL, NULL, &w, &h);
461
462         if (w < h) {
463                 item_w = w / GRID_ROW_COUNT;
464         } else {
465                 item_w = h / GRID_ROW_COUNT;
466         }
467         item_h = item_w * GRID_ITEM_HEIGHT_REL;
468         icon_size = item_h * GRID_ICON_SIZE_REL;
469         _D("item_size : %d, %d, icon_size : %d", item_w, item_h, icon_size);
470
471         evas_object_data_set(grid, PRIVATE_DATA_KEY_ITEM_WIDTH, (void *) item_w);
472         evas_object_data_set(grid, PRIVATE_DATA_KEY_ITEM_HEIGHT, (void *) item_h);
473         evas_object_data_set(grid, PRIVATE_DATA_KEY_ICON_WIDTH, (void *) icon_size);
474         evas_object_data_set(grid, PRIVATE_DATA_KEY_ICON_HEIGHT, (void *) icon_size);
475
476         elm_gengrid_item_size_set(grid, item_w, item_h);
477         elm_gengrid_align_set(grid, 0.0, 0.0);
478         elm_gengrid_horizontal_set(grid, EINA_FALSE);
479         elm_gengrid_multi_select_set(grid, EINA_FALSE);
480         elm_object_style_set(grid, "popup");
481
482         gic = elm_gengrid_item_class_new();
483         goto_if(!gic, ERROR);
484         gic->func.text_get = __text_get;
485         gic->func.content_get = __content_get;
486         gic->func.state_get = NULL;
487         gic->func.del = __del;
488         gic->item_style = "default";
489
490         evas_object_data_set(grid, PRIVATE_DATA_KEY_GRID_LIST, attach_panel->content_list);
491         evas_object_data_set(grid, PRIVATE_DATA_KEY_GIC, gic);
492         evas_object_data_set(grid, PRIVATE_DATA_KEY_LIST_INDEX, NULL);
493         evas_object_data_set(grid, DATA_KEY_EDGE_TOP, (void *)1);
494         evas_object_smart_callback_add(grid, "edge,top", __edge_top_cb, NULL);
495         evas_object_smart_callback_add(grid, "scroll", __scroll_cb, NULL);
496         evas_object_smart_callback_add(grid, "language,changed", __lang_changed_cb, NULL);
497
498         elm_scroller_movement_block_set(grid, ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL);
499
500         evas_object_show(grid);
501
502         return grid;
503
504 ERROR:
505         _grid_destroy(grid);
506         return NULL;
507 }
508
509
510
511 void _grid_destroy(Evas_Object *grid)
512 {
513         ret_if(!grid);
514
515         Ecore_Animator *animator = NULL;
516
517         evas_object_data_del(grid, PRIVATE_DATA_KEY_GRID_LIST);
518         evas_object_data_del(grid, PRIVATE_DATA_KEY_LIST_INDEX);
519         evas_object_data_del(grid, PRIVATE_DATA_KEY_ICON_WIDTH);
520         evas_object_data_del(grid, PRIVATE_DATA_KEY_ICON_HEIGHT);
521         evas_object_data_del(grid, PRIVATE_DATA_KEY_ITEM_WIDTH);
522         evas_object_data_del(grid, PRIVATE_DATA_KEY_ITEM_HEIGHT);
523         evas_object_data_del(grid, DATA_KEY_EDGE_TOP);
524
525         evas_object_data_del(grid, PRIVATE_DATA_KEY_GIC);
526
527         animator = evas_object_data_del(grid, PRIVATE_DATA_KEY_ANIMATOR);
528         if (animator) {
529                 ecore_animator_del(animator);
530                 animator = NULL;
531         }
532
533         evas_object_del(grid);
534 }
535
536
537
538 Elm_Object_Item *_grid_append_item(Evas_Object *grid, content_s *content_info)
539 {
540         Elm_Gengrid_Item_Class *gic = NULL;
541         Elm_Object_Item *item = NULL;
542
543         retv_if(!grid, NULL);
544         retv_if(!content_info, NULL);
545
546         gic = evas_object_data_get(grid, PRIVATE_DATA_KEY_GIC);
547         retv_if(!gic, NULL);
548
549         item = elm_gengrid_item_append(grid, gic, content_info, __item_selected, content_info);
550         retv_if(!item, NULL);
551         _D("grid append item : %s", content_info->innate_content_info->name);
552         content_info->grid_item = item;
553
554         return item;
555 }
556
557
558
559 void _grid_remove_item(Evas_Object *grid, content_s *content_info)
560 {
561         Elm_Object_Item *item = NULL;
562
563         ret_if(!grid);
564         ret_if(!content_info);
565
566         item = content_info->grid_item;
567         ret_if(!item);
568         elm_object_item_del(item);
569         content_info->grid_item = NULL;
570 }
571
572
573
574 int _grid_count_item(Evas_Object *grid)
575 {
576         int count = 0;
577
578         retv_if(!grid, 0);
579
580         count = elm_gengrid_items_count(grid);
581
582         return count;
583 }