f584a24908c5218ae40f4f9cfa33816c573e477d
[apps/native/home/homescreen-efl.git] / src / app_grid.c
1 /*
2  * Copyright 2012  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 "app_grid.h"
18 #include "homescreen-efl.h"
19 #include "app_item.h"
20 #include "app_icon.h"
21 #include "page_scroller.h"
22 #include "all_apps.h"
23 #include "folder_panel.h"
24 #include "util.h"
25 #include "popup.h"
26 #include "data_model.h"
27
28 typedef enum {
29         NEXT_PAGE_CB = 0,
30         PREV_PAGE_CB,
31         NONE_PAGE_CB
32 } page_change_action_t;
33
34 typedef enum {
35         MODE_NORMAL = 0,
36         MODE_EDIT,
37         MODE_FOLDER,
38 } possible_view_modes_t;
39
40 typedef struct {
41         page_change_action_t action;
42         Evas_Object *parent;
43 } change_page_data_t;
44
45 static struct {
46         Tree_node_t *repositioned_node;
47         Tree_node_t *opened_folder_node;
48         Tree_node_t *destination_folder;
49         Evas_Object *repositioned_icon_layout;
50         Evas_Object *src_grid;
51         Evas_Object *repositioned_icon;
52         Elm_Object_Item *repositioned_item;
53         int src_idx;
54         bool is_dnd_on;
55         Evas_Coord dx;
56         Evas_Coord dy;
57         Elm_Gengrid_Item_Class *gic;
58         Evas_Coord w;
59         Evas_Coord h;
60         int f_x;
61         int f_y;
62         int f_w;
63         int f_h;
64         Ecore_Timer *change_page_timer;
65         Ecore_Timer *outside_folder_timer;
66         change_page_data_t cp_data;
67 } s_info = {
68         .repositioned_node = NULL,
69         .opened_folder_node = NULL,
70         .destination_folder = NULL,
71         .repositioned_icon_layout = NULL,
72         .src_grid = NULL,
73         .repositioned_icon = NULL,
74         .repositioned_item = NULL,
75         .src_idx = 1,
76         .is_dnd_on = false,
77         .gic = NULL,
78         .dx = -1,
79         .dy = -1,
80         .w = -1,
81         .h = -1,
82         .f_x = -1,
83         .f_y = -1,
84         .f_w = -1,
85         .f_h = -1,
86         .change_page_timer = NULL,
87         .outside_folder_timer = NULL,
88         .cp_data = {
89                 action: NONE_PAGE_CB,
90                 parent: NULL
91         }
92 };
93
94 /*================================= PRIVATE FUNCTIONS ============================================*/
95 static bool __app_grid_fill(Evas_Object *grid, Tree_node_t *data);
96 static Evas_Object *__app_grid_create_ly(Evas_Object *parent);
97 static bool __app_grid_resize(Evas_Object *app_grid, Evas_Coord new_w, Evas_Coord new_h);
98 static Evas_Object *__app_grid_get_icon_container_ptr(Elm_Object_Item *it);
99 static Eina_Bool __app_grid_change_page_cb(void *data);
100 static void __app_grid_check_page_change(Evas_Object *scroller, int x, int y);
101 static void __app_grid_clear_reposition_structure(void);
102 static Eina_Bool __app_grid_close_folder_cb(void *data);
103 static Evas_Object *__app_grid_create_item_container(Evas_Object *parent);
104
105 /*================================= GENGRID CALLBACK FUNCTIONS ===================================*/
106 static void __app_grid_item_longpressed_cb(void *data, Evas_Object *obj, void *ei);
107 static Evas_Object *__app_grid_get_content(void *data, Evas_Object *obj, const char *part);
108 static Eina_Bool __app_grid_get_state(void *data, Evas_Object *obj, const char *part);
109 static void __app_grid_del_content(void *data, Evas_Object *obj);
110 static char *__app_grid_get_text(void *data, Evas_Object *obj, const char *part);
111 static void __app_grid_resize_cb(void *data, Evas *e, Evas_Object *obj, void *ei);
112
113 /*================================= MOUSE HANDLERS ===============================================*/
114 static Eina_Bool _app_grid_mouse_move_cb(void *data, int type, void *event);
115 static Eina_Bool __app_grid_mouse_up_cb(void *data, int type, void *event);
116
117 /*================================= DND FUNCTIONS ================================================*/
118 static void __app_grid_return_to_origin_pos(void);
119 static void __app_grid_icon_drop(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y,
120                 Elm_Xdnd_Action action);
121 static void __app_grid_drag_done(void *data, Evas_Object *obj);
122 static Evas_Event_Flags __app_grid_icon_move(void *data, void *event_info);
123 static Evas_Event_Flags __app_grid_icon_move_end(void *data, void *event_info);
124
125 /*================================= PUBLIC FUNCTIONS DEFS ========================================*/
126 HAPI Evas_Object *app_grid_create(Evas_Object *parent, Tree_node_t *data, Evas_Coord gengrid_width,
127                         Evas_Coord gengrid_height, app_grid_type_t type)
128 {
129         Evas_Object *gengrid = NULL;
130         Evas_Object *layout = NULL;
131         Evas_Object *rect = NULL;
132
133         if (!parent) {
134                 LOGE("[INVALID_PARAM]['parent'='%p']", parent);
135                 return NULL;
136         }
137
138         rect = evas_object_rectangle_add(evas_object_evas_get(parent));
139         if (!rect) {
140                 LOGE("[FAILED][rect=NULL]");
141                 return NULL;
142         }
143
144         layout = __app_grid_create_ly(parent);
145         if (!layout) {
146                 LOGE("[FAILED][__app_grid_create_ly]");
147                 evas_object_del(rect);
148                 return NULL;
149         }
150
151         evas_object_color_set(rect, 0, 0, 0, 0);
152         evas_object_size_hint_min_set(rect, gengrid_width, gengrid_height);
153         evas_object_size_hint_max_set(rect, gengrid_width, gengrid_height);
154         elm_object_part_content_set(layout, PART_APP_GRID_SIZE_SETTER, rect);
155
156         gengrid = elm_gengrid_add(layout);
157         if (!gengrid) {
158                 LOGE("[FAILED][elm_gengrid_add]");
159                 evas_object_del(layout);
160                 evas_object_del(rect);
161                 return NULL;
162         }
163
164         evas_object_size_hint_weight_set(gengrid, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
165         evas_object_show(gengrid);
166
167         if (!s_info.gic) {
168                 if (!(s_info.gic = elm_gengrid_item_class_new())) {
169                         LOGE("[FAILED][elm_gengrid_item_class_new]");
170                         evas_object_del(layout);
171                         evas_object_del(rect);
172                         return NULL;
173                 }
174
175                 s_info.gic->item_style  = "default";
176                 s_info.gic->func.content_get = __app_grid_get_content;
177                 s_info.gic->func.del = __app_grid_del_content;
178                 s_info.gic->func.text_get = __app_grid_get_text;
179                 s_info.gic->func.state_get = __app_grid_get_state;
180
181                 ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _app_grid_mouse_move_cb, parent);
182                 ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, __app_grid_mouse_up_cb, NULL);
183         }
184
185         elm_object_scale_set(gengrid, 0.5);
186
187         elm_gengrid_select_mode_set(gengrid, ELM_OBJECT_SELECT_MODE_NONE);
188         elm_gengrid_reorder_mode_set(gengrid, EINA_FALSE);
189         elm_gengrid_align_set(gengrid, 0.0, 0.0);
190
191         if (!__app_grid_fill(gengrid, data)) {
192                 LOGE("[FAILED][__app_grid_fill]");
193                 evas_object_del(layout);
194                 evas_object_del(rect);
195                 return NULL;
196         }
197
198         if (type == APP_GRID_TYPE_ALL_APPS) {
199                 s_info.w = gengrid_width;
200                 s_info.h = gengrid_height;
201         } else if (type == APP_GRID_TYPE_FOLDER) {
202                 elm_object_signal_emit(layout, SIGNAL_APP_GRID_BG_HIDE, SIGNAL_SOURCE);
203         }
204
205         elm_object_part_content_set(layout, PART_APP_GRID_CONTENT, gengrid);
206         evas_object_smart_callback_add(gengrid, "longpressed", __app_grid_item_longpressed_cb, NULL);
207
208         data->data->layout = layout;
209         evas_object_event_callback_add(gengrid, EVAS_CALLBACK_RESIZE, __app_grid_resize_cb, (void *)type);
210
211         /*It is used only internal.*/
212         evas_object_data_set(gengrid, KEY_APP_GRID_DATA, layout);
213
214         elm_scroller_movement_block_set(gengrid, ELM_SCROLLER_MOVEMENT_BLOCK_VERTICAL);
215         elm_scroller_movement_block_set(gengrid, ELM_SCROLLER_MOVEMENT_BLOCK_HORIZONTAL);
216         elm_gengrid_wheel_disabled_set(gengrid, EINA_TRUE);
217
218         return layout;
219 }
220
221 HAPI Elm_Object_Item *app_grid_append_item(Evas_Object *layout, Evas_Object *icon_to_append)
222 {
223         Elm_Object_Item *result = NULL;
224         Evas_Object *container = NULL;
225
226         if (!layout || !icon_to_append) {
227                 LOGE("[INVALID_PARAM][layout='%p'][icon_to_append='%p']", layout, icon_to_append);
228                 return NULL;
229         }
230
231         Evas_Object *grid = elm_object_part_content_get(layout, PART_APP_GRID_CONTENT);
232         if (!grid) {
233                 LOGE("[FAILED][elm_object_part_content_get]");
234                 return NULL;
235         }
236
237         if (!(result = elm_gengrid_item_append(grid, s_info.gic,
238                         (container = app_grid_item_pack(grid, icon_to_append)), NULL, NULL))) {
239                 LOGE("Failed to append item");
240                 return NULL;
241         }
242
243         evas_object_show(icon_to_append);
244         return result;
245 }
246
247 HAPI Elm_Object_Item *app_grid_insert_item_relative(Evas_Object *layout, Evas_Object *item,
248                                 Elm_Object_Item *rel_it)
249 {
250         Evas_Object *app_grid = NULL, *container = NULL;
251         Elm_Object_Item *result = NULL;
252         int dst_idx = -1;
253
254         if (!layout || !item) {
255                 LOGE("[INVALID_PARAM][layout='%p'][item='%p']", layout, item);
256                 return NULL;
257         }
258
259         app_grid = elm_object_part_content_get(layout, PART_APP_GRID_CONTENT);
260         if (!app_grid) {
261                 LOGE("[FAILED][elm_object_part_content_get]");
262                 return NULL;
263         }
264
265         if (rel_it) {
266                 dst_idx = elm_gengrid_item_index_get(rel_it);
267
268                 if ((s_info.src_grid == app_grid && s_info.src_idx > dst_idx)
269                                 || (s_info.src_grid != app_grid)) {
270                         if (!(result = elm_gengrid_item_insert_before(app_grid, s_info.gic,
271                                 (container = app_grid_item_pack(app_grid, item)), rel_it, NULL, NULL))) {
272                                 LOGE("[FAILED][elm_gengrid_item_insert_before]");
273                                 evas_object_del(container);
274                                 return NULL;
275                         }
276                 } else if (s_info.src_grid == app_grid && s_info.src_idx < dst_idx) {
277                         if (!(result = elm_gengrid_item_insert_after(app_grid, s_info.gic,
278                                 (container = app_grid_item_pack(app_grid, item)), rel_it, NULL, NULL))) {
279                                 LOGE("[FAILED][elm_gengrid_item_insert_before]");
280                                 return NULL;
281                         }
282                 }
283         } else {
284                 if (!(result = elm_gengrid_item_append(app_grid, s_info.gic,
285                                 (container = app_grid_item_pack(app_grid, item)), NULL, NULL))) {
286                         LOGE("[FAILED][elm_gengrid_item_append]");
287                         return NULL;
288                 }
289         }
290
291         evas_object_show(item);
292         return result;
293 }
294
295 HAPI Evas_Object *app_grid_item_pack(Evas_Object *p, Evas_Object *c)
296 {
297         Evas_Object *container = NULL;
298
299         if (!p) { /*When c is null it is not a big problem...it creates then empty gengrid item */
300                 LOGD("[ERR][INVALID_PARAM]['p'='%p']", p);
301                 return NULL;
302         }
303
304         /*This items will be removed when gengrid items will be deleted.
305         It was checked in EVAS_CALLBACK_DEL function. */
306         container = __app_grid_create_item_container(home_screen_get_win());
307         if (!container) {
308                 LOGE("[FAILED][container=NULL]");
309                 return NULL;
310         }
311
312         if (c)
313                 elm_object_part_content_set(container, PART_APP_GRID_ITEM, c);
314
315         return container;
316 }
317
318 HAPI void app_grid_unpack_item(Elm_Object_Item *item)
319 {
320         Evas_Object *container = NULL;
321
322         if (!item) {
323                 LOGE("[INVALID_PARAM][item=NULL]");
324                 return;
325         }
326
327         container = elm_object_item_part_content_get(item, GRID_CONTENT);
328         if (!container) {
329                 LOGE("[FAILED][elm_object_item_part_content_get]");
330                 return;
331         }
332
333         elm_object_part_content_unset(container, PART_APP_GRID_ITEM);
334 }
335
336 HAPI Eina_Bool app_grid_get_item_content(Elm_Object_Item *item, Evas_Object **icon,
337                                 Tree_node_t **data)
338 {
339         Evas_Object *ic = NULL;
340         Evas_Object *container = NULL;
341
342         if (!item) {
343                 LOGE("[INVALID_PARAM][item='%p']", item);
344                 return EINA_FALSE;
345         }
346
347         container = elm_object_item_part_content_get(item, GRID_CONTENT);
348         if (!container) {
349                 LOGE("[FAILED][elm_object_item_part_content_get]");
350                 return EINA_FALSE;
351         }
352
353         ic = elm_object_part_content_get(container, PART_APP_GRID_ITEM);
354         if (!ic) {
355                 LOGE("[FAILED][eina_list_data_get]");
356                 return EINA_FALSE;
357         }
358
359         if (icon)
360                 *icon = ic;
361
362         if (data) {
363                 *data = evas_object_data_get(ic, KEY_ICON_DATA);
364                 if (!(*data)) {
365                         LOGE("[FAILED][evas_object_data_get]");
366                         /*eina_list_free(box_content);*/
367                         return EINA_FALSE;
368                 }
369         }
370         return EINA_TRUE;
371 }
372
373 static Evas_Event_Flags __app_grid_icon_move(void *data, void *event_info)
374 {
375         Elm_Gesture_Momentum_Info *pos_info = event_info;
376
377         if(s_info.repositioned_icon == NULL)
378                 return EVAS_EVENT_FLAG_NONE;
379
380         evas_object_move(s_info.repositioned_icon, pos_info->x2 - s_info.dx, pos_info->y2 - s_info.dy);
381
382         if (folder_panel_is_folder_visible()) {
383                 LOGD("Folder is visible");
384                 if ((pos_info->y2 <= s_info.f_y || pos_info->y2 >= s_info.f_y + s_info.f_h) &&
385                                 !s_info.outside_folder_timer) {
386
387                         LOGD("Icon is outside folder");
388                         s_info.outside_folder_timer = ecore_timer_add(1.0, __app_grid_close_folder_cb, NULL);
389                         if (!s_info.outside_folder_timer) {
390                                 LOGE("[FAILED][timer=NULL]");
391                                 return EVAS_EVENT_FLAG_ON_HOLD;
392                         }
393                 } else if (pos_info->y2 >= s_info.f_y && pos_info->y2 <= s_info.f_y + s_info.f_h) {
394                         LOGD("Icons position is on folder");
395                         ecore_timer_del(s_info.outside_folder_timer);
396                         s_info.outside_folder_timer = NULL;
397                 }
398         }
399
400         return EVAS_EVENT_FLAG_NONE;
401 }
402
403 static Eina_Bool __app_grid_icon_move_cb_set(void *data)
404 {
405         LOGD("Set icon move cb");
406         int ret = 0;
407
408         ret = home_screen_gesture_cb_set(ELM_GESTURE_MOMENTUM, ELM_GESTURE_STATE_MOVE,
409                         __app_grid_icon_move, NULL);
410         ret |= home_screen_gesture_cb_set(ELM_GESTURE_MOMENTUM, ELM_GESTURE_STATE_END,
411                         __app_grid_icon_move_end, NULL);
412         ret |= home_screen_gesture_cb_set(ELM_GESTURE_MOMENTUM, ELM_GESTURE_STATE_ABORT,
413                         __app_grid_icon_move_end, NULL);
414
415         if (ret) {
416                 LOGE("Can not set icon move callbacks");
417                 return EINA_TRUE;
418         }
419
420         return EINA_FALSE;
421 }
422
423 static Eina_Bool __app_grid_icon_move_cb_del(void *data)
424 {
425         LOGD("Delete icon move cb");
426         int ret = 0;
427
428         ret = home_screen_gesture_cb_unset(ELM_GESTURE_MOMENTUM, ELM_GESTURE_STATE_MOVE,
429                         __app_grid_icon_move, NULL);
430         ret |= home_screen_gesture_cb_unset(ELM_GESTURE_MOMENTUM, ELM_GESTURE_STATE_END,
431                         __app_grid_icon_move_end, NULL);
432         ret |= home_screen_gesture_cb_unset(ELM_GESTURE_MOMENTUM, ELM_GESTURE_STATE_ABORT,
433                         __app_grid_icon_move_end, NULL);
434
435         if (ret)
436                 LOGE("Can not unset callbacks");
437
438         return ECORE_CALLBACK_CANCEL;
439 }
440
441 static Evas_Event_Flags __app_grid_icon_move_end(void *data, void *event_info)
442 {
443         Elm_Gesture_Momentum_Info *pos_info = event_info;
444         LOGD("Drag end at: x,y=<%d,%d>", pos_info->x2, pos_info->y2);
445
446
447         if(s_info.repositioned_icon != NULL) {
448                 __app_grid_icon_drop(NULL, s_info.src_grid, pos_info->x2,
449                                 pos_info->y2, ELM_XDND_ACTION_UNKNOWN);
450                 __app_grid_drag_done(NULL, NULL);
451         }
452
453         /* quickfix: idler adds delay so cb func might be deleted after it is finished
454          * removing cb inside its body causes memory errors
455         */
456         ecore_idler_add(__app_grid_icon_move_cb_del, NULL);
457
458         return EVAS_EVENT_FLAG_NONE;
459 }
460
461 /*=====================GENGRID CALLBACKS IMPLEMENTATION===========================================*/
462 static void __app_grid_item_longpressed_cb(void *data, Evas_Object *obj, void *ei)
463 {
464         Elm_Object_Item *it = (Elm_Object_Item *)ei;
465         Evas_Coord x, y, w, h, m_x, m_y;
466         Evas_Object *icon_layout = NULL;
467         Evas_Object *icon = NULL;
468         Tree_node_t *icon_node = NULL;
469         homescreen_view_t view_type = HOMESCREEN_VIEW_UNKNOWN;
470
471         view_type = home_screen_get_view_type();
472
473         if (view_type != HOMESCREEN_VIEW_ALL_APPS &&
474                         view_type != HOMESCREEN_VIEW_ALL_APPS_EDIT)
475                 return;
476
477         if (!it || !app_grid_get_item_content(it, &icon_layout, NULL)) {
478                 LOGE("[FAILED][app_grid_item_content_get]");
479                 return;
480         }
481
482         if (!evas_object_data_get(icon_layout, KEY_IS_REPOSITIONABLE))
483                 return;
484
485         if (!icon_layout) {
486                 LOGE("[FAILED][icon_layout=NULL]");
487                 return;
488         }
489
490         if (view_type == HOMESCREEN_VIEW_ALL_APPS)
491                 home_screen_set_view_type(HOMESCREEN_VIEW_ALL_APPS_EDIT);
492
493         icon = elm_object_part_content_get(icon_layout, PART_ICON_CONTENT);
494         if (!icon) {
495                 LOGE("[FAILED][icon=NULL]");
496                 return;
497         }
498
499         icon_node = evas_object_data_get(icon_layout, KEY_ICON_DATA);
500         if (!icon_node) {
501                 LOGE("[FAILED][icon_node=NULL]");
502                 return;
503         }
504
505         /*check if the repositioned item is from a folder.
506         It is necessary for removing item from the folder.*/
507         if (icon_node->parent && icon_node->parent->parent && icon_node->parent->parent->data
508                                 && icon_node->parent->parent->data->type == APP_ITEM_FOLDER) {
509                 s_info.opened_folder_node = icon_node->parent->parent;
510                 folder_panel_get_folder_geometry(&s_info.f_x, &s_info.f_y, &s_info.f_w, &s_info.f_h);
511         }
512
513         evas_object_geometry_get(icon, &x, &y, &w, &h);
514         evas_pointer_output_xy_get(evas_object_evas_get(obj), &m_x, &m_y);
515         s_info.dx = abs(m_x - x);
516         s_info.dy = abs(m_y - y);
517
518         /*check if user perform longpress action on icon or on item.
519         (item is a container for icon..is bigger because it must have place also for icon name)*/
520         if ((m_x >= x && m_x <= x+w) && (m_y >= y && m_y <= y + h)) {
521                 s_info.repositioned_icon_layout = icon_layout;
522                 s_info.repositioned_icon = icon;
523                 s_info.repositioned_item = it;
524                 s_info.repositioned_node = icon_node;
525                 s_info.src_grid = obj;
526                 s_info.src_idx = elm_gengrid_item_index_get(s_info.repositioned_item);
527                 s_info.is_dnd_on = true;
528
529                 app_grid_unpack_item(it);
530
531                 if (__app_grid_icon_move_cb_set(NULL)) {
532                         LOGE("Gesture cb set failed");
533
534                         __app_grid_icon_move_cb_del(NULL);
535                 }
536
537                 evas_object_data_set(icon, KEY_REPOSITION_DATA, icon_layout);
538                 /*This is necessary for hide only box content in grid*/
539                 elm_object_part_content_unset(icon_layout, PART_ICON_CONTENT);
540                 evas_object_hide(icon_layout);
541                 all_apps_set_scrolling_blocked_state(true);
542                 folder_panel_enable_entry(false);
543         }
544 }
545
546 static char *__app_grid_get_text(void *data, Evas_Object *obj, const char *part)
547 {
548         return NULL;
549 }
550
551 static Evas_Object *__app_grid_get_content(void *data, Evas_Object *obj, const char *part)
552 {
553         if (!data) {
554                 LOGE("[INVALID_PARAM][data='%p']", data);
555                 return NULL;
556         }
557
558         if (!strcmp(GRID_CONTENT, part))
559                 return (Evas_Object *) data;
560
561         return NULL;
562 }
563
564 static Eina_Bool __app_grid_get_state(void *data, Evas_Object *obj, const char *part)
565 {
566         return EINA_FALSE;
567 }
568
569 static void __app_grid_del_content(void *data, Evas_Object *obj)
570 {
571         LOGD("DELETING :  ", evas_object_type_get(obj));
572
573 }
574
575 static void __app_grid_resize_cb(void *data, Evas *e, Evas_Object *obj, void *ei)
576 {
577         int w = -1, h = -1, item_w = -1, item_h = -1;
578         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
579
580         if ((app_grid_type_t)data == APP_GRID_TYPE_ALL_APPS) {
581                 item_w = w/APP_COLS;
582                 item_h = h/APP_ROWS;
583         } else if ((app_grid_type_t)data == APP_GRID_TYPE_FOLDER) {
584                 item_w = (int)(w/FOLDER_COL_APPS - FOLDER_ITEM_MARGIN*home_screen_get_root_width());
585                 item_h = h/FOLDER_ROW_APPS;
586         }
587
588         elm_gengrid_item_size_set(obj, item_w, item_h);
589 }
590
591 /*=========================== MOUSE HANDLERS =====================================================*/
592 static Eina_Bool __app_grid_mouse_up_cb(void *data, int type, void *event)
593 {
594         home_screen_set_indice_state(INDICE_OFF);
595         return ECORE_CALLBACK_RENEW;
596 }
597
598 static Eina_Bool _app_grid_mouse_move_cb(void *data, int type, void *event)
599 {
600         if (s_info.is_dnd_on) {
601                 Evas_Object *scroller = (Evas_Object *) data;
602                 Ecore_Event_Mouse_Move *move = event;
603                 __app_grid_check_page_change(scroller, move->x, move->y);
604         }
605
606         return ECORE_CALLBACK_RENEW;
607 }
608
609 /*========================= PRIVATE FUNCTIONS ====================================================*/
610 static bool __app_grid_fill(Evas_Object *grid, Tree_node_t *data)
611 {
612         Evas_Object *icon = NULL, *box = NULL;
613         app_item_t *item = NULL;
614         Tree_node_t *it = NULL;
615
616         if (!data || !grid) {
617                 LOGE("[INVALID_PARAM][grid='%p'][data='%p']", grid, data);
618                 return false;
619         }
620
621         TREE_NODE_FOREACH(data, it) {
622                 item = it->data;
623                 if (!item) {
624                         LOGE("[FAILED][item=%p", item);
625                         continue;
626                 }
627
628                 if (!item->exec || !item->icon || !item->label || !item->appid) {
629                         LOGE("[FAILED][exec='%p'][icon='%p'][label='%p'][appid='%p']",
630                                 item->exec, item->label, item->icon, item->appid);
631                         continue;
632                 }
633
634                 LOGI("add item: [%s]", item->label);
635
636                 if (item->type == APP_ITEM_ICON) {
637                         icon = app_icon_create(it, APP_ICON_TYPE_APP);
638                 } else if (item->type == APP_ITEM_FOLDER) {
639                         folder_panel_create(it);
640                         app_icon_update_folder_icon(it);
641                         icon = item->layout;
642                 }
643
644                 if (!icon) {
645                         LOGE("[FAILED][app_icon_create]");
646                         return false;
647                 }
648
649                 if (!(item->grid_item = elm_gengrid_item_append(grid, s_info.gic,
650                                 (box = app_grid_item_pack(grid, icon)), NULL, NULL))) {
651                         LOGE("Failed to append an item!");
652                         evas_object_del(box);
653                         if (!box) {/*app_grid_item_pack had failed so the icon is still allocated:*/
654                                 app_icon_destroy(icon);
655                         }
656                         return false;
657                 }
658
659                 item->layout = icon;
660         }
661
662         return true;
663 }
664
665 static Evas_Object *__app_grid_create_ly(Evas_Object *parent)
666 {
667         Evas_Object *ly = NULL;
668
669         if (!parent) {
670                 LOGE("[INVALID_PARAM][parent='%p']", parent);
671                 return NULL;
672         }
673
674         ly = elm_layout_add(parent);
675         if (!ly) {
676                 LOGE("[FAILED][elm_layout_add]");
677                 return NULL;
678         }
679
680         if (!elm_layout_file_set(ly, util_get_res_file_path(EDJE_DIR"/app_grid.edj"), GROUP_APP_GRID)) {
681                 LOGE("[FAILED][elm_layout_file_set][%s]", util_get_res_file_path(EDJE_DIR"/app_grid.edj"));
682                 evas_object_del(ly);
683                 return NULL;
684         }
685
686         evas_object_size_hint_weight_set(ly, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
687         evas_object_size_hint_align_set(ly, EVAS_HINT_FILL, EVAS_HINT_FILL);
688         evas_object_show(ly);
689
690         return ly;
691 }
692
693 void app_grid_set_view_mode(Evas_Object *app_grid, homescreen_view_t view)
694 {
695         if (!app_grid) {
696                 LOGE("[INVALID_PARAM]");
697                 return;
698         }
699
700         switch (view) {
701         case HOMESCREEN_VIEW_ALL_APPS:
702                 elm_object_signal_emit(app_grid, SIGNAL_CHOOSE_MODE_OFF, SIGNAL_SOURCE);
703                 elm_object_signal_emit(app_grid, SIGNAL_EDIT_MODE_OFF, SIGNAL_SOURCE);
704                 __app_grid_resize(app_grid, s_info.w, s_info.h);
705                 break;
706         case HOMESCREEN_VIEW_ALL_APPS_EDIT:
707                 elm_object_signal_emit(app_grid, SIGNAL_CHOOSE_MODE_OFF, SIGNAL_SOURCE);
708                 elm_object_signal_emit(app_grid, SIGNAL_EDIT_MODE_ON, SIGNAL_SOURCE);
709                 __app_grid_resize(app_grid, EDIT_MODE_SCALE*s_info.w, EDIT_MODE_SCALE*s_info.h);
710                 break;
711         case HOMESCREEN_VIEW_ALL_APPS_CHOOSE:
712                 elm_object_signal_emit(app_grid, SIGNAL_EDIT_MODE_OFF, SIGNAL_SOURCE);
713                 elm_object_signal_emit(app_grid, SIGNAL_CHOOSE_MODE_ON, SIGNAL_SOURCE);
714                 __app_grid_resize(app_grid, CHOOSE_MODE_SCALE*s_info.w, CHOOSE_MODE_SCALE*s_info.h);
715                 break;
716         default:
717                 LOGE("[FAILED][type='%d']", view);
718                 break;
719         }
720 }
721
722 static bool __app_grid_resize(Evas_Object *app_grid, Evas_Coord new_w, Evas_Coord new_h)
723 {
724         Evas_Object *gengrid = NULL;
725
726         Evas_Coord new_item_w = new_w/APP_COLS;
727         Evas_Coord new_item_h = new_h/APP_ROWS;
728
729         if (!app_grid) {
730                 LOGE("[INVALID_PARAM][app_grid='%p']", app_grid);
731                 return false;
732         }
733
734         gengrid = elm_object_part_content_get(app_grid, PART_APP_GRID_CONTENT);
735         if (!gengrid) {
736                 LOGE("[FAILED][elm_object_part_content_get]");
737                 return false;
738         }
739
740         if (new_item_w < 0 || new_item_h < 0) {
741                 LOGE("[INVALID_SIZE]");
742                 return false;
743         }
744
745         /*elm_gengrid_item_size_set(gengrid, new_item_w, new_item_h);*/
746
747         return true;
748 }
749
750 static Eina_Bool __app_grid_change_page_cb(void *data)
751 {
752         LOGI("__app_grid_change_page_cb");
753         change_page_data_t *ch_page_data = (change_page_data_t *) data;
754         Evas_Object *parent = NULL;
755
756         s_info.change_page_timer = NULL;
757
758         if (!ch_page_data) {
759                 LOGE("[INVALID_PARAM][ch_page_data='%p']", ch_page_data);
760                 return ECORE_CALLBACK_CANCEL;
761         } else if (!ch_page_data->parent) {
762                 LOGE("[INVALID_PARAM][ch_page_data->parent='%p']", ch_page_data->parent);
763                 return ECORE_CALLBACK_CANCEL;
764         }
765
766         parent = ch_page_data->parent;
767
768         if (ch_page_data->action == NEXT_PAGE_CB) {
769                 LOGI("next_page_signal");
770                 elm_object_signal_emit(parent, SIGNAL_NEXT_PAGE_CHANGE, SIGNAL_SOURCE);
771         }
772
773         if (ch_page_data->action == PREV_PAGE_CB) {
774                 LOGI("prev_page_signal");
775                 elm_object_signal_emit(parent, SIGNAL_PREV_PAGE_CHANGE, SIGNAL_SOURCE);
776         }
777
778         return ECORE_CALLBACK_CANCEL;
779 }
780
781 static void __app_grid_check_page_change(Evas_Object *scroller, int x, int y)
782 {
783         if (!scroller) {
784                 LOGE("[INVALID_PARAM][scroller='%p']", scroller);
785                 return;
786         }
787
788         s_info.cp_data.parent = scroller;
789         home_screen_set_indice_state(INDICE_OFF);
790
791         if (x < CHANGE_PAGE_RIGHT_AREA * home_screen_get_root_width() &&
792                 x > CHANGE_PAGE_LEFT_AREA * home_screen_get_root_width()  &&
793                 s_info.change_page_timer) {
794                 ecore_timer_del(s_info.change_page_timer);
795                 s_info.change_page_timer = NULL;
796                 return;
797         }
798
799         if (x >= CHANGE_PAGE_RIGHT_AREA * home_screen_get_root_width()) {
800                 home_screen_set_indice_state(INDICE_NEXT_PAGE_ON);
801                 s_info.cp_data.action = NEXT_PAGE_CB;
802         }
803
804         if (x <= CHANGE_PAGE_LEFT_AREA * home_screen_get_root_width()) {
805                 home_screen_set_indice_state(INDICE_PREV_PAGE_ON);
806                 s_info.cp_data.action = PREV_PAGE_CB;
807         }
808
809         if (!s_info.change_page_timer) {
810                 s_info.change_page_timer = ecore_timer_add(CHANGE_PAGE_TIMER, __app_grid_change_page_cb,
811                                 (void *) &s_info.cp_data);
812         }
813 }
814
815 static Evas_Object *__app_grid_get_icon_container_ptr(Elm_Object_Item *it)
816 {
817         Evas_Object *container = NULL;
818
819         if (!it) {
820                 LOGE("[INVALID_PARAM][it='%p']", it);
821                 return NULL;
822         }
823
824         container = elm_object_item_part_content_get(it, GRID_CONTENT);
825         return container;
826 }
827
828 static void __app_grid_clear_reposition_structure(void)
829 {
830         s_info.destination_folder = NULL;
831         s_info.repositioned_icon_layout = NULL;
832         s_info.repositioned_item = NULL;
833         s_info.repositioned_icon = NULL;
834         s_info.repositioned_node = NULL;
835         s_info.opened_folder_node = NULL;
836         s_info.src_grid = NULL;
837         s_info.src_idx = -1;
838         s_info.is_dnd_on = false;
839
840         s_info.f_x = -1;
841         s_info.f_y = -1;
842         s_info.f_w = -1;
843         s_info.f_h = -1;
844
845         if (s_info.outside_folder_timer) {
846                 ecore_timer_del(s_info.outside_folder_timer);
847                 s_info.outside_folder_timer = NULL;
848         }
849
850         if (s_info.change_page_timer) {
851                 ecore_timer_del(s_info.change_page_timer);
852                 s_info.change_page_timer = NULL;
853         }
854 }
855
856 static Eina_Bool __app_grid_close_folder_cb(void *data)
857 {
858         data_model_detach_from_folder(s_info.opened_folder_node, s_info.repositioned_node);
859         folder_panel_close_folder();
860         return EINA_FALSE;
861 }
862
863 static Evas_Object *__app_grid_create_item_container(Evas_Object *parent)
864 {
865         Evas_Object *container = NULL;
866
867         if (!parent) {
868                 LOGE("[INVALID_PARAM]");
869                 return NULL;
870         }
871
872         container = elm_layout_add(parent);
873
874         if (!elm_layout_file_set(container, util_get_res_file_path(EDJE_DIR"/app_grid.edj"), GROUP_APP_GRID_ITEM_CONTAINER)) {
875                 LOGE("[FAILED][elm_layout_file_set][%s]", util_get_res_file_path(EDJE_DIR"/app_grid.edj"));
876                 evas_object_del(container);
877                 return NULL;
878         }
879
880         evas_object_size_hint_weight_set(container, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
881         evas_object_show(container);
882         return container;
883 }
884
885 /*=============================== DND FUNCTIONS ==================================================*/
886
887 static void __app_grid_return_to_origin_pos(void)
888 {
889         Evas_Object *container = NULL;
890
891         if (!s_info.repositioned_item || !s_info.repositioned_icon_layout) {
892                 LOGE("[FAILED][repositioned_item='%p'][repositioned_icon='%p']",
893                                 s_info.repositioned_item, s_info.repositioned_icon_layout);
894                 return;
895         }
896
897         container = __app_grid_get_icon_container_ptr(s_info.repositioned_item);
898         if (!container) {
899                 LOGE("[FAILED][__app_grid_get_icon_container_ptr]");
900                 return;
901         }
902
903         elm_object_part_content_set(container, PART_APP_GRID_ITEM, s_info.repositioned_icon_layout);
904         elm_object_part_content_set(s_info.repositioned_icon_layout,
905                                 PART_ICON_CONTENT, s_info.repositioned_icon);
906         evas_object_show(s_info.repositioned_icon_layout);
907 }
908
909 static void __app_grid_icon_drop(void *data, Evas_Object *obj, Evas_Coord x, Evas_Coord y,
910                                 Elm_Xdnd_Action action)
911 {
912         static Elm_Object_Item *it = NULL;
913         Evas_Object *icon = NULL;
914         Evas_Object *old_icon = NULL;
915         Elm_Object_Item *old_it = it;
916         Tree_node_t *destination_icon_data = NULL;
917
918         it = elm_gengrid_at_xy_item_get(obj, x, y, NULL, NULL);
919
920         app_grid_get_item_content(old_it, &old_icon, NULL);
921         app_grid_get_item_content(it, &icon, &destination_icon_data);
922
923         if (!s_info.repositioned_node || !s_info.repositioned_node->data) {
924                 LOGE("[INVALID_DATA]");
925                 return;
926         }
927
928         if (it != old_it) {
929                 elm_object_signal_emit(old_icon, SIGNAL_UNHIGHLIGHT_FOLDER, SIGNAL_SOURCE);
930                 /*function not be invoked when s_info.repositioned_node == NULL;*/
931                 if (s_info.repositioned_node->data->type == APP_ITEM_FOLDER ||
932                         folder_panel_get_items_count(destination_icon_data) >= FOLDER_MAX_ITEMS) {
933                         elm_object_signal_emit(icon, SIGNAL_HIGHLIGHT_IMPOSSIBLE_FOLDER, SIGNAL_SOURCE);
934                 } else {
935                         elm_object_signal_emit(icon, SIGNAL_HIGHLIGHT_FOLDER, SIGNAL_SOURCE);
936                 }
937         }
938
939         if (destination_icon_data && destination_icon_data->data->type == APP_ITEM_FOLDER) {
940                 s_info.destination_folder = destination_icon_data;
941         } else {
942                 s_info.destination_folder = NULL;
943         }
944 }
945
946 static void __app_grid_drag_done(void *data, Evas_Object *obj)
947 {
948         Tree_node_t *folder = s_info.destination_folder;
949         Tree_node_t *item = s_info.repositioned_node;
950         Tree_node_t *src_folder = s_info.opened_folder_node;
951
952         char trbuf[PATH_MAX] = {0, };
953
954         /*Check if folder has empty space*/
955         if (item && folder && folder_panel_get_items_count(folder) < FOLDER_MAX_ITEMS
956                 && item->data->type != APP_ITEM_FOLDER) {
957                 home_screen_mvc_drag_item_to_folder_cb(item, folder);
958                 evas_object_hide(s_info.repositioned_icon);
959         } else if (item && folder && folder_panel_get_items_count(folder) >= FOLDER_MAX_ITEMS) {
960                 popup_data_t *p_data = popup_create_data();
961                 if (!p_data) {
962                         LOGE("[FAILED][failed to create popup data]");
963                         return;
964                 }
965
966                 snprintf(trbuf, sizeof(trbuf), _("IDS_HS_TPOP_MAXIMUM_NUMBER_OF_APPLICATIONS_IN_FOLDER_HPD_REACHED"),
967                         FOLDER_APPS_PAGE);
968
969                 p_data->type = POPUP_INFO;
970                 p_data->popup_title_text = NULL;
971                 p_data->popup_content_text = strdup(trbuf);
972                 p_data->popup_confirm_text = NULL;
973                 p_data->popup_cancel_text = NULL;
974                 p_data->orientation = ELM_POPUP_ORIENT_CENTER;
975                 p_data->visible_time = 1.5;
976
977                 popup_show(p_data, NULL, NULL, NULL);
978
979                 __app_grid_return_to_origin_pos();
980         } else if (item && src_folder && !folder_panel_is_folder_visible()) {
981                 home_screen_mvc_drag_item_from_folder_cb();
982                 elm_object_part_content_set(s_info.repositioned_icon_layout, PART_ICON_CONTENT,
983                                 s_info.repositioned_icon);
984                 app_icon_set_view_mode(s_info.repositioned_icon_layout, home_screen_get_view_type(), false);
985         } else {
986                 __app_grid_return_to_origin_pos();
987         }
988
989         if (folder && folder->data->layout)
990                 elm_object_signal_emit(folder->data->layout, SIGNAL_UNHIGHLIGHT_FOLDER, SIGNAL_SOURCE);
991
992         __app_grid_clear_reposition_structure();
993         all_apps_set_scrolling_blocked_state(false);
994         folder_panel_enable_entry(true);
995 }