call item unrealized callback more reliably
[framework/uifw/elementary.git] / src / lib / elm_gengrid.c
1 #include <Elementary.h>
2 #include <Elementary_Cursor.h>
3 #include "elm_priv.h"
4 #include "els_scroller.h"
5
6 /* --
7  * TODO:
8  * Handle non-homogeneous objects too.
9  */
10
11  typedef struct _Widget_Data Widget_Data;
12  typedef struct _Pan         Pan;
13
14 #define PRELOAD 1
15 #define REORDER_EFFECT_TIME 0.5
16
17  struct _Elm_Gengrid_Item
18 {
19    ELM_WIDGET_ITEM;
20    EINA_INLIST;
21    Evas_Object                  *spacer;
22    const Elm_Gengrid_Item_Class *itc;
23    Elm_Gengrid_Item             *parent;
24    Ecore_Timer                  *long_timer;
25    Ecore_Animator               *item_moving_effect_timer;
26    Widget_Data                  *wd;
27    Eina_List                    *labels, *icons, *states, *icon_objs;
28    struct
29      {
30         Evas_Smart_Cb func;
31         const void   *data;
32      } func;
33
34    Evas_Coord   x, y, gx, gy, dx, dy, ox, oy, tx, ty, rx, ry;
35    unsigned int moving_effect_start_time;
36    int          relcount;
37    int          walking;
38    int          prev_group;
39
40    struct
41      {
42         const void                 *data;
43         Elm_Tooltip_Item_Content_Cb content_cb;
44         Evas_Smart_Cb               del_cb;
45         const char                 *style;
46         Eina_Bool                   free_size : 1;
47      } tooltip;
48
49    const char *mouse_cursor;
50
51    Eina_Bool   is_group : 1;
52    Eina_Bool   want_unrealize : 1;
53    Eina_Bool   group_realized : 1;
54    Eina_Bool   realized : 1;
55    Eina_Bool   dragging : 1;
56    Eina_Bool   down : 1;
57    Eina_Bool   delete_me : 1;
58    Eina_Bool   display_only : 1;
59    Eina_Bool   disabled : 1;
60    Eina_Bool   selected : 1;
61    Eina_Bool   highlighted : 1;
62    Eina_Bool   moving : 1;
63 };
64
65 struct _Widget_Data
66 {
67    Eina_Inlist_Sorted_State *state;
68    Evas_Object      *self, *scr;
69    Evas_Object      *pan_smart;
70    Pan              *pan;
71    Eina_Inlist      *items;
72    Eina_List        *group_items;
73    Ecore_Job        *calc_job;
74    Eina_List        *selected;
75    Elm_Gengrid_Item *last_selected_item, *reorder_item;
76    double            align_x, align_y;
77
78    Evas_Coord        pan_x, pan_y, old_pan_x, old_pan_y;
79    Evas_Coord        item_width, item_height; /* Each it size */
80    Evas_Coord        group_item_width, group_item_height; /* Each group it size */
81    Evas_Coord        minw, minh; /* Total obj size */
82    Evas_Coord        reorder_item_x, reorder_item_y;
83    unsigned int      nmax;
84    long              count;
85    long              items_lost;
86    int               walking;
87
88    Eina_Bool         horizontal : 1;
89    Eina_Bool         on_hold : 1;
90    Eina_Bool         longpressed : 1;
91    Eina_Bool         multi : 1;
92    Eina_Bool         no_select : 1;
93    Eina_Bool         wasselected : 1;
94    Eina_Bool         always_select : 1;
95    Eina_Bool         clear_me : 1;
96    Eina_Bool         h_bounce : 1;
97    Eina_Bool         v_bounce : 1;
98    Eina_Bool         reorder_mode : 1;
99    Eina_Bool         reorder_item_changed : 1;
100    Eina_Bool         move_effect_enabled : 1;
101 };
102
103 #define ELM_GENGRID_ITEM_FROM_INLIST(it) \
104    ((it) ? EINA_INLIST_CONTAINER_GET(it, Elm_Gengrid_Item) : NULL)
105
106 struct _Pan
107 {
108    Evas_Object_Smart_Clipped_Data __clipped_data;
109    Widget_Data                   *wd;
110 };
111
112 static const char *widtype = NULL;
113 static void      _item_highlight(Elm_Gengrid_Item *it);
114 static void      _item_unrealize(Elm_Gengrid_Item *it);
115 static void      _item_select(Elm_Gengrid_Item *it);
116 static void      _item_unselect(Elm_Gengrid_Item *it);
117 static void      _calc_job(void *data);
118 static void      _on_focus_hook(void        *data,
119                                 Evas_Object *obj);
120 static Eina_Bool _item_multi_select_up(Widget_Data *wd);
121 static Eina_Bool _item_multi_select_down(Widget_Data *wd);
122 static Eina_Bool _item_multi_select_left(Widget_Data *wd);
123 static Eina_Bool _item_multi_select_right(Widget_Data *wd);
124 static Eina_Bool _item_single_select_up(Widget_Data *wd);
125 static Eina_Bool _item_single_select_down(Widget_Data *wd);
126 static Eina_Bool _item_single_select_left(Widget_Data *wd);
127 static Eina_Bool _item_single_select_right(Widget_Data *wd);
128 static Eina_Bool _event_hook(Evas_Object       *obj,
129                              Evas_Object       *src,
130                              Evas_Callback_Type type,
131                              void              *event_info);
132 static Eina_Bool _deselect_all_items(Widget_Data *wd);
133
134 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_VERSION;
135 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
136
137 static const char SIG_ACTIVATED[] = "activated";
138 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
139 static const char SIG_LONGPRESSED[] = "longpressed";
140 static const char SIG_SELECTED[] = "selected";
141 static const char SIG_UNSELECTED[] = "unselected";
142 static const char SIG_REALIZED[] = "realized";
143 static const char SIG_UNREALIZED[] = "unrealized";
144 static const char SIG_CHANGED[] = "changed";
145 static const char SIG_DRAG_START_UP[] = "drag,start,up";
146 static const char SIG_DRAG_START_DOWN[] = "drag,start,down";
147 static const char SIG_DRAG_START_LEFT[] = "drag,start,left";
148 static const char SIG_DRAG_START_RIGHT[] = "drag,start,right";
149 static const char SIG_DRAG_STOP[] = "drag,stop";
150 static const char SIG_DRAG[] = "drag";
151 static const char SIG_SCROLL[] = "scroll";
152 static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start";
153 static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop";
154 static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
155 static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
156 static const char SIG_SCROLL_EDGE_TOP[] = "scroll,edge,top"; // TODO : remove this
157 static const char SIG_SCROLL_EDGE_BOTTOM[] = "scroll,edge,bottom"; // TODO : remove this
158 static const char SIG_SCROLL_EDGE_LEFT[] = "scroll,edge,left"; // TODO : remove this
159 static const char SIG_SCROLL_EDGE_RIGHT[] = "scroll,edge,right"; // TODO : remove this
160 static const char SIG_EDGE_TOP[] = "edge,top";
161 static const char SIG_EDGE_BOTTOM[] = "edge,bottom";
162 static const char SIG_EDGE_LEFT[] = "edge,left";
163 static const char SIG_EDGE_RIGHT[] = "edge,right";
164 static const char SIG_MOVED[] = "moved";
165
166 static const Evas_Smart_Cb_Description _signals[] = {
167    {SIG_ACTIVATED, ""},
168    {SIG_CLICKED_DOUBLE, ""},
169    {SIG_LONGPRESSED, ""},
170    {SIG_SELECTED, ""},
171    {SIG_UNSELECTED, ""},
172    {SIG_REALIZED, ""},
173    {SIG_UNREALIZED, ""},
174    {SIG_CHANGED, ""},
175    {SIG_DRAG_START_UP, ""},
176    {SIG_DRAG_START_DOWN, ""},
177    {SIG_DRAG_START_LEFT, ""},
178    {SIG_DRAG_START_RIGHT, ""},
179    {SIG_DRAG_STOP, ""},
180    {SIG_DRAG, ""},
181    {SIG_SCROLL, ""},
182    {SIG_SCROLL_ANIM_START, ""},
183    {SIG_SCROLL_ANIM_STOP, ""},
184    {SIG_SCROLL_DRAG_START, ""},
185    {SIG_SCROLL_DRAG_STOP, ""},
186    {SIG_SCROLL_EDGE_TOP, ""},
187    {SIG_SCROLL_EDGE_BOTTOM, ""},
188    {SIG_SCROLL_EDGE_LEFT, ""},
189    {SIG_SCROLL_EDGE_RIGHT, ""},
190    {SIG_EDGE_TOP, ""},
191    {SIG_EDGE_BOTTOM, ""},
192    {SIG_EDGE_LEFT, ""},
193    {SIG_EDGE_RIGHT, ""},
194    {SIG_MOVED, ""},
195    {NULL, NULL}
196 };
197
198 static Eina_Compare_Cb _elm_gengrid_item_compare_cb;
199 static Eina_Compare_Cb _elm_gengrid_item_compare_data_cb;
200
201 static Eina_Bool
202 _event_hook(Evas_Object       *obj,
203             Evas_Object *src   __UNUSED__,
204             Evas_Callback_Type type,
205             void              *event_info)
206 {
207    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
208    Evas_Event_Key_Down *ev = event_info;
209    Widget_Data *wd = elm_widget_data_get(obj);
210    if (!wd) return EINA_FALSE;
211    if (!wd->items) return EINA_FALSE;
212    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
213    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
214
215    Elm_Gengrid_Item *it = NULL;
216    Evas_Coord x = 0;
217    Evas_Coord y = 0;
218    Evas_Coord step_x = 0;
219    Evas_Coord step_y = 0;
220    Evas_Coord v_w = 0;
221    Evas_Coord v_h = 0;
222    Evas_Coord page_x = 0;
223    Evas_Coord page_y = 0;
224
225    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
226    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
227    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
228    elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
229
230    if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
231      {
232         if ((wd->horizontal) &&
233             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
234               (_item_multi_select_up(wd)))
235              || (_item_single_select_up(wd))))
236           {
237              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
238              return EINA_TRUE;
239           }
240         else if ((!wd->horizontal) &&
241                  (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
242                    (_item_multi_select_left(wd)))
243                   || (_item_single_select_left(wd))))
244           {
245              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
246              return EINA_TRUE;
247           }
248         else
249           x -= step_x;
250      }
251    else if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right")))
252      {
253         if ((wd->horizontal) &&
254             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
255               (_item_multi_select_down(wd)))
256              || (_item_single_select_down(wd))))
257           {
258              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
259              return EINA_TRUE;
260           }
261         else if ((!wd->horizontal) &&
262                  (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
263                    (_item_multi_select_right(wd)))
264                   || (_item_single_select_right(wd))))
265           {
266              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
267              return EINA_TRUE;
268           }
269         else
270           x += step_x;
271      }
272    else if ((!strcmp(ev->keyname, "Up")) || (!strcmp(ev->keyname, "KP_Up")))
273      {
274         if ((wd->horizontal) &&
275             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
276               (_item_multi_select_left(wd)))
277              || (_item_single_select_left(wd))))
278           {
279              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
280              return EINA_TRUE;
281           }
282         else if ((!wd->horizontal) &&
283                  (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
284                    (_item_multi_select_up(wd)))
285                   || (_item_single_select_up(wd))))
286           {
287              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
288              return EINA_TRUE;
289           }
290         else
291           y -= step_y;
292      }
293    else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
294      {
295         if ((wd->horizontal) &&
296             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
297               (_item_multi_select_right(wd)))
298              || (_item_single_select_right(wd))))
299           {
300              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
301              return EINA_TRUE;
302           }
303         else if ((!wd->horizontal) &&
304                  (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
305                    (_item_multi_select_down(wd)))
306                   || (_item_single_select_down(wd))))
307           {
308              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
309              return EINA_TRUE;
310           }
311         else
312           y += step_y;
313      }
314    else if ((!strcmp(ev->keyname, "Home")) || (!strcmp(ev->keyname, "KP_Home")))
315      {
316         it = elm_gengrid_first_item_get(obj);
317         elm_gengrid_item_bring_in(it);
318         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
319         return EINA_TRUE;
320      }
321    else if ((!strcmp(ev->keyname, "End")) || (!strcmp(ev->keyname, "KP_End")))
322      {
323         it = elm_gengrid_last_item_get(obj);
324         elm_gengrid_item_bring_in(it);
325         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
326         return EINA_TRUE;
327      }
328    else if ((!strcmp(ev->keyname, "Prior")) || (!strcmp(ev->keyname, "KP_Prior")))
329      {
330         if (wd->horizontal)
331           {
332              if (page_x < 0)
333                x -= -(page_x * v_w) / 100;
334              else
335                x -= page_x;
336           }
337         else
338           {
339              if (page_y < 0)
340                y -= -(page_y * v_h) / 100;
341              else
342                y -= page_y;
343           }
344      }
345    else if ((!strcmp(ev->keyname, "Next")) || (!strcmp(ev->keyname, "KP_Next")))
346      {
347         if (wd->horizontal)
348           {
349              if (page_x < 0)
350                x += -(page_x * v_w) / 100;
351              else
352                x += page_x;
353           }
354         else
355           {
356              if (page_y < 0)
357                y += -(page_y * v_h) / 100;
358              else
359                y += page_y;
360           }
361      }
362    else if (!strcmp(ev->keyname, "Escape"))
363      {
364         if (!_deselect_all_items(wd)) return EINA_FALSE;
365         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
366         return EINA_TRUE;
367      }
368    else if ((!strcmp(ev->keyname, "Return")) ||
369             (!strcmp(ev->keyname, "KP_Enter")) ||
370             (!strcmp(ev->keyname, "space")))
371      {
372         it = elm_gengrid_selected_item_get(obj);
373         evas_object_smart_callback_call(it->wd->self, SIG_ACTIVATED, it);
374      }
375    else return EINA_FALSE;
376
377    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
378    elm_smart_scroller_child_pos_set(wd->scr, x, y);
379    return EINA_TRUE;
380 }
381
382 static Eina_Bool
383 _deselect_all_items(Widget_Data *wd)
384 {
385    if (!wd->selected) return EINA_FALSE;
386    while (wd->selected)
387      elm_gengrid_item_selected_set(wd->selected->data, EINA_FALSE);
388
389    return EINA_TRUE;
390 }
391
392 static Eina_Bool
393 _item_multi_select_left(Widget_Data *wd)
394 {
395    if (!wd->selected) return EINA_FALSE;
396
397    Elm_Gengrid_Item *prev = elm_gengrid_item_prev_get(wd->last_selected_item);
398    if (!prev) return EINA_TRUE;
399    if (elm_gengrid_item_selected_get(prev))
400      {
401         elm_gengrid_item_selected_set(wd->last_selected_item, EINA_FALSE);
402         wd->last_selected_item = prev;
403         elm_gengrid_item_show(wd->last_selected_item);
404      }
405    else
406      {
407         elm_gengrid_item_selected_set(prev, EINA_TRUE);
408         elm_gengrid_item_show(prev);
409      }
410
411    return EINA_TRUE;
412 }
413
414 static Eina_Bool
415 _item_multi_select_right(Widget_Data *wd)
416 {
417    if (!wd->selected) return EINA_FALSE;
418
419    Elm_Gengrid_Item *next = elm_gengrid_item_next_get(wd->last_selected_item);
420    if (!next) return EINA_TRUE;
421    if (elm_gengrid_item_selected_get(next))
422      {
423         elm_gengrid_item_selected_set(wd->last_selected_item, EINA_FALSE);
424         wd->last_selected_item = next;
425         elm_gengrid_item_show(wd->last_selected_item);
426      }
427    else
428      {
429         elm_gengrid_item_selected_set(next, EINA_TRUE);
430         elm_gengrid_item_show(next);
431      }
432
433    return EINA_TRUE;
434 }
435
436 static Eina_Bool
437 _item_multi_select_up(Widget_Data *wd)
438 {
439    unsigned int i;
440    Eina_Bool r = EINA_TRUE;
441
442    if (!wd->selected) return EINA_FALSE;
443
444    for (i = 0; (r) && (i < wd->nmax); i++)
445      r &= _item_multi_select_left(wd);
446
447    return r;
448 }
449
450 static Eina_Bool
451 _item_multi_select_down(Widget_Data *wd)
452 {
453    unsigned int i;
454    Eina_Bool r = EINA_TRUE;
455
456    if (!wd->selected) return EINA_FALSE;
457
458    for (i = 0; (r) && (i < wd->nmax); i++)
459      r &= _item_multi_select_right(wd);
460
461    return r;
462 }
463
464 static Eina_Bool
465 _item_single_select_up(Widget_Data *wd)
466 {
467    unsigned int i;
468
469    Elm_Gengrid_Item *prev;
470
471    if (!wd->selected)
472      {
473         prev = ELM_GENGRID_ITEM_FROM_INLIST(wd->items->last);
474         while ((prev) && (prev->delete_me))
475           prev = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(prev)->prev);
476         elm_gengrid_item_selected_set(prev, EINA_TRUE);
477         elm_gengrid_item_show(prev);
478         return EINA_TRUE;
479      }
480    else prev = elm_gengrid_item_prev_get(wd->last_selected_item);
481
482    if (!prev) return EINA_FALSE;
483
484    for (i = 1; i < wd->nmax; i++)
485      {
486         Elm_Gengrid_Item *tmp = elm_gengrid_item_prev_get(prev);
487         if (!tmp) return EINA_FALSE;
488         prev = tmp;
489      }
490
491    _deselect_all_items(wd);
492
493    elm_gengrid_item_selected_set(prev, EINA_TRUE);
494    elm_gengrid_item_show(prev);
495    return EINA_TRUE;
496 }
497
498 static Eina_Bool
499 _item_single_select_down(Widget_Data *wd)
500 {
501    unsigned int i;
502
503    Elm_Gengrid_Item *next;
504
505    if (!wd->selected)
506      {
507         next = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
508         while ((next) && (next->delete_me))
509           next = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(next)->next);
510         elm_gengrid_item_selected_set(next, EINA_TRUE);
511         elm_gengrid_item_show(next);
512         return EINA_TRUE;
513      }
514    else next = elm_gengrid_item_next_get(wd->last_selected_item);
515
516    if (!next) return EINA_FALSE;
517
518    for (i = 1; i < wd->nmax; i++)
519      {
520         Elm_Gengrid_Item *tmp = elm_gengrid_item_next_get(next);
521         if (!tmp) return EINA_FALSE;
522         next = tmp;
523      }
524
525    _deselect_all_items(wd);
526
527    elm_gengrid_item_selected_set(next, EINA_TRUE);
528    elm_gengrid_item_show(next);
529    return EINA_TRUE;
530 }
531
532 static Eina_Bool
533 _item_single_select_left(Widget_Data *wd)
534 {
535    Elm_Gengrid_Item *prev;
536    if (!wd->selected)
537      {
538         prev = ELM_GENGRID_ITEM_FROM_INLIST(wd->items->last);
539         while ((prev) && (prev->delete_me))
540           prev = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(prev)->prev);
541      }
542    else prev = elm_gengrid_item_prev_get(wd->last_selected_item);
543
544    if (!prev) return EINA_FALSE;
545
546    _deselect_all_items(wd);
547
548    elm_gengrid_item_selected_set(prev, EINA_TRUE);
549    elm_gengrid_item_show(prev);
550    return EINA_TRUE;
551 }
552
553 static Eina_Bool
554 _item_single_select_right(Widget_Data *wd)
555 {
556    Elm_Gengrid_Item *next;
557    if (!wd->selected)
558      {
559         next = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
560         while ((next) && (next->delete_me))
561           next = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(next)->next);
562      }
563    else next = elm_gengrid_item_next_get(wd->last_selected_item);
564
565    if (!next) return EINA_FALSE;
566
567    _deselect_all_items(wd);
568
569    elm_gengrid_item_selected_set(next, EINA_TRUE);
570    elm_gengrid_item_show(next);
571    return EINA_TRUE;
572 }
573
574 static void
575 _on_focus_hook(void *data   __UNUSED__,
576                Evas_Object *obj)
577 {
578    Widget_Data *wd = elm_widget_data_get(obj);
579    if (!wd) return;
580    if (elm_widget_focus_get(obj))
581      {
582         edje_object_signal_emit(wd->self, "elm,action,focus", "elm");
583         evas_object_focus_set(wd->self, EINA_TRUE);
584         if ((wd->selected) && (!wd->last_selected_item))
585           wd->last_selected_item = eina_list_data_get(wd->selected);
586      }
587    else
588      {
589         edje_object_signal_emit(wd->self, "elm,action,unfocus", "elm");
590         evas_object_focus_set(wd->self, EINA_FALSE);
591      }
592 }
593
594 static void
595 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
596 {
597    Widget_Data *wd = elm_widget_data_get(obj);
598    Elm_Gengrid_Item *it;
599    if (!wd) return;
600    elm_smart_scroller_mirrored_set(wd->scr, rtl);
601    if (!wd->items) return;
602    it = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
603
604    while (it)
605      {
606         edje_object_mirrored_set(VIEW(it), rtl);
607         elm_gengrid_item_update(it);
608         it = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
609      }
610 }
611
612 static void
613 _theme_hook(Evas_Object *obj)
614 {
615    Widget_Data *wd = elm_widget_data_get(obj);
616    if (!wd) return;
617    _elm_widget_mirrored_reload(obj);
618    _mirrored_set(obj, elm_widget_mirrored_get(obj));
619    elm_smart_scroller_object_theme_set(obj, wd->scr, "gengrid", "base",
620                                        elm_widget_style_get(obj));
621 }
622
623 static void
624 _del_pre_hook(Evas_Object *obj)
625 {
626    Widget_Data *wd = elm_widget_data_get(obj);
627    if (!wd) return;
628    elm_gengrid_clear(obj);
629    evas_object_del(wd->pan_smart);
630    wd->pan_smart = NULL;
631 }
632
633 static void
634 _del_hook(Evas_Object *obj)
635 {
636    Widget_Data *wd = elm_widget_data_get(obj);
637    free(wd);
638 }
639
640 static void
641 _signal_emit_hook(Evas_Object *obj,
642                   const char  *emission,
643                   const char  *source)
644 {
645    Widget_Data *wd = elm_widget_data_get(obj);
646    if (!wd) return;
647    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
648                            emission, source);
649 }
650
651 static void
652 _signal_callback_add_hook(Evas_Object *obj,
653                           const char  *emission,
654                           const char  *source,
655                           Edje_Signal_Cb func_cb,
656                           void *data)
657 {
658    Widget_Data *wd = elm_widget_data_get(obj);
659    if (!wd) return;
660    edje_object_signal_callback_add(elm_smart_scroller_edje_object_get(wd->scr),
661                                    emission, source, func_cb, data);
662 }
663
664 static void
665 _signal_callback_del_hook(Evas_Object *obj,
666                           const char  *emission,
667                           const char  *source,
668                           Edje_Signal_Cb func_cb,
669                           void *data)
670 {
671    Widget_Data *wd = elm_widget_data_get(obj);
672    if (!wd) return;
673    edje_object_signal_callback_del_full(elm_smart_scroller_edje_object_get(wd->scr),
674                                         emission, source, func_cb, data);
675 }
676
677 static void
678 _mouse_move(void        *data,
679             Evas *evas   __UNUSED__,
680             Evas_Object *obj,
681             void        *event_info)
682 {
683    Elm_Gengrid_Item *it = data;
684    Evas_Event_Mouse_Move *ev = event_info;
685    Evas_Coord minw = 0, minh = 0, x, y, dx, dy, adx, ady;
686    Evas_Coord ox, oy, ow, oh, it_scrl_x, it_scrl_y;
687
688    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
689      {
690         if (!it->wd->on_hold)
691           {
692              it->wd->on_hold = EINA_TRUE;
693              if (!it->wd->wasselected)
694                _item_unselect(it);
695           }
696      }
697    if ((it->dragging) && (it->down))
698      {
699         if (it->long_timer)
700           {
701              ecore_timer_del(it->long_timer);
702              it->long_timer = NULL;
703           }
704         evas_object_smart_callback_call(it->wd->self, SIG_DRAG, it);
705         return;
706      }
707    if ((!it->down) || (it->wd->longpressed))
708      {
709         if (it->long_timer)
710           {
711              ecore_timer_del(it->long_timer);
712              it->long_timer = NULL;
713           }
714         if ((it->wd->reorder_mode) && (it->wd->reorder_item))
715           {
716              evas_object_geometry_get(it->wd->pan_smart, &ox, &oy, &ow, &oh);
717
718              it_scrl_x = ev->cur.canvas.x - it->wd->reorder_item->dx;
719              it_scrl_y = ev->cur.canvas.y - it->wd->reorder_item->dy;
720
721              if (it_scrl_x < ox) it->wd->reorder_item_x = ox;
722              else if (it_scrl_x + it->wd->item_width > ox + ow)
723                it->wd->reorder_item_x = ox + ow - it->wd->item_width;
724              else it->wd->reorder_item_x = it_scrl_x;
725
726              if (it_scrl_y < oy) it->wd->reorder_item_y = oy;
727              else if (it_scrl_y + it->wd->item_height > oy + oh)
728                it->wd->reorder_item_y = oy + oh - it->wd->item_height;
729              else it->wd->reorder_item_y = it_scrl_y;
730
731              if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
732              it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
733           }
734         return;
735      }
736    if (!it->display_only)
737      elm_coords_finger_size_adjust(1, &minw, 1, &minh);
738    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
739    x = ev->cur.canvas.x - x;
740    y = ev->cur.canvas.y - y;
741    dx = x - it->dx;
742    adx = dx;
743    if (adx < 0) adx = -dx;
744    dy = y - it->dy;
745    ady = dy;
746    if (ady < 0) ady = -dy;
747    minw /= 2;
748    minh /= 2;
749    if ((adx > minw) || (ady > minh))
750      {
751         const char *left_drag, *right_drag;
752         if (!elm_widget_mirrored_get(it->wd->self))
753           {
754              left_drag = SIG_DRAG_START_LEFT;
755              right_drag = SIG_DRAG_START_RIGHT;
756           }
757         else
758           {
759              left_drag = SIG_DRAG_START_RIGHT;
760              right_drag = SIG_DRAG_START_LEFT;
761           }
762
763         it->dragging = 1;
764         if (it->long_timer)
765           {
766              ecore_timer_del(it->long_timer);
767              it->long_timer = NULL;
768           }
769         if (!it->wd->wasselected)
770           _item_unselect(it);
771         if (dy < 0)
772           {
773              if (ady > adx)
774                evas_object_smart_callback_call(it->wd->self, SIG_DRAG_START_UP,
775                                                it);
776              else
777                {
778                   if (dx < 0)
779                     evas_object_smart_callback_call(it->wd->self,
780                                                     left_drag, it);
781                }
782           }
783         else
784           {
785              if (ady > adx)
786                evas_object_smart_callback_call(it->wd->self,
787                                                SIG_DRAG_START_DOWN, it);
788              else
789                {
790                   if (dx < 0)
791                     evas_object_smart_callback_call(it->wd->self,
792                                                     left_drag, it);
793                   else
794                     evas_object_smart_callback_call(it->wd->self,
795                                                     right_drag, it);
796                }
797           }
798      }
799 }
800
801 static Eina_Bool
802 _long_press(void *data)
803 {
804    Elm_Gengrid_Item *it = data;
805
806    it->long_timer = NULL;
807    if ((it->disabled) || (it->dragging)) return ECORE_CALLBACK_CANCEL;
808    it->wd->longpressed = EINA_TRUE;
809    evas_object_smart_callback_call(it->wd->self, SIG_LONGPRESSED, it);
810    if (it->wd->reorder_mode)
811      {
812         it->wd->reorder_item = it;
813         evas_object_raise(VIEW(it));
814         elm_smart_scroller_hold_set(it->wd->scr, EINA_TRUE);
815         elm_smart_scroller_bounce_allow_set(it->wd->scr, EINA_FALSE, EINA_FALSE);
816         edje_object_signal_emit(VIEW(it), "elm,state,reorder,enabled", "elm");
817      }
818    return ECORE_CALLBACK_CANCEL;
819 }
820
821 static void
822 _mouse_down(void        *data,
823             Evas *evas   __UNUSED__,
824             Evas_Object *obj,
825             void        *event_info)
826 {
827    Elm_Gengrid_Item *it = data;
828    Evas_Event_Mouse_Down *ev = event_info;
829    Evas_Coord x, y;
830
831    if (ev->button != 1) return;
832    it->down = 1;
833    it->dragging = 0;
834    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
835    it->dx = ev->canvas.x - x;
836    it->dy = ev->canvas.y - y;
837    it->wd->longpressed = EINA_FALSE;
838    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE;
839    else it->wd->on_hold = EINA_FALSE;
840    it->wd->wasselected = it->selected;
841    _item_highlight(it);
842    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
843      {
844         evas_object_smart_callback_call(it->wd->self, SIG_CLICKED_DOUBLE, it);
845         evas_object_smart_callback_call(it->wd->self, SIG_ACTIVATED, it);
846      }
847    if (it->long_timer) ecore_timer_del(it->long_timer);
848    if (it->realized)
849      it->long_timer = ecore_timer_add(_elm_config->longpress_timeout,
850                                         _long_press, it);
851    else
852      it->long_timer = NULL;
853 }
854
855 static void
856 _mouse_up(void            *data,
857           Evas *evas       __UNUSED__,
858           Evas_Object *obj __UNUSED__,
859           void            *event_info)
860 {
861    Elm_Gengrid_Item *it = data;
862    Evas_Event_Mouse_Up *ev = event_info;
863    Eina_Bool dragged = EINA_FALSE;
864
865    if (ev->button != 1) return;
866    it->down = EINA_FALSE;
867    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE;
868    else it->wd->on_hold = EINA_FALSE;
869    if (it->long_timer)
870      {
871         ecore_timer_del(it->long_timer);
872         it->long_timer = NULL;
873      }
874    if (it->dragging)
875      {
876         it->dragging = EINA_FALSE;
877         evas_object_smart_callback_call(it->wd->self, SIG_DRAG_STOP, it);
878         dragged = EINA_TRUE;
879      }
880    if (it->wd->on_hold)
881      {
882         it->wd->longpressed = EINA_FALSE;
883         it->wd->on_hold = EINA_FALSE;
884         return;
885      }
886    if ((it->wd->reorder_mode) && (it->wd->reorder_item))
887      {
888         evas_object_smart_callback_call(it->wd->self, SIG_MOVED, it->wd->reorder_item);
889         it->wd->reorder_item = NULL;
890         it->wd->move_effect_enabled = EINA_FALSE;
891         if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
892           it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
893
894         elm_smart_scroller_hold_set(it->wd->scr, EINA_FALSE);
895         elm_smart_scroller_bounce_allow_set(it->wd->scr, it->wd->h_bounce, it->wd->v_bounce);
896         edje_object_signal_emit(VIEW(it), "elm,state,reorder,disabled", "elm");
897      }
898    if (it->wd->longpressed)
899      {
900         it->wd->longpressed = EINA_FALSE;
901         if (!it->wd->wasselected) _item_unselect(it);
902         it->wd->wasselected = EINA_FALSE;
903         return;
904      }
905    if (dragged)
906      {
907         if (it->want_unrealize) _item_unrealize(it);
908      }
909    if ((it->disabled) || (dragged)) return;
910    if (it->wd->multi)
911      {
912         if (!it->selected)
913           {
914              _item_highlight(it);
915              _item_select(it);
916           }
917         else _item_unselect(it);
918      }
919    else
920      {
921         if (!it->selected)
922           {
923              while (it->wd->selected)
924                _item_unselect(it->wd->selected->data);
925           }
926         else
927           {
928              const Eina_List *l, *l_next;
929              Elm_Gengrid_Item *item2;
930
931              EINA_LIST_FOREACH_SAFE(it->wd->selected, l, l_next, item2)
932                 if (item2 != it) _item_unselect(item2);
933           }
934         _item_highlight(it);
935         _item_select(it);
936      }
937 }
938
939 static void
940 _item_highlight(Elm_Gengrid_Item *it)
941 {
942    if ((it->wd->no_select) || (it->delete_me) || (it->highlighted)) return;
943    edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm");
944    it->highlighted = EINA_TRUE;
945 }
946
947 static void
948 _item_realize(Elm_Gengrid_Item *it)
949 {
950    char buf[1024];
951    char style[1024];
952
953    if ((it->realized) || (it->delete_me)) return;
954    VIEW(it) = edje_object_add(evas_object_evas_get(it->wd->self));
955    edje_object_scale_set(VIEW(it), elm_widget_scale_get(it->wd->self) *
956                          _elm_config->scale);
957    edje_object_mirrored_set(VIEW(it), elm_widget_mirrored_get(WIDGET(it)));
958    evas_object_smart_member_add(VIEW(it), it->wd->pan_smart);
959    elm_widget_sub_object_add(it->wd->self, VIEW(it));
960    snprintf(style, sizeof(style), "item/%s",
961             it->itc->item_style ? it->itc->item_style : "default");
962    _elm_theme_object_set(it->wd->self, VIEW(it), "gengrid", style,
963                          elm_widget_style_get(it->wd->self));
964    it->spacer =
965       evas_object_rectangle_add(evas_object_evas_get(it->wd->self));
966    evas_object_color_set(it->spacer, 0, 0, 0, 0);
967    elm_widget_sub_object_add(it->wd->self, it->spacer);
968    evas_object_size_hint_min_set(it->spacer, 2 * _elm_config->scale, 1);
969    edje_object_part_swallow(VIEW(it), "elm.swallow.pad", it->spacer);
970
971    if (it->itc->func.label_get)
972      {
973         const Eina_List *l;
974         const char *key;
975
976         it->labels =
977            elm_widget_stringlist_get(edje_object_data_get(VIEW(it),
978                                                           "labels"));
979         EINA_LIST_FOREACH(it->labels, l, key)
980           {
981              char *s = it->itc->func.label_get
982                 ((void *)it->base.data, it->wd->self, l->data);
983              if (s)
984                {
985                   edje_object_part_text_set(VIEW(it), l->data, s);
986                   free(s);
987                }
988           }
989      }
990
991    if (it->itc->func.icon_get)
992      {
993         const Eina_List *l;
994         const char *key;
995
996         it->icons =
997            elm_widget_stringlist_get(edje_object_data_get(VIEW(it),
998                                                           "icons"));
999         EINA_LIST_FOREACH(it->icons, l, key)
1000           {
1001              Evas_Object *ic = it->itc->func.icon_get
1002                 ((void *)it->base.data, it->wd->self, l->data);
1003              if (ic)
1004                {
1005                   it->icon_objs = eina_list_append(it->icon_objs, ic);
1006                   edje_object_part_swallow(VIEW(it), key, ic);
1007                   evas_object_show(ic);
1008                   elm_widget_sub_object_add(it->wd->self, ic);
1009                }
1010           }
1011      }
1012
1013    if (it->itc->func.state_get)
1014      {
1015         const Eina_List *l;
1016         const char *key;
1017
1018         it->states =
1019            elm_widget_stringlist_get(edje_object_data_get(VIEW(it),
1020                                                           "states"));
1021         EINA_LIST_FOREACH(it->states, l, key)
1022           {
1023              Eina_Bool on = it->itc->func.state_get
1024                 ((void *)it->base.data, it->wd->self, l->data);
1025              if (on)
1026                {
1027                   snprintf(buf, sizeof(buf), "elm,state,%s,active", key);
1028                   edje_object_signal_emit(VIEW(it), buf, "elm");
1029                }
1030           }
1031      }
1032
1033    if (it->is_group)
1034      {
1035         if ((!it->wd->group_item_width) && (!it->wd->group_item_height))
1036           {
1037              edje_object_size_min_restricted_calc(VIEW(it),
1038                                                   &it->wd->group_item_width,
1039                                                   &it->wd->group_item_height,
1040                                                   it->wd->group_item_width,
1041                                                   it->wd->group_item_height);
1042           }
1043      }
1044    else
1045      {
1046         if ((!it->wd->item_width) && (!it->wd->item_height))
1047           {
1048              edje_object_size_min_restricted_calc(VIEW(it),
1049                                                   &it->wd->item_width,
1050                                                   &it->wd->item_height,
1051                                                   it->wd->item_width,
1052                                                   it->wd->item_height);
1053              elm_coords_finger_size_adjust(1, &it->wd->item_width,
1054                                            1, &it->wd->item_height);
1055           }
1056
1057         evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_DOWN,
1058                                        _mouse_down, it);
1059         evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_UP,
1060                                        _mouse_up, it);
1061         evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_MOVE,
1062                                        _mouse_move, it);
1063
1064         if (it->selected)
1065           edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm");
1066         if (it->disabled)
1067           edje_object_signal_emit(VIEW(it), "elm,state,disabled", "elm");
1068      }
1069    evas_object_show(VIEW(it));
1070
1071    if (it->tooltip.content_cb)
1072      {
1073         elm_widget_item_tooltip_content_cb_set(it,
1074                                                it->tooltip.content_cb,
1075                                                it->tooltip.data, NULL);
1076         elm_widget_item_tooltip_style_set(it, it->tooltip.style);
1077         elm_widget_item_tooltip_size_restrict_disable(it, it->tooltip.free_size);
1078      }
1079
1080    if (it->mouse_cursor)
1081      elm_widget_item_cursor_set(it, it->mouse_cursor);
1082
1083    it->realized = EINA_TRUE;
1084    it->want_unrealize = EINA_FALSE;
1085 }
1086
1087 static void
1088 _item_unrealize(Elm_Gengrid_Item *it, Eina_Bool calc)
1089 {
1090    Evas_Object *icon;
1091
1092    if (!it->realized) return;
1093    if (!calc)
1094      evas_object_smart_callback_call(WIDGET(it), SIG_UNREALIZED, it);
1095    if (it->long_timer)
1096      {
1097         ecore_timer_del(it->long_timer);
1098         it->long_timer = NULL;
1099      }
1100    evas_object_del(VIEW(it));
1101    VIEW(it) = NULL;
1102    evas_object_del(it->spacer);
1103    it->spacer = NULL;
1104    elm_widget_stringlist_free(it->labels);
1105    it->labels = NULL;
1106    elm_widget_stringlist_free(it->icons);
1107    it->icons = NULL;
1108    elm_widget_stringlist_free(it->states);
1109    it->states = NULL;
1110
1111    EINA_LIST_FREE(it->icon_objs, icon)
1112       evas_object_del(icon);
1113
1114    it->realized = EINA_FALSE;
1115    it->want_unrealize = EINA_FALSE;
1116 }
1117
1118 static Eina_Bool
1119 _reorder_item_moving_effect_timer_cb(void *data)
1120 {
1121    Elm_Gengrid_Item *it = data;
1122    double time, t;
1123    Evas_Coord dx, dy;
1124
1125    time = REORDER_EFFECT_TIME;
1126    t = ((0.0 > (t = ecore_loop_time_get()-it->moving_effect_start_time)) ? 0.0 : t);
1127    dx = ((it->tx - it->ox) / 10) * _elm_config->scale;
1128    dy = ((it->ty - it->oy) / 10) * _elm_config->scale;
1129
1130    if (t <= time)
1131      {
1132         it->rx += (1 * sin((t / time) * (M_PI / 2)) * dx);
1133         it->ry += (1 * sin((t / time) * (M_PI / 2)) * dy);
1134      }
1135    else
1136      {
1137         it->rx += dx;
1138         it->ry += dy;
1139      }
1140
1141    if ((((dx > 0) && (it->rx >= it->tx)) || ((dx <= 0) && (it->rx <= it->tx))) &&
1142        (((dy > 0) && (it->ry >= it->ty)) || ((dy <= 0) && (it->ry <= it->ty))))
1143      {
1144         evas_object_move(VIEW(it), it->tx, it->ty);
1145         if (it->is_group)
1146           {
1147              Evas_Coord vw, vh;
1148              evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &vw, &vh);
1149              if (it->wd->horizontal)
1150                evas_object_resize(VIEW(it), it->wd->group_item_width, vh);
1151              else
1152                evas_object_resize(VIEW(it), vw, it->wd->group_item_height);
1153           }
1154         else
1155           evas_object_resize(VIEW(it), it->wd->item_width, it->wd->item_height);
1156         it->moving = EINA_FALSE;
1157         it->item_moving_effect_timer = NULL;
1158         return ECORE_CALLBACK_CANCEL;
1159      }
1160
1161    evas_object_move(VIEW(it), it->rx, it->ry);
1162    if (it->is_group)
1163      {
1164         Evas_Coord vw, vh;
1165         evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &vw, &vh);
1166         if (it->wd->horizontal)
1167           evas_object_resize(VIEW(it), it->wd->group_item_width, vh);
1168         else
1169           evas_object_resize(VIEW(it), vw, it->wd->group_item_height);
1170      }
1171    else
1172      evas_object_resize(VIEW(it), it->wd->item_width, it->wd->item_height);
1173
1174    return ECORE_CALLBACK_RENEW;
1175 }
1176
1177 static void
1178 _group_item_place(Pan *sd)
1179 {
1180    Evas_Coord iw, ih, vw, vh;
1181    Eina_List *l;
1182    Eina_Bool was_realized;
1183    Elm_Gengrid_Item *it;
1184    evas_object_geometry_get(sd->wd->pan_smart, NULL, NULL, &vw, &vh);
1185    if (sd->wd->horizontal)
1186      {
1187         iw = sd->wd->group_item_width;
1188         ih = vh;
1189      }
1190    else
1191      {
1192         iw = vw;
1193         ih = sd->wd->group_item_height;
1194      }
1195    EINA_LIST_FOREACH(sd->wd->group_items, l, it)
1196      {
1197         was_realized = it->realized;
1198         if (it->group_realized)
1199           {
1200              _item_realize(it);
1201              if (!was_realized)
1202                evas_object_smart_callback_call(it->wd->self, SIG_REALIZED, it);
1203              evas_object_move(VIEW(it), it->gx, it->gy);
1204              evas_object_resize(VIEW(it), iw, ih);
1205              evas_object_raise(VIEW(it));
1206           }
1207         else
1208           _item_unrealize(it);
1209      }
1210 }
1211
1212
1213 static void
1214 _item_place(Elm_Gengrid_Item *it,
1215             Evas_Coord        cx,
1216             Evas_Coord        cy)
1217 {
1218    Evas_Coord x, y, ox, oy, cvx, cvy, cvw, cvh, iw, ih, ww;
1219    Evas_Coord tch, tcw, alignw = 0, alignh = 0, vw, vh;
1220    Eina_Bool reorder_item_move_forward = EINA_FALSE;
1221    long items_count;
1222    it->x = cx;
1223    it->y = cy;
1224    evas_object_geometry_get(it->wd->pan_smart, &ox, &oy, &vw, &vh);
1225
1226    /* Preload rows/columns at each side of the Gengrid */
1227    cvx = ox - PRELOAD * it->wd->item_width;
1228    cvy = oy - PRELOAD * it->wd->item_height;
1229    cvw = vw + 2 * PRELOAD * it->wd->item_width;
1230    cvh = vh + 2 * PRELOAD * it->wd->item_height;
1231
1232    alignh = 0;
1233    alignw = 0;
1234
1235    items_count = it->wd->count - eina_list_count(it->wd->group_items) + it->wd->items_lost;
1236    if (it->wd->horizontal)
1237      {
1238         int columns, items_visible = 0, items_row;
1239
1240         if (it->wd->item_height > 0)
1241           items_visible = vh / it->wd->item_height;
1242         if (items_visible < 1)
1243           items_visible = 1;
1244
1245         columns = items_count / items_visible;
1246         if (items_count % items_visible)
1247           columns++;
1248
1249         tcw = (it->wd->item_width * columns) + (it->wd->group_item_width * eina_list_count(it->wd->group_items));
1250         alignw = (vw - tcw) * it->wd->align_x;
1251
1252         items_row = items_visible;
1253         if (items_row > it->wd->count)
1254           items_row = it->wd->count;
1255         tch = items_row * it->wd->item_height;
1256         alignh = (vh - tch) * it->wd->align_y;
1257      }
1258    else
1259      {
1260         int rows, items_visible = 0, items_col;
1261
1262         if (it->wd->item_width > 0)
1263           items_visible = vw / it->wd->item_width;
1264         if (items_visible < 1)
1265           items_visible = 1;
1266
1267         rows = items_count / items_visible;
1268         if (items_count % items_visible)
1269           rows++;
1270
1271         tch = (it->wd->item_height * rows) + (it->wd->group_item_height * eina_list_count(it->wd->group_items));
1272         alignh = (vh - tch) * it->wd->align_y;
1273
1274         items_col = items_visible;
1275         if (items_col > it->wd->count)
1276           items_col = it->wd->count;
1277         tcw = items_col * it->wd->item_width;
1278         alignw = (vw - tcw) * it->wd->align_x;
1279      }
1280
1281    if (it->is_group)
1282      {
1283         if (it->wd->horizontal)
1284           {
1285              x = (((cx - it->prev_group) * it->wd->item_width) + (it->prev_group * it->wd->group_item_width)) - it->wd->pan_x + ox + alignw;
1286              y = 0;
1287              iw = it->wd->group_item_width;
1288              ih = vh;
1289           }
1290         else
1291           {
1292              x = 0;
1293              y = (((cy - it->prev_group) * it->wd->item_height) + (it->prev_group * it->wd->group_item_height)) - it->wd->pan_y + oy + alignh;
1294              iw = vw;
1295              ih = it->wd->group_item_height;
1296           }
1297         it->gx = x;
1298         it->gy = y;
1299      }
1300    else
1301      {
1302         if (it->wd->horizontal)
1303           {
1304              x = (((cx - it->prev_group) * it->wd->item_width) + (it->prev_group * it->wd->group_item_width)) - it->wd->pan_x + ox + alignw;
1305              y = (cy * it->wd->item_height) - it->wd->pan_y + oy + alignh;
1306           }
1307         else
1308           {
1309              x = (cx * it->wd->item_width) - it->wd->pan_x + ox + alignw;
1310              y = (((cy - it->prev_group) * it->wd->item_height) + (it->prev_group * it->wd->group_item_height)) - it->wd->pan_y + oy + alignh;
1311           }
1312         if (elm_widget_mirrored_get(it->wd->self))
1313           {  /* Switch items side and componsate for pan_x when in RTL mode */
1314              evas_object_geometry_get(it->wd->self, NULL, NULL, &ww, NULL);
1315              x = ww - x - it->wd->item_width - it->wd->pan_x - it->wd->pan_x;
1316           }
1317         iw = it->wd->item_width;
1318         ih = it->wd->item_height;
1319      }
1320
1321    Eina_Bool was_realized = it->realized;
1322    if (ELM_RECTS_INTERSECT(x, y, iw, ih, cvx, cvy, cvw, cvh))
1323      {
1324         _item_realize(it);
1325         if (!was_realized)
1326           evas_object_smart_callback_call(it->wd->self, SIG_REALIZED, it);
1327         if (it->parent)
1328           {
1329              if (it->wd->horizontal)
1330                {
1331                   if (it->parent->gx < 0)
1332                     {
1333                        it->parent->gx = x + it->wd->item_width - it->wd->group_item_width;
1334                        if (it->parent->gx > 0)
1335                          it->parent->gx = 0;
1336                     }
1337                }
1338              else
1339                {
1340                   if (it->parent->gy < 0)
1341                     {
1342                        it->parent->gy = y + it->wd->item_height - it->wd->group_item_height;
1343                        if (it->parent->gy > 0)
1344                          it->parent->gy = 0;
1345                     }
1346                   it->parent->group_realized = EINA_TRUE;
1347                }
1348           }
1349         if (it->wd->reorder_mode)
1350           {
1351              if (it->wd->reorder_item)
1352                {
1353                   if (it->moving) return;
1354
1355                   if (!it->wd->move_effect_enabled)
1356                     {
1357                        it->ox = x;
1358                        it->oy = y;
1359                     }
1360                   if (it->wd->reorder_item == it)
1361                     {
1362                        evas_object_move(VIEW(it),
1363                                         it->wd->reorder_item_x, it->wd->reorder_item_y);
1364                        evas_object_resize(VIEW(it), iw, ih);
1365                        return;
1366                     }
1367                   else
1368                     {
1369                        if (it->wd->move_effect_enabled)
1370                          {
1371                             if ((it->ox != x) || (it->oy != y))
1372                               {
1373                                  if (((it->wd->old_pan_x == it->wd->pan_x) && (it->wd->old_pan_y == it->wd->pan_y)) ||
1374                                      ((it->wd->old_pan_x != it->wd->pan_x) && !(it->ox - it->wd->pan_x + it->wd->old_pan_x == x)) ||
1375                                      ((it->wd->old_pan_y != it->wd->pan_y) && !(it->oy - it->wd->pan_y + it->wd->old_pan_y == y)))
1376                                    {
1377                                       it->tx = x;
1378                                       it->ty = y;
1379                                       it->rx = it->ox;
1380                                       it->ry = it->oy;
1381                                       it->moving = EINA_TRUE;
1382                                       it->moving_effect_start_time = ecore_loop_time_get();
1383                                       it->item_moving_effect_timer = ecore_animator_add(_reorder_item_moving_effect_timer_cb, it);
1384                                       return;
1385                                    }
1386                               }
1387                          }
1388
1389                        /* need fix here */
1390                        Evas_Coord nx, ny, nw, nh;
1391                        if (it->is_group)
1392                          {
1393                             if (it->wd->horizontal)
1394                               {
1395                                  nx = x + (it->wd->group_item_width / 2);
1396                                  ny = y;
1397                                  nw = 1;
1398                                  nh = vh;
1399                               }
1400                             else
1401                               {
1402                                  nx = x;
1403                                  ny = y + (it->wd->group_item_height / 2);
1404                                  nw = vw;
1405                                  nh = 1;
1406                               }
1407                          }
1408                        else
1409                          {
1410                             nx = x + (it->wd->item_width / 2);
1411                             ny = y + (it->wd->item_height / 2);
1412                             nw = 1;
1413                             nh = 1;
1414                          }
1415
1416                        if ( ELM_RECTS_INTERSECT(it->wd->reorder_item_x, it->wd->reorder_item_y,
1417                                                 it->wd->item_width, it->wd->item_height,
1418                                                 nx, ny, nw, nh))
1419                          {
1420                             if (it->wd->horizontal)
1421                               {
1422                                  if ((it->wd->nmax * it->wd->reorder_item->x + it->wd->reorder_item->y) >
1423                                      (it->wd->nmax * it->x + it->y))
1424                                    reorder_item_move_forward = EINA_TRUE;
1425                               }
1426                             else
1427                               {
1428                                  if ((it->wd->nmax * it->wd->reorder_item->y + it->wd->reorder_item->x) >
1429                                      (it->wd->nmax * it->y + it->x))
1430                                    reorder_item_move_forward = EINA_TRUE;
1431                               }
1432
1433                             it->wd->items = eina_inlist_remove(it->wd->items,
1434                                                                  EINA_INLIST_GET(it->wd->reorder_item));
1435                             if (reorder_item_move_forward)
1436                               it->wd->items = eina_inlist_prepend_relative(it->wd->items,
1437                                                                              EINA_INLIST_GET(it->wd->reorder_item),
1438                                                                              EINA_INLIST_GET(it));
1439                             else
1440                               it->wd->items = eina_inlist_append_relative(it->wd->items,
1441                                                                             EINA_INLIST_GET(it->wd->reorder_item),
1442                                                                             EINA_INLIST_GET(it));
1443
1444                             it->wd->reorder_item_changed = EINA_TRUE;
1445                             it->wd->move_effect_enabled = EINA_TRUE;
1446                             if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
1447                               it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
1448
1449                             return;
1450                          }
1451                     }
1452                }
1453              else if (it->item_moving_effect_timer)
1454                {
1455                   ecore_animator_del(it->item_moving_effect_timer);
1456                   it->item_moving_effect_timer = NULL;
1457                   it->moving = EINA_FALSE;
1458                }
1459           }
1460         if (!it->is_group)
1461           {
1462              evas_object_move(VIEW(it), x, y);
1463              evas_object_resize(VIEW(it), iw, ih);
1464           }
1465         else
1466           it->group_realized = EINA_TRUE;
1467      }
1468    else
1469      {
1470         if (!it->is_group)
1471           _item_unrealize(it);
1472         else
1473           it->group_realized = EINA_FALSE;
1474      }
1475 }
1476
1477 static const char *
1478 _item_label_hook(Elm_Gengrid_Item *it, const char *part)
1479 {
1480    if (!it->itc->func.label_get) return NULL;
1481    return edje_object_part_text_get(VIEW(it), part);
1482 }
1483
1484 static Elm_Gengrid_Item *
1485 _item_new(Widget_Data                  *wd,
1486              const Elm_Gengrid_Item_Class *itc,
1487              const void                   *data,
1488              Evas_Smart_Cb                 func,
1489              const void                   *func_data)
1490 {
1491    Elm_Gengrid_Item *it;
1492
1493    it = elm_widget_item_new(wd->self, Elm_Gengrid_Item);
1494    if (!it) return NULL;
1495    wd->count++;
1496    it->wd = wd;
1497    it->itc = itc;
1498    it->base.data = data;
1499    it->func.func = func;
1500    it->func.data = func_data;
1501    it->mouse_cursor = NULL;
1502    it->is_group = !strcmp(it->itc->item_style, "group_index");
1503    elm_widget_item_text_get_hook_set(it, _item_label_hook);
1504
1505    return it;
1506 }
1507
1508 static void
1509 _item_del(Elm_Gengrid_Item *it)
1510 {
1511    elm_widget_item_pre_notify_del(it);
1512    if (it->selected)
1513      it->wd->selected = eina_list_remove(it->wd->selected, it);
1514    if (it->realized) _item_unrealize(it);
1515    if ((!it->delete_me) && (it->itc->func.del))
1516      it->itc->func.del((void *)it->base.data, it->wd->self);
1517    it->delete_me = EINA_TRUE;
1518    it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
1519    if (it->long_timer) ecore_timer_del(it->long_timer);
1520    if (it->tooltip.del_cb)
1521      it->tooltip.del_cb((void *)it->tooltip.data, WIDGET(it), it);
1522    it->wd->walking -= it->walking;
1523    it->wd->count--;
1524    if (it->is_group)
1525      it->wd->group_items = eina_list_remove(it->wd->group_items, it);
1526    if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
1527    it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
1528    elm_widget_item_del(it);
1529 }
1530
1531 static void
1532 _item_select(Elm_Gengrid_Item *it)
1533 {
1534    if ((it->wd->no_select) || (it->delete_me)) return;
1535    if (it->selected)
1536      {
1537         if (it->wd->always_select) goto call;
1538         return;
1539      }
1540    it->selected = EINA_TRUE;
1541    it->wd->selected = eina_list_append(it->wd->selected, it);
1542 call:
1543    it->walking++;
1544    it->wd->walking++;
1545    if (it->func.func)
1546      it->func.func((void *)it->func.data, it->wd->self, it);
1547    if (!it->delete_me)
1548      evas_object_smart_callback_call(it->wd->self, SIG_SELECTED, it);
1549    it->walking--;
1550    it->wd->walking--;
1551    it->wd->last_selected_item = it;
1552    if ((it->wd->clear_me) && (!it->wd->walking))
1553      elm_gengrid_clear(WIDGET(it));
1554    else
1555      {
1556         if ((!it->walking) && (it->delete_me))
1557           if (!it->relcount) _item_del(it);
1558      }
1559 }
1560
1561 static void
1562 _item_unselect(Elm_Gengrid_Item *it)
1563 {
1564    if ((it->delete_me) || (!it->highlighted)) return;
1565    edje_object_signal_emit(VIEW(it), "elm,state,unselected", "elm");
1566    it->highlighted = EINA_FALSE;
1567    if (it->selected)
1568      {
1569         it->selected = EINA_FALSE;
1570         it->wd->selected = eina_list_remove(it->wd->selected, it);
1571         evas_object_smart_callback_call(it->wd->self, SIG_UNSELECTED, it);
1572      }
1573 }
1574
1575 static void
1576 _calc_job(void *data)
1577 {
1578    Widget_Data *wd = data;
1579    Evas_Coord minw = 0, minh = 0, nmax = 0, cvw, cvh;
1580    Elm_Gengrid_Item *it, *group_item = NULL;
1581    int count_group = 0;
1582    long count = 0;
1583    wd->items_lost = 0;
1584
1585    evas_object_geometry_get(wd->pan_smart, NULL, NULL, &cvw, &cvh);
1586    if ((cvw != 0) || (cvh != 0))
1587      {
1588         if ((wd->horizontal) && (wd->item_height > 0))
1589           nmax = cvh / wd->item_height;
1590         else if (wd->item_width > 0)
1591           nmax = cvw / wd->item_width;
1592
1593         if (nmax < 1)
1594           nmax = 1;
1595
1596         EINA_INLIST_FOREACH(wd->items, it)
1597           {
1598              if (it->prev_group != count_group)
1599                it->prev_group = count_group;
1600              if (it->is_group)
1601                {
1602                   count = count % nmax;
1603                   if (count)
1604                     wd->items_lost += nmax - count;
1605                   //printf("%d items and I lost %d\n", count, wd->items_lost);
1606                   count_group++;
1607                   if (count) count = 0;
1608                   group_item = it;
1609                }
1610              else
1611                {
1612                   if (it->parent != group_item)
1613                     it->parent = group_item;
1614                   count++;
1615                }
1616           }
1617         count = wd->count + wd->items_lost - count_group;
1618         if (wd->horizontal)
1619           {
1620              minw = (ceil(count / (float)nmax) * wd->item_width) + (count_group * wd->group_item_width);
1621              minh = nmax * wd->item_height;
1622           }
1623         else
1624           {
1625              minw = nmax * wd->item_width;
1626              minh = (ceil(count / (float)nmax) * wd->item_height) + (count_group * wd->group_item_height);
1627           }
1628
1629         if ((minw != wd->minw) || (minh != wd->minh))
1630           {
1631              wd->minh = minh;
1632              wd->minw = minw;
1633              evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
1634           }
1635
1636         wd->nmax = nmax;
1637         evas_object_smart_changed(wd->pan_smart);
1638      }
1639    wd->calc_job = NULL;
1640 }
1641
1642 static void
1643 _pan_add(Evas_Object *obj)
1644 {
1645    Pan *sd;
1646    Evas_Object_Smart_Clipped_Data *cd;
1647
1648    _pan_sc.add(obj);
1649    cd = evas_object_smart_data_get(obj);
1650    sd = ELM_NEW(Pan);
1651    if (!sd) return;
1652    sd->__clipped_data = *cd;
1653    free(cd);
1654    evas_object_smart_data_set(obj, sd);
1655 }
1656
1657 static void
1658 _pan_del(Evas_Object *obj)
1659 {
1660    Pan *sd = evas_object_smart_data_get(obj);
1661
1662    if (!sd) return;
1663    _pan_sc.del(obj);
1664 }
1665
1666 static void
1667 _pan_set(Evas_Object *obj,
1668          Evas_Coord   x,
1669          Evas_Coord   y)
1670 {
1671    Pan *sd = evas_object_smart_data_get(obj);
1672    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
1673    sd->wd->pan_x = x;
1674    sd->wd->pan_y = y;
1675    evas_object_smart_changed(obj);
1676 }
1677
1678 static void
1679 _pan_get(Evas_Object *obj,
1680          Evas_Coord  *x,
1681          Evas_Coord  *y)
1682 {
1683    Pan *sd = evas_object_smart_data_get(obj);
1684    if (x) *x = sd->wd->pan_x;
1685    if (y) *y = sd->wd->pan_y;
1686 }
1687
1688 static void
1689 _pan_child_size_get(Evas_Object *obj,
1690                     Evas_Coord  *w,
1691                     Evas_Coord  *h)
1692 {
1693    Pan *sd = evas_object_smart_data_get(obj);
1694    if (w) *w = sd->wd->minw;
1695    if (h) *h = sd->wd->minh;
1696 }
1697
1698 static void
1699 _pan_max_get(Evas_Object *obj,
1700              Evas_Coord  *x,
1701              Evas_Coord  *y)
1702 {
1703    Pan *sd = evas_object_smart_data_get(obj);
1704    Evas_Coord ow, oh;
1705
1706    if (!sd) return;
1707    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1708    if (x)
1709      *x = (ow < sd->wd->minw) ? sd->wd->minw - ow : 0;
1710    if (y)
1711      *y = (oh < sd->wd->minh) ? sd->wd->minh - oh : 0;
1712 }
1713
1714 static void
1715 _pan_min_get(Evas_Object *obj,
1716              Evas_Coord  *x,
1717              Evas_Coord  *y)
1718 {
1719    Pan *sd = evas_object_smart_data_get(obj);
1720    Evas_Coord mx, my;
1721
1722    if (!sd) return;
1723    _pan_max_get(obj, &mx, &my);
1724    if (x)
1725      *x = -mx * sd->wd->align_x;
1726    if (y)
1727      *y = -my * sd->wd->align_y;
1728 }
1729
1730 static void
1731 _pan_resize(Evas_Object *obj,
1732             Evas_Coord   w,
1733             Evas_Coord   h)
1734 {
1735    Pan *sd = evas_object_smart_data_get(obj);
1736    Evas_Coord ow, oh;
1737
1738    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1739    if ((ow == w) && (oh == h)) return;
1740    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1741    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1742 }
1743
1744 static void
1745 _pan_calculate(Evas_Object *obj)
1746 {
1747    Pan *sd = evas_object_smart_data_get(obj);
1748    Evas_Coord cx = 0, cy = 0;
1749    Elm_Gengrid_Item *it;
1750
1751    if (!sd) return;
1752    if (!sd->wd->nmax) return;
1753
1754    sd->wd->reorder_item_changed = EINA_FALSE;
1755
1756    EINA_INLIST_FOREACH(sd->wd->items, it)
1757      {
1758         if (it->is_group)
1759           {
1760              if (sd->wd->horizontal)
1761                {
1762                   if (cy)
1763                     {
1764                        cx++;
1765                        cy = 0;
1766                     }
1767                }
1768              else
1769                {
1770                   if (cx)
1771                     {
1772                        cx = 0;
1773                        cy++;
1774                     }
1775                }
1776           }
1777         _item_place(it, cx, cy);
1778         if (sd->wd->reorder_item_changed) return;
1779         if (it->is_group)
1780           {
1781              if (sd->wd->horizontal)
1782                {
1783                   cx++;
1784                   cy = 0;
1785                }
1786              else
1787                {
1788                   cx = 0;
1789                   cy++;
1790                }
1791           }
1792         else
1793           {
1794              if (sd->wd->horizontal)
1795                {
1796                   cy = (cy + 1) % sd->wd->nmax;
1797                   if (!cy) cx++;
1798                }
1799              else
1800                {
1801                   cx = (cx + 1) % sd->wd->nmax;
1802                   if (!cx) cy++;
1803                }
1804           }
1805      }
1806    _group_item_place(sd);
1807
1808
1809    if ((sd->wd->reorder_mode) && (sd->wd->reorder_item))
1810      {
1811         if (!sd->wd->reorder_item_changed)
1812           {
1813              sd->wd->old_pan_x = sd->wd->pan_x;
1814              sd->wd->old_pan_y = sd->wd->pan_y;
1815           }
1816         sd->wd->move_effect_enabled = EINA_FALSE;
1817      }
1818    evas_object_smart_callback_call(sd->wd->self, SIG_CHANGED, NULL);
1819 }
1820
1821 static void
1822 _pan_move(Evas_Object *obj,
1823           Evas_Coord x __UNUSED__,
1824           Evas_Coord y __UNUSED__)
1825 {
1826    Pan *sd = evas_object_smart_data_get(obj);
1827    if (!sd) return;
1828    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1829    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1830 }
1831
1832 static void
1833 _hold_on(void *data       __UNUSED__,
1834          Evas_Object     *obj,
1835          void *event_info __UNUSED__)
1836 {
1837    Widget_Data *wd = elm_widget_data_get(obj);
1838    if (!wd) return;
1839    elm_smart_scroller_hold_set(wd->scr, 1);
1840 }
1841
1842 static void
1843 _hold_off(void *data       __UNUSED__,
1844           Evas_Object     *obj,
1845           void *event_info __UNUSED__)
1846 {
1847    Widget_Data *wd = elm_widget_data_get(obj);
1848    if (!wd) return;
1849    elm_smart_scroller_hold_set(wd->scr, 0);
1850 }
1851
1852 static void
1853 _freeze_on(void *data       __UNUSED__,
1854            Evas_Object     *obj,
1855            void *event_info __UNUSED__)
1856 {
1857    Widget_Data *wd = elm_widget_data_get(obj);
1858    if (!wd) return;
1859    elm_smart_scroller_freeze_set(wd->scr, 1);
1860 }
1861
1862 static void
1863 _freeze_off(void *data       __UNUSED__,
1864             Evas_Object     *obj,
1865             void *event_info __UNUSED__)
1866 {
1867    Widget_Data *wd = elm_widget_data_get(obj);
1868    if (!wd) return;
1869    elm_smart_scroller_freeze_set(wd->scr, 0);
1870 }
1871
1872 static void
1873 _scr_anim_start(void        *data,
1874                 Evas_Object *obj __UNUSED__,
1875                 void        *event_info __UNUSED__)
1876 {
1877    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_START, NULL);
1878 }
1879
1880 static void
1881 _scr_anim_stop(void        *data,
1882                 Evas_Object *obj __UNUSED__,
1883                 void        *event_info __UNUSED__)
1884 {
1885    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_STOP, NULL);
1886 }
1887
1888 static void
1889 _scr_drag_start(void            *data,
1890                 Evas_Object *obj __UNUSED__,
1891                 void *event_info __UNUSED__)
1892 {
1893    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
1894 }
1895
1896 static void
1897 _scr_drag_stop(void            *data,
1898                Evas_Object *obj __UNUSED__,
1899                void *event_info __UNUSED__)
1900 {
1901    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
1902 }
1903
1904 static void
1905 _edge_left(void        *data,
1906            Evas_Object *scr __UNUSED__,
1907            void        *event_info __UNUSED__)
1908 {
1909    evas_object_smart_callback_call(data, SIG_SCROLL_EDGE_LEFT, NULL);
1910    evas_object_smart_callback_call(data, SIG_EDGE_LEFT, NULL);
1911 }
1912
1913 static void
1914 _edge_right(void        *data,
1915             Evas_Object *scr __UNUSED__,
1916             void        *event_info __UNUSED__)
1917 {
1918    evas_object_smart_callback_call(data, SIG_SCROLL_EDGE_RIGHT, NULL);
1919    evas_object_smart_callback_call(data, SIG_EDGE_RIGHT, NULL);
1920 }
1921
1922 static void
1923 _edge_top(void        *data,
1924           Evas_Object *scr __UNUSED__,
1925           void        *event_info __UNUSED__)
1926 {
1927    evas_object_smart_callback_call(data, SIG_SCROLL_EDGE_TOP, NULL);
1928    evas_object_smart_callback_call(data, SIG_EDGE_TOP, NULL);
1929 }
1930
1931 static void
1932 _edge_bottom(void        *data,
1933              Evas_Object *scr __UNUSED__,
1934              void        *event_info __UNUSED__)
1935 {
1936    evas_object_smart_callback_call(data, SIG_SCROLL_EDGE_BOTTOM, NULL);
1937    evas_object_smart_callback_call(data, SIG_EDGE_BOTTOM, NULL);
1938 }
1939
1940 static void
1941 _scr_scroll(void            *data,
1942             Evas_Object *obj __UNUSED__,
1943             void *event_info __UNUSED__)
1944 {
1945    evas_object_smart_callback_call(data, SIG_SCROLL, NULL);
1946 }
1947
1948 static int
1949 _elm_gengrid_item_compare_data(const void *data, const void *data1)
1950 {
1951    const Elm_Gengrid_Item *it = data;
1952    const Elm_Gengrid_Item *item1 = data1;
1953
1954    return _elm_gengrid_item_compare_data_cb(it->base.data, item1->base.data);
1955 }
1956
1957 static int
1958 _elm_gengrid_item_compare(const void *data, const void *data1)
1959 {
1960    Elm_Gengrid_Item *it, *item1;
1961    it = ELM_GENGRID_ITEM_FROM_INLIST(data);
1962    item1 = ELM_GENGRID_ITEM_FROM_INLIST(data1);
1963    return _elm_gengrid_item_compare_cb(it, item1);
1964 }
1965
1966 EAPI Evas_Object *
1967 elm_gengrid_add(Evas_Object *parent)
1968 {
1969    Evas_Object *obj;
1970    Evas *e;
1971    Widget_Data *wd;
1972    static Evas_Smart *smart = NULL;
1973    Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
1974
1975    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1976
1977    ELM_SET_WIDTYPE(widtype, "gengrid");
1978    elm_widget_type_set(obj, "gengrid");
1979    elm_widget_sub_object_add(parent, obj);
1980    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1981    elm_widget_data_set(obj, wd);
1982    elm_widget_del_hook_set(obj, _del_hook);
1983    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1984    elm_widget_theme_hook_set(obj, _theme_hook);
1985    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
1986    elm_widget_can_focus_set(obj, EINA_TRUE);
1987    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
1988    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
1989    elm_widget_event_hook_set(obj, _event_hook);
1990
1991    wd->scr = elm_smart_scroller_add(e);
1992    elm_smart_scroller_widget_set(wd->scr, obj);
1993    elm_smart_scroller_object_theme_set(obj, wd->scr, "gengrid", "base",
1994                                        "default");
1995    elm_widget_resize_object_set(obj, wd->scr);
1996
1997    evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, obj);
1998    evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, obj);
1999    evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
2000    evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
2001    evas_object_smart_callback_add(wd->scr, "edge,left", _edge_left, obj);
2002    evas_object_smart_callback_add(wd->scr, "edge,right", _edge_right, obj);
2003    evas_object_smart_callback_add(wd->scr, "edge,top", _edge_top, obj);
2004    evas_object_smart_callback_add(wd->scr, "edge,bottom", _edge_bottom,
2005                                   obj);
2006    evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj);
2007
2008    elm_smart_scroller_bounce_allow_set(wd->scr, bounce, bounce);
2009
2010    wd->self = obj;
2011    wd->align_x = 0.5;
2012    wd->align_y = 0.5;
2013    wd->h_bounce = bounce;
2014    wd->v_bounce = bounce;
2015    wd->no_select = EINA_FALSE;
2016
2017    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
2018    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
2019    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
2020    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
2021
2022    evas_object_smart_callbacks_descriptions_set(obj, _signals);
2023
2024    if (!smart)
2025      {
2026         static Evas_Smart_Class sc;
2027
2028         evas_object_smart_clipped_smart_set(&_pan_sc);
2029         sc = _pan_sc;
2030         sc.name = "elm_gengrid_pan";
2031         sc.version = EVAS_SMART_CLASS_VERSION;
2032         sc.add = _pan_add;
2033         sc.del = _pan_del;
2034         sc.resize = _pan_resize;
2035         sc.move = _pan_move;
2036         sc.calculate = _pan_calculate;
2037         smart = evas_smart_class_new(&sc);
2038      }
2039    if (smart)
2040      {
2041         wd->pan_smart = evas_object_smart_add(e, smart);
2042         wd->pan = evas_object_smart_data_get(wd->pan_smart);
2043         wd->pan->wd = wd;
2044      }
2045
2046    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
2047                                      _pan_set, _pan_get, _pan_max_get,
2048                                      _pan_min_get, _pan_child_size_get);
2049
2050    _mirrored_set(obj, elm_widget_mirrored_get(obj));
2051    return obj;
2052 }
2053
2054 EAPI void
2055 elm_gengrid_item_size_set(Evas_Object *obj,
2056                           Evas_Coord   w,
2057                           Evas_Coord   h)
2058 {
2059    ELM_CHECK_WIDTYPE(obj, widtype);
2060    Widget_Data *wd = elm_widget_data_get(obj);
2061    if (!wd) return;
2062    if ((wd->item_width == w) && (wd->item_height == h)) return;
2063    wd->item_width = w;
2064    wd->item_height = h;
2065    if (wd->calc_job) ecore_job_del(wd->calc_job);
2066    wd->calc_job = ecore_job_add(_calc_job, wd);
2067 }
2068
2069 EAPI void
2070 elm_gengrid_item_size_get(const Evas_Object *obj,
2071                           Evas_Coord        *w,
2072                           Evas_Coord        *h)
2073 {
2074    ELM_CHECK_WIDTYPE(obj, widtype);
2075    Widget_Data *wd = elm_widget_data_get(obj);
2076    if (!wd) return;
2077    if (w) *w = wd->item_width;
2078    if (h) *h = wd->item_height;
2079 }
2080
2081 EAPI void
2082 elm_gengrid_group_item_size_set(Evas_Object *obj,
2083                           Evas_Coord   w,
2084                           Evas_Coord   h)
2085 {
2086    ELM_CHECK_WIDTYPE(obj, widtype);
2087    Widget_Data *wd = elm_widget_data_get(obj);
2088    if (!wd) return;
2089    if ((wd->group_item_width == w) && (wd->group_item_height == h)) return;
2090    wd->group_item_width = w;
2091    wd->group_item_height = h;
2092    if (wd->calc_job) ecore_job_del(wd->calc_job);
2093    wd->calc_job = ecore_job_add(_calc_job, wd);
2094 }
2095
2096 EAPI void
2097 elm_gengrid_group_item_size_get(const Evas_Object *obj,
2098                           Evas_Coord        *w,
2099                           Evas_Coord        *h)
2100 {
2101    ELM_CHECK_WIDTYPE(obj, widtype);
2102    Widget_Data *wd = elm_widget_data_get(obj);
2103    if (!wd) return;
2104    if (w) *w = wd->group_item_width;
2105    if (h) *h = wd->group_item_height;
2106 }
2107
2108 EAPI void
2109 elm_gengrid_align_set(Evas_Object *obj,
2110                       double       align_x,
2111                       double       align_y)
2112 {
2113    ELM_CHECK_WIDTYPE(obj, widtype);
2114
2115    Widget_Data *wd = elm_widget_data_get(obj);
2116    double old_h = wd->align_x, old_y = wd->align_y;
2117
2118    if (align_x > 1.0)
2119      align_x = 1.0;
2120    else if (align_x < 0.0)
2121      align_x = 0.0;
2122    wd->align_x = align_x;
2123
2124    if (align_y > 1.0)
2125      align_y = 1.0;
2126    else if (align_y < 0.0)
2127      align_y = 0.0;
2128    wd->align_y = align_y;
2129
2130    if ((old_h != wd->align_x) || (old_y != wd->align_y))
2131      evas_object_smart_calculate(wd->pan_smart);
2132 }
2133
2134 EAPI void
2135 elm_gengrid_align_get(const Evas_Object *obj,
2136                       double            *align_x,
2137                       double            *align_y)
2138 {
2139    ELM_CHECK_WIDTYPE(obj, widtype);
2140    Widget_Data *wd = elm_widget_data_get(obj);
2141    if (align_x) *align_x = wd->align_x;
2142    if (align_y) *align_y = wd->align_y;
2143 }
2144
2145 EAPI Elm_Gengrid_Item *
2146 elm_gengrid_item_append(Evas_Object                  *obj,
2147                         const Elm_Gengrid_Item_Class *itc,
2148                         const void                   *data,
2149                         Evas_Smart_Cb                 func,
2150                         const void                   *func_data)
2151 {
2152    Elm_Gengrid_Item *it;
2153    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2154    Widget_Data *wd = elm_widget_data_get(obj);
2155    if (!wd) return NULL;
2156
2157    it = _item_new(wd, itc, data, func, func_data);
2158    if (!it) return NULL;
2159    wd->items = eina_inlist_append(wd->items, EINA_INLIST_GET(it));
2160
2161    if (it->is_group)
2162      wd->group_items = eina_list_prepend(wd->group_items, it);
2163
2164    if (wd->calc_job) ecore_job_del(wd->calc_job);
2165    wd->calc_job = ecore_job_add(_calc_job, wd);
2166
2167    return it;
2168 }
2169
2170 EAPI Elm_Gengrid_Item *
2171 elm_gengrid_item_prepend(Evas_Object                  *obj,
2172                          const Elm_Gengrid_Item_Class *itc,
2173                          const void                   *data,
2174                          Evas_Smart_Cb                 func,
2175                          const void                   *func_data)
2176 {
2177    Elm_Gengrid_Item *it;
2178    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2179    Widget_Data *wd = elm_widget_data_get(obj);
2180    if (!wd) return NULL;
2181
2182    it = _item_new(wd, itc, data, func, func_data);
2183    if (!it) return NULL;
2184    wd->items = eina_inlist_prepend(wd->items, EINA_INLIST_GET(it));
2185    if (it->is_group)
2186      wd->group_items = eina_list_append(wd->group_items, it);
2187
2188    if (wd->calc_job) ecore_job_del(wd->calc_job);
2189    wd->calc_job = ecore_job_add(_calc_job, wd);
2190
2191    return it;
2192 }
2193
2194 EAPI Elm_Gengrid_Item *
2195 elm_gengrid_item_insert_before(Evas_Object                  *obj,
2196                                const Elm_Gengrid_Item_Class *itc,
2197                                const void                   *data,
2198                                Elm_Gengrid_Item             *relative,
2199                                Evas_Smart_Cb                 func,
2200                                const void                   *func_data)
2201 {
2202    Elm_Gengrid_Item *it;
2203    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2204    EINA_SAFETY_ON_NULL_RETURN_VAL(relative, NULL);
2205    Widget_Data *wd = elm_widget_data_get(obj);
2206    if (!wd) return NULL;
2207
2208    it = _item_new(wd, itc, data, func, func_data);
2209    if (!it) return NULL;
2210    wd->items = eina_inlist_prepend_relative
2211       (wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(relative));
2212    if (it->is_group)
2213      wd->group_items = eina_list_append_relative(wd->group_items, it, relative->parent);
2214
2215    if (wd->calc_job) ecore_job_del(wd->calc_job);
2216    wd->calc_job = ecore_job_add(_calc_job, wd);
2217
2218    return it;
2219 }
2220
2221 EAPI Elm_Gengrid_Item *
2222 elm_gengrid_item_insert_after(Evas_Object                  *obj,
2223                               const Elm_Gengrid_Item_Class *itc,
2224                               const void                   *data,
2225                               Elm_Gengrid_Item             *relative,
2226                               Evas_Smart_Cb                 func,
2227                               const void                   *func_data)
2228 {
2229    Elm_Gengrid_Item *it;
2230    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2231    EINA_SAFETY_ON_NULL_RETURN_VAL(relative, NULL);
2232    Widget_Data *wd = elm_widget_data_get(obj);
2233    if (!wd) return NULL;
2234
2235    it = _item_new(wd, itc, data, func, func_data);
2236    if (!it) return NULL;
2237    wd->items = eina_inlist_append_relative
2238       (wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(relative));
2239    if (it->is_group)
2240      wd->group_items = eina_list_prepend_relative(wd->group_items, it, relative->parent);
2241
2242    if (wd->calc_job) ecore_job_del(wd->calc_job);
2243    wd->calc_job = ecore_job_add(_calc_job, wd);
2244
2245    return it;
2246 }
2247
2248 EAPI Elm_Gengrid_Item *
2249 elm_gengrid_item_direct_sorted_insert(Evas_Object                  *obj,
2250                                       const Elm_Gengrid_Item_Class *itc,
2251                                       const void                   *data,
2252                                       Eina_Compare_Cb               comp,
2253                                       Evas_Smart_Cb                 func,
2254                                       const void                   *func_data)
2255 {
2256    Elm_Gengrid_Item *it;
2257    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2258    Widget_Data *wd = elm_widget_data_get(obj);
2259    if (!wd) return NULL;
2260
2261    it = _item_new(wd, itc, data, func, func_data);
2262    if (!it) return NULL;
2263
2264    if (!wd->state)
2265      wd->state = eina_inlist_sorted_state_new();
2266
2267    _elm_gengrid_item_compare_cb = comp;
2268    wd->items = eina_inlist_sorted_state_insert(wd->items, EINA_INLIST_GET(it),
2269                                          _elm_gengrid_item_compare, wd->state);
2270    if (wd->calc_job) ecore_job_del(wd->calc_job);
2271    wd->calc_job = ecore_job_add(_calc_job, wd);
2272
2273    return it;
2274 }
2275
2276 EAPI Elm_Gengrid_Item *
2277 elm_gengrid_item_sorted_insert(Evas_Object                  *obj,
2278                                const Elm_Gengrid_Item_Class *itc,
2279                                const void                   *data,
2280                                Eina_Compare_Cb               comp,
2281                                Evas_Smart_Cb                 func,
2282                                const void                   *func_data)
2283 {
2284    _elm_gengrid_item_compare_data_cb = comp;
2285
2286    return elm_gengrid_item_direct_sorted_insert(obj, itc, data, _elm_gengrid_item_compare_data, func, func_data);
2287 }
2288
2289 EAPI void
2290 elm_gengrid_item_del(Elm_Gengrid_Item *it)
2291 {
2292    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2293    if ((it->relcount > 0) || (it->walking > 0))
2294      {
2295         it->delete_me = EINA_TRUE;
2296         elm_widget_item_pre_notify_del(it);
2297         if (it->selected)
2298           it->wd->selected = eina_list_remove(it->wd->selected, it);
2299         if (it->itc->func.del)
2300           it->itc->func.del((void *)it->base.data, it->wd->self);
2301         return;
2302      }
2303
2304    _item_del(it);
2305 }
2306
2307 EAPI void
2308 elm_gengrid_horizontal_set(Evas_Object *obj,
2309                            Eina_Bool    setting)
2310 {
2311    ELM_CHECK_WIDTYPE(obj, widtype);
2312    Widget_Data *wd = elm_widget_data_get(obj);
2313    if (!wd) return;
2314    if (setting == wd->horizontal) return;
2315    wd->horizontal = setting;
2316
2317    /* Update the items to conform to the new layout */
2318    if (wd->calc_job) ecore_job_del(wd->calc_job);
2319    wd->calc_job = ecore_job_add(_calc_job, wd);
2320 }
2321
2322 EAPI Eina_Bool
2323 elm_gengrid_horizontal_get(const Evas_Object *obj)
2324 {
2325    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2326    Widget_Data *wd = elm_widget_data_get(obj);
2327    if (!wd) return EINA_FALSE;
2328    return wd->horizontal;
2329 }
2330
2331 EAPI void
2332 elm_gengrid_clear(Evas_Object *obj)
2333 {
2334    ELM_CHECK_WIDTYPE(obj, widtype);
2335    Widget_Data *wd = elm_widget_data_get(obj);
2336    if (!wd) return;
2337
2338    if (wd->state)
2339      {
2340         eina_inlist_sorted_state_free(wd->state);
2341         wd->state = NULL;
2342      }
2343    if (wd->calc_job)
2344      {
2345         ecore_job_del(wd->calc_job);
2346         wd->calc_job = NULL;
2347      }
2348
2349    if (wd->walking > 0)
2350      {
2351         Elm_Gengrid_Item *it;
2352         wd->clear_me = 1;
2353         EINA_INLIST_FOREACH(wd->items, it)
2354            it->delete_me = 1;
2355         return;
2356      }
2357    wd->clear_me = 0;
2358    while (wd->items)
2359      {
2360         Elm_Gengrid_Item *it = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
2361
2362         wd->items = eina_inlist_remove(wd->items, wd->items);
2363         elm_widget_item_pre_notify_del(it);
2364         if (it->realized) _item_unrealize(it);
2365         if (it->itc->func.del)
2366           it->itc->func.del((void *)it->base.data, wd->self);
2367         if (it->long_timer) ecore_timer_del(it->long_timer);
2368         elm_widget_item_del(it);
2369      }
2370
2371    if (wd->selected)
2372      {
2373         eina_list_free(wd->selected);
2374         wd->selected = NULL;
2375      }
2376
2377    wd->pan_x = 0;
2378    wd->pan_y = 0;
2379    wd->minw = 0;
2380    wd->minh = 0;
2381    wd->count = 0;
2382    evas_object_size_hint_min_set(wd->pan_smart, wd->minw, wd->minh);
2383    evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
2384 }
2385
2386 EAPI const Evas_Object *
2387 elm_gengrid_item_object_get(const Elm_Gengrid_Item *it)
2388 {
2389    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2390    return VIEW(it);
2391 }
2392
2393 EAPI void
2394 elm_gengrid_item_update(Elm_Gengrid_Item *it)
2395 {
2396    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2397    if (!it->realized) return;
2398    if (it->want_unrealize) return;
2399    _item_unrealize(it);
2400    _item_realize(it);
2401    _item_place(it, it->x, it->y);
2402 }
2403
2404 EAPI void *
2405 elm_gengrid_item_data_get(const Elm_Gengrid_Item *it)
2406 {
2407    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2408    return elm_widget_item_data_get(it);
2409 }
2410
2411 EAPI void
2412 elm_gengrid_item_data_set(Elm_Gengrid_Item *it,
2413                           const void       *data)
2414 {
2415    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2416    elm_widget_item_data_set(it, data);
2417 }
2418
2419 EAPI const Elm_Gengrid_Item_Class *
2420 elm_gengrid_item_item_class_get(const Elm_Gengrid_Item *it)
2421 {
2422    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2423    if (it->delete_me) return NULL;
2424    return it->itc;
2425 }
2426
2427 EAPI void
2428 elm_gengrid_item_item_class_set(Elm_Gengrid_Item *it,
2429                                 const Elm_Gengrid_Item_Class *itc)
2430 {
2431    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2432    EINA_SAFETY_ON_NULL_RETURN(itc);
2433    if (it->delete_me) return;
2434    it->itc = itc;
2435    elm_gengrid_item_update(it);
2436 }
2437
2438 EAPI void
2439 elm_gengrid_item_pos_get(const Elm_Gengrid_Item *it,
2440                          unsigned int           *x,
2441                          unsigned int           *y)
2442 {
2443    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2444    if (x) *x = it->x;
2445    if (y) *y = it->y;
2446 }
2447
2448 EAPI void
2449 elm_gengrid_multi_select_set(Evas_Object *obj,
2450                              Eina_Bool    multi)
2451 {
2452    ELM_CHECK_WIDTYPE(obj, widtype);
2453    Widget_Data *wd = elm_widget_data_get(obj);
2454    if (!wd) return;
2455    wd->multi = multi;
2456 }
2457
2458 EAPI Eina_Bool
2459 elm_gengrid_multi_select_get(const Evas_Object *obj)
2460 {
2461    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2462    Widget_Data *wd = elm_widget_data_get(obj);
2463    if (!wd) return EINA_FALSE;
2464    return wd->multi;
2465 }
2466
2467 EAPI Elm_Gengrid_Item *
2468 elm_gengrid_selected_item_get(const Evas_Object *obj)
2469 {
2470    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2471    Widget_Data *wd = elm_widget_data_get(obj);
2472    if (!wd) return NULL;
2473    if (wd->selected) return wd->selected->data;
2474    return NULL;
2475 }
2476
2477 EAPI const Eina_List *
2478 elm_gengrid_selected_items_get(const Evas_Object *obj)
2479 {
2480    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2481    Widget_Data *wd = elm_widget_data_get(obj);
2482    if (!wd) return NULL;
2483    return wd->selected;
2484 }
2485
2486 EAPI void
2487 elm_gengrid_item_selected_set(Elm_Gengrid_Item *it,
2488                               Eina_Bool         selected)
2489 {
2490    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2491    Widget_Data *wd = it->wd;
2492    if (!wd) return;
2493    if (it->delete_me) return;
2494    selected = !!selected;
2495    if (it->selected == selected) return;
2496
2497    if (selected)
2498      {
2499         if (!wd->multi)
2500           {
2501              while (wd->selected)
2502                _item_unselect(wd->selected->data);
2503           }
2504         _item_highlight(it);
2505         _item_select(it);
2506      }
2507    else
2508      _item_unselect(it);
2509 }
2510
2511 EAPI Eina_Bool
2512 elm_gengrid_item_selected_get(const Elm_Gengrid_Item *it)
2513 {
2514    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2515    return it->selected;
2516 }
2517
2518 EAPI void
2519 elm_gengrid_item_disabled_set(Elm_Gengrid_Item *it,
2520                               Eina_Bool         disabled)
2521 {
2522    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2523    if (it->disabled == disabled) return;
2524    if (it->delete_me) return;
2525    it->disabled = !!disabled;
2526    if (it->realized)
2527      {
2528         if (it->disabled)
2529           edje_object_signal_emit(VIEW(it), "elm,state,disabled", "elm");
2530         else
2531           edje_object_signal_emit(VIEW(it), "elm,state,enabled", "elm");
2532      }
2533 }
2534
2535 EAPI Eina_Bool
2536 elm_gengrid_item_disabled_get(const Elm_Gengrid_Item *it)
2537 {
2538    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2539    if (it->delete_me) return EINA_FALSE;
2540    return it->disabled;
2541 }
2542
2543 static Evas_Object *
2544 _elm_gengrid_item_label_create(void        *data,
2545                                Evas_Object *obj __UNUSED__,
2546                                Evas_Object *tooltip,
2547                                void *it   __UNUSED__)
2548 {
2549    Evas_Object *label = elm_label_add(tooltip);
2550    if (!label)
2551      return NULL;
2552    elm_object_style_set(label, "tooltip");
2553    elm_object_text_set(label, data);
2554    return label;
2555 }
2556
2557 static void
2558 _elm_gengrid_item_label_del_cb(void            *data,
2559                                Evas_Object *obj __UNUSED__,
2560                                void *event_info __UNUSED__)
2561 {
2562    eina_stringshare_del(data);
2563 }
2564
2565 EAPI void
2566 elm_gengrid_item_tooltip_text_set(Elm_Gengrid_Item *it,
2567                                   const char       *text)
2568 {
2569    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2570    text = eina_stringshare_add(text);
2571    elm_gengrid_item_tooltip_content_cb_set(it, _elm_gengrid_item_label_create,
2572                                            text,
2573                                            _elm_gengrid_item_label_del_cb);
2574 }
2575
2576 EAPI void
2577 elm_gengrid_item_tooltip_content_cb_set(Elm_Gengrid_Item           *it,
2578                                         Elm_Tooltip_Item_Content_Cb func,
2579                                         const void                 *data,
2580                                         Evas_Smart_Cb               del_cb)
2581 {
2582    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_GOTO(it, error);
2583
2584    if ((it->tooltip.content_cb == func) && (it->tooltip.data == data))
2585      return;
2586
2587    if (it->tooltip.del_cb)
2588      it->tooltip.del_cb((void *)it->tooltip.data,
2589                           WIDGET(it), it);
2590    it->tooltip.content_cb = func;
2591    it->tooltip.data = data;
2592    it->tooltip.del_cb = del_cb;
2593    if (VIEW(it))
2594      {
2595         elm_widget_item_tooltip_content_cb_set(it,
2596                                                it->tooltip.content_cb,
2597                                                it->tooltip.data, NULL);
2598         elm_widget_item_tooltip_style_set(it, it->tooltip.style);
2599         elm_widget_item_tooltip_size_restrict_disable(it, it->tooltip.free_size);
2600      }
2601
2602    return;
2603
2604 error:
2605    if (del_cb) del_cb((void *)data, NULL, NULL);
2606 }
2607
2608 EAPI void
2609 elm_gengrid_item_tooltip_unset(Elm_Gengrid_Item *it)
2610 {
2611    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2612    if ((VIEW(it)) && (it->tooltip.content_cb))
2613      elm_widget_item_tooltip_unset(it);
2614
2615    if (it->tooltip.del_cb)
2616      it->tooltip.del_cb((void *)it->tooltip.data, WIDGET(it), it);
2617    it->tooltip.del_cb = NULL;
2618    it->tooltip.content_cb = NULL;
2619    it->tooltip.data = NULL;
2620    it->tooltip.free_size = EINA_FALSE;
2621    if (it->tooltip.style)
2622      elm_gengrid_item_tooltip_style_set(it, NULL);
2623 }
2624
2625 EAPI void
2626 elm_gengrid_item_tooltip_style_set(Elm_Gengrid_Item *it,
2627                                    const char       *style)
2628 {
2629    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2630    eina_stringshare_replace(&it->tooltip.style, style);
2631    if (VIEW(it)) elm_widget_item_tooltip_style_set(it, style);
2632 }
2633
2634 EAPI const char *
2635 elm_gengrid_item_tooltip_style_get(const Elm_Gengrid_Item *it)
2636 {
2637    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2638    return it->tooltip.style;
2639 }
2640
2641 EAPI Eina_Bool
2642 elm_gengrid_item_tooltip_size_restrict_disable(Elm_Gengrid_Item *it, Eina_Bool disable)
2643 {
2644    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2645    it->tooltip.free_size = disable;
2646    if (VIEW(it)) return elm_widget_item_tooltip_size_restrict_disable(it, disable);
2647    return EINA_TRUE;
2648 }
2649
2650 EAPI Eina_Bool
2651 elm_gengrid_item_tooltip_size_restrict_disabled_get(const Elm_Gengrid_Item *it)
2652 {
2653    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2654    return it->tooltip.free_size;
2655 }
2656
2657 EAPI void
2658 elm_gengrid_item_cursor_set(Elm_Gengrid_Item *it,
2659                             const char       *cursor)
2660 {
2661    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2662    eina_stringshare_replace(&it->mouse_cursor, cursor);
2663    if (VIEW(it)) elm_widget_item_cursor_set(it, cursor);
2664 }
2665
2666 EAPI const char *
2667 elm_gengrid_item_cursor_get(const Elm_Gengrid_Item *it)
2668 {
2669    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2670    return elm_widget_item_cursor_get(it);
2671 }
2672
2673 EAPI void
2674 elm_gengrid_item_cursor_unset(Elm_Gengrid_Item *it)
2675 {
2676    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2677    if (!it->mouse_cursor)
2678      return;
2679
2680    if (VIEW(it))
2681      elm_widget_item_cursor_unset(it);
2682
2683    eina_stringshare_del(it->mouse_cursor);
2684    it->mouse_cursor = NULL;
2685 }
2686
2687 EAPI void
2688 elm_gengrid_item_cursor_style_set(Elm_Gengrid_Item *it,
2689                                   const char       *style)
2690 {
2691    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2692    elm_widget_item_cursor_style_set(it, style);
2693 }
2694
2695 EAPI const char *
2696 elm_gengrid_item_cursor_style_get(const Elm_Gengrid_Item *it)
2697 {
2698    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2699    return elm_widget_item_cursor_style_get(it);
2700 }
2701
2702 EAPI void
2703 elm_gengrid_item_cursor_engine_only_set(Elm_Gengrid_Item *it,
2704                                         Eina_Bool         engine_only)
2705 {
2706    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2707    elm_widget_item_cursor_engine_only_set(it, engine_only);
2708 }
2709
2710 EAPI Eina_Bool
2711 elm_gengrid_item_cursor_engine_only_get(const Elm_Gengrid_Item *it)
2712 {
2713    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2714    return elm_widget_item_cursor_engine_only_get(it);
2715 }
2716
2717 EAPI void
2718 elm_gengrid_reorder_mode_set(Evas_Object *obj,
2719                              Eina_Bool    reorder_mode)
2720 {
2721    ELM_CHECK_WIDTYPE(obj, widtype);
2722    Widget_Data *wd = elm_widget_data_get(obj);
2723    if (!wd) return;
2724    wd->reorder_mode = reorder_mode;
2725 }
2726
2727 EAPI Eina_Bool
2728 elm_gengrid_reorder_mode_get(const Evas_Object *obj)
2729 {
2730    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2731    Widget_Data *wd = elm_widget_data_get(obj);
2732    if (!wd) return EINA_FALSE;
2733    return wd->reorder_mode;
2734 }
2735
2736 EAPI void
2737 elm_gengrid_always_select_mode_set(Evas_Object *obj,
2738                                    Eina_Bool    always_select)
2739 {
2740    ELM_CHECK_WIDTYPE(obj, widtype);
2741    Widget_Data *wd = elm_widget_data_get(obj);
2742    if (!wd) return;
2743    wd->always_select = always_select;
2744 }
2745
2746 EAPI Eina_Bool
2747 elm_gengrid_always_select_mode_get(const Evas_Object *obj)
2748 {
2749    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2750    Widget_Data *wd = elm_widget_data_get(obj);
2751    if (!wd) return EINA_FALSE;
2752    return wd->always_select;
2753 }
2754
2755 EAPI void
2756 elm_gengrid_no_select_mode_set(Evas_Object *obj,
2757                                Eina_Bool    no_select)
2758 {
2759    ELM_CHECK_WIDTYPE(obj, widtype);
2760    Widget_Data *wd = elm_widget_data_get(obj);
2761    if (!wd) return;
2762    wd->no_select = no_select;
2763 }
2764
2765 EAPI Eina_Bool
2766 elm_gengrid_no_select_mode_get(const Evas_Object *obj)
2767 {
2768    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2769    Widget_Data *wd = elm_widget_data_get(obj);
2770    if (!wd) return EINA_FALSE;
2771    return wd->no_select;
2772 }
2773
2774 EAPI void
2775 elm_gengrid_bounce_set(Evas_Object *obj,
2776                        Eina_Bool    h_bounce,
2777                        Eina_Bool    v_bounce)
2778 {
2779    ELM_CHECK_WIDTYPE(obj, widtype);
2780    Widget_Data *wd = elm_widget_data_get(obj);
2781    if (!wd) return;
2782    elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
2783    wd->h_bounce = h_bounce;
2784    wd->v_bounce = v_bounce;
2785 }
2786
2787 EAPI void
2788 elm_gengrid_bounce_get(const Evas_Object *obj,
2789                        Eina_Bool         *h_bounce,
2790                        Eina_Bool         *v_bounce)
2791 {
2792    ELM_CHECK_WIDTYPE(obj, widtype);
2793    Widget_Data *wd = elm_widget_data_get(obj);
2794    if (!wd) return;
2795    if (h_bounce) *h_bounce = wd->h_bounce;
2796    if (v_bounce) *v_bounce = wd->v_bounce;
2797 }
2798
2799 EAPI void
2800 elm_gengrid_page_relative_set(Evas_Object *obj,
2801                               double       h_pagerel,
2802                               double       v_pagerel)
2803 {
2804    Evas_Coord pagesize_h;
2805    Evas_Coord pagesize_v;
2806
2807    ELM_CHECK_WIDTYPE(obj, widtype);
2808    Widget_Data *wd = elm_widget_data_get(obj);
2809    if (!wd) return;
2810
2811    elm_smart_scroller_paging_get(wd->scr, NULL, NULL, &pagesize_h, &pagesize_v);
2812    elm_smart_scroller_paging_set(wd->scr, h_pagerel, v_pagerel, pagesize_h,
2813                                  pagesize_v);
2814 }
2815
2816 EAPI void
2817 elm_gengrid_page_relative_get(const Evas_Object *obj, double *h_pagerel, double *v_pagerel)
2818 {
2819    ELM_CHECK_WIDTYPE(obj, widtype);
2820    Widget_Data *wd = elm_widget_data_get(obj);
2821    if (!wd) return;
2822
2823    elm_smart_scroller_paging_get(wd->scr, h_pagerel, v_pagerel, NULL, NULL);
2824 }
2825
2826 EAPI void
2827 elm_gengrid_page_size_set(Evas_Object *obj,
2828                           Evas_Coord   h_pagesize,
2829                           Evas_Coord   v_pagesize)
2830 {
2831    double pagerel_h;
2832    double pagerel_v;
2833
2834    ELM_CHECK_WIDTYPE(obj, widtype);
2835    Widget_Data *wd = elm_widget_data_get(obj);
2836    if (!wd) return;
2837    elm_smart_scroller_paging_get(wd->scr, &pagerel_h, &pagerel_v, NULL, NULL);
2838    elm_smart_scroller_paging_set(wd->scr, pagerel_h, pagerel_v, h_pagesize,
2839                                  v_pagesize);
2840 }
2841
2842 EAPI void
2843 elm_gengrid_current_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber)
2844 {
2845    ELM_CHECK_WIDTYPE(obj, widtype);
2846    Widget_Data *wd = elm_widget_data_get(obj);
2847    if (!wd) return;
2848    if (wd->scr)
2849      elm_smart_scroller_current_page_get(wd->scr, h_pagenumber, v_pagenumber);
2850 }
2851
2852 EAPI void
2853 elm_gengrid_last_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber)
2854 {
2855    ELM_CHECK_WIDTYPE(obj, widtype);
2856    Widget_Data *wd = elm_widget_data_get(obj);
2857    if (!wd) return;
2858    if (wd->scr)
2859      elm_smart_scroller_last_page_get(wd->scr, h_pagenumber, v_pagenumber);
2860 }
2861
2862 EAPI void
2863 elm_gengrid_page_show(const Evas_Object *obj, int h_pagenumber, int v_pagenumber)
2864 {
2865    ELM_CHECK_WIDTYPE(obj, widtype);
2866    Widget_Data *wd = elm_widget_data_get(obj);
2867    if (!wd) return;
2868    if (wd->scr)
2869      elm_smart_scroller_page_show(wd->scr, h_pagenumber, v_pagenumber);
2870 }
2871
2872 EAPI void
2873 elm_gengrid_page_bring_in(const Evas_Object *obj, int h_pagenumber, int v_pagenumber)
2874 {
2875    ELM_CHECK_WIDTYPE(obj, widtype);
2876    Widget_Data *wd = elm_widget_data_get(obj);
2877    if (!wd) return;
2878    if (wd->scr)
2879      elm_smart_scroller_page_bring_in(wd->scr, h_pagenumber, v_pagenumber);
2880 }
2881
2882 EAPI Elm_Gengrid_Item *
2883 elm_gengrid_first_item_get(const Evas_Object *obj)
2884 {
2885    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2886    Widget_Data *wd = elm_widget_data_get(obj);
2887    if (!wd) return NULL;
2888    if (!wd->items) return NULL;
2889    Elm_Gengrid_Item *it = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
2890    while ((it) && (it->delete_me))
2891      it = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
2892    return it;
2893 }
2894
2895 EAPI Elm_Gengrid_Item *
2896 elm_gengrid_last_item_get(const Evas_Object *obj)
2897 {
2898    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2899    Widget_Data *wd = elm_widget_data_get(obj);
2900    if (!wd) return NULL;
2901    if (!wd->items) return NULL;
2902    Elm_Gengrid_Item *it = ELM_GENGRID_ITEM_FROM_INLIST(wd->items->last);
2903    while ((it) && (it->delete_me))
2904      it = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
2905    return it;
2906 }
2907
2908 EAPI Elm_Gengrid_Item *
2909 elm_gengrid_item_next_get(const Elm_Gengrid_Item *it)
2910 {
2911    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2912    while (it)
2913      {
2914         it = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
2915         if ((it) && (!it->delete_me)) break;
2916      }
2917    return (Elm_Gengrid_Item *)it;
2918 }
2919
2920 EAPI Elm_Gengrid_Item *
2921 elm_gengrid_item_prev_get(const Elm_Gengrid_Item *it)
2922 {
2923    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2924    while (it)
2925      {
2926         it = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
2927         if ((it) && (!it->delete_me)) break;
2928      }
2929    return (Elm_Gengrid_Item *)it;
2930 }
2931
2932 EAPI Evas_Object *
2933 elm_gengrid_item_gengrid_get(const Elm_Gengrid_Item *it)
2934 {
2935    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2936    return WIDGET(it);
2937 }
2938
2939 EAPI void
2940 elm_gengrid_item_show(Elm_Gengrid_Item *it)
2941 {
2942    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2943    Widget_Data *wd = elm_widget_data_get(it->wd->self);
2944    Evas_Coord minx = 0, miny = 0;
2945
2946    if (!wd) return;
2947    if ((!it) || (it->delete_me)) return;
2948    _pan_min_get(wd->pan_smart, &minx, &miny);
2949
2950    if (wd->horizontal)
2951      elm_smart_scroller_region_bring_in(it->wd->scr,
2952                                         ((it->x - it->prev_group) * wd->item_width) + (it->prev_group * it->wd->group_item_width) + minx,
2953                                         it->y * wd->item_height + miny,
2954                                         it->wd->item_width,
2955                                         it->wd->item_height);
2956    else
2957      elm_smart_scroller_region_bring_in(it->wd->scr,
2958                                         it->x * wd->item_width + minx,
2959                                         ((it->y - it->prev_group)* wd->item_height) + (it->prev_group * it->wd->group_item_height) + miny,
2960                                         it->wd->item_width,
2961                                         it->wd->item_height);
2962 }
2963
2964 EAPI void
2965 elm_gengrid_item_bring_in(Elm_Gengrid_Item *it)
2966 {
2967    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2968    if (it->delete_me) return;
2969
2970    Evas_Coord minx = 0, miny = 0;
2971    Widget_Data *wd = elm_widget_data_get(it->wd->self);
2972    if (!wd) return;
2973    _pan_min_get(wd->pan_smart, &minx, &miny);
2974
2975    if (wd->horizontal)
2976      elm_smart_scroller_region_bring_in(it->wd->scr,
2977                                         ((it->x - it->prev_group) * wd->item_width) + (it->prev_group * it->wd->group_item_width) + minx,
2978                                         it->y * wd->item_height + miny,
2979                                         it->wd->item_width,
2980                                         it->wd->item_height);
2981    else
2982      elm_smart_scroller_region_bring_in(it->wd->scr,
2983                                         it->x * wd->item_width + minx,
2984                                         ((it->y - it->prev_group)* wd->item_height) + (it->prev_group * it->wd->group_item_height) + miny,
2985                                         it->wd->item_width,
2986                                         it->wd->item_height);
2987 }