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