more internal renames
[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               base;
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(it->base.view, 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(it->base.view);
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(it->base.view, "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(it->base.view, "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(it->base.view, "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    it->base.view = edje_object_add(evas_object_evas_get(it->wd->self));
955    edje_object_scale_set(it->base.view, elm_widget_scale_get(it->wd->self) *
956                          _elm_config->scale);
957    edje_object_mirrored_set(it->base.view, elm_widget_mirrored_get(it->base.widget));
958    evas_object_smart_member_add(it->base.view, it->wd->pan_smart);
959    elm_widget_sub_object_add(it->wd->self, it->base.view);
960    snprintf(style, sizeof(style), "it/%s",
961             it->itc->item_style ? it->itc->item_style : "default");
962    _elm_theme_object_set(it->wd->self, it->base.view, "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(it->base.view, "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(it->base.view,
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(it->base.view, 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(it->base.view,
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(it->base.view, 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(it->base.view,
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(it->base.view, 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(it->base.view,
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(it->base.view,
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(it->base.view, EVAS_CALLBACK_MOUSE_DOWN,
1058                                        _mouse_down, it);
1059         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_UP,
1060                                        _mouse_up, it);
1061         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_MOVE,
1062                                        _mouse_move, it);
1063
1064         if (it->selected)
1065           edje_object_signal_emit(it->base.view, "elm,state,selected", "elm");
1066         if (it->disabled)
1067           edje_object_signal_emit(it->base.view, "elm,state,disabled", "elm");
1068      }
1069    evas_object_show(it->base.view);
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)
1089 {
1090    Evas_Object *icon;
1091
1092    if (!it->realized) return;
1093    if (it->long_timer)
1094      {
1095         ecore_timer_del(it->long_timer);
1096         it->long_timer = NULL;
1097      }
1098    evas_object_del(it->base.view);
1099    it->base.view = NULL;
1100    evas_object_del(it->spacer);
1101    it->spacer = NULL;
1102    elm_widget_stringlist_free(it->labels);
1103    it->labels = NULL;
1104    elm_widget_stringlist_free(it->icons);
1105    it->icons = NULL;
1106    elm_widget_stringlist_free(it->states);
1107    it->states = NULL;
1108
1109    EINA_LIST_FREE(it->icon_objs, icon)
1110       evas_object_del(icon);
1111
1112    it->realized = EINA_FALSE;
1113    it->want_unrealize = EINA_FALSE;
1114 }
1115
1116 static Eina_Bool
1117 _reorder_item_moving_effect_timer_cb(void *data)
1118 {
1119    Elm_Gengrid_Item *it = data;
1120    double time, t;
1121    Evas_Coord dx, dy;
1122
1123    time = REORDER_EFFECT_TIME;
1124    t = ((0.0 > (t = ecore_loop_time_get()-it->moving_effect_start_time)) ? 0.0 : t);
1125    dx = ((it->tx - it->ox) / 10) * _elm_config->scale;
1126    dy = ((it->ty - it->oy) / 10) * _elm_config->scale;
1127
1128    if (t <= time)
1129      {
1130         it->rx += (1 * sin((t / time) * (M_PI / 2)) * dx);
1131         it->ry += (1 * sin((t / time) * (M_PI / 2)) * dy);
1132      }
1133    else
1134      {
1135         it->rx += dx;
1136         it->ry += dy;
1137      }
1138
1139    if ((((dx > 0) && (it->rx >= it->tx)) || ((dx <= 0) && (it->rx <= it->tx))) &&
1140        (((dy > 0) && (it->ry >= it->ty)) || ((dy <= 0) && (it->ry <= it->ty))))
1141      {
1142         evas_object_move(it->base.view, it->tx, it->ty);
1143         if (it->is_group)
1144           {
1145              Evas_Coord vw, vh;
1146              evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &vw, &vh);
1147              if (it->wd->horizontal)
1148                evas_object_resize(it->base.view, it->wd->group_item_width, vh);
1149              else
1150                evas_object_resize(it->base.view, vw, it->wd->group_item_height);
1151           }
1152         else
1153           evas_object_resize(it->base.view, it->wd->item_width, it->wd->item_height);
1154         it->moving = EINA_FALSE;
1155         it->item_moving_effect_timer = NULL;
1156         return ECORE_CALLBACK_CANCEL;
1157      }
1158
1159    evas_object_move(it->base.view, it->rx, it->ry);
1160    if (it->is_group)
1161      {
1162         Evas_Coord vw, vh;
1163         evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &vw, &vh);
1164         if (it->wd->horizontal)
1165           evas_object_resize(it->base.view, it->wd->group_item_width, vh);
1166         else
1167           evas_object_resize(it->base.view, vw, it->wd->group_item_height);
1168      }
1169    else
1170      evas_object_resize(it->base.view, it->wd->item_width, it->wd->item_height);
1171
1172    return ECORE_CALLBACK_RENEW;
1173 }
1174
1175 static void
1176 _group_item_place(Pan *sd)
1177 {
1178    Evas_Coord iw, ih, vw, vh;
1179    Eina_List *l;
1180    Eina_Bool was_realized;
1181    Elm_Gengrid_Item *it;
1182    evas_object_geometry_get(sd->wd->pan_smart, NULL, NULL, &vw, &vh);
1183    if (sd->wd->horizontal)
1184      {
1185         iw = sd->wd->group_item_width;
1186         ih = vh;
1187      }
1188    else
1189      {
1190         iw = vw;
1191         ih = sd->wd->group_item_height;
1192      }
1193    EINA_LIST_FOREACH(sd->wd->group_items, l, it)
1194      {
1195         was_realized = it->realized;
1196         if (it->group_realized)
1197           {
1198              _item_realize(it);
1199              if (!was_realized)
1200                evas_object_smart_callback_call(it->wd->self, SIG_REALIZED, it);
1201              evas_object_move(it->base.view, it->gx, it->gy);
1202              evas_object_resize(it->base.view, iw, ih);
1203              evas_object_raise(it->base.view);
1204           }
1205         else
1206           {
1207              _item_unrealize(it);
1208              if (was_realized)
1209                evas_object_smart_callback_call(it->wd->self, SIG_UNREALIZED, it);
1210           }
1211      }
1212 }
1213
1214
1215 static void
1216 _item_place(Elm_Gengrid_Item *it,
1217             Evas_Coord        cx,
1218             Evas_Coord        cy)
1219 {
1220    Evas_Coord x, y, ox, oy, cvx, cvy, cvw, cvh, iw, ih, ww;
1221    Evas_Coord tch, tcw, alignw = 0, alignh = 0, vw, vh;
1222    Eina_Bool reorder_item_move_forward = EINA_FALSE;
1223    long items_count;
1224    it->x = cx;
1225    it->y = cy;
1226    evas_object_geometry_get(it->wd->pan_smart, &ox, &oy, &vw, &vh);
1227
1228    /* Preload rows/columns at each side of the Gengrid */
1229    cvx = ox - PRELOAD * it->wd->item_width;
1230    cvy = oy - PRELOAD * it->wd->item_height;
1231    cvw = vw + 2 * PRELOAD * it->wd->item_width;
1232    cvh = vh + 2 * PRELOAD * it->wd->item_height;
1233
1234    alignh = 0;
1235    alignw = 0;
1236
1237    items_count = it->wd->count - eina_list_count(it->wd->group_items) + it->wd->items_lost;
1238    if (it->wd->horizontal)
1239      {
1240         int columns, items_visible = 0, items_row;
1241
1242         if (it->wd->item_height > 0)
1243           items_visible = vh / it->wd->item_height;
1244         if (items_visible < 1)
1245           items_visible = 1;
1246
1247         columns = items_count / items_visible;
1248         if (items_count % items_visible)
1249           columns++;
1250
1251         tcw = (it->wd->item_width * columns) + (it->wd->group_item_width * eina_list_count(it->wd->group_items));
1252         alignw = (vw - tcw) * it->wd->align_x;
1253
1254         items_row = items_visible;
1255         if (items_row > it->wd->count)
1256           items_row = it->wd->count;
1257         tch = items_row * it->wd->item_height;
1258         alignh = (vh - tch) * it->wd->align_y;
1259      }
1260    else
1261      {
1262         int rows, items_visible = 0, items_col;
1263
1264         if (it->wd->item_width > 0)
1265           items_visible = vw / it->wd->item_width;
1266         if (items_visible < 1)
1267           items_visible = 1;
1268
1269         rows = items_count / items_visible;
1270         if (items_count % items_visible)
1271           rows++;
1272
1273         tch = (it->wd->item_height * rows) + (it->wd->group_item_height * eina_list_count(it->wd->group_items));
1274         alignh = (vh - tch) * it->wd->align_y;
1275
1276         items_col = items_visible;
1277         if (items_col > it->wd->count)
1278           items_col = it->wd->count;
1279         tcw = items_col * it->wd->item_width;
1280         alignw = (vw - tcw) * it->wd->align_x;
1281      }
1282
1283    if (it->is_group)
1284      {
1285         if (it->wd->horizontal)
1286           {
1287              x = (((cx - it->prev_group) * it->wd->item_width) + (it->prev_group * it->wd->group_item_width)) - it->wd->pan_x + ox + alignw;
1288              y = 0;
1289              iw = it->wd->group_item_width;
1290              ih = vh;
1291           }
1292         else
1293           {
1294              x = 0;
1295              y = (((cy - it->prev_group) * it->wd->item_height) + (it->prev_group * it->wd->group_item_height)) - it->wd->pan_y + oy + alignh;
1296              iw = vw;
1297              ih = it->wd->group_item_height;
1298           }
1299         it->gx = x;
1300         it->gy = y;
1301      }
1302    else
1303      {
1304         if (it->wd->horizontal)
1305           {
1306              x = (((cx - it->prev_group) * it->wd->item_width) + (it->prev_group * it->wd->group_item_width)) - it->wd->pan_x + ox + alignw;
1307              y = (cy * it->wd->item_height) - it->wd->pan_y + oy + alignh;
1308           }
1309         else
1310           {
1311              x = (cx * it->wd->item_width) - it->wd->pan_x + ox + alignw;
1312              y = (((cy - it->prev_group) * it->wd->item_height) + (it->prev_group * it->wd->group_item_height)) - it->wd->pan_y + oy + alignh;
1313           }
1314         if (elm_widget_mirrored_get(it->wd->self))
1315           {  /* Switch items side and componsate for pan_x when in RTL mode */
1316              evas_object_geometry_get(it->wd->self, NULL, NULL, &ww, NULL);
1317              x = ww - x - it->wd->item_width - it->wd->pan_x - it->wd->pan_x;
1318           }
1319         iw = it->wd->item_width;
1320         ih = it->wd->item_height;
1321      }
1322
1323    Eina_Bool was_realized = it->realized;
1324    if (ELM_RECTS_INTERSECT(x, y, iw, ih, cvx, cvy, cvw, cvh))
1325      {
1326         _item_realize(it);
1327         if (!was_realized)
1328           evas_object_smart_callback_call(it->wd->self, SIG_REALIZED, it);
1329         if (it->parent)
1330           {
1331              if (it->wd->horizontal)
1332                {
1333                   if (it->parent->gx < 0)
1334                     {
1335                        it->parent->gx = x + it->wd->item_width - it->wd->group_item_width;
1336                        if (it->parent->gx > 0)
1337                          it->parent->gx = 0;
1338                     }
1339                }
1340              else
1341                {
1342                   if (it->parent->gy < 0)
1343                     {
1344                        it->parent->gy = y + it->wd->item_height - it->wd->group_item_height;
1345                        if (it->parent->gy > 0)
1346                          it->parent->gy = 0;
1347                     }
1348                   it->parent->group_realized = EINA_TRUE;
1349                }
1350           }
1351         if (it->wd->reorder_mode)
1352           {
1353              if (it->wd->reorder_item)
1354                {
1355                   if (it->moving) return;
1356
1357                   if (!it->wd->move_effect_enabled)
1358                     {
1359                        it->ox = x;
1360                        it->oy = y;
1361                     }
1362                   if (it->wd->reorder_item == it)
1363                     {
1364                        evas_object_move(it->base.view,
1365                                         it->wd->reorder_item_x, it->wd->reorder_item_y);
1366                        evas_object_resize(it->base.view, iw, ih);
1367                        return;
1368                     }
1369                   else
1370                     {
1371                        if (it->wd->move_effect_enabled)
1372                          {
1373                             if ((it->ox != x) || (it->oy != y))
1374                               {
1375                                  if (((it->wd->old_pan_x == it->wd->pan_x) && (it->wd->old_pan_y == it->wd->pan_y)) ||
1376                                      ((it->wd->old_pan_x != it->wd->pan_x) && !(it->ox - it->wd->pan_x + it->wd->old_pan_x == x)) ||
1377                                      ((it->wd->old_pan_y != it->wd->pan_y) && !(it->oy - it->wd->pan_y + it->wd->old_pan_y == y)))
1378                                    {
1379                                       it->tx = x;
1380                                       it->ty = y;
1381                                       it->rx = it->ox;
1382                                       it->ry = it->oy;
1383                                       it->moving = EINA_TRUE;
1384                                       it->moving_effect_start_time = ecore_loop_time_get();
1385                                       it->item_moving_effect_timer = ecore_animator_add(_reorder_item_moving_effect_timer_cb, it);
1386                                       return;
1387                                    }
1388                               }
1389                          }
1390
1391                        /* need fix here */
1392                        Evas_Coord nx, ny, nw, nh;
1393                        if (it->is_group)
1394                          {
1395                             if (it->wd->horizontal)
1396                               {
1397                                  nx = x + (it->wd->group_item_width / 2);
1398                                  ny = y;
1399                                  nw = 1;
1400                                  nh = vh;
1401                               }
1402                             else
1403                               {
1404                                  nx = x;
1405                                  ny = y + (it->wd->group_item_height / 2);
1406                                  nw = vw;
1407                                  nh = 1;
1408                               }
1409                          }
1410                        else
1411                          {
1412                             nx = x + (it->wd->item_width / 2);
1413                             ny = y + (it->wd->item_height / 2);
1414                             nw = 1;
1415                             nh = 1;
1416                          }
1417
1418                        if ( ELM_RECTS_INTERSECT(it->wd->reorder_item_x, it->wd->reorder_item_y,
1419                                                 it->wd->item_width, it->wd->item_height,
1420                                                 nx, ny, nw, nh))
1421                          {
1422                             if (it->wd->horizontal)
1423                               {
1424                                  if ((it->wd->nmax * it->wd->reorder_item->x + it->wd->reorder_item->y) >
1425                                      (it->wd->nmax * it->x + it->y))
1426                                    reorder_item_move_forward = EINA_TRUE;
1427                               }
1428                             else
1429                               {
1430                                  if ((it->wd->nmax * it->wd->reorder_item->y + it->wd->reorder_item->x) >
1431                                      (it->wd->nmax * it->y + it->x))
1432                                    reorder_item_move_forward = EINA_TRUE;
1433                               }
1434
1435                             it->wd->items = eina_inlist_remove(it->wd->items,
1436                                                                  EINA_INLIST_GET(it->wd->reorder_item));
1437                             if (reorder_item_move_forward)
1438                               it->wd->items = eina_inlist_prepend_relative(it->wd->items,
1439                                                                              EINA_INLIST_GET(it->wd->reorder_item),
1440                                                                              EINA_INLIST_GET(it));
1441                             else
1442                               it->wd->items = eina_inlist_append_relative(it->wd->items,
1443                                                                             EINA_INLIST_GET(it->wd->reorder_item),
1444                                                                             EINA_INLIST_GET(it));
1445
1446                             it->wd->reorder_item_changed = EINA_TRUE;
1447                             it->wd->move_effect_enabled = EINA_TRUE;
1448                             if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
1449                               it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
1450
1451                             return;
1452                          }
1453                     }
1454                }
1455              else if (it->item_moving_effect_timer)
1456                {
1457                   ecore_animator_del(it->item_moving_effect_timer);
1458                   it->item_moving_effect_timer = NULL;
1459                   it->moving = EINA_FALSE;
1460                }
1461           }
1462         if (!it->is_group)
1463           {
1464              evas_object_move(it->base.view, x, y);
1465              evas_object_resize(it->base.view, iw, ih);
1466           }
1467         else
1468           it->group_realized = EINA_TRUE;
1469      }
1470    else
1471      {
1472         if (!it->is_group)
1473           {
1474              _item_unrealize(it);
1475              if (was_realized)
1476                evas_object_smart_callback_call(it->wd->self, SIG_UNREALIZED, it);
1477           }
1478         else
1479           it->group_realized = EINA_FALSE;
1480      }
1481 }
1482
1483 static const char *
1484 _item_label_hook(Elm_Gengrid_Item *it, const char *part)
1485 {
1486    if (!it->itc->func.label_get) return NULL;
1487    return edje_object_part_text_get(it->base.view, part);
1488 }
1489
1490 static Elm_Gengrid_Item *
1491 _item_create(Widget_Data                  *wd,
1492              const Elm_Gengrid_Item_Class *itc,
1493              const void                   *data,
1494              Evas_Smart_Cb                 func,
1495              const void                   *func_data)
1496 {
1497    Elm_Gengrid_Item *it;
1498
1499    it = elm_widget_item_new(wd->self, Elm_Gengrid_Item);
1500    if (!it) return NULL;
1501    wd->count++;
1502    it->wd = wd;
1503    it->itc = itc;
1504    it->base.data = data;
1505    it->func.func = func;
1506    it->func.data = func_data;
1507    it->mouse_cursor = NULL;
1508    it->is_group = !strcmp(it->itc->item_style, "group_index");
1509    elm_widget_item_text_get_hook_set(it, _item_label_hook);
1510
1511    return it;
1512 }
1513
1514 static void
1515 _item_del(Elm_Gengrid_Item *it)
1516 {
1517    elm_widget_item_pre_notify_del(it);
1518    if (it->selected)
1519      it->wd->selected = eina_list_remove(it->wd->selected, it);
1520    if (it->realized) _item_unrealize(it);
1521    if ((!it->delete_me) && (it->itc->func.del))
1522      it->itc->func.del((void *)it->base.data, it->wd->self);
1523    it->delete_me = EINA_TRUE;
1524    it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
1525    if (it->long_timer) ecore_timer_del(it->long_timer);
1526    if (it->tooltip.del_cb)
1527      it->tooltip.del_cb((void *)it->tooltip.data, it->base.widget, it);
1528    it->wd->walking -= it->walking;
1529    it->wd->count--;
1530    if (it->is_group)
1531      it->wd->group_items = eina_list_remove(it->wd->group_items, it);
1532    if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
1533    it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
1534    elm_widget_item_del(it);
1535 }
1536
1537 static void
1538 _item_select(Elm_Gengrid_Item *it)
1539 {
1540    if ((it->wd->no_select) || (it->delete_me)) return;
1541    if (it->selected)
1542      {
1543         if (it->wd->always_select) goto call;
1544         return;
1545      }
1546    it->selected = EINA_TRUE;
1547    it->wd->selected = eina_list_append(it->wd->selected, it);
1548 call:
1549    it->walking++;
1550    it->wd->walking++;
1551    if (it->func.func)
1552      it->func.func((void *)it->func.data, it->wd->self, it);
1553    if (!it->delete_me)
1554      evas_object_smart_callback_call(it->wd->self, SIG_SELECTED, it);
1555    it->walking--;
1556    it->wd->walking--;
1557    it->wd->last_selected_item = it;
1558    if ((it->wd->clear_me) && (!it->wd->walking))
1559      elm_gengrid_clear(it->base.widget);
1560    else
1561      {
1562         if ((!it->walking) && (it->delete_me))
1563           if (!it->relcount) _item_del(it);
1564      }
1565 }
1566
1567 static void
1568 _item_unselect(Elm_Gengrid_Item *it)
1569 {
1570    if ((it->delete_me) || (!it->highlighted)) return;
1571    edje_object_signal_emit(it->base.view, "elm,state,unselected", "elm");
1572    it->highlighted = EINA_FALSE;
1573    if (it->selected)
1574      {
1575         it->selected = EINA_FALSE;
1576         it->wd->selected = eina_list_remove(it->wd->selected, it);
1577         evas_object_smart_callback_call(it->wd->self, SIG_UNSELECTED, it);
1578      }
1579 }
1580
1581 static void
1582 _calc_job(void *data)
1583 {
1584    Widget_Data *wd = data;
1585    Evas_Coord minw = 0, minh = 0, nmax = 0, cvw, cvh;
1586    Elm_Gengrid_Item *it, *group_item = NULL;
1587    int count_group = 0;
1588    long count = 0;
1589    wd->items_lost = 0;
1590
1591    evas_object_geometry_get(wd->pan_smart, NULL, NULL, &cvw, &cvh);
1592    if ((cvw != 0) || (cvh != 0))
1593      {
1594         if ((wd->horizontal) && (wd->item_height > 0))
1595           nmax = cvh / wd->item_height;
1596         else if (wd->item_width > 0)
1597           nmax = cvw / wd->item_width;
1598
1599         if (nmax < 1)
1600           nmax = 1;
1601
1602         EINA_INLIST_FOREACH(wd->items, it)
1603           {
1604              if (it->prev_group != count_group)
1605                it->prev_group = count_group;
1606              if (it->is_group)
1607                {
1608                   count = count % nmax;
1609                   if (count)
1610                     wd->items_lost += nmax - count;
1611                   //printf("%d items and I lost %d\n", count, wd->items_lost);
1612                   count_group++;
1613                   if (count) count = 0;
1614                   group_item = it;
1615                }
1616              else
1617                {
1618                   if (it->parent != group_item)
1619                     it->parent = group_item;
1620                   count++;
1621                }
1622           }
1623         count = wd->count + wd->items_lost - count_group;
1624         if (wd->horizontal)
1625           {
1626              minw = (ceil(count / (float)nmax) * wd->item_width) + (count_group * wd->group_item_width);
1627              minh = nmax * wd->item_height;
1628           }
1629         else
1630           {
1631              minw = nmax * wd->item_width;
1632              minh = (ceil(count / (float)nmax) * wd->item_height) + (count_group * wd->group_item_height);
1633           }
1634
1635         if ((minw != wd->minw) || (minh != wd->minh))
1636           {
1637              wd->minh = minh;
1638              wd->minw = minw;
1639              evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
1640           }
1641
1642         wd->nmax = nmax;
1643         evas_object_smart_changed(wd->pan_smart);
1644      }
1645    wd->calc_job = NULL;
1646 }
1647
1648 static void
1649 _pan_add(Evas_Object *obj)
1650 {
1651    Pan *sd;
1652    Evas_Object_Smart_Clipped_Data *cd;
1653
1654    _pan_sc.add(obj);
1655    cd = evas_object_smart_data_get(obj);
1656    sd = ELM_NEW(Pan);
1657    if (!sd) return;
1658    sd->__clipped_data = *cd;
1659    free(cd);
1660    evas_object_smart_data_set(obj, sd);
1661 }
1662
1663 static void
1664 _pan_del(Evas_Object *obj)
1665 {
1666    Pan *sd = evas_object_smart_data_get(obj);
1667
1668    if (!sd) return;
1669    _pan_sc.del(obj);
1670 }
1671
1672 static void
1673 _pan_set(Evas_Object *obj,
1674          Evas_Coord   x,
1675          Evas_Coord   y)
1676 {
1677    Pan *sd = evas_object_smart_data_get(obj);
1678    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
1679    sd->wd->pan_x = x;
1680    sd->wd->pan_y = y;
1681    evas_object_smart_changed(obj);
1682 }
1683
1684 static void
1685 _pan_get(Evas_Object *obj,
1686          Evas_Coord  *x,
1687          Evas_Coord  *y)
1688 {
1689    Pan *sd = evas_object_smart_data_get(obj);
1690    if (x) *x = sd->wd->pan_x;
1691    if (y) *y = sd->wd->pan_y;
1692 }
1693
1694 static void
1695 _pan_child_size_get(Evas_Object *obj,
1696                     Evas_Coord  *w,
1697                     Evas_Coord  *h)
1698 {
1699    Pan *sd = evas_object_smart_data_get(obj);
1700    if (w) *w = sd->wd->minw;
1701    if (h) *h = sd->wd->minh;
1702 }
1703
1704 static void
1705 _pan_max_get(Evas_Object *obj,
1706              Evas_Coord  *x,
1707              Evas_Coord  *y)
1708 {
1709    Pan *sd = evas_object_smart_data_get(obj);
1710    Evas_Coord ow, oh;
1711
1712    if (!sd) return;
1713    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1714    if (x)
1715      *x = (ow < sd->wd->minw) ? sd->wd->minw - ow : 0;
1716    if (y)
1717      *y = (oh < sd->wd->minh) ? sd->wd->minh - oh : 0;
1718 }
1719
1720 static void
1721 _pan_min_get(Evas_Object *obj,
1722              Evas_Coord  *x,
1723              Evas_Coord  *y)
1724 {
1725    Pan *sd = evas_object_smart_data_get(obj);
1726    Evas_Coord mx, my;
1727
1728    if (!sd) return;
1729    _pan_max_get(obj, &mx, &my);
1730    if (x)
1731      *x = -mx * sd->wd->align_x;
1732    if (y)
1733      *y = -my * sd->wd->align_y;
1734 }
1735
1736 static void
1737 _pan_resize(Evas_Object *obj,
1738             Evas_Coord   w,
1739             Evas_Coord   h)
1740 {
1741    Pan *sd = evas_object_smart_data_get(obj);
1742    Evas_Coord ow, oh;
1743
1744    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
1745    if ((ow == w) && (oh == h)) return;
1746    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1747    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1748 }
1749
1750 static void
1751 _pan_calculate(Evas_Object *obj)
1752 {
1753    Pan *sd = evas_object_smart_data_get(obj);
1754    Evas_Coord cx = 0, cy = 0;
1755    Elm_Gengrid_Item *it;
1756
1757    if (!sd) return;
1758    if (!sd->wd->nmax) return;
1759
1760    sd->wd->reorder_item_changed = EINA_FALSE;
1761
1762    EINA_INLIST_FOREACH(sd->wd->items, it)
1763      {
1764         if (it->is_group)
1765           {
1766              if (sd->wd->horizontal)
1767                {
1768                   if (cy)
1769                     {
1770                        cx++;
1771                        cy = 0;
1772                     }
1773                }
1774              else
1775                {
1776                   if (cx)
1777                     {
1778                        cx = 0;
1779                        cy++;
1780                     }
1781                }
1782           }
1783         _item_place(it, cx, cy);
1784         if (sd->wd->reorder_item_changed) return;
1785         if (it->is_group)
1786           {
1787              if (sd->wd->horizontal)
1788                {
1789                   cx++;
1790                   cy = 0;
1791                }
1792              else
1793                {
1794                   cx = 0;
1795                   cy++;
1796                }
1797           }
1798         else
1799           {
1800              if (sd->wd->horizontal)
1801                {
1802                   cy = (cy + 1) % sd->wd->nmax;
1803                   if (!cy) cx++;
1804                }
1805              else
1806                {
1807                   cx = (cx + 1) % sd->wd->nmax;
1808                   if (!cx) cy++;
1809                }
1810           }
1811      }
1812    _group_item_place(sd);
1813
1814
1815    if ((sd->wd->reorder_mode) && (sd->wd->reorder_item))
1816      {
1817         if (!sd->wd->reorder_item_changed)
1818           {
1819              sd->wd->old_pan_x = sd->wd->pan_x;
1820              sd->wd->old_pan_y = sd->wd->pan_y;
1821           }
1822         sd->wd->move_effect_enabled = EINA_FALSE;
1823      }
1824    evas_object_smart_callback_call(sd->wd->self, SIG_CHANGED, NULL);
1825 }
1826
1827 static void
1828 _pan_move(Evas_Object *obj,
1829           Evas_Coord x __UNUSED__,
1830           Evas_Coord y __UNUSED__)
1831 {
1832    Pan *sd = evas_object_smart_data_get(obj);
1833    if (!sd) return;
1834    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
1835    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
1836 }
1837
1838 static void
1839 _hold_on(void *data       __UNUSED__,
1840          Evas_Object     *obj,
1841          void *event_info __UNUSED__)
1842 {
1843    Widget_Data *wd = elm_widget_data_get(obj);
1844    if (!wd) return;
1845    elm_smart_scroller_hold_set(wd->scr, 1);
1846 }
1847
1848 static void
1849 _hold_off(void *data       __UNUSED__,
1850           Evas_Object     *obj,
1851           void *event_info __UNUSED__)
1852 {
1853    Widget_Data *wd = elm_widget_data_get(obj);
1854    if (!wd) return;
1855    elm_smart_scroller_hold_set(wd->scr, 0);
1856 }
1857
1858 static void
1859 _freeze_on(void *data       __UNUSED__,
1860            Evas_Object     *obj,
1861            void *event_info __UNUSED__)
1862 {
1863    Widget_Data *wd = elm_widget_data_get(obj);
1864    if (!wd) return;
1865    elm_smart_scroller_freeze_set(wd->scr, 1);
1866 }
1867
1868 static void
1869 _freeze_off(void *data       __UNUSED__,
1870             Evas_Object     *obj,
1871             void *event_info __UNUSED__)
1872 {
1873    Widget_Data *wd = elm_widget_data_get(obj);
1874    if (!wd) return;
1875    elm_smart_scroller_freeze_set(wd->scr, 0);
1876 }
1877
1878 static void
1879 _scr_anim_start(void        *data,
1880                 Evas_Object *obj __UNUSED__,
1881                 void        *event_info __UNUSED__)
1882 {
1883    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_START, NULL);
1884 }
1885
1886 static void
1887 _scr_anim_stop(void        *data,
1888                 Evas_Object *obj __UNUSED__,
1889                 void        *event_info __UNUSED__)
1890 {
1891    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_STOP, NULL);
1892 }
1893
1894 static void
1895 _scr_drag_start(void            *data,
1896                 Evas_Object *obj __UNUSED__,
1897                 void *event_info __UNUSED__)
1898 {
1899    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
1900 }
1901
1902 static void
1903 _scr_drag_stop(void            *data,
1904                Evas_Object *obj __UNUSED__,
1905                void *event_info __UNUSED__)
1906 {
1907    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
1908 }
1909
1910 static void
1911 _edge_left(void        *data,
1912            Evas_Object *scr __UNUSED__,
1913            void        *event_info __UNUSED__)
1914 {
1915    evas_object_smart_callback_call(data, SIG_SCROLL_EDGE_LEFT, NULL);
1916    evas_object_smart_callback_call(data, SIG_EDGE_LEFT, NULL);
1917 }
1918
1919 static void
1920 _edge_right(void        *data,
1921             Evas_Object *scr __UNUSED__,
1922             void        *event_info __UNUSED__)
1923 {
1924    evas_object_smart_callback_call(data, SIG_SCROLL_EDGE_RIGHT, NULL);
1925    evas_object_smart_callback_call(data, SIG_EDGE_RIGHT, NULL);
1926 }
1927
1928 static void
1929 _edge_top(void        *data,
1930           Evas_Object *scr __UNUSED__,
1931           void        *event_info __UNUSED__)
1932 {
1933    evas_object_smart_callback_call(data, SIG_SCROLL_EDGE_TOP, NULL);
1934    evas_object_smart_callback_call(data, SIG_EDGE_TOP, NULL);
1935 }
1936
1937 static void
1938 _edge_bottom(void        *data,
1939              Evas_Object *scr __UNUSED__,
1940              void        *event_info __UNUSED__)
1941 {
1942    evas_object_smart_callback_call(data, SIG_SCROLL_EDGE_BOTTOM, NULL);
1943    evas_object_smart_callback_call(data, SIG_EDGE_BOTTOM, NULL);
1944 }
1945
1946 static void
1947 _scr_scroll(void            *data,
1948             Evas_Object *obj __UNUSED__,
1949             void *event_info __UNUSED__)
1950 {
1951    evas_object_smart_callback_call(data, SIG_SCROLL, NULL);
1952 }
1953
1954 static int
1955 _elm_gengrid_item_compare_data(const void *data, const void *data1)
1956 {
1957    const Elm_Gengrid_Item *it = data;
1958    const Elm_Gengrid_Item *item1 = data1;
1959
1960    return _elm_gengrid_item_compare_data_cb(it->base.data, item1->base.data);
1961 }
1962
1963 static int
1964 _elm_gengrid_item_compare(const void *data, const void *data1)
1965 {
1966    Elm_Gengrid_Item *it, *item1;
1967    it = ELM_GENGRID_ITEM_FROM_INLIST(data);
1968    item1 = ELM_GENGRID_ITEM_FROM_INLIST(data1);
1969    return _elm_gengrid_item_compare_cb(it, item1);
1970 }
1971
1972 EAPI Evas_Object *
1973 elm_gengrid_add(Evas_Object *parent)
1974 {
1975    Evas_Object *obj;
1976    Evas *e;
1977    Widget_Data *wd;
1978    static Evas_Smart *smart = NULL;
1979    Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
1980
1981    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1982
1983    ELM_SET_WIDTYPE(widtype, "gengrid");
1984    elm_widget_type_set(obj, "gengrid");
1985    elm_widget_sub_object_add(parent, obj);
1986    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1987    elm_widget_data_set(obj, wd);
1988    elm_widget_del_hook_set(obj, _del_hook);
1989    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1990    elm_widget_theme_hook_set(obj, _theme_hook);
1991    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
1992    elm_widget_can_focus_set(obj, EINA_TRUE);
1993    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
1994    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
1995    elm_widget_event_hook_set(obj, _event_hook);
1996
1997    wd->scr = elm_smart_scroller_add(e);
1998    elm_smart_scroller_widget_set(wd->scr, obj);
1999    elm_smart_scroller_object_theme_set(obj, wd->scr, "gengrid", "base",
2000                                        "default");
2001    elm_widget_resize_object_set(obj, wd->scr);
2002
2003    evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, obj);
2004    evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, obj);
2005    evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
2006    evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
2007    evas_object_smart_callback_add(wd->scr, "edge,left", _edge_left, obj);
2008    evas_object_smart_callback_add(wd->scr, "edge,right", _edge_right, obj);
2009    evas_object_smart_callback_add(wd->scr, "edge,top", _edge_top, obj);
2010    evas_object_smart_callback_add(wd->scr, "edge,bottom", _edge_bottom,
2011                                   obj);
2012    evas_object_smart_callback_add(wd->scr, "scroll", _scr_scroll, obj);
2013
2014    elm_smart_scroller_bounce_allow_set(wd->scr, bounce, bounce);
2015
2016    wd->self = obj;
2017    wd->align_x = 0.5;
2018    wd->align_y = 0.5;
2019    wd->h_bounce = bounce;
2020    wd->v_bounce = bounce;
2021    wd->no_select = EINA_FALSE;
2022
2023    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
2024    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
2025    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
2026    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
2027
2028    evas_object_smart_callbacks_descriptions_set(obj, _signals);
2029
2030    if (!smart)
2031      {
2032         static Evas_Smart_Class sc;
2033
2034         evas_object_smart_clipped_smart_set(&_pan_sc);
2035         sc = _pan_sc;
2036         sc.name = "elm_gengrid_pan";
2037         sc.version = EVAS_SMART_CLASS_VERSION;
2038         sc.add = _pan_add;
2039         sc.del = _pan_del;
2040         sc.resize = _pan_resize;
2041         sc.move = _pan_move;
2042         sc.calculate = _pan_calculate;
2043         smart = evas_smart_class_new(&sc);
2044      }
2045    if (smart)
2046      {
2047         wd->pan_smart = evas_object_smart_add(e, smart);
2048         wd->pan = evas_object_smart_data_get(wd->pan_smart);
2049         wd->pan->wd = wd;
2050      }
2051
2052    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
2053                                      _pan_set, _pan_get, _pan_max_get,
2054                                      _pan_min_get, _pan_child_size_get);
2055
2056    _mirrored_set(obj, elm_widget_mirrored_get(obj));
2057    return obj;
2058 }
2059
2060 EAPI void
2061 elm_gengrid_item_size_set(Evas_Object *obj,
2062                           Evas_Coord   w,
2063                           Evas_Coord   h)
2064 {
2065    ELM_CHECK_WIDTYPE(obj, widtype);
2066    Widget_Data *wd = elm_widget_data_get(obj);
2067    if (!wd) return;
2068    if ((wd->item_width == w) && (wd->item_height == h)) return;
2069    wd->item_width = w;
2070    wd->item_height = h;
2071    if (wd->calc_job) ecore_job_del(wd->calc_job);
2072    wd->calc_job = ecore_job_add(_calc_job, wd);
2073 }
2074
2075 EAPI void
2076 elm_gengrid_item_size_get(const Evas_Object *obj,
2077                           Evas_Coord        *w,
2078                           Evas_Coord        *h)
2079 {
2080    ELM_CHECK_WIDTYPE(obj, widtype);
2081    Widget_Data *wd = elm_widget_data_get(obj);
2082    if (!wd) return;
2083    if (w) *w = wd->item_width;
2084    if (h) *h = wd->item_height;
2085 }
2086
2087 EAPI void
2088 elm_gengrid_group_item_size_set(Evas_Object *obj,
2089                           Evas_Coord   w,
2090                           Evas_Coord   h)
2091 {
2092    ELM_CHECK_WIDTYPE(obj, widtype);
2093    Widget_Data *wd = elm_widget_data_get(obj);
2094    if (!wd) return;
2095    if ((wd->group_item_width == w) && (wd->group_item_height == h)) return;
2096    wd->group_item_width = w;
2097    wd->group_item_height = h;
2098    if (wd->calc_job) ecore_job_del(wd->calc_job);
2099    wd->calc_job = ecore_job_add(_calc_job, wd);
2100 }
2101
2102 EAPI void
2103 elm_gengrid_group_item_size_get(const Evas_Object *obj,
2104                           Evas_Coord        *w,
2105                           Evas_Coord        *h)
2106 {
2107    ELM_CHECK_WIDTYPE(obj, widtype);
2108    Widget_Data *wd = elm_widget_data_get(obj);
2109    if (!wd) return;
2110    if (w) *w = wd->group_item_width;
2111    if (h) *h = wd->group_item_height;
2112 }
2113
2114 EAPI void
2115 elm_gengrid_align_set(Evas_Object *obj,
2116                       double       align_x,
2117                       double       align_y)
2118 {
2119    ELM_CHECK_WIDTYPE(obj, widtype);
2120
2121    Widget_Data *wd = elm_widget_data_get(obj);
2122    double old_h = wd->align_x, old_y = wd->align_y;
2123
2124    if (align_x > 1.0)
2125      align_x = 1.0;
2126    else if (align_x < 0.0)
2127      align_x = 0.0;
2128    wd->align_x = align_x;
2129
2130    if (align_y > 1.0)
2131      align_y = 1.0;
2132    else if (align_y < 0.0)
2133      align_y = 0.0;
2134    wd->align_y = align_y;
2135
2136    if ((old_h != wd->align_x) || (old_y != wd->align_y))
2137      evas_object_smart_calculate(wd->pan_smart);
2138 }
2139
2140 EAPI void
2141 elm_gengrid_align_get(const Evas_Object *obj,
2142                       double            *align_x,
2143                       double            *align_y)
2144 {
2145    ELM_CHECK_WIDTYPE(obj, widtype);
2146    Widget_Data *wd = elm_widget_data_get(obj);
2147    if (align_x) *align_x = wd->align_x;
2148    if (align_y) *align_y = wd->align_y;
2149 }
2150
2151 EAPI Elm_Gengrid_Item *
2152 elm_gengrid_item_append(Evas_Object                  *obj,
2153                         const Elm_Gengrid_Item_Class *itc,
2154                         const void                   *data,
2155                         Evas_Smart_Cb                 func,
2156                         const void                   *func_data)
2157 {
2158    Elm_Gengrid_Item *it;
2159    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2160    Widget_Data *wd = elm_widget_data_get(obj);
2161    if (!wd) return NULL;
2162
2163    it = _item_create(wd, itc, data, func, func_data);
2164    if (!it) return NULL;
2165    wd->items = eina_inlist_append(wd->items, EINA_INLIST_GET(it));
2166
2167    if (it->is_group)
2168      wd->group_items = eina_list_prepend(wd->group_items, it);
2169
2170    if (wd->calc_job) ecore_job_del(wd->calc_job);
2171    wd->calc_job = ecore_job_add(_calc_job, wd);
2172
2173    return it;
2174 }
2175
2176 EAPI Elm_Gengrid_Item *
2177 elm_gengrid_item_prepend(Evas_Object                  *obj,
2178                          const Elm_Gengrid_Item_Class *itc,
2179                          const void                   *data,
2180                          Evas_Smart_Cb                 func,
2181                          const void                   *func_data)
2182 {
2183    Elm_Gengrid_Item *it;
2184    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2185    Widget_Data *wd = elm_widget_data_get(obj);
2186    if (!wd) return NULL;
2187
2188    it = _item_create(wd, itc, data, func, func_data);
2189    if (!it) return NULL;
2190    wd->items = eina_inlist_prepend(wd->items, EINA_INLIST_GET(it));
2191    if (it->is_group)
2192      wd->group_items = eina_list_append(wd->group_items, it);
2193
2194    if (wd->calc_job) ecore_job_del(wd->calc_job);
2195    wd->calc_job = ecore_job_add(_calc_job, wd);
2196
2197    return it;
2198 }
2199
2200 EAPI Elm_Gengrid_Item *
2201 elm_gengrid_item_insert_before(Evas_Object                  *obj,
2202                                const Elm_Gengrid_Item_Class *itc,
2203                                const void                   *data,
2204                                Elm_Gengrid_Item             *relative,
2205                                Evas_Smart_Cb                 func,
2206                                const void                   *func_data)
2207 {
2208    Elm_Gengrid_Item *it;
2209    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2210    EINA_SAFETY_ON_NULL_RETURN_VAL(relative, NULL);
2211    Widget_Data *wd = elm_widget_data_get(obj);
2212    if (!wd) return NULL;
2213
2214    it = _item_create(wd, itc, data, func, func_data);
2215    if (!it) return NULL;
2216    wd->items = eina_inlist_prepend_relative
2217       (wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(relative));
2218    if (it->is_group)
2219      wd->group_items = eina_list_append_relative(wd->group_items, it, relative->parent);
2220
2221    if (wd->calc_job) ecore_job_del(wd->calc_job);
2222    wd->calc_job = ecore_job_add(_calc_job, wd);
2223
2224    return it;
2225 }
2226
2227 EAPI Elm_Gengrid_Item *
2228 elm_gengrid_item_insert_after(Evas_Object                  *obj,
2229                               const Elm_Gengrid_Item_Class *itc,
2230                               const void                   *data,
2231                               Elm_Gengrid_Item             *relative,
2232                               Evas_Smart_Cb                 func,
2233                               const void                   *func_data)
2234 {
2235    Elm_Gengrid_Item *it;
2236    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2237    EINA_SAFETY_ON_NULL_RETURN_VAL(relative, NULL);
2238    Widget_Data *wd = elm_widget_data_get(obj);
2239    if (!wd) return NULL;
2240
2241    it = _item_create(wd, itc, data, func, func_data);
2242    if (!it) return NULL;
2243    wd->items = eina_inlist_append_relative
2244       (wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(relative));
2245    if (it->is_group)
2246      wd->group_items = eina_list_prepend_relative(wd->group_items, it, relative->parent);
2247
2248    if (wd->calc_job) ecore_job_del(wd->calc_job);
2249    wd->calc_job = ecore_job_add(_calc_job, wd);
2250
2251    return it;
2252 }
2253
2254 EAPI Elm_Gengrid_Item *
2255 elm_gengrid_item_direct_sorted_insert(Evas_Object                  *obj,
2256                                       const Elm_Gengrid_Item_Class *itc,
2257                                       const void                   *data,
2258                                       Eina_Compare_Cb               comp,
2259                                       Evas_Smart_Cb                 func,
2260                                       const void                   *func_data)
2261 {
2262    Elm_Gengrid_Item *it;
2263    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2264    Widget_Data *wd = elm_widget_data_get(obj);
2265    if (!wd) return NULL;
2266
2267    it = _item_create(wd, itc, data, func, func_data);
2268    if (!it) return NULL;
2269
2270    if (!wd->state)
2271      wd->state = eina_inlist_sorted_state_new();
2272
2273    _elm_gengrid_item_compare_cb = comp;
2274    wd->items = eina_inlist_sorted_state_insert(wd->items, EINA_INLIST_GET(it),
2275                                          _elm_gengrid_item_compare, wd->state);
2276    if (wd->calc_job) ecore_job_del(wd->calc_job);
2277    wd->calc_job = ecore_job_add(_calc_job, wd);
2278
2279    return it;
2280 }
2281
2282 EAPI Elm_Gengrid_Item *
2283 elm_gengrid_item_sorted_insert(Evas_Object                  *obj,
2284                                const Elm_Gengrid_Item_Class *itc,
2285                                const void                   *data,
2286                                Eina_Compare_Cb               comp,
2287                                Evas_Smart_Cb                 func,
2288                                const void                   *func_data)
2289 {
2290    _elm_gengrid_item_compare_data_cb = comp;
2291
2292    return elm_gengrid_item_direct_sorted_insert(obj, itc, data, _elm_gengrid_item_compare_data, func, func_data);
2293 }
2294
2295 EAPI void
2296 elm_gengrid_item_del(Elm_Gengrid_Item *it)
2297 {
2298    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2299    if ((it->relcount > 0) || (it->walking > 0))
2300      {
2301         it->delete_me = EINA_TRUE;
2302         elm_widget_item_pre_notify_del(it);
2303         if (it->selected)
2304           it->wd->selected = eina_list_remove(it->wd->selected, it);
2305         if (it->itc->func.del)
2306           it->itc->func.del((void *)it->base.data, it->wd->self);
2307         return;
2308      }
2309
2310    _item_del(it);
2311 }
2312
2313 EAPI void
2314 elm_gengrid_horizontal_set(Evas_Object *obj,
2315                            Eina_Bool    setting)
2316 {
2317    ELM_CHECK_WIDTYPE(obj, widtype);
2318    Widget_Data *wd = elm_widget_data_get(obj);
2319    if (!wd) return;
2320    if (setting == wd->horizontal) return;
2321    wd->horizontal = setting;
2322
2323    /* Update the items to conform to the new layout */
2324    if (wd->calc_job) ecore_job_del(wd->calc_job);
2325    wd->calc_job = ecore_job_add(_calc_job, wd);
2326 }
2327
2328 EAPI Eina_Bool
2329 elm_gengrid_horizontal_get(const Evas_Object *obj)
2330 {
2331    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2332    Widget_Data *wd = elm_widget_data_get(obj);
2333    if (!wd) return EINA_FALSE;
2334    return wd->horizontal;
2335 }
2336
2337 EAPI void
2338 elm_gengrid_clear(Evas_Object *obj)
2339 {
2340    ELM_CHECK_WIDTYPE(obj, widtype);
2341    Widget_Data *wd = elm_widget_data_get(obj);
2342    if (!wd) return;
2343
2344    if (wd->state)
2345      {
2346         eina_inlist_sorted_state_free(wd->state);
2347         wd->state = NULL;
2348      }
2349    if (wd->calc_job)
2350      {
2351         ecore_job_del(wd->calc_job);
2352         wd->calc_job = NULL;
2353      }
2354
2355    if (wd->walking > 0)
2356      {
2357         Elm_Gengrid_Item *it;
2358         wd->clear_me = 1;
2359         EINA_INLIST_FOREACH(wd->items, it)
2360            it->delete_me = 1;
2361         return;
2362      }
2363    wd->clear_me = 0;
2364    while (wd->items)
2365      {
2366         Elm_Gengrid_Item *it = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
2367
2368         wd->items = eina_inlist_remove(wd->items, wd->items);
2369         elm_widget_item_pre_notify_del(it);
2370         if (it->realized) _item_unrealize(it);
2371         if (it->itc->func.del)
2372           it->itc->func.del((void *)it->base.data, wd->self);
2373         if (it->long_timer) ecore_timer_del(it->long_timer);
2374         elm_widget_item_del(it);
2375      }
2376
2377    if (wd->selected)
2378      {
2379         eina_list_free(wd->selected);
2380         wd->selected = NULL;
2381      }
2382
2383    wd->pan_x = 0;
2384    wd->pan_y = 0;
2385    wd->minw = 0;
2386    wd->minh = 0;
2387    wd->count = 0;
2388    evas_object_size_hint_min_set(wd->pan_smart, wd->minw, wd->minh);
2389    evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
2390 }
2391
2392 EAPI const Evas_Object *
2393 elm_gengrid_item_object_get(const Elm_Gengrid_Item *it)
2394 {
2395    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2396    return it->base.view;
2397 }
2398
2399 EAPI void
2400 elm_gengrid_item_update(Elm_Gengrid_Item *it)
2401 {
2402    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2403    if (!it->realized) return;
2404    if (it->want_unrealize) return;
2405    _item_unrealize(it);
2406    _item_realize(it);
2407    _item_place(it, it->x, it->y);
2408 }
2409
2410 EAPI void *
2411 elm_gengrid_item_data_get(const Elm_Gengrid_Item *it)
2412 {
2413    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2414    return elm_widget_item_data_get(it);
2415 }
2416
2417 EAPI void
2418 elm_gengrid_item_data_set(Elm_Gengrid_Item *it,
2419                           const void       *data)
2420 {
2421    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2422    elm_widget_item_data_set(it, data);
2423 }
2424
2425 EAPI const Elm_Gengrid_Item_Class *
2426 elm_gengrid_item_item_class_get(const Elm_Gengrid_Item *it)
2427 {
2428    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2429    if (it->delete_me) return NULL;
2430    return it->itc;
2431 }
2432
2433 EAPI void
2434 elm_gengrid_item_item_class_set(Elm_Gengrid_Item *it,
2435                                 const Elm_Gengrid_Item_Class *itc)
2436 {
2437    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2438    EINA_SAFETY_ON_NULL_RETURN(itc);
2439    if (it->delete_me) return;
2440    it->itc = itc;
2441    elm_gengrid_item_update(it);
2442 }
2443
2444 EAPI void
2445 elm_gengrid_item_pos_get(const Elm_Gengrid_Item *it,
2446                          unsigned int           *x,
2447                          unsigned int           *y)
2448 {
2449    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2450    if (x) *x = it->x;
2451    if (y) *y = it->y;
2452 }
2453
2454 EAPI void
2455 elm_gengrid_multi_select_set(Evas_Object *obj,
2456                              Eina_Bool    multi)
2457 {
2458    ELM_CHECK_WIDTYPE(obj, widtype);
2459    Widget_Data *wd = elm_widget_data_get(obj);
2460    if (!wd) return;
2461    wd->multi = multi;
2462 }
2463
2464 EAPI Eina_Bool
2465 elm_gengrid_multi_select_get(const Evas_Object *obj)
2466 {
2467    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2468    Widget_Data *wd = elm_widget_data_get(obj);
2469    if (!wd) return EINA_FALSE;
2470    return wd->multi;
2471 }
2472
2473 EAPI Elm_Gengrid_Item *
2474 elm_gengrid_selected_item_get(const Evas_Object *obj)
2475 {
2476    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2477    Widget_Data *wd = elm_widget_data_get(obj);
2478    if (!wd) return NULL;
2479    if (wd->selected) return wd->selected->data;
2480    return NULL;
2481 }
2482
2483 EAPI const Eina_List *
2484 elm_gengrid_selected_items_get(const Evas_Object *obj)
2485 {
2486    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2487    Widget_Data *wd = elm_widget_data_get(obj);
2488    if (!wd) return NULL;
2489    return wd->selected;
2490 }
2491
2492 EAPI void
2493 elm_gengrid_item_selected_set(Elm_Gengrid_Item *it,
2494                               Eina_Bool         selected)
2495 {
2496    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2497    Widget_Data *wd = it->wd;
2498    if (!wd) return;
2499    if (it->delete_me) return;
2500    selected = !!selected;
2501    if (it->selected == selected) return;
2502
2503    if (selected)
2504      {
2505         if (!wd->multi)
2506           {
2507              while (wd->selected)
2508                _item_unselect(wd->selected->data);
2509           }
2510         _item_highlight(it);
2511         _item_select(it);
2512      }
2513    else
2514      _item_unselect(it);
2515 }
2516
2517 EAPI Eina_Bool
2518 elm_gengrid_item_selected_get(const Elm_Gengrid_Item *it)
2519 {
2520    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2521    return it->selected;
2522 }
2523
2524 EAPI void
2525 elm_gengrid_item_disabled_set(Elm_Gengrid_Item *it,
2526                               Eina_Bool         disabled)
2527 {
2528    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2529    if (it->disabled == disabled) return;
2530    if (it->delete_me) return;
2531    it->disabled = !!disabled;
2532    if (it->realized)
2533      {
2534         if (it->disabled)
2535           edje_object_signal_emit(it->base.view, "elm,state,disabled", "elm");
2536         else
2537           edje_object_signal_emit(it->base.view, "elm,state,enabled", "elm");
2538      }
2539 }
2540
2541 EAPI Eina_Bool
2542 elm_gengrid_item_disabled_get(const Elm_Gengrid_Item *it)
2543 {
2544    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2545    if (it->delete_me) return EINA_FALSE;
2546    return it->disabled;
2547 }
2548
2549 static Evas_Object *
2550 _elm_gengrid_item_label_create(void        *data,
2551                                Evas_Object *obj __UNUSED__,
2552                                Evas_Object *tooltip,
2553                                void *it   __UNUSED__)
2554 {
2555    Evas_Object *label = elm_label_add(tooltip);
2556    if (!label)
2557      return NULL;
2558    elm_object_style_set(label, "tooltip");
2559    elm_object_text_set(label, data);
2560    return label;
2561 }
2562
2563 static void
2564 _elm_gengrid_item_label_del_cb(void            *data,
2565                                Evas_Object *obj __UNUSED__,
2566                                void *event_info __UNUSED__)
2567 {
2568    eina_stringshare_del(data);
2569 }
2570
2571 EAPI void
2572 elm_gengrid_item_tooltip_text_set(Elm_Gengrid_Item *it,
2573                                   const char       *text)
2574 {
2575    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2576    text = eina_stringshare_add(text);
2577    elm_gengrid_item_tooltip_content_cb_set(it, _elm_gengrid_item_label_create,
2578                                            text,
2579                                            _elm_gengrid_item_label_del_cb);
2580 }
2581
2582 EAPI void
2583 elm_gengrid_item_tooltip_content_cb_set(Elm_Gengrid_Item           *it,
2584                                         Elm_Tooltip_Item_Content_Cb func,
2585                                         const void                 *data,
2586                                         Evas_Smart_Cb               del_cb)
2587 {
2588    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_GOTO(it, error);
2589
2590    if ((it->tooltip.content_cb == func) && (it->tooltip.data == data))
2591      return;
2592
2593    if (it->tooltip.del_cb)
2594      it->tooltip.del_cb((void *)it->tooltip.data,
2595                           it->base.widget, it);
2596    it->tooltip.content_cb = func;
2597    it->tooltip.data = data;
2598    it->tooltip.del_cb = del_cb;
2599    if (it->base.view)
2600      {
2601         elm_widget_item_tooltip_content_cb_set(it,
2602                                                it->tooltip.content_cb,
2603                                                it->tooltip.data, NULL);
2604         elm_widget_item_tooltip_style_set(it, it->tooltip.style);
2605         elm_widget_item_tooltip_size_restrict_disable(it, it->tooltip.free_size);
2606      }
2607
2608    return;
2609
2610 error:
2611    if (del_cb) del_cb((void *)data, NULL, NULL);
2612 }
2613
2614 EAPI void
2615 elm_gengrid_item_tooltip_unset(Elm_Gengrid_Item *it)
2616 {
2617    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2618    if ((it->base.view) && (it->tooltip.content_cb))
2619      elm_widget_item_tooltip_unset(it);
2620
2621    if (it->tooltip.del_cb)
2622      it->tooltip.del_cb((void *)it->tooltip.data, it->base.widget, it);
2623    it->tooltip.del_cb = NULL;
2624    it->tooltip.content_cb = NULL;
2625    it->tooltip.data = NULL;
2626    it->tooltip.free_size = EINA_FALSE;
2627    if (it->tooltip.style)
2628      elm_gengrid_item_tooltip_style_set(it, NULL);
2629 }
2630
2631 EAPI void
2632 elm_gengrid_item_tooltip_style_set(Elm_Gengrid_Item *it,
2633                                    const char       *style)
2634 {
2635    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2636    eina_stringshare_replace(&it->tooltip.style, style);
2637    if (it->base.view) elm_widget_item_tooltip_style_set(it, style);
2638 }
2639
2640 EAPI const char *
2641 elm_gengrid_item_tooltip_style_get(const Elm_Gengrid_Item *it)
2642 {
2643    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2644    return it->tooltip.style;
2645 }
2646
2647 EAPI Eina_Bool
2648 elm_gengrid_item_tooltip_size_restrict_disable(Elm_Gengrid_Item *it, Eina_Bool disable)
2649 {
2650    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2651    it->tooltip.free_size = disable;
2652    if (it->base.view) return elm_widget_item_tooltip_size_restrict_disable(it, disable);
2653    return EINA_TRUE;
2654 }
2655
2656 EAPI Eina_Bool
2657 elm_gengrid_item_tooltip_size_restrict_disabled_get(const Elm_Gengrid_Item *it)
2658 {
2659    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2660    return it->tooltip.free_size;
2661 }
2662
2663 EAPI void
2664 elm_gengrid_item_cursor_set(Elm_Gengrid_Item *it,
2665                             const char       *cursor)
2666 {
2667    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2668    eina_stringshare_replace(&it->mouse_cursor, cursor);
2669    if (it->base.view) elm_widget_item_cursor_set(it, cursor);
2670 }
2671
2672 EAPI const char *
2673 elm_gengrid_item_cursor_get(const Elm_Gengrid_Item *it)
2674 {
2675    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2676    return elm_widget_item_cursor_get(it);
2677 }
2678
2679 EAPI void
2680 elm_gengrid_item_cursor_unset(Elm_Gengrid_Item *it)
2681 {
2682    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2683    if (!it->mouse_cursor)
2684      return;
2685
2686    if (it->base.view)
2687      elm_widget_item_cursor_unset(it);
2688
2689    eina_stringshare_del(it->mouse_cursor);
2690    it->mouse_cursor = NULL;
2691 }
2692
2693 EAPI void
2694 elm_gengrid_item_cursor_style_set(Elm_Gengrid_Item *it,
2695                                   const char       *style)
2696 {
2697    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2698    elm_widget_item_cursor_style_set(it, style);
2699 }
2700
2701 EAPI const char *
2702 elm_gengrid_item_cursor_style_get(const Elm_Gengrid_Item *it)
2703 {
2704    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2705    return elm_widget_item_cursor_style_get(it);
2706 }
2707
2708 EAPI void
2709 elm_gengrid_item_cursor_engine_only_set(Elm_Gengrid_Item *it,
2710                                         Eina_Bool         engine_only)
2711 {
2712    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2713    elm_widget_item_cursor_engine_only_set(it, engine_only);
2714 }
2715
2716 EAPI Eina_Bool
2717 elm_gengrid_item_cursor_engine_only_get(const Elm_Gengrid_Item *it)
2718 {
2719    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
2720    return elm_widget_item_cursor_engine_only_get(it);
2721 }
2722
2723 EAPI void
2724 elm_gengrid_reorder_mode_set(Evas_Object *obj,
2725                              Eina_Bool    reorder_mode)
2726 {
2727    ELM_CHECK_WIDTYPE(obj, widtype);
2728    Widget_Data *wd = elm_widget_data_get(obj);
2729    if (!wd) return;
2730    wd->reorder_mode = reorder_mode;
2731 }
2732
2733 EAPI Eina_Bool
2734 elm_gengrid_reorder_mode_get(const Evas_Object *obj)
2735 {
2736    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2737    Widget_Data *wd = elm_widget_data_get(obj);
2738    if (!wd) return EINA_FALSE;
2739    return wd->reorder_mode;
2740 }
2741
2742 EAPI void
2743 elm_gengrid_always_select_mode_set(Evas_Object *obj,
2744                                    Eina_Bool    always_select)
2745 {
2746    ELM_CHECK_WIDTYPE(obj, widtype);
2747    Widget_Data *wd = elm_widget_data_get(obj);
2748    if (!wd) return;
2749    wd->always_select = always_select;
2750 }
2751
2752 EAPI Eina_Bool
2753 elm_gengrid_always_select_mode_get(const Evas_Object *obj)
2754 {
2755    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2756    Widget_Data *wd = elm_widget_data_get(obj);
2757    if (!wd) return EINA_FALSE;
2758    return wd->always_select;
2759 }
2760
2761 EAPI void
2762 elm_gengrid_no_select_mode_set(Evas_Object *obj,
2763                                Eina_Bool    no_select)
2764 {
2765    ELM_CHECK_WIDTYPE(obj, widtype);
2766    Widget_Data *wd = elm_widget_data_get(obj);
2767    if (!wd) return;
2768    wd->no_select = no_select;
2769 }
2770
2771 EAPI Eina_Bool
2772 elm_gengrid_no_select_mode_get(const Evas_Object *obj)
2773 {
2774    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
2775    Widget_Data *wd = elm_widget_data_get(obj);
2776    if (!wd) return EINA_FALSE;
2777    return wd->no_select;
2778 }
2779
2780 EAPI void
2781 elm_gengrid_bounce_set(Evas_Object *obj,
2782                        Eina_Bool    h_bounce,
2783                        Eina_Bool    v_bounce)
2784 {
2785    ELM_CHECK_WIDTYPE(obj, widtype);
2786    Widget_Data *wd = elm_widget_data_get(obj);
2787    if (!wd) return;
2788    elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
2789    wd->h_bounce = h_bounce;
2790    wd->v_bounce = v_bounce;
2791 }
2792
2793 EAPI void
2794 elm_gengrid_bounce_get(const Evas_Object *obj,
2795                        Eina_Bool         *h_bounce,
2796                        Eina_Bool         *v_bounce)
2797 {
2798    ELM_CHECK_WIDTYPE(obj, widtype);
2799    Widget_Data *wd = elm_widget_data_get(obj);
2800    if (!wd) return;
2801    if (h_bounce) *h_bounce = wd->h_bounce;
2802    if (v_bounce) *v_bounce = wd->v_bounce;
2803 }
2804
2805 EAPI void
2806 elm_gengrid_page_relative_set(Evas_Object *obj,
2807                               double       h_pagerel,
2808                               double       v_pagerel)
2809 {
2810    Evas_Coord pagesize_h;
2811    Evas_Coord pagesize_v;
2812
2813    ELM_CHECK_WIDTYPE(obj, widtype);
2814    Widget_Data *wd = elm_widget_data_get(obj);
2815    if (!wd) return;
2816
2817    elm_smart_scroller_paging_get(wd->scr, NULL, NULL, &pagesize_h, &pagesize_v);
2818    elm_smart_scroller_paging_set(wd->scr, h_pagerel, v_pagerel, pagesize_h,
2819                                  pagesize_v);
2820 }
2821
2822 EAPI void
2823 elm_gengrid_page_relative_get(const Evas_Object *obj, double *h_pagerel, double *v_pagerel)
2824 {
2825    ELM_CHECK_WIDTYPE(obj, widtype);
2826    Widget_Data *wd = elm_widget_data_get(obj);
2827    if (!wd) return;
2828
2829    elm_smart_scroller_paging_get(wd->scr, h_pagerel, v_pagerel, NULL, NULL);
2830 }
2831
2832 EAPI void
2833 elm_gengrid_page_size_set(Evas_Object *obj,
2834                           Evas_Coord   h_pagesize,
2835                           Evas_Coord   v_pagesize)
2836 {
2837    double pagerel_h;
2838    double pagerel_v;
2839
2840    ELM_CHECK_WIDTYPE(obj, widtype);
2841    Widget_Data *wd = elm_widget_data_get(obj);
2842    if (!wd) return;
2843    elm_smart_scroller_paging_get(wd->scr, &pagerel_h, &pagerel_v, NULL, NULL);
2844    elm_smart_scroller_paging_set(wd->scr, pagerel_h, pagerel_v, h_pagesize,
2845                                  v_pagesize);
2846 }
2847
2848 EAPI void
2849 elm_gengrid_current_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber)
2850 {
2851    ELM_CHECK_WIDTYPE(obj, widtype);
2852    Widget_Data *wd = elm_widget_data_get(obj);
2853    if (!wd) return;
2854    if (wd->scr)
2855      elm_smart_scroller_current_page_get(wd->scr, h_pagenumber, v_pagenumber);
2856 }
2857
2858 EAPI void
2859 elm_gengrid_last_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber)
2860 {
2861    ELM_CHECK_WIDTYPE(obj, widtype);
2862    Widget_Data *wd = elm_widget_data_get(obj);
2863    if (!wd) return;
2864    if (wd->scr)
2865      elm_smart_scroller_last_page_get(wd->scr, h_pagenumber, v_pagenumber);
2866 }
2867
2868 EAPI void
2869 elm_gengrid_page_show(const Evas_Object *obj, int h_pagenumber, int v_pagenumber)
2870 {
2871    ELM_CHECK_WIDTYPE(obj, widtype);
2872    Widget_Data *wd = elm_widget_data_get(obj);
2873    if (!wd) return;
2874    if (wd->scr)
2875      elm_smart_scroller_page_show(wd->scr, h_pagenumber, v_pagenumber);
2876 }
2877
2878 EAPI void
2879 elm_gengrid_page_bring_in(const Evas_Object *obj, int h_pagenumber, int v_pagenumber)
2880 {
2881    ELM_CHECK_WIDTYPE(obj, widtype);
2882    Widget_Data *wd = elm_widget_data_get(obj);
2883    if (!wd) return;
2884    if (wd->scr)
2885      elm_smart_scroller_page_bring_in(wd->scr, h_pagenumber, v_pagenumber);
2886 }
2887
2888 EAPI Elm_Gengrid_Item *
2889 elm_gengrid_first_item_get(const Evas_Object *obj)
2890 {
2891    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2892    Widget_Data *wd = elm_widget_data_get(obj);
2893    if (!wd) return NULL;
2894    if (!wd->items) return NULL;
2895    Elm_Gengrid_Item *it = ELM_GENGRID_ITEM_FROM_INLIST(wd->items);
2896    while ((it) && (it->delete_me))
2897      it = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
2898    return it;
2899 }
2900
2901 EAPI Elm_Gengrid_Item *
2902 elm_gengrid_last_item_get(const Evas_Object *obj)
2903 {
2904    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
2905    Widget_Data *wd = elm_widget_data_get(obj);
2906    if (!wd) return NULL;
2907    if (!wd->items) return NULL;
2908    Elm_Gengrid_Item *it = ELM_GENGRID_ITEM_FROM_INLIST(wd->items->last);
2909    while ((it) && (it->delete_me))
2910      it = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
2911    return it;
2912 }
2913
2914 EAPI Elm_Gengrid_Item *
2915 elm_gengrid_item_next_get(const Elm_Gengrid_Item *it)
2916 {
2917    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2918    while (it)
2919      {
2920         it = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
2921         if ((it) && (!it->delete_me)) break;
2922      }
2923    return (Elm_Gengrid_Item *)it;
2924 }
2925
2926 EAPI Elm_Gengrid_Item *
2927 elm_gengrid_item_prev_get(const Elm_Gengrid_Item *it)
2928 {
2929    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2930    while (it)
2931      {
2932         it = ELM_GENGRID_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
2933         if ((it) && (!it->delete_me)) break;
2934      }
2935    return (Elm_Gengrid_Item *)it;
2936 }
2937
2938 EAPI Evas_Object *
2939 elm_gengrid_item_gengrid_get(const Elm_Gengrid_Item *it)
2940 {
2941    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
2942    return it->base.widget;
2943 }
2944
2945 EAPI void
2946 elm_gengrid_item_show(Elm_Gengrid_Item *it)
2947 {
2948    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2949    Widget_Data *wd = elm_widget_data_get(it->wd->self);
2950    Evas_Coord minx = 0, miny = 0;
2951
2952    if (!wd) return;
2953    if ((!it) || (it->delete_me)) return;
2954    _pan_min_get(wd->pan_smart, &minx, &miny);
2955
2956    if (wd->horizontal)
2957      elm_smart_scroller_region_bring_in(it->wd->scr,
2958                                         ((it->x - it->prev_group) * wd->item_width) + (it->prev_group * it->wd->group_item_width) + minx,
2959                                         it->y * wd->item_height + miny,
2960                                         it->wd->item_width,
2961                                         it->wd->item_height);
2962    else
2963      elm_smart_scroller_region_bring_in(it->wd->scr,
2964                                         it->x * wd->item_width + minx,
2965                                         ((it->y - it->prev_group)* wd->item_height) + (it->prev_group * it->wd->group_item_height) + miny,
2966                                         it->wd->item_width,
2967                                         it->wd->item_height);
2968 }
2969
2970 EAPI void
2971 elm_gengrid_item_bring_in(Elm_Gengrid_Item *it)
2972 {
2973    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
2974    if (it->delete_me) return;
2975
2976    Evas_Coord minx = 0, miny = 0;
2977    Widget_Data *wd = elm_widget_data_get(it->wd->self);
2978    if (!wd) return;
2979    _pan_min_get(wd->pan_smart, &minx, &miny);
2980
2981    if (wd->horizontal)
2982      elm_smart_scroller_region_bring_in(it->wd->scr,
2983                                         ((it->x - it->prev_group) * wd->item_width) + (it->prev_group * it->wd->group_item_width) + minx,
2984                                         it->y * wd->item_height + miny,
2985                                         it->wd->item_width,
2986                                         it->wd->item_height);
2987    else
2988      elm_smart_scroller_region_bring_in(it->wd->scr,
2989                                         it->x * wd->item_width + minx,
2990                                         ((it->y - it->prev_group)* wd->item_height) + (it->prev_group * it->wd->group_item_height) + miny,
2991                                         it->wd->item_width,
2992                                         it->wd->item_height);
2993 }