elm genlist: Added "scroll,anim,start", "scroll,anim,stop",
[framework/uifw/elementary.git] / src / lib / elm_genlist.c
1 #include <assert.h>
2
3 #include <Elementary.h>
4 #include <Elementary_Cursor.h>
5 #include "elm_priv.h"
6
7 #define SWIPE_MOVES         12
8 #define MAX_ITEMS_PER_BLOCK 32
9 #define REORDER_EFFECT_TIME 0.5
10
11 typedef struct _Widget_Data Widget_Data;
12 typedef struct _Item_Block  Item_Block;
13 typedef struct _Pan         Pan;
14 typedef struct _Item_Cache  Item_Cache;
15
16 struct _Widget_Data
17 {
18    Evas_Object      *obj, *scr, *pan_smart;
19    Eina_Inlist      *items, *blocks;
20    Eina_List        *group_items;
21    Pan              *pan;
22    Evas_Coord        pan_x, pan_y, old_pan_y, w, h, minw, minh, realminw, prev_viewport_w;
23    Ecore_Job        *calc_job, *update_job;
24    Ecore_Idle_Enterer *queue_idle_enterer;
25    Ecore_Idler        *must_recalc_idler;
26    Eina_List        *queue, *selected;
27    Elm_Genlist_Item *show_item, *last_selected_item, *anchor_item, *mode_item, *reorder_it, *reorder_rel, *expanded_item;
28    Eina_Inlist      *item_cache;
29    Evas_Coord        anchor_y, reorder_start_y;
30    Elm_List_Mode     mode;
31    Ecore_Timer      *multi_timer, *scr_hold_timer;
32    Ecore_Animator   *reorder_move_animator;
33    const char       *mode_type;
34    unsigned int      start_time;
35    Evas_Coord        prev_x, prev_y, prev_mx, prev_my;
36    Evas_Coord        cur_x, cur_y, cur_mx, cur_my;
37    Eina_Bool         mouse_down : 1;
38    Eina_Bool         multi_down : 1;
39    Eina_Bool         multi_timeout : 1;
40    Eina_Bool         multitouched : 1;
41    Eina_Bool         on_hold : 1;
42    Eina_Bool         multi : 1;
43    Eina_Bool         always_select : 1;
44    Eina_Bool         longpressed : 1;
45    Eina_Bool         wasselected : 1;
46    Eina_Bool         no_select : 1;
47    Eina_Bool         bring_in : 1;
48    Eina_Bool         compress : 1;
49    Eina_Bool         height_for_width : 1;
50    Eina_Bool         homogeneous : 1;
51    Eina_Bool         clear_me : 1;
52    Eina_Bool         swipe : 1;
53    Eina_Bool         reorder_mode : 1;
54    Eina_Bool         reorder_pan_move : 1;
55    Eina_Bool         auto_scroll_enabled : 1;
56    struct
57    {
58       Evas_Coord x, y;
59    } history[SWIPE_MOVES];
60    int               multi_device;
61    int               item_cache_count;
62    int               item_cache_max;
63    int               movements;
64    int               walking;
65    int               item_width;
66    int               item_height;
67    int               group_item_width;
68    int               group_item_height;
69    int               max_items_per_block;
70    double            longpress_timeout;
71 };
72
73 struct _Item_Block
74 {
75    EINA_INLIST;
76    int          count;
77    int          num;
78    int          reorder_offset;
79    Widget_Data *wd;
80    Eina_List   *items;
81    Evas_Coord   x, y, w, h, minw, minh;
82    Eina_Bool    want_unrealize : 1;
83    Eina_Bool    realized : 1;
84    Eina_Bool    changed : 1;
85    Eina_Bool    updateme : 1;
86    Eina_Bool    showme : 1;
87    Eina_Bool    must_recalc : 1;
88 };
89
90 struct _Elm_Genlist_Item
91 {
92    Elm_Widget_Item               base;
93    EINA_INLIST;
94    Widget_Data                  *wd;
95    Item_Block                   *block;
96    Eina_List                    *items;
97    Evas_Coord                    x, y, w, h, minw, minh;
98    const Elm_Genlist_Item_Class *itc;
99    Elm_Genlist_Item             *parent;
100    Elm_Genlist_Item             *group_item;
101    Elm_Genlist_Item_Flags        flags;
102    struct
103    {
104       Evas_Smart_Cb func;
105       const void   *data;
106    } func;
107
108    Evas_Object                  *spacer;
109    Eina_List                    *labels, *icons, *states, *icon_objs;
110    Eina_List                    *mode_labels, *mode_icons, *mode_states, *mode_icon_objs;
111    Ecore_Timer                  *long_timer;
112    Ecore_Timer                  *swipe_timer;
113    Evas_Coord                    dx, dy;
114    Evas_Coord                    scrl_x, scrl_y, old_scrl_y;
115
116    Elm_Genlist_Item             *rel;
117    Evas_Object                  *mode_view;
118
119    struct
120    {
121       const void                 *data;
122       Elm_Tooltip_Item_Content_Cb content_cb;
123       Evas_Smart_Cb               del_cb;
124       const char                 *style;
125       Eina_Bool                   free_size : 1;
126    } tooltip;
127
128    const char                   *mouse_cursor;
129
130    int                           relcount;
131    int                           walking;
132    int                           expanded_depth;
133    int                           order_num_in;
134
135    Eina_Bool                     before : 1;
136
137    Eina_Bool                     want_unrealize : 1;
138    Eina_Bool                     want_realize : 1;
139    Eina_Bool                     realized : 1;
140    Eina_Bool                     selected : 1;
141    Eina_Bool                     highlighted : 1;
142    Eina_Bool                     expanded : 1;
143    Eina_Bool                     disabled : 1;
144    Eina_Bool                     display_only : 1;
145    Eina_Bool                     mincalcd : 1;
146    Eina_Bool                     queued : 1;
147    Eina_Bool                     showme : 1;
148    Eina_Bool                     delete_me : 1;
149    Eina_Bool                     down : 1;
150    Eina_Bool                     dragging : 1;
151    Eina_Bool                     updateme : 1;
152    Eina_Bool                     nocache : 1;
153    Eina_Bool                     stacking_even : 1;
154    Eina_Bool                     nostacking : 1;
155    Eina_Bool                     move_effect_enabled : 1;
156 };
157
158 struct _Item_Cache
159 {
160    EINA_INLIST;
161
162    Evas_Object *base_view, *spacer;
163
164    const char  *item_style; // it->itc->item_style
165    Eina_Bool    tree : 1; // it->flags & ELM_GENLIST_ITEM_SUBITEMS
166    Eina_Bool    compress : 1; // it->wd->compress
167
168    Eina_Bool    selected : 1; // it->selected
169    Eina_Bool    disabled : 1; // it->disabled
170    Eina_Bool    expanded : 1; // it->expanded
171 };
172
173 #define ELM_GENLIST_ITEM_FROM_INLIST(item) \
174   ((item) ? EINA_INLIST_CONTAINER_GET(item, Elm_Genlist_Item) : NULL)
175
176 struct _Pan
177 {
178    Evas_Object_Smart_Clipped_Data __clipped_data;
179    Widget_Data                   *wd;
180    Ecore_Job                     *resize_job;
181 };
182
183 static const char *widtype = NULL;
184 static void      _item_cache_zero(Widget_Data *wd);
185 static void      _del_hook(Evas_Object *obj);
186 static void      _mirrored_set(Evas_Object *obj,
187                                Eina_Bool    rtl);
188 static void      _theme_hook(Evas_Object *obj);
189 static void      _show_region_hook(void        *data,
190                                    Evas_Object *obj);
191 static void      _sizing_eval(Evas_Object *obj);
192 static void      _item_realize(Elm_Genlist_Item *it,
193                                int               in,
194                                Eina_Bool         calc);
195 static void      _item_unrealize(Elm_Genlist_Item *it,
196                                  Eina_Bool         calc);
197 static void      _item_block_unrealize(Item_Block *itb);
198 static void      _calc_job(void *data);
199 static void      _on_focus_hook(void        *data,
200                                 Evas_Object *obj);
201 static Eina_Bool _item_multi_select_up(Widget_Data *wd);
202 static Eina_Bool _item_multi_select_down(Widget_Data *wd);
203 static Eina_Bool _item_single_select_up(Widget_Data *wd);
204 static Eina_Bool _item_single_select_down(Widget_Data *wd);
205 static Eina_Bool _event_hook(Evas_Object       *obj,
206                              Evas_Object       *src,
207                              Evas_Callback_Type type,
208                              void              *event_info);
209 static void      _signal_emit_hook(Evas_Object *obj,
210                                    const char *emission,
211                                    const char *source);
212 static Eina_Bool _deselect_all_items(Widget_Data *wd);
213 static void      _pan_calculate(Evas_Object *obj);
214 static void      _item_position(Elm_Genlist_Item *it,
215                                 Evas_Object      *obj,
216                                 Evas_Coord        it_x,
217                                 Evas_Coord        it_y);
218 static void      _mode_item_realize(Elm_Genlist_Item *it);
219 static void      _mode_item_unrealize(Elm_Genlist_Item *it);
220 static void      _item_mode_set(Elm_Genlist_Item *it);
221 static void      _item_mode_unset(Widget_Data *wd);
222 static void      _group_items_recalc(void *data);
223 static void      _item_move_after(Elm_Genlist_Item *it,
224                                   Elm_Genlist_Item *after);
225 static void      _item_move_before(Elm_Genlist_Item *it,
226                                    Elm_Genlist_Item *before);
227 static void      _item_auto_scroll(Widget_Data *wd);
228
229 static Evas_Smart_Class _pan_sc = EVAS_SMART_CLASS_INIT_VERSION;
230
231 static const char SIG_ACTIVATED[] = "activated";
232 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
233 static const char SIG_SELECTED[] = "selected";
234 static const char SIG_UNSELECTED[] = "unselected";
235 static const char SIG_EXPANDED[] = "expanded";
236 static const char SIG_CONTRACTED[] = "contracted";
237 static const char SIG_EXPAND_REQUEST[] = "expand,request";
238 static const char SIG_CONTRACT_REQUEST[] = "contract,request";
239 static const char SIG_REALIZED[] = "realized";
240 static const char SIG_UNREALIZED[] = "unrealized";
241 static const char SIG_DRAG_START_UP[] = "drag,start,up";
242 static const char SIG_DRAG_START_DOWN[] = "drag,start,down";
243 static const char SIG_DRAG_START_LEFT[] = "drag,start,left";
244 static const char SIG_DRAG_START_RIGHT[] = "drag,start,right";
245 static const char SIG_DRAG_STOP[] = "drag,stop";
246 static const char SIG_DRAG[] = "drag";
247 static const char SIG_LONGPRESSED[] = "longpressed";
248 static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start";
249 static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop";
250 static const char SIG_SCROLL_DRAG_START[] = "scroll,drag,start";
251 static const char SIG_SCROLL_DRAG_STOP[] = "scroll,drag,stop";
252 static const char SIG_SCROLL_EDGE_TOP[] = "scroll,edge,top";
253 static const char SIG_SCROLL_EDGE_BOTTOM[] = "scroll,edge,bottom";
254 static const char SIG_SCROLL_EDGE_LEFT[] = "scroll,edge,left";
255 static const char SIG_SCROLL_EDGE_RIGHT[] = "scroll,edge,right";
256 static const char SIG_MULTI_SWIPE_LEFT[] = "multi,swipe,left";
257 static const char SIG_MULTI_SWIPE_RIGHT[] = "multi,swipe,right";
258 static const char SIG_MULTI_SWIPE_UP[] = "multi,swipe,up";
259 static const char SIG_MULTI_SWIPE_DOWN[] = "multi,swipe,down";
260 static const char SIG_MULTI_PINCH_OUT[] = "multi,pinch,out";
261 static const char SIG_MULTI_PINCH_IN[] = "multi,pinch,in";
262 static const char SIG_SWIPE[] = "swipe";
263
264 static const Evas_Smart_Cb_Description _signals[] = {
265    {SIG_CLICKED_DOUBLE, ""},
266    {SIG_ACTIVATED, ""},
267    {SIG_SELECTED, ""},
268    {SIG_UNSELECTED, ""},
269    {SIG_EXPANDED, ""},
270    {SIG_CONTRACTED, ""},
271    {SIG_EXPAND_REQUEST, ""},
272    {SIG_CONTRACT_REQUEST, ""},
273    {SIG_REALIZED, ""},
274    {SIG_UNREALIZED, ""},
275    {SIG_DRAG_START_UP, ""},
276    {SIG_DRAG_START_DOWN, ""},
277    {SIG_DRAG_START_LEFT, ""},
278    {SIG_DRAG_START_RIGHT, ""},
279    {SIG_DRAG_STOP, ""},
280    {SIG_DRAG, ""},
281    {SIG_LONGPRESSED, ""},
282    {SIG_SCROLL_ANIM_START, ""},
283    {SIG_SCROLL_ANIM_STOP, ""},
284    {SIG_SCROLL_DRAG_START, ""},
285    {SIG_SCROLL_DRAG_STOP, ""},
286    {SIG_SCROLL_EDGE_TOP, ""},
287    {SIG_SCROLL_EDGE_BOTTOM, ""},
288    {SIG_SCROLL_EDGE_LEFT, ""},
289    {SIG_SCROLL_EDGE_RIGHT, ""},
290    {SIG_MULTI_SWIPE_LEFT, ""},
291    {SIG_MULTI_SWIPE_RIGHT, ""},
292    {SIG_MULTI_SWIPE_UP, ""},
293    {SIG_MULTI_SWIPE_DOWN, ""},
294    {SIG_MULTI_PINCH_OUT, ""},
295    {SIG_MULTI_PINCH_IN, ""},
296    {SIG_SWIPE, ""},
297    {NULL, NULL}
298 };
299
300 static Eina_Compare_Cb _elm_genlist_item_compare_cb;
301 static Eina_Compare_Cb _elm_genlist_item_compare_data_cb;
302
303 static Eina_Bool
304 _event_hook(Evas_Object       *obj,
305             Evas_Object       *src __UNUSED__,
306             Evas_Callback_Type type,
307             void              *event_info)
308 {
309    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
310    Evas_Event_Key_Down *ev = event_info;
311    Widget_Data *wd = elm_widget_data_get(obj);
312    if (!wd) return EINA_FALSE;
313    if (!wd->items) return EINA_FALSE;
314    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
315    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
316
317    Elm_Genlist_Item *it = NULL;
318    Evas_Coord x = 0;
319    Evas_Coord y = 0;
320    Evas_Coord step_x = 0;
321    Evas_Coord step_y = 0;
322    Evas_Coord v_w = 0;
323    Evas_Coord v_h = 0;
324    Evas_Coord page_x = 0;
325    Evas_Coord page_y = 0;
326
327    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
328    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
329    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
330    elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
331
332    if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
333      {
334         x -= step_x;
335      }
336    else if ((!strcmp(ev->keyname, "Right")) ||
337             (!strcmp(ev->keyname, "KP_Right")))
338      {
339         x += step_x;
340      }
341    else if ((!strcmp(ev->keyname, "Up")) || (!strcmp(ev->keyname, "KP_Up")))
342      {
343         if (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
344              (_item_multi_select_up(wd)))
345             || (_item_single_select_up(wd)))
346           {
347              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
348              return EINA_TRUE;
349           }
350         else
351           y -= step_y;
352      }
353    else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
354      {
355         if (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
356              (_item_multi_select_down(wd)))
357             || (_item_single_select_down(wd)))
358           {
359              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
360              return EINA_TRUE;
361           }
362         else
363           y += step_y;
364      }
365    else if ((!strcmp(ev->keyname, "Home")) ||
366             (!strcmp(ev->keyname, "KP_Home")))
367      {
368         it = elm_genlist_first_item_get(obj);
369         elm_genlist_item_bring_in(it);
370         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
371         return EINA_TRUE;
372      }
373    else if ((!strcmp(ev->keyname, "End")) ||
374             (!strcmp(ev->keyname, "KP_End")))
375      {
376         it = elm_genlist_last_item_get(obj);
377         elm_genlist_item_bring_in(it);
378         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
379         return EINA_TRUE;
380      }
381    else if ((!strcmp(ev->keyname, "Prior")) ||
382             (!strcmp(ev->keyname, "KP_Prior")))
383      {
384         if (page_y < 0)
385           y -= -(page_y * v_h) / 100;
386         else
387           y -= page_y;
388      }
389    else if ((!strcmp(ev->keyname, "Next")) ||
390             (!strcmp(ev->keyname, "KP_Next")))
391      {
392         if (page_y < 0)
393           y += -(page_y * v_h) / 100;
394         else
395           y += page_y;
396      }
397    else if (((!strcmp(ev->keyname, "Return")) ||
398             (!strcmp(ev->keyname, "KP_Enter")) ||
399             (!strcmp(ev->keyname, "space")))
400            && (!wd->multi) && (wd->selected))
401      {
402         it = elm_genlist_selected_item_get(obj);
403         elm_genlist_item_expanded_set(it,
404                                       !elm_genlist_item_expanded_get(it));
405         evas_object_smart_callback_call(it->base.widget, SIG_ACTIVATED, it);
406      }
407    else if (!strcmp(ev->keyname, "Escape"))
408      {
409         if (!_deselect_all_items(wd)) return EINA_FALSE;
410         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
411         return EINA_TRUE;
412      }
413    else return EINA_FALSE;
414
415    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
416    elm_smart_scroller_child_pos_set(wd->scr, x, y);
417    return EINA_TRUE;
418 }
419
420 static Eina_Bool
421 _deselect_all_items(Widget_Data *wd)
422 {
423    if (!wd->selected) return EINA_FALSE;
424    while (wd->selected)
425      elm_genlist_item_selected_set(wd->selected->data, EINA_FALSE);
426
427    return EINA_TRUE;
428 }
429
430 static Eina_Bool
431 _item_multi_select_up(Widget_Data *wd)
432 {
433    if (!wd->selected) return EINA_FALSE;
434    if (!wd->multi) return EINA_FALSE;
435
436    Elm_Genlist_Item *prev = elm_genlist_item_prev_get(wd->last_selected_item);
437    if (!prev) return EINA_TRUE;
438
439    if (elm_genlist_item_selected_get(prev))
440      {
441         elm_genlist_item_selected_set(wd->last_selected_item, EINA_FALSE);
442         wd->last_selected_item = prev;
443         elm_genlist_item_show(wd->last_selected_item);
444      }
445    else
446      {
447         elm_genlist_item_selected_set(prev, EINA_TRUE);
448         elm_genlist_item_show(prev);
449      }
450    return EINA_TRUE;
451 }
452
453 static Eina_Bool
454 _item_multi_select_down(Widget_Data *wd)
455 {
456    if (!wd->selected) return EINA_FALSE;
457    if (!wd->multi) return EINA_FALSE;
458
459    Elm_Genlist_Item *next = elm_genlist_item_next_get(wd->last_selected_item);
460    if (!next) return EINA_TRUE;
461
462    if (elm_genlist_item_selected_get(next))
463      {
464         elm_genlist_item_selected_set(wd->last_selected_item, EINA_FALSE);
465         wd->last_selected_item = next;
466         elm_genlist_item_show(wd->last_selected_item);
467      }
468    else
469      {
470         elm_genlist_item_selected_set(next, EINA_TRUE);
471         elm_genlist_item_show(next);
472      }
473    return EINA_TRUE;
474 }
475
476 static Eina_Bool
477 _item_single_select_up(Widget_Data *wd)
478 {
479    Elm_Genlist_Item *prev;
480    if (!wd->selected)
481      {
482         prev = ELM_GENLIST_ITEM_FROM_INLIST(wd->items->last);
483         while ((prev) && (prev->delete_me))
484           prev = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(prev)->prev);
485      }
486    else prev = elm_genlist_item_prev_get(wd->last_selected_item);
487
488    if (!prev) return EINA_FALSE;
489
490    _deselect_all_items(wd);
491
492    elm_genlist_item_selected_set(prev, EINA_TRUE);
493    elm_genlist_item_show(prev);
494    return EINA_TRUE;
495 }
496
497 static Eina_Bool
498 _item_single_select_down(Widget_Data *wd)
499 {
500    Elm_Genlist_Item *next;
501    if (!wd->selected)
502      {
503         next = ELM_GENLIST_ITEM_FROM_INLIST(wd->items);
504         while ((next) && (next->delete_me))
505           next = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(next)->next);
506      }
507    else next = elm_genlist_item_next_get(wd->last_selected_item);
508
509    if (!next) return EINA_FALSE;
510
511    _deselect_all_items(wd);
512
513    elm_genlist_item_selected_set(next, EINA_TRUE);
514    elm_genlist_item_show(next);
515    return EINA_TRUE;
516 }
517
518 static void
519 _on_focus_hook(void        *data __UNUSED__,
520                Evas_Object *obj)
521 {
522    Widget_Data *wd = elm_widget_data_get(obj);
523    if (!wd) return;
524    if (elm_widget_focus_get(obj))
525      {
526         elm_object_signal_emit(wd->obj, "elm,action,focus", "elm");
527         evas_object_focus_set(wd->obj, EINA_TRUE);
528         if ((wd->selected) && (!wd->last_selected_item))
529           wd->last_selected_item = eina_list_data_get(wd->selected);
530      }
531    else
532      {
533         elm_object_signal_emit(wd->obj, "elm,action,unfocus", "elm");
534         evas_object_focus_set(wd->obj, EINA_FALSE);
535      }
536 }
537
538 static void
539 _del_hook(Evas_Object *obj)
540 {
541    Widget_Data *wd = elm_widget_data_get(obj);
542    if (!wd) return;
543    _item_cache_zero(wd);
544    if (wd->calc_job) ecore_job_del(wd->calc_job);
545    if (wd->update_job) ecore_job_del(wd->update_job);
546    if (wd->queue_idle_enterer) ecore_idle_enterer_del(wd->queue_idle_enterer);
547    if (wd->must_recalc_idler) ecore_idler_del(wd->must_recalc_idler);
548    if (wd->multi_timer) ecore_timer_del(wd->multi_timer);
549    if (wd->mode_type) eina_stringshare_del(wd->mode_type);
550    if (wd->scr_hold_timer) ecore_timer_del(wd->scr_hold_timer);
551    free(wd);
552 }
553
554 static void
555 _del_pre_hook(Evas_Object *obj)
556 {
557    Widget_Data *wd = elm_widget_data_get(obj);
558    if (!wd) return;
559    evas_object_del(wd->pan_smart);
560    wd->pan_smart = NULL;
561    elm_genlist_clear(obj);
562 }
563
564 static void
565 _mirrored_set(Evas_Object *obj,
566               Eina_Bool    rtl)
567 {
568    Widget_Data *wd = elm_widget_data_get(obj);
569    if (!wd) return;
570    _item_cache_zero(wd);
571    elm_smart_scroller_mirrored_set(wd->scr, rtl);
572 }
573
574 static void
575 _theme_hook(Evas_Object *obj)
576 {
577    Widget_Data *wd = elm_widget_data_get(obj);
578    Item_Block *itb;
579    if (!wd) return;
580    evas_event_freeze(evas_object_evas_get(wd->obj));
581    _item_cache_zero(wd);
582    _elm_widget_mirrored_reload(obj);
583    _mirrored_set(obj, elm_widget_mirrored_get(obj));
584    elm_smart_scroller_object_theme_set(obj, wd->scr, "genlist", "base",
585                                        elm_widget_style_get(obj));
586    edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
587    wd->item_width = wd->item_height = 0;
588    wd->group_item_width = wd->group_item_height = 0;
589    wd->minw = wd->minh = wd->realminw = 0;
590    EINA_INLIST_FOREACH(wd->blocks, itb)
591      {
592         Eina_List *l;
593         Elm_Genlist_Item *it;
594
595         if (itb->realized) _item_block_unrealize(itb);
596         EINA_LIST_FOREACH(itb->items, l, it)
597           it->mincalcd = EINA_FALSE;
598
599         itb->changed = EINA_TRUE;
600      }
601    if (wd->calc_job) ecore_job_del(wd->calc_job);
602    wd->calc_job = ecore_job_add(_calc_job, wd);
603    _sizing_eval(obj);
604    evas_event_thaw(evas_object_evas_get(wd->obj));
605    evas_event_thaw_eval(evas_object_evas_get(wd->obj));
606 }
607
608 static void
609 _show_region_hook(void        *data,
610                   Evas_Object *obj)
611 {
612    Widget_Data *wd = elm_widget_data_get(data);
613    Evas_Coord x, y, w, h;
614    if (!wd) return;
615    elm_widget_show_region_get(obj, &x, &y, &w, &h);
616    //x & y are screen coordinates, Add with pan coordinates
617    x += wd->pan_x;
618    y += wd->pan_y;
619    elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
620 }
621
622 static void
623 _sizing_eval(Evas_Object *obj)
624 {
625    Widget_Data *wd = elm_widget_data_get(obj);
626    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
627    if (!wd) return;
628    evas_object_size_hint_min_get(wd->scr, &minw, &minh);
629    evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
630    minh = -1;
631    if (wd->height_for_width)
632      {
633         Evas_Coord vw, vh;
634
635         elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
636         if ((vw != 0) && (vw != wd->prev_viewport_w))
637           {
638              Item_Block *itb;
639
640              wd->prev_viewport_w = vw;
641              EINA_INLIST_FOREACH(wd->blocks, itb)
642                {
643                   itb->must_recalc = EINA_TRUE;
644                }
645              if (wd->calc_job) ecore_job_del(wd->calc_job);
646              wd->calc_job = ecore_job_add(_calc_job, wd);
647           }
648      }
649    if (wd->mode == ELM_LIST_LIMIT)
650      {
651         Evas_Coord vmw, vmh, vw, vh;
652
653         minw = wd->realminw;
654         maxw = -1;
655         elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
656         if ((minw > 0) && (vw < minw)) vw = minw;
657         else if ((maxw > 0) && (vw > maxw))
658           vw = maxw;
659         edje_object_size_min_calc
660           (elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh);
661         minw = vmw + minw;
662      }
663    else
664      {
665         Evas_Coord vmw, vmh;
666
667         edje_object_size_min_calc
668           (elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh);
669         minw = vmw;
670         minh = vmh;
671      }
672    evas_object_size_hint_min_set(obj, minw, minh);
673    evas_object_size_hint_max_set(obj, maxw, maxh);
674 }
675
676 static void
677 _signal_emit_hook(Evas_Object *obj,
678                   const char  *emission,
679                   const char  *source)
680 {
681    Widget_Data *wd = elm_widget_data_get(obj);
682    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
683                            emission, source);
684 }
685
686 static void
687 _item_highlight(Elm_Genlist_Item *it)
688 {
689    const char *selectraise;
690    if ((it->wd->no_select) || (it->delete_me) || (it->highlighted) ||
691        (it->disabled) || (it->display_only) || (it->mode_view))
692      return;
693    edje_object_signal_emit(it->base.view, "elm,state,selected", "elm");
694    selectraise = edje_object_data_get(it->base.view, "selectraise");
695    if ((selectraise) && (!strcmp(selectraise, "on")))
696      {
697         evas_object_raise(it->base.view);
698         if ((it->group_item) && (it->group_item->realized))
699           evas_object_raise(it->group_item->base.view);
700      }
701    it->highlighted = EINA_TRUE;
702 }
703
704 static void
705 _item_unhighlight(Elm_Genlist_Item *it)
706 {
707    const char *stacking, *selectraise;
708    if ((it->delete_me) || (!it->highlighted)) return;
709    edje_object_signal_emit(it->base.view, "elm,state,unselected", "elm");
710    stacking = edje_object_data_get(it->base.view, "stacking");
711    selectraise = edje_object_data_get(it->base.view, "selectraise");
712    if (!it->nostacking)
713      {
714        if ((it->order_num_in & 0x1) ^ it->stacking_even) evas_object_lower(it->base.view);
715        else evas_object_raise(it->base.view);
716      }
717    it->highlighted = EINA_FALSE;
718 }
719
720 static void
721 _item_block_del(Elm_Genlist_Item *it)
722 {
723    Eina_Inlist *il;
724    Item_Block *itb = it->block;
725
726    itb->items = eina_list_remove(itb->items, it);
727    itb->count--;
728    itb->changed = EINA_TRUE;
729    if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
730    it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
731    if (itb->count < 1)
732      {
733         il = EINA_INLIST_GET(itb);
734         Item_Block *itbn = (Item_Block *)(il->next);
735         if (it->parent)
736           it->parent->items = eina_list_remove(it->parent->items, it);
737         else
738           it->wd->blocks = eina_inlist_remove(it->wd->blocks, il);
739         free(itb);
740         if (itbn) itbn->changed = EINA_TRUE;
741      }
742    else
743      {
744         if (itb->count < itb->wd->max_items_per_block/2)
745           {
746              il = EINA_INLIST_GET(itb);
747              Item_Block *itbp = (Item_Block *)(il->prev);
748              Item_Block *itbn = (Item_Block *)(il->next);
749              if ((itbp) && ((itbp->count + itb->count) < itb->wd->max_items_per_block + itb->wd->max_items_per_block/2))
750                {
751                   Elm_Genlist_Item *it2;
752
753                   EINA_LIST_FREE(itb->items, it2)
754                     {
755                        it2->block = itbp;
756                        itbp->items = eina_list_append(itbp->items, it2);
757                        itbp->count++;
758                        itbp->changed = EINA_TRUE;
759                     }
760                   it->wd->blocks = eina_inlist_remove(it->wd->blocks,
761                                                       EINA_INLIST_GET(itb));
762                   free(itb);
763                }
764              else if ((itbn) && ((itbn->count + itb->count) < itb->wd->max_items_per_block + itb->wd->max_items_per_block/2))
765                {
766                   while (itb->items)
767                     {
768                        Eina_List *last = eina_list_last(itb->items);
769                        Elm_Genlist_Item *it2 = last->data;
770
771                        it2->block = itbn;
772                        itb->items = eina_list_remove_list(itb->items, last);
773                        itbn->items = eina_list_prepend(itbn->items, it2);
774                        itbn->count++;
775                        itbn->changed = EINA_TRUE;
776                     }
777                   it->wd->blocks =
778                     eina_inlist_remove(it->wd->blocks, EINA_INLIST_GET(itb));
779                   free(itb);
780                }
781           }
782      }
783 }
784
785 static void
786 _item_del(Elm_Genlist_Item *it)
787 {
788    Evas_Object *tob = it->wd->obj;
789
790    evas_event_freeze(evas_object_evas_get(tob));
791    elm_widget_item_pre_notify_del(it);
792    elm_genlist_item_subitems_clear(it);
793    it->wd->walking -= it->walking;
794    if (it->wd->show_item == it) it->wd->show_item = NULL;
795    if (it->selected) it->wd->selected = eina_list_remove(it->wd->selected, it);
796    if (it->realized) _item_unrealize(it, EINA_FALSE);
797    if (it->block) _item_block_del(it);
798    if ((!it->delete_me) && (it->itc->func.del))
799      it->itc->func.del((void *)it->base.data, it->base.widget);
800    it->delete_me = EINA_TRUE;
801    if (it->queued)
802      it->wd->queue = eina_list_remove(it->wd->queue, it);
803    if (it->wd->anchor_item == it)
804      {
805         it->wd->anchor_item = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
806         if (!it->wd->anchor_item)
807           it->wd->anchor_item = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
808      }
809    it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
810    if (it->parent)
811      it->parent->items = eina_list_remove(it->parent->items, it);
812    if (it->flags & ELM_GENLIST_ITEM_GROUP)
813      it->wd->group_items = eina_list_remove(it->wd->group_items, it);
814    if (it->long_timer) ecore_timer_del(it->long_timer);
815    if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
816
817    if (it->tooltip.del_cb)
818      it->tooltip.del_cb((void *)it->tooltip.data, it->base.widget, it);
819
820    evas_event_thaw(evas_object_evas_get(tob));
821    evas_event_thaw_eval(evas_object_evas_get(tob));
822
823    elm_widget_item_del(it);
824 }
825
826 static void
827 _item_select(Elm_Genlist_Item *it)
828 {
829    if ((it->wd->no_select) || (it->delete_me) || (it->mode_view)) return;
830    if (it->selected)
831      {
832         if (it->wd->always_select) goto call;
833         return;
834      }
835    it->selected = EINA_TRUE;
836    it->wd->selected = eina_list_append(it->wd->selected, it);
837 call:
838    evas_object_ref(it->base.widget);
839    it->walking++;
840    it->wd->walking++;
841    if (it->func.func) it->func.func((void *)it->func.data, it->base.widget, it);
842    if (!it->delete_me)
843      evas_object_smart_callback_call(it->base.widget, SIG_SELECTED, it);
844    it->walking--;
845    it->wd->walking--;
846    if ((it->wd->clear_me) && (!it->wd->walking))
847      elm_genlist_clear(it->base.widget);
848    else
849      {
850         if ((!it->walking) && (it->delete_me))
851           {
852              if (!it->relcount) _item_del(it);
853           }
854      }
855    it->wd->last_selected_item = it;
856    evas_object_unref(it->base.widget);
857 }
858
859 static void
860 _item_unselect(Elm_Genlist_Item *it)
861 {
862    if ((it->delete_me) || (!it->selected)) return;
863    it->selected = EINA_FALSE;
864    it->wd->selected = eina_list_remove(it->wd->selected, it);
865    evas_object_smart_callback_call(it->base.widget, SIG_UNSELECTED, it);
866 }
867
868 static void
869 _mouse_move(void        *data,
870             Evas        *evas __UNUSED__,
871             Evas_Object *obj,
872             void        *event_info)
873 {
874    Elm_Genlist_Item *it = data;
875    Evas_Event_Mouse_Move *ev = event_info;
876    Evas_Coord minw = 0, minh = 0, x, y, dx, dy, adx, ady;
877    Evas_Coord ox, oy, ow, oh, it_scrl_y, y_pos;
878
879    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
880      {
881         if (!it->wd->on_hold)
882           {
883              it->wd->on_hold = EINA_TRUE;
884              if (!it->wd->wasselected)
885                {
886                   _item_unhighlight(it);
887                   _item_unselect(it);
888                }
889           }
890      }
891    if (it->wd->multitouched)
892      {
893         it->wd->cur_x = ev->cur.canvas.x;
894         it->wd->cur_y = ev->cur.canvas.y;
895         return;
896      }
897    if ((it->dragging) && (it->down))
898      {
899         if (it->wd->movements == SWIPE_MOVES) it->wd->swipe = EINA_TRUE;
900         else
901           {
902              it->wd->history[it->wd->movements].x = ev->cur.canvas.x;
903              it->wd->history[it->wd->movements].y = ev->cur.canvas.y;
904              if (abs((it->wd->history[it->wd->movements].x -
905                       it->wd->history[0].x)) > 40)
906                it->wd->swipe = EINA_TRUE;
907              else
908                it->wd->movements++;
909           }
910         if (it->long_timer)
911           {
912              ecore_timer_del(it->long_timer);
913              it->long_timer = NULL;
914           }
915         evas_object_smart_callback_call(it->base.widget, SIG_DRAG, it);
916         return;
917      }
918    if ((!it->down) /* || (it->wd->on_hold)*/ || (it->wd->longpressed))
919      {
920         if (it->long_timer)
921           {
922              ecore_timer_del(it->long_timer);
923              it->long_timer = NULL;
924           }
925         if ((it->wd->reorder_mode) && (it->wd->reorder_it))
926           {
927              evas_object_geometry_get(it->wd->pan_smart, &ox, &oy, &ow, &oh);
928              it_scrl_y = ev->cur.canvas.y - it->wd->reorder_it->dy;
929
930              if (!it->wd->reorder_start_y)
931                it->wd->reorder_start_y = it->block->y + it->y;
932
933              if (it_scrl_y < oy) y_pos = oy;
934              else if (it_scrl_y + it->wd->reorder_it->h > oy+oh)
935                 y_pos = oy + oh - it->wd->reorder_it->h;
936              else y_pos = it_scrl_y;
937
938              _item_position(it, it->base.view, it->scrl_x, y_pos);
939
940              if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
941              it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
942           }
943         return;
944      }
945    if (!it->display_only)
946      elm_coords_finger_size_adjust(1, &minw, 1, &minh);
947    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
948    x = ev->cur.canvas.x - x;
949    y = ev->cur.canvas.y - y;
950    dx = x - it->dx;
951    adx = dx;
952    if (adx < 0) adx = -dx;
953    dy = y - it->dy;
954    ady = dy;
955    if (ady < 0) ady = -dy;
956    minw /= 2;
957    minh /= 2;
958    if ((adx > minw) || (ady > minh))
959      {
960         it->dragging = EINA_TRUE;
961         if (it->long_timer)
962           {
963              ecore_timer_del(it->long_timer);
964              it->long_timer = NULL;
965           }
966         if (!it->wd->wasselected)
967           {
968              _item_unhighlight(it);
969              _item_unselect(it);
970           }
971         if (dy < 0)
972           {
973              if (ady > adx)
974                evas_object_smart_callback_call(it->base.widget,
975                                                SIG_DRAG_START_UP, it);
976              else
977                {
978                   if (dx < 0)
979                     evas_object_smart_callback_call(it->base.widget,
980                                                     SIG_DRAG_START_LEFT, it);
981                   else
982                     evas_object_smart_callback_call(it->base.widget,
983                                                     SIG_DRAG_START_RIGHT, it);
984                }
985           }
986         else
987           {
988              if (ady > adx)
989                evas_object_smart_callback_call(it->base.widget,
990                                                SIG_DRAG_START_DOWN, it);
991              else
992                {
993                   if (dx < 0)
994                     evas_object_smart_callback_call(it->base.widget,
995                                                     SIG_DRAG_START_LEFT, it);
996                   else
997                     evas_object_smart_callback_call(it->base.widget,
998                                                     SIG_DRAG_START_RIGHT, it);
999                }
1000           }
1001      }
1002 }
1003
1004 static Eina_Bool
1005 _long_press(void *data)
1006 {
1007    Elm_Genlist_Item *it = data, *it_tmp;
1008    Eina_List *list, *l;
1009
1010    it->long_timer = NULL;
1011    if ((it->disabled) || (it->dragging) || (it->display_only))
1012      return ECORE_CALLBACK_CANCEL;
1013    it->wd->longpressed = EINA_TRUE;
1014    evas_object_smart_callback_call(it->base.widget, SIG_LONGPRESSED, it);
1015    if ((it->wd->reorder_mode) && (it->flags != ELM_GENLIST_ITEM_GROUP))
1016      {
1017         it->wd->reorder_it = it;
1018         it->wd->reorder_start_y = 0;
1019
1020         evas_object_raise(it->base.view);
1021         elm_smart_scroller_hold_set(it->wd->scr, EINA_TRUE);
1022
1023         list = elm_genlist_realized_items_get(it->wd->obj);
1024         EINA_LIST_FOREACH(list, l, it_tmp)
1025           {
1026              if (it != it_tmp) _item_unselect(it_tmp);
1027           }
1028         if (elm_genlist_item_expanded_get(it))
1029           {
1030              elm_genlist_item_expanded_set(it, EINA_FALSE);
1031              return ECORE_CALLBACK_RENEW;
1032           }
1033         edje_object_signal_emit(it->base.view, "elm,state,reorder,enabled", "elm");
1034      }
1035    return ECORE_CALLBACK_CANCEL;
1036 }
1037
1038 static void
1039 _swipe(Elm_Genlist_Item *it)
1040 {
1041    int i, sum = 0;
1042
1043    if (!it) return;
1044    if ((it->display_only) || (it->disabled)) return;
1045    it->wd->swipe = EINA_FALSE;
1046    for (i = 0; i < it->wd->movements; i++)
1047      {
1048         sum += it->wd->history[i].x;
1049         if (abs(it->wd->history[0].y - it->wd->history[i].y) > 10) return;
1050      }
1051
1052    sum /= it->wd->movements;
1053    if (abs(sum - it->wd->history[0].x) <= 10) return;
1054    evas_object_smart_callback_call(it->base.widget, SIG_SWIPE, it);
1055 }
1056
1057 static Eina_Bool
1058 _swipe_cancel(void *data)
1059 {
1060    Elm_Genlist_Item *it = data;
1061
1062    if (!it) return ECORE_CALLBACK_CANCEL;
1063    it->wd->swipe = EINA_FALSE;
1064    it->wd->movements = 0;
1065    return ECORE_CALLBACK_RENEW;
1066 }
1067
1068 static Eina_Bool
1069 _multi_cancel(void *data)
1070 {
1071    Widget_Data *wd = data;
1072
1073    if (!wd) return ECORE_CALLBACK_CANCEL;
1074    wd->multi_timeout = EINA_TRUE;
1075    return ECORE_CALLBACK_RENEW;
1076 }
1077
1078 static void
1079 _multi_touch_gesture_eval(void *data)
1080 {
1081    Elm_Genlist_Item *it = data;
1082
1083    it->wd->multitouched = EINA_FALSE;
1084    if (it->wd->multi_timer)
1085      {
1086         ecore_timer_del(it->wd->multi_timer);
1087         it->wd->multi_timer = NULL;
1088      }
1089    if (it->wd->multi_timeout)
1090      {
1091         it->wd->multi_timeout = EINA_FALSE;
1092         return;
1093      }
1094
1095    Evas_Coord minw = 0, minh = 0;
1096    Evas_Coord off_x, off_y, off_mx, off_my;
1097
1098    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
1099    off_x = abs(it->wd->cur_x - it->wd->prev_x);
1100    off_y = abs(it->wd->cur_y - it->wd->prev_y);
1101    off_mx = abs(it->wd->cur_mx - it->wd->prev_mx);
1102    off_my = abs(it->wd->cur_my - it->wd->prev_my);
1103
1104    if (((off_x > minw) || (off_y > minh)) && ((off_mx > minw) || (off_my > minh)))
1105      {
1106         if ((off_x + off_mx) > (off_y + off_my))
1107           {
1108              if ((it->wd->cur_x > it->wd->prev_x) && (it->wd->cur_mx > it->wd->prev_mx))
1109                evas_object_smart_callback_call(it->base.widget,
1110                                                SIG_MULTI_SWIPE_RIGHT, it);
1111              else if ((it->wd->cur_x < it->wd->prev_x) && (it->wd->cur_mx < it->wd->prev_mx))
1112                evas_object_smart_callback_call(it->base.widget,
1113                                                SIG_MULTI_SWIPE_LEFT, it);
1114              else if (abs(it->wd->cur_x - it->wd->cur_mx) > abs(it->wd->prev_x - it->wd->prev_mx))
1115                evas_object_smart_callback_call(it->base.widget,
1116                                                SIG_MULTI_PINCH_OUT, it);
1117              else
1118                evas_object_smart_callback_call(it->base.widget,
1119                                                SIG_MULTI_PINCH_IN, it);
1120           }
1121         else
1122           {
1123              if ((it->wd->cur_y > it->wd->prev_y) && (it->wd->cur_my > it->wd->prev_my))
1124                evas_object_smart_callback_call(it->base.widget,
1125                                                SIG_MULTI_SWIPE_DOWN, it);
1126              else if ((it->wd->cur_y < it->wd->prev_y) && (it->wd->cur_my < it->wd->prev_my))
1127                evas_object_smart_callback_call(it->base.widget,
1128                                                SIG_MULTI_SWIPE_UP, it);
1129              else if (abs(it->wd->cur_y - it->wd->cur_my) > abs(it->wd->prev_y - it->wd->prev_my))
1130                evas_object_smart_callback_call(it->base.widget,
1131                                                SIG_MULTI_PINCH_OUT, it);
1132              else
1133                evas_object_smart_callback_call(it->base.widget,
1134                                                SIG_MULTI_PINCH_IN, it);
1135           }
1136      }
1137    it->wd->multi_timeout = EINA_FALSE;
1138 }
1139
1140 static void
1141 _multi_down(void        *data,
1142             Evas        *evas __UNUSED__,
1143             Evas_Object *obj __UNUSED__,
1144             void        *event_info)
1145 {
1146    Elm_Genlist_Item *it = data;
1147    Evas_Event_Multi_Down *ev = event_info;
1148
1149    if ((it->wd->multi_device != 0) || (it->wd->multitouched) || (it->wd->multi_timeout)) return;
1150    it->wd->multi_device = ev->device;
1151    it->wd->multi_down = EINA_TRUE;
1152    it->wd->multitouched = EINA_TRUE;
1153    it->wd->prev_mx = ev->canvas.x;
1154    it->wd->prev_my = ev->canvas.y;
1155    if (!it->wd->wasselected)
1156      {
1157         _item_unhighlight(it);
1158         _item_unselect(it);
1159      }
1160    it->wd->wasselected = EINA_FALSE;
1161    it->wd->longpressed = EINA_FALSE;
1162    if (it->long_timer)
1163      {
1164         ecore_timer_del(it->long_timer);
1165         it->long_timer = NULL;
1166      }
1167    if (it->dragging)
1168      {
1169         it->dragging = EINA_FALSE;
1170         evas_object_smart_callback_call(it->base.widget, SIG_DRAG_STOP, it);
1171      }
1172    if (it->swipe_timer)
1173      {
1174         ecore_timer_del(it->swipe_timer);
1175         it->swipe_timer = NULL;
1176      }
1177    if (it->wd->on_hold)
1178      {
1179         it->wd->swipe = EINA_FALSE;
1180         it->wd->movements = 0;
1181         it->wd->on_hold = EINA_FALSE;
1182      }
1183 }
1184
1185 static void
1186 _multi_up(void        *data,
1187           Evas        *evas __UNUSED__,
1188           Evas_Object *obj __UNUSED__,
1189           void        *event_info)
1190 {
1191    Elm_Genlist_Item *it = data;
1192    Evas_Event_Multi_Up *ev = event_info;
1193
1194    if (it->wd->multi_device != ev->device) return;
1195    it->wd->multi_device = 0;
1196    it->wd->multi_down = EINA_FALSE;
1197    if (it->wd->mouse_down) return;
1198    _multi_touch_gesture_eval(data);
1199 }
1200
1201 static void
1202 _multi_move(void        *data,
1203             Evas        *evas __UNUSED__,
1204             Evas_Object *obj __UNUSED__,
1205             void        *event_info)
1206 {
1207    Elm_Genlist_Item *it = data;
1208    Evas_Event_Multi_Move *ev = event_info;
1209
1210    if (it->wd->multi_device != ev->device) return;
1211    it->wd->cur_mx = ev->cur.canvas.x;
1212    it->wd->cur_my = ev->cur.canvas.y;
1213 }
1214
1215 static void
1216 _mouse_down(void        *data,
1217             Evas        *evas __UNUSED__,
1218             Evas_Object *obj,
1219             void        *event_info)
1220 {
1221    Elm_Genlist_Item *it = data;
1222    Evas_Event_Mouse_Down *ev = event_info;
1223    Evas_Coord x, y;
1224
1225    if (ev->button != 1) return;
1226    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
1227      {
1228         it->wd->on_hold = EINA_TRUE;
1229      }
1230
1231    it->down = EINA_TRUE;
1232    it->dragging = EINA_FALSE;
1233    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1234    it->dx = ev->canvas.x - x;
1235    it->dy = ev->canvas.y - y;
1236    it->wd->mouse_down = EINA_TRUE;
1237    if (!it->wd->multitouched)
1238      {
1239         it->wd->prev_x = ev->canvas.x;
1240         it->wd->prev_y = ev->canvas.y;
1241         it->wd->multi_timeout = EINA_FALSE;
1242         if (it->wd->multi_timer) ecore_timer_del(it->wd->multi_timer);
1243         it->wd->multi_timer = ecore_timer_add(1, _multi_cancel, it->wd);
1244      }
1245    it->wd->longpressed = EINA_FALSE;
1246    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE;
1247    else it->wd->on_hold = EINA_FALSE;
1248    if (it->wd->on_hold) return;
1249    it->wd->wasselected = it->selected;
1250    _item_highlight(it);
1251    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
1252      if ((!it->disabled) && (!it->display_only))
1253        {
1254           evas_object_smart_callback_call(it->base.widget, SIG_CLICKED_DOUBLE, it);
1255           evas_object_smart_callback_call(it->base.widget, SIG_ACTIVATED, it);
1256        }
1257    if (it->long_timer) ecore_timer_del(it->long_timer);
1258    if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
1259    it->swipe_timer = ecore_timer_add(0.4, _swipe_cancel, it);
1260    if (it->realized)
1261      it->long_timer = ecore_timer_add(it->wd->longpress_timeout, _long_press,
1262                                       it);
1263    else
1264      it->long_timer = NULL;
1265    it->wd->swipe = EINA_FALSE;
1266    it->wd->movements = 0;
1267 }
1268
1269 static void
1270 _mouse_up(void        *data,
1271           Evas        *evas __UNUSED__,
1272           Evas_Object *obj __UNUSED__,
1273           void        *event_info)
1274 {
1275    Elm_Genlist_Item *it = data;
1276    Evas_Event_Mouse_Up *ev = event_info;
1277    Eina_Bool dragged = EINA_FALSE;
1278
1279    if (ev->button != 1) return;
1280    it->down = EINA_FALSE;
1281    it->wd->mouse_down = EINA_FALSE;
1282    if (it->wd->multitouched)
1283      {
1284         if ((!it->wd->multi) && (!it->selected) && (it->highlighted)) _item_unhighlight(it);
1285         if (it->wd->multi_down) return;
1286         _multi_touch_gesture_eval(data);
1287         return;
1288      }
1289    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) it->wd->on_hold = EINA_TRUE;
1290    else it->wd->on_hold = EINA_FALSE;
1291    if (it->long_timer)
1292      {
1293         ecore_timer_del(it->long_timer);
1294         it->long_timer = NULL;
1295      }
1296    if (it->dragging)
1297      {
1298         it->dragging = EINA_FALSE;
1299         evas_object_smart_callback_call(it->base.widget, SIG_DRAG_STOP, it);
1300         dragged = 1;
1301      }
1302    if (it->swipe_timer)
1303      {
1304         ecore_timer_del(it->swipe_timer);
1305         it->swipe_timer = NULL;
1306      }
1307    if (it->wd->multi_timer)
1308      {
1309         ecore_timer_del(it->wd->multi_timer);
1310         it->wd->multi_timer = NULL;
1311         it->wd->multi_timeout = EINA_FALSE;
1312      }
1313    if (it->wd->on_hold)
1314      {
1315         if (it->wd->swipe) _swipe(data);
1316         it->wd->longpressed = EINA_FALSE;
1317         it->wd->on_hold = EINA_FALSE;
1318         return;
1319      }
1320    if ((it->wd->reorder_mode) && (it->wd->reorder_it))
1321      {
1322         Evas_Coord it_scrl_y = ev->canvas.y - it->wd->reorder_it->dy;
1323
1324         if (it->wd->reorder_rel)
1325           {
1326              if (it->wd->reorder_it->parent == it->wd->reorder_rel->parent)
1327                {
1328                   if (it_scrl_y <= it->wd->reorder_rel->scrl_y)
1329                      _item_move_before(it->wd->reorder_it, it->wd->reorder_rel);
1330                   else
1331                      _item_move_after(it->wd->reorder_it, it->wd->reorder_rel);
1332                }
1333              else
1334                {
1335                   if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
1336                   it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
1337                }
1338           }
1339         edje_object_signal_emit(it->base.view, "elm,state,reorder,disabled", "elm");
1340         it->wd->reorder_it = it->wd->reorder_rel = NULL;
1341         elm_smart_scroller_hold_set(it->wd->scr, EINA_FALSE);
1342      }
1343    if (it->wd->longpressed)
1344      {
1345         it->wd->longpressed = EINA_FALSE;
1346         if (!it->wd->wasselected)
1347           {
1348              _item_unhighlight(it);
1349              _item_unselect(it);
1350           }
1351         it->wd->wasselected = EINA_FALSE;
1352         return;
1353      }
1354    if (dragged)
1355      {
1356         if (it->want_unrealize)
1357           {
1358              _item_unrealize(it, EINA_FALSE);
1359              if (it->block->want_unrealize)
1360                _item_block_unrealize(it->block);
1361           }
1362      }
1363    if ((it->disabled) || (dragged) || (it->display_only)) return;
1364    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
1365    if (it->wd->multi)
1366      {
1367         if (!it->selected)
1368           {
1369              _item_highlight(it);
1370              _item_select(it);
1371           }
1372         else
1373           {
1374              _item_unhighlight(it);
1375              _item_unselect(it);
1376           }
1377      }
1378    else
1379      {
1380         if (!it->selected)
1381           {
1382              Widget_Data *wd = it->wd;
1383              if (wd)
1384                {
1385                   while (wd->selected)
1386                     {
1387                        _item_unhighlight(wd->selected->data);
1388                        _item_unselect(wd->selected->data);
1389                     }
1390                }
1391           }
1392         else
1393           {
1394              const Eina_List *l, *l_next;
1395              Elm_Genlist_Item *it2;
1396
1397              EINA_LIST_FOREACH_SAFE(it->wd->selected, l, l_next, it2)
1398                 if (it2 != it)
1399                   {
1400                      _item_unhighlight(it2);
1401                      _item_unselect(it2);
1402                   }
1403              //_item_highlight(it);
1404              //_item_select(it);
1405           }
1406         _item_highlight(it);
1407         _item_select(it);
1408      }
1409 }
1410
1411 static void
1412 _signal_expand_toggle(void        *data,
1413                       Evas_Object *obj __UNUSED__,
1414                       const char  *emission __UNUSED__,
1415                       const char  *source __UNUSED__)
1416 {
1417    Elm_Genlist_Item *it = data;
1418
1419    if (it->expanded)
1420      evas_object_smart_callback_call(it->base.widget, SIG_CONTRACT_REQUEST, it);
1421    else
1422      evas_object_smart_callback_call(it->base.widget, SIG_EXPAND_REQUEST, it);
1423 }
1424
1425 static void
1426 _signal_expand(void        *data,
1427                Evas_Object *obj __UNUSED__,
1428                const char  *emission __UNUSED__,
1429                const char  *source __UNUSED__)
1430 {
1431    Elm_Genlist_Item *it = data;
1432
1433    if (!it->expanded)
1434      evas_object_smart_callback_call(it->base.widget, SIG_EXPAND_REQUEST, it);
1435 }
1436
1437 static void
1438 _signal_contract(void        *data,
1439                  Evas_Object *obj __UNUSED__,
1440                  const char  *emission __UNUSED__,
1441                  const char  *source __UNUSED__)
1442 {
1443    Elm_Genlist_Item *it = data;
1444
1445    if (it->expanded)
1446      evas_object_smart_callback_call(it->base.widget, SIG_CONTRACT_REQUEST, it);
1447 }
1448
1449 static Eina_Bool
1450 _scr_hold_timer_cb(void *data)
1451 {
1452    if (!data) return ECORE_CALLBACK_CANCEL;
1453    Widget_Data *wd = data;
1454    elm_smart_scroller_hold_set(wd->scr, EINA_FALSE);
1455    wd->scr_hold_timer = NULL;
1456    return ECORE_CALLBACK_CANCEL;
1457 }
1458
1459 static void
1460 _mode_finished_signal_cb(void        *data,
1461                          Evas_Object *obj,
1462                          const char  *emission __UNUSED__,
1463                          const char  *source __UNUSED__)
1464 {
1465    if (!data) return;
1466    if (!obj) return;
1467    Elm_Genlist_Item *it = data;
1468    if ((it->delete_me) || (!it->realized) || (!it->mode_view)) return;
1469    char buf[1024];
1470    Evas *te = evas_object_evas_get(obj);
1471
1472    evas_event_freeze(te);
1473    it->nocache = EINA_FALSE;
1474    _mode_item_unrealize(it);
1475    snprintf(buf, sizeof(buf), "elm,state,%s,passive,finished", it->wd->mode_type);
1476    edje_object_signal_callback_del_full(obj, buf, "elm", _mode_finished_signal_cb, it);
1477    evas_event_thaw(te);
1478    evas_event_thaw_eval(te);
1479 }
1480
1481 static void
1482 _item_cache_clean(Widget_Data *wd)
1483 {
1484    evas_event_freeze(evas_object_evas_get(wd->obj));
1485    while ((wd->item_cache) && (wd->item_cache_count > wd->item_cache_max))
1486      {
1487         Item_Cache *itc;
1488
1489         itc = EINA_INLIST_CONTAINER_GET(wd->item_cache->last, Item_Cache);
1490         wd->item_cache = eina_inlist_remove(wd->item_cache,
1491                                             wd->item_cache->last);
1492         wd->item_cache_count--;
1493         if (itc->spacer) evas_object_del(itc->spacer);
1494         if (itc->base_view) evas_object_del(itc->base_view);
1495         if (itc->item_style) eina_stringshare_del(itc->item_style);
1496         free(itc);
1497      }
1498    evas_event_thaw(evas_object_evas_get(wd->obj));
1499    evas_event_thaw_eval(evas_object_evas_get(wd->obj));
1500 }
1501
1502 static void
1503 _item_cache_zero(Widget_Data *wd)
1504 {
1505    int pmax = wd->item_cache_max;
1506    wd->item_cache_max = 0;
1507    _item_cache_clean(wd);
1508    wd->item_cache_max = pmax;
1509 }
1510
1511 static void
1512 _item_cache_add(Elm_Genlist_Item *it)
1513 {
1514    Item_Cache *itc;
1515
1516    evas_event_freeze(evas_object_evas_get(it->wd->obj));
1517    if (it->wd->item_cache_max <= 0)
1518      {
1519         evas_object_del(it->base.view);
1520         it->base.view = NULL;
1521         evas_object_del(it->spacer);
1522         it->spacer = NULL;
1523         evas_event_thaw(evas_object_evas_get(it->wd->obj));
1524         evas_event_thaw_eval(evas_object_evas_get(it->wd->obj));
1525         return;
1526      }
1527
1528    it->wd->item_cache_count++;
1529    itc = calloc(1, sizeof(Item_Cache));
1530    it->wd->item_cache = eina_inlist_prepend(it->wd->item_cache,
1531                                             EINA_INLIST_GET(itc));
1532    itc->spacer = it->spacer;
1533    it->spacer = NULL;
1534    itc->base_view = it->base.view;
1535    it->base.view = NULL;
1536    evas_object_hide(itc->base_view);
1537    evas_object_move(itc->base_view, -9999, -9999);
1538    itc->item_style = eina_stringshare_add(it->itc->item_style);
1539    if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) itc->tree = 1;
1540    itc->compress = (it->wd->compress);
1541    itc->selected = it->selected;
1542    itc->disabled = it->disabled;
1543    itc->expanded = it->expanded;
1544    if (it->long_timer)
1545      {
1546         ecore_timer_del(it->long_timer);
1547         it->long_timer = NULL;
1548      }
1549    if (it->swipe_timer)
1550      {
1551         ecore_timer_del(it->swipe_timer);
1552         it->swipe_timer = NULL;
1553      }
1554    // FIXME: other callbacks?
1555    edje_object_signal_callback_del_full(itc->base_view,
1556                                         "elm,action,expand,toggle",
1557                                         "elm", _signal_expand_toggle, it);
1558    edje_object_signal_callback_del_full(itc->base_view, "elm,action,expand",
1559                                         "elm",
1560                                         _signal_expand, it);
1561    edje_object_signal_callback_del_full(itc->base_view, "elm,action,contract",
1562                                         "elm", _signal_contract, it);
1563    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MOUSE_DOWN,
1564                                        _mouse_down, it);
1565    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MOUSE_UP,
1566                                        _mouse_up, it);
1567    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MOUSE_MOVE,
1568                                        _mouse_move, it);
1569    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MULTI_DOWN,
1570                                        _multi_down, it);
1571    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MULTI_UP,
1572                                        _multi_up, it);
1573    evas_object_event_callback_del_full(itc->base_view, EVAS_CALLBACK_MULTI_MOVE,
1574                                        _multi_move, it);
1575    _item_cache_clean(it->wd);
1576    evas_event_thaw(evas_object_evas_get(it->wd->obj));
1577    evas_event_thaw_eval(evas_object_evas_get(it->wd->obj));
1578 }
1579
1580 static Item_Cache *
1581 _item_cache_find(Elm_Genlist_Item *it)
1582 {
1583    Item_Cache *itc;
1584    Eina_Bool tree = 0;
1585
1586    if (it->flags & ELM_GENLIST_ITEM_SUBITEMS) tree = 1;
1587    EINA_INLIST_FOREACH(it->wd->item_cache, itc)
1588      {
1589         if ((itc->selected) || (itc->disabled) || (itc->expanded))
1590           continue;
1591         if ((itc->tree == tree) &&
1592             (itc->compress == it->wd->compress) &&
1593             (!strcmp(it->itc->item_style, itc->item_style)))
1594           {
1595              it->wd->item_cache = eina_inlist_remove(it->wd->item_cache,
1596                                                      EINA_INLIST_GET(itc));
1597              it->wd->item_cache_count--;
1598              return itc;
1599           }
1600      }
1601    return NULL;
1602 }
1603
1604 static void
1605 _elm_genlist_item_odd_even_update(Elm_Genlist_Item *it)
1606 {
1607    if (!it->nostacking)
1608      {
1609         if ((it->order_num_in & 0x1) ^ it->stacking_even)
1610           evas_object_lower(it->base.view);
1611         else
1612           evas_object_raise(it->base.view);
1613      }
1614
1615    if (it->order_num_in & 0x1)
1616      edje_object_signal_emit(it->base.view, "elm,state,odd", "elm");
1617    else
1618      edje_object_signal_emit(it->base.view, "elm,state,even", "elm");
1619 }
1620
1621 static void
1622 _elm_genlist_item_state_update(Elm_Genlist_Item *it, Item_Cache *itc)
1623 {
1624    if (itc)
1625      {
1626         if (it->selected != itc->selected)
1627           {
1628              if (it->selected)
1629                edje_object_signal_emit(it->base.view,
1630                                        "elm,state,selected", "elm");
1631           }
1632         if (it->disabled != itc->disabled)
1633           {
1634              if (it->disabled)
1635                edje_object_signal_emit(it->base.view,
1636                                        "elm,state,disabled", "elm");
1637           }
1638         if (it->expanded != itc->expanded)
1639           {
1640              if (it->expanded)
1641                edje_object_signal_emit(it->base.view,
1642                                        "elm,state,expanded", "elm");
1643           }
1644      }
1645    else
1646      {
1647         if (it->selected)
1648           edje_object_signal_emit(it->base.view,
1649                                   "elm,state,selected", "elm");
1650         if (it->disabled)
1651           edje_object_signal_emit(it->base.view,
1652                                   "elm,state,disabled", "elm");
1653         if (it->expanded)
1654           edje_object_signal_emit(it->base.view,
1655                                   "elm,state,expanded", "elm");
1656      }
1657 }
1658
1659 static void
1660 _item_cache_free(Item_Cache *itc)
1661 {
1662    if (itc->spacer) evas_object_del(itc->spacer);
1663    if (itc->base_view) evas_object_del(itc->base_view);
1664    if (itc->item_style) eina_stringshare_del(itc->item_style);
1665    free(itc);
1666 }
1667
1668 static const char *
1669 _item_label_hook(Elm_Genlist_Item *it, const char *part)
1670 {
1671    if (!it->itc->func.label_get) return NULL;
1672    return edje_object_part_text_get(it->base.view, part);
1673 }
1674
1675 static void
1676 _item_label_realize(Elm_Genlist_Item *it,
1677                     Evas_Object *target,
1678                     Eina_List **source)
1679 {
1680    if (it->itc->func.label_get)
1681      {
1682         const Eina_List *l;
1683         const char *key;
1684
1685         *source = elm_widget_stringlist_get(edje_object_data_get(target, "labels"));
1686         EINA_LIST_FOREACH(*source, l, key)
1687           {
1688              char *s = it->itc->func.label_get
1689                 ((void *)it->base.data, it->base.widget, key);
1690
1691              if (s)
1692                {
1693                   edje_object_part_text_set(target, key, s);
1694                   free(s);
1695                }
1696              else
1697                {
1698                   edje_object_part_text_set(target, key, "");
1699                }
1700           }
1701      }
1702 }
1703
1704 static Eina_List *
1705 _item_icon_realize(Elm_Genlist_Item *it,
1706                    Evas_Object *target,
1707                    Eina_List **source)
1708 {
1709    Eina_List *res = NULL;
1710
1711    if (it->itc->func.icon_get)
1712      {
1713         const Eina_List *l;
1714         const char *key;
1715
1716         *source = elm_widget_stringlist_get(edje_object_data_get(target, "icons"));
1717         EINA_LIST_FOREACH(*source, l, key)
1718           {
1719              Evas_Object *ic = it->itc->func.icon_get
1720                 ((void *)it->base.data, it->base.widget, key);
1721
1722              if (ic)
1723                {
1724                   res = eina_list_append(res, ic);
1725                   edje_object_part_swallow(target, key, ic);
1726                   evas_object_show(ic);
1727                   elm_widget_sub_object_add(it->base.widget, ic);
1728                   if (it->disabled)
1729                     elm_widget_disabled_set(ic, EINA_TRUE);
1730                }
1731           }
1732      }
1733
1734    return res;
1735 }
1736
1737 static void
1738 _item_state_realize(Elm_Genlist_Item *it,
1739                     Evas_Object *target,
1740                     Eina_List **source)
1741 {
1742    if (it->itc->func.state_get)
1743      {
1744         const Eina_List *l;
1745         const char *key;
1746         char buf[4096];
1747
1748         *source = elm_widget_stringlist_get(edje_object_data_get(target, "states"));
1749         EINA_LIST_FOREACH(*source, l, key)
1750           {
1751              Eina_Bool on = it->itc->func.state_get
1752                 ((void *)it->base.data, it->base.widget, key);
1753
1754              if (on)
1755                {
1756                   snprintf(buf, sizeof(buf), "elm,state,%s,active", key);
1757                   edje_object_signal_emit(target, buf, "elm");
1758                }
1759              else
1760                {
1761                   snprintf(buf, sizeof(buf), "elm,state,%s,passive", key);
1762                   edje_object_signal_emit(target, buf, "elm");
1763                }
1764           }
1765      }
1766 }
1767
1768 static void
1769 _item_realize(Elm_Genlist_Item *it,
1770               int               in,
1771               Eina_Bool         calc)
1772 {
1773    Elm_Genlist_Item *it2;
1774    const char *treesize;
1775    char buf[1024];
1776    int depth, tsize = 20;
1777    Item_Cache *itc = NULL;
1778
1779    if (it->delete_me) return;
1780    //evas_event_freeze(evas_object_evas_get(it->wd->obj));
1781    if (it->realized)
1782      {
1783         if (it->order_num_in != in)
1784           {
1785              it->order_num_in = in;
1786              _elm_genlist_item_odd_even_update(it);
1787              _elm_genlist_item_state_update(it, NULL);
1788           }
1789         //evas_event_thaw(evas_object_evas_get(it->wd->obj));
1790         //evas_event_thaw_eval(evas_object_evas_get(it->wd->obj));
1791         return;
1792      }
1793    it->order_num_in = in;
1794
1795    if (it->nocache)
1796      it->nocache = EINA_FALSE;
1797    else
1798      itc = _item_cache_find(it);
1799    if (itc)
1800      {
1801         it->base.view = itc->base_view;
1802         itc->base_view = NULL;
1803         it->spacer = itc->spacer;
1804         itc->spacer = NULL;
1805      }
1806    else
1807      {
1808         const char *stacking_even;
1809         const char *stacking;
1810
1811         it->base.view = edje_object_add(evas_object_evas_get(it->base.widget));
1812         edje_object_scale_set(it->base.view,
1813                               elm_widget_scale_get(it->base.widget) *
1814                               _elm_config->scale);
1815         evas_object_smart_member_add(it->base.view, it->wd->pan_smart);
1816         elm_widget_sub_object_add(it->base.widget, it->base.view);
1817
1818         if (it->flags & ELM_GENLIST_ITEM_SUBITEMS)
1819           strncpy(buf, "tree", sizeof(buf));
1820         else strncpy(buf, "item", sizeof(buf));
1821         if (it->wd->compress)
1822           strncat(buf, "_compress", sizeof(buf) - strlen(buf));
1823
1824         strncat(buf, "/", sizeof(buf) - strlen(buf));
1825         strncat(buf, it->itc->item_style, sizeof(buf) - strlen(buf));
1826
1827         _elm_theme_object_set(it->base.widget, it->base.view, "genlist", buf,
1828                               elm_widget_style_get(it->base.widget));
1829
1830         stacking_even = edje_object_data_get(it->base.view, "stacking_even");
1831         if (!stacking_even) stacking_even = "above";
1832         it->stacking_even = !!strcmp("above", stacking_even);
1833
1834         stacking = edje_object_data_get(it->base.view, "stacking");
1835         if (!stacking) stacking = "yes";
1836         it->nostacking = !!strcmp("yes", stacking);
1837
1838         edje_object_mirrored_set(it->base.view,
1839                                  elm_widget_mirrored_get(it->base.widget));
1840         it->spacer =
1841           evas_object_rectangle_add(evas_object_evas_get(it->base.widget));
1842         evas_object_color_set(it->spacer, 0, 0, 0, 0);
1843         elm_widget_sub_object_add(it->base.widget, it->spacer);
1844      }
1845
1846    _elm_genlist_item_odd_even_update(it);
1847
1848    for (it2 = it, depth = 0; it2->parent; it2 = it2->parent)
1849      {
1850         if (it2->parent->flags != ELM_GENLIST_ITEM_GROUP) depth += 1;
1851      }
1852    it->expanded_depth = depth;
1853    treesize = edje_object_data_get(it->base.view, "treesize");
1854    if (treesize) tsize = atoi(treesize);
1855    evas_object_size_hint_min_set(it->spacer,
1856                                  (depth * tsize) * _elm_config->scale, 1);
1857    edje_object_part_swallow(it->base.view, "elm.swallow.pad", it->spacer);
1858    if (!calc)
1859      {
1860         edje_object_signal_callback_add(it->base.view,
1861                                         "elm,action,expand,toggle",
1862                                         "elm", _signal_expand_toggle, it);
1863         edje_object_signal_callback_add(it->base.view, "elm,action,expand",
1864                                         "elm", _signal_expand, it);
1865         edje_object_signal_callback_add(it->base.view, "elm,action,contract",
1866                                         "elm", _signal_contract, it);
1867         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_DOWN,
1868                                        _mouse_down, it);
1869         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_UP,
1870                                        _mouse_up, it);
1871         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_MOVE,
1872                                        _mouse_move, it);
1873         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MULTI_DOWN,
1874                                        _multi_down, it);
1875         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MULTI_UP,
1876                                        _multi_up, it);
1877         evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MULTI_MOVE,
1878                                        _multi_move, it);
1879
1880         _elm_genlist_item_state_update(it, itc);
1881      }
1882
1883    if ((calc) && (it->wd->homogeneous) &&
1884        ((it->wd->item_width) ||
1885         ((it->wd->item_width) && (it->wd->group_item_width))))
1886      {
1887         /* homogenous genlist shortcut */
1888         if (!it->mincalcd)
1889           {
1890              if (it->flags & ELM_GENLIST_ITEM_GROUP)
1891                {
1892                   it->w = it->minw = it->wd->group_item_width;
1893                   it->h = it->minh = it->wd->group_item_height;
1894                }
1895              else
1896                {
1897                   it->w = it->minw = it->wd->item_width;
1898                   it->h = it->minh = it->wd->item_height;
1899                }
1900              it->mincalcd = EINA_TRUE;
1901           }
1902      }
1903    else
1904      {
1905         /* FIXME: If you see that assert, please notify us and we
1906            will clean our mess */
1907         assert(eina_list_count(it->icon_objs) == 0);
1908
1909         _item_label_realize(it, it->base.view, &it->labels);
1910         it->icon_objs = _item_icon_realize(it, it->base.view, &it->icons);
1911         _item_state_realize(it, it->base.view, &it->states);
1912
1913         if (!it->mincalcd)
1914           {
1915              Evas_Coord mw = -1, mh = -1;
1916
1917              if (!it->display_only)
1918                elm_coords_finger_size_adjust(1, &mw, 1, &mh);
1919              if (it->wd->height_for_width) mw = it->wd->prev_viewport_w;
1920              edje_object_size_min_restricted_calc(it->base.view, &mw, &mh, mw,
1921                                                   mh);
1922              if (!it->display_only)
1923                elm_coords_finger_size_adjust(1, &mw, 1, &mh);
1924              it->w = it->minw = mw;
1925              it->h = it->minh = mh;
1926              it->mincalcd = EINA_TRUE;
1927
1928              if ((!it->wd->group_item_width) && (it->flags == ELM_GENLIST_ITEM_GROUP))
1929                {
1930                   it->wd->group_item_width = mw;
1931                   it->wd->group_item_height = mh;
1932                }
1933              else if ((!it->wd->item_width) && (it->flags == ELM_GENLIST_ITEM_NONE))
1934                {
1935                   it->wd->item_width = mw;
1936                   it->wd->item_height = mh;
1937                }
1938           }
1939         if (!calc) evas_object_show(it->base.view);
1940      }
1941
1942    if (it->tooltip.content_cb)
1943      {
1944         elm_widget_item_tooltip_content_cb_set(it,
1945                                                it->tooltip.content_cb,
1946                                                it->tooltip.data, NULL);
1947         elm_widget_item_tooltip_style_set(it, it->tooltip.style);
1948         elm_widget_item_tooltip_size_restrict_disable(it, it->tooltip.free_size);
1949      }
1950
1951    if (it->mouse_cursor)
1952      elm_widget_item_cursor_set(it, it->mouse_cursor);
1953
1954    it->realized = EINA_TRUE;
1955    it->want_unrealize = EINA_FALSE;
1956
1957    if (itc) _item_cache_free(itc);
1958    //evas_event_thaw(evas_object_evas_get(it->wd->obj));
1959    //evas_event_thaw_eval(evas_object_evas_get(it->wd->obj));
1960    if (!calc)
1961      evas_object_smart_callback_call(it->base.widget, SIG_REALIZED, it);
1962    edje_object_message_signal_process(it->base.view);
1963 }
1964
1965 static void
1966 _item_unrealize(Elm_Genlist_Item *it,
1967                 Eina_Bool         calc)
1968 {
1969    Evas_Object *icon;
1970
1971    if (!it->realized) return;
1972    if (it->wd->reorder_it == it) return;
1973    evas_event_freeze(evas_object_evas_get(it->wd->obj));
1974    if (!calc)
1975      evas_object_smart_callback_call(it->base.widget, SIG_UNREALIZED, it);
1976    if (it->long_timer)
1977      {
1978         ecore_timer_del(it->long_timer);
1979         it->long_timer = NULL;
1980      }
1981    if (it->nocache)
1982      {
1983         evas_object_del(it->base.view);
1984         it->base.view = NULL;
1985         evas_object_del(it->spacer);
1986         it->spacer = NULL;
1987      }
1988    else
1989      {
1990         edje_object_mirrored_set(it->base.view,
1991                                  elm_widget_mirrored_get(it->base.widget));
1992         edje_object_scale_set(it->base.view,
1993                               elm_widget_scale_get(it->base.widget)
1994                               * _elm_config->scale);
1995         _item_cache_add(it);
1996      }
1997    elm_widget_stringlist_free(it->labels);
1998    it->labels = NULL;
1999    elm_widget_stringlist_free(it->icons);
2000    it->icons = NULL;
2001    elm_widget_stringlist_free(it->states);
2002
2003    EINA_LIST_FREE(it->icon_objs, icon)
2004      evas_object_del(icon);
2005
2006    _mode_item_unrealize(it);
2007    it->states = NULL;
2008    it->realized = EINA_FALSE;
2009    it->want_unrealize = EINA_FALSE;
2010    evas_event_thaw(evas_object_evas_get(it->wd->obj));
2011    evas_event_thaw_eval(evas_object_evas_get(it->wd->obj));
2012 }
2013
2014 static Eina_Bool
2015 _item_block_recalc(Item_Block *itb,
2016                    int         in,
2017                    Eina_Bool   qadd)
2018 {
2019    const Eina_List *l;
2020    Elm_Genlist_Item *it;
2021    Evas_Coord minw = 0, minh = 0;
2022    Eina_Bool showme = EINA_FALSE, changed = EINA_FALSE;
2023    Evas_Coord y = 0;
2024
2025    //evas_event_freeze(evas_object_evas_get(itb->wd->obj));
2026    itb->num = in;
2027    EINA_LIST_FOREACH(itb->items, l, it)
2028      {
2029         if (it->delete_me) continue;
2030         showme |= it->showme;
2031         if (!itb->realized)
2032           {
2033              if (qadd)
2034                {
2035                   if (!it->mincalcd) changed = EINA_TRUE;
2036                   if (changed)
2037                     {
2038                        _item_realize(it, in, EINA_TRUE);
2039                        _item_unrealize(it, EINA_TRUE);
2040                     }
2041                }
2042              else
2043                {
2044                   _item_realize(it, in, EINA_TRUE);
2045                   _item_unrealize(it, EINA_TRUE);
2046                }
2047           }
2048         else
2049           _item_realize(it, in, EINA_FALSE);
2050         minh += it->minh;
2051         if (minw < it->minw) minw = it->minw;
2052         in++;
2053         it->x = 0;
2054         it->y = y;
2055         y += it->h;
2056      }
2057    itb->minw = minw;
2058    itb->minh = minh;
2059    itb->changed = EINA_FALSE;
2060    //evas_event_thaw(evas_object_evas_get(itb->wd->obj));
2061    //evas_event_thaw_eval(evas_object_evas_get(itb->wd->obj));
2062    return showme;
2063 }
2064
2065 static void
2066 _item_block_realize(Item_Block *itb)
2067 {
2068    if (itb->realized) return;
2069    itb->realized = EINA_TRUE;
2070    itb->want_unrealize = EINA_FALSE;
2071 }
2072
2073 static void
2074 _item_block_unrealize(Item_Block *itb)
2075 {
2076    const Eina_List *l;
2077    Elm_Genlist_Item *it;
2078    Eina_Bool dragging = EINA_FALSE;
2079
2080    if (!itb->realized) return;
2081    evas_event_freeze(evas_object_evas_get(itb->wd->obj));
2082    EINA_LIST_FOREACH(itb->items, l, it)
2083      {
2084         if (it->flags != ELM_GENLIST_ITEM_GROUP)
2085           {
2086              if (it->dragging)
2087                {
2088                   dragging = EINA_TRUE;
2089                   it->want_unrealize = EINA_TRUE;
2090                }
2091              else
2092                _item_unrealize(it, EINA_FALSE);
2093           }
2094      }
2095    if (!dragging)
2096      {
2097         itb->realized = EINA_FALSE;
2098         itb->want_unrealize = EINA_TRUE;
2099      }
2100    else
2101      itb->want_unrealize = EINA_FALSE;
2102    evas_event_thaw(evas_object_evas_get(itb->wd->obj));
2103    evas_event_thaw_eval(evas_object_evas_get(itb->wd->obj));
2104 }
2105
2106 static int
2107 _get_space_for_reorder_item(Elm_Genlist_Item *it)
2108 {
2109    Evas_Coord rox, roy, row, roh, oy, oh;
2110    Eina_Bool top = EINA_FALSE;
2111    Elm_Genlist_Item *reorder_it = it->wd->reorder_it;
2112    if (!reorder_it) return 0;
2113
2114    evas_object_geometry_get(it->wd->pan_smart, NULL, &oy, NULL, &oh);
2115    evas_object_geometry_get(it->wd->reorder_it->base.view, &rox, &roy, &row, &roh);
2116
2117    if ((it->wd->reorder_start_y < it->block->y) &&
2118        (roy - oy + (roh / 2) >= it->block->y - it->wd->pan_y))
2119      {
2120         it->block->reorder_offset = it->wd->reorder_it->h * -1;
2121         if (it->block->count == 1)
2122            it->wd->reorder_rel = it;
2123      }
2124    else if ((it->wd->reorder_start_y >= it->block->y) &&
2125             (roy - oy + (roh / 2) <= it->block->y - it->wd->pan_y))
2126      {
2127         it->block->reorder_offset = it->wd->reorder_it->h;
2128      }
2129    else
2130      it->block->reorder_offset = 0;
2131
2132    it->scrl_y += it->block->reorder_offset;
2133
2134    top = (ELM_RECTS_INTERSECT(it->scrl_x, it->scrl_y, it->w, it->h,
2135                               rox, roy + (roh / 2), row, 1));
2136    if (top)
2137      {
2138         it->wd->reorder_rel = it;
2139         it->scrl_y += it->wd->reorder_it->h;
2140         return it->wd->reorder_it->h;
2141      }
2142    else
2143      return 0;
2144 }
2145
2146 static Eina_Bool
2147 _reorder_move_animator_cb(void *data)
2148 {
2149    Elm_Genlist_Item *it = data;
2150    Eina_Bool down = EINA_FALSE;
2151    double t;
2152    int y, dy = it->h / 10 * _elm_config->scale, diff;
2153
2154    t = ((0.0 > (t = ecore_loop_time_get()-it->wd->start_time)) ? 0.0 : t);
2155
2156    if (t <= REORDER_EFFECT_TIME) y = (1 * sin((t / REORDER_EFFECT_TIME) * (M_PI / 2)) * dy);
2157    else y = dy;
2158
2159    diff = abs(it->old_scrl_y - it->scrl_y);
2160    if (diff > it->h) y = diff / 2;
2161
2162    if (it->old_scrl_y < it->scrl_y)
2163      {
2164         it->old_scrl_y += y;
2165         down = EINA_TRUE;
2166      }
2167    else if (it->old_scrl_y > it->scrl_y)
2168      {
2169         it->old_scrl_y -= y;
2170         down = EINA_FALSE;
2171      }
2172    _item_position(it, it->base.view, it->scrl_x, it->old_scrl_y);
2173    _group_items_recalc(it->wd);
2174
2175    if ((it->wd->reorder_pan_move) ||
2176        (down && it->old_scrl_y >= it->scrl_y) ||
2177        (!down && it->old_scrl_y <= it->scrl_y))
2178      {
2179         it->old_scrl_y = it->scrl_y;
2180         it->move_effect_enabled = EINA_FALSE;
2181         it->wd->reorder_move_animator = NULL;
2182         return ECORE_CALLBACK_CANCEL;
2183      }
2184    return ECORE_CALLBACK_RENEW;
2185 }
2186
2187 static void
2188 _item_position(Elm_Genlist_Item *it,
2189                Evas_Object      *view,
2190                Evas_Coord        it_x,
2191                Evas_Coord        it_y)
2192 {
2193    if (!it) return;
2194    if (!view) return;
2195
2196    evas_event_freeze(evas_object_evas_get(it->wd->obj));
2197    evas_object_resize(view, it->w, it->h);
2198    evas_object_move(view, it_x, it_y);
2199    evas_object_show(view);
2200    evas_event_thaw(evas_object_evas_get(it->wd->obj));
2201    evas_event_thaw_eval(evas_object_evas_get(it->wd->obj));
2202 }
2203
2204 static void
2205 _item_block_position(Item_Block *itb,
2206                      int         in)
2207 {
2208    const Eina_List *l;
2209    Elm_Genlist_Item *it;
2210    Elm_Genlist_Item *git;
2211    Evas_Coord y = 0, ox, oy, ow, oh, cvx, cvy, cvw, cvh;
2212    int vis;
2213
2214    evas_event_freeze(evas_object_evas_get(itb->wd->obj));
2215    evas_object_geometry_get(itb->wd->pan_smart, &ox, &oy, &ow, &oh);
2216    evas_output_viewport_get(evas_object_evas_get(itb->wd->obj), &cvx, &cvy,
2217                             &cvw, &cvh);
2218    EINA_LIST_FOREACH(itb->items, l, it)
2219      {
2220         if (it->delete_me) continue;
2221         else if (it->wd->reorder_it == it) continue;
2222         it->x = 0;
2223         it->y = y;
2224         it->w = itb->w;
2225         it->scrl_x = itb->x + it->x - it->wd->pan_x + ox;
2226         it->scrl_y = itb->y + it->y - it->wd->pan_y + oy;
2227
2228         vis = (ELM_RECTS_INTERSECT(it->scrl_x, it->scrl_y, it->w, it->h,
2229                                    cvx, cvy, cvw, cvh));
2230         if (it->flags != ELM_GENLIST_ITEM_GROUP)
2231           {
2232              if ((itb->realized) && (!it->realized))
2233                {
2234                   if (vis) _item_realize(it, in, EINA_FALSE);
2235                }
2236              if (it->realized)
2237                {
2238                   if (vis)
2239                     {
2240                        if (it->wd->reorder_mode)
2241                           y += _get_space_for_reorder_item(it);
2242                        git = it->group_item;
2243                        if (git)
2244                          {
2245                             if (git->scrl_y < oy)
2246                               git->scrl_y = oy;
2247                             if ((git->scrl_y + git->h) > (it->scrl_y + it->h))
2248                               git->scrl_y = (it->scrl_y + it->h) - git->h;
2249                             git->want_realize = EINA_TRUE;
2250                          }
2251                        if ((it->wd->reorder_it) && (it->old_scrl_y != it->scrl_y))
2252                          {
2253                             if (!it->move_effect_enabled)
2254                               {
2255                                  it->move_effect_enabled = EINA_TRUE;
2256                                  it->wd->reorder_move_animator =
2257                                     ecore_animator_add(
2258                                        _reorder_move_animator_cb, it);
2259                               }
2260                          }
2261                        if (!it->move_effect_enabled)
2262                          {
2263                             if (it->mode_view)
2264                                _item_position(it, it->mode_view, it->scrl_x,
2265                                               it->scrl_y);
2266                             else
2267                                _item_position(it, it->base.view, it->scrl_x,
2268                                               it->scrl_y);
2269                             it->old_scrl_y = it->scrl_y;
2270                          }
2271                     }
2272                   else
2273                     {
2274                        if (!it->dragging) _item_unrealize(it, EINA_FALSE);
2275                     }
2276                }
2277              in++;
2278           }
2279         else
2280           {
2281              if (vis) it->want_realize = EINA_TRUE;
2282           }
2283         y += it->h;
2284      }
2285    evas_event_thaw(evas_object_evas_get(itb->wd->obj));
2286    evas_event_thaw_eval(evas_object_evas_get(itb->wd->obj));
2287 }
2288
2289 static void
2290 _group_items_recalc(void *data)
2291 {
2292    Widget_Data *wd = data;
2293    Eina_List *l;
2294    Elm_Genlist_Item *git;
2295
2296    evas_event_freeze(evas_object_evas_get(wd->obj));
2297    EINA_LIST_FOREACH(wd->group_items, l, git)
2298      {
2299         if (git->want_realize)
2300           {
2301              if (!git->realized)
2302                _item_realize(git, 0, EINA_FALSE);
2303              evas_object_resize(git->base.view, wd->minw, git->h);
2304              evas_object_move(git->base.view, git->scrl_x, git->scrl_y);
2305              evas_object_show(git->base.view);
2306              evas_object_raise(git->base.view);
2307           }
2308         else if (!git->want_realize && git->realized)
2309           {
2310              if (!git->dragging)
2311                _item_unrealize(git, EINA_FALSE);
2312           }
2313      }
2314    evas_event_thaw(evas_object_evas_get(wd->obj));
2315    evas_event_thaw_eval(evas_object_evas_get(wd->obj));
2316 }
2317
2318 static Eina_Bool
2319 _must_recalc_idler(void *data)
2320 {
2321    Widget_Data *wd = data;
2322    if (wd->calc_job) ecore_job_del(wd->calc_job);
2323    wd->calc_job = ecore_job_add(_calc_job, wd);
2324    wd->must_recalc_idler = NULL;
2325    return ECORE_CALLBACK_CANCEL;
2326 }
2327
2328 static void
2329 _calc_job(void *data)
2330 {
2331    Widget_Data *wd = data;
2332    Item_Block *itb, *chb = NULL;
2333    Evas_Coord minw = -1, minh = 0, y = 0, ow;
2334    int in = 0;
2335    double t0, t;
2336    Eina_Bool minw_change = EINA_FALSE, changed = EINA_FALSE;
2337    Eina_Bool did_must_recalc = EINA_FALSE;
2338    if (!wd) return;
2339
2340    t0 = ecore_time_get();
2341    evas_object_geometry_get(wd->pan_smart, NULL, NULL, &ow, &wd->h);
2342    if (wd->w != ow)
2343      wd->w = ow;
2344
2345    evas_event_freeze(evas_object_evas_get(wd->obj));
2346    EINA_INLIST_FOREACH(wd->blocks, itb)
2347      {
2348         Eina_Bool showme = EINA_FALSE;
2349
2350         itb->num = in;
2351         showme = itb->showme;
2352         itb->showme = EINA_FALSE;
2353         if (chb)
2354           {
2355              if (itb->realized) _item_block_unrealize(itb);
2356           }
2357         if ((itb->changed) || (changed) ||
2358             ((itb->must_recalc) && (!did_must_recalc)))
2359           {
2360              if ((changed) || (itb->must_recalc))
2361                {
2362                   Eina_List *l;
2363                   Elm_Genlist_Item *it;
2364                   EINA_LIST_FOREACH(itb->items, l, it)
2365                     if (it->mincalcd) it->mincalcd = EINA_FALSE;
2366                   itb->changed = EINA_TRUE;
2367                   if (itb->must_recalc) did_must_recalc = EINA_TRUE;
2368                   itb->must_recalc = EINA_FALSE;
2369                }
2370              if (itb->realized) _item_block_unrealize(itb);
2371              showme = _item_block_recalc(itb, in, EINA_FALSE);
2372              chb = itb;
2373           }
2374         itb->y = y;
2375         itb->x = 0;
2376         minh += itb->minh;
2377         if (minw == -1) minw = itb->minw;
2378         else if ((!itb->must_recalc) && (minw < itb->minw))
2379           {
2380              minw = itb->minw;
2381              minw_change = EINA_TRUE;
2382           }
2383         itb->w = minw;
2384         itb->h = itb->minh;
2385         y += itb->h;
2386         in += itb->count;
2387         if ((showme) && (wd->show_item) && (!wd->show_item->queued))
2388           {
2389              wd->show_item->showme = EINA_FALSE;
2390              if (wd->bring_in)
2391                elm_smart_scroller_region_bring_in(wd->scr,
2392                                                   wd->show_item->x +
2393                                                   wd->show_item->block->x,
2394                                                   wd->show_item->y +
2395                                                   wd->show_item->block->y,
2396                                                   wd->show_item->block->w,
2397                                                   wd->show_item->h);
2398              else
2399                elm_smart_scroller_child_region_show(wd->scr,
2400                                                     wd->show_item->x +
2401                                                     wd->show_item->block->x,
2402                                                     wd->show_item->y +
2403                                                     wd->show_item->block->y,
2404                                                     wd->show_item->block->w,
2405                                                     wd->show_item->h);
2406              wd->show_item = NULL;
2407           }
2408      }
2409    if (minw_change)
2410      {
2411         EINA_INLIST_FOREACH(wd->blocks, itb)
2412           {
2413              itb->minw = minw;
2414              itb->w = itb->minw;
2415           }
2416      }
2417    if ((chb) && (EINA_INLIST_GET(chb)->next))
2418      {
2419         EINA_INLIST_FOREACH(EINA_INLIST_GET(chb)->next, itb)
2420           {
2421              if (itb->realized) _item_block_unrealize(itb);
2422           }
2423      }
2424    wd->realminw = minw;
2425    if (minw < wd->w) minw = wd->w;
2426    if ((minw != wd->minw) || (minh != wd->minh))
2427      {
2428         wd->minw = minw;
2429         wd->minh = minh;
2430         evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
2431         _sizing_eval(wd->obj);
2432         if ((wd->anchor_item) && (wd->anchor_item->block) && (!wd->auto_scroll_enabled))
2433           {
2434              Elm_Genlist_Item *it;
2435              Evas_Coord it_y;
2436
2437              it = wd->anchor_item;
2438              it_y = wd->anchor_y;
2439              elm_smart_scroller_child_pos_set(wd->scr, wd->pan_x,
2440                                               it->block->y + it->y + it_y);
2441              wd->anchor_item = it;
2442              wd->anchor_y = it_y;
2443           }
2444      }
2445    t = ecore_time_get();
2446    if (did_must_recalc)
2447      {
2448         if (!wd->must_recalc_idler)
2449           wd->must_recalc_idler = ecore_idler_add(_must_recalc_idler, wd);
2450      }
2451    wd->calc_job = NULL;
2452    evas_object_smart_changed(wd->pan_smart);
2453    evas_event_thaw(evas_object_evas_get(wd->obj));
2454    evas_event_thaw_eval(evas_object_evas_get(wd->obj));
2455 }
2456
2457 static void
2458 _update_job(void *data)
2459 {
2460    Widget_Data *wd = data;
2461    Eina_List *l2;
2462    Item_Block *itb;
2463    int num, num0;
2464    Eina_Bool position = EINA_FALSE, recalc = EINA_FALSE;
2465    if (!wd) return;
2466    wd->update_job = NULL;
2467    num = 0;
2468
2469    evas_event_freeze(evas_object_evas_get(wd->obj));
2470    EINA_INLIST_FOREACH(wd->blocks, itb)
2471      {
2472         Evas_Coord itminw, itminh;
2473         Elm_Genlist_Item *it;
2474
2475         if (!itb->updateme)
2476           {
2477              num += itb->count;
2478              if (position)
2479                _item_block_position(itb, num);
2480              continue;
2481           }
2482         num0 = num;
2483         recalc = EINA_FALSE;
2484         EINA_LIST_FOREACH(itb->items, l2, it)
2485           {
2486              if (it->updateme)
2487                {
2488                   itminw = it->minw;
2489                   itminh = it->minh;
2490
2491                   it->updateme = EINA_FALSE;
2492                   if (it->realized)
2493                     {
2494                        _item_unrealize(it, EINA_FALSE);
2495                        _item_realize(it, num, EINA_FALSE);
2496                        position = EINA_TRUE;
2497                     }
2498                   else
2499                     {
2500                        _item_realize(it, num, EINA_TRUE);
2501                        _item_unrealize(it, EINA_TRUE);
2502                     }
2503                   if ((it->minw != itminw) || (it->minh != itminh))
2504                     recalc = EINA_TRUE;
2505                }
2506              num++;
2507           }
2508         itb->updateme = EINA_FALSE;
2509         if (recalc)
2510           {
2511              position = EINA_TRUE;
2512              itb->changed = EINA_TRUE;
2513              _item_block_recalc(itb, num0, EINA_FALSE);
2514              _item_block_position(itb, num0);
2515           }
2516      }
2517    if (position)
2518      {
2519         if (wd->calc_job) ecore_job_del(wd->calc_job);
2520         wd->calc_job = ecore_job_add(_calc_job, wd);
2521      }
2522    evas_event_thaw(evas_object_evas_get(wd->obj));
2523    evas_event_thaw_eval(evas_object_evas_get(wd->obj));
2524 }
2525
2526 static void
2527 _pan_set(Evas_Object *obj,
2528          Evas_Coord   x,
2529          Evas_Coord   y)
2530 {
2531    Pan *sd = evas_object_smart_data_get(obj);
2532    Item_Block *itb;
2533
2534    //   Evas_Coord ow, oh;
2535    //   evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
2536    //   ow = sd->wd->minw - ow;
2537    //   if (ow < 0) ow = 0;
2538    //   oh = sd->wd->minh - oh;
2539    //   if (oh < 0) oh = 0;
2540    //   if (x < 0) x = 0;
2541    //   if (y < 0) y = 0;
2542    //   if (x > ow) x = ow;
2543    //   if (y > oh) y = oh;
2544    if ((x == sd->wd->pan_x) && (y == sd->wd->pan_y)) return;
2545    sd->wd->pan_x = x;
2546    sd->wd->pan_y = y;
2547
2548    EINA_INLIST_FOREACH(sd->wd->blocks, itb)
2549      {
2550         if ((itb->y + itb->h) > y)
2551           {
2552              Elm_Genlist_Item *it;
2553              Eina_List *l2;
2554
2555              EINA_LIST_FOREACH(itb->items, l2, it)
2556                {
2557                   if ((itb->y + it->y) >= y)
2558                     {
2559                        sd->wd->anchor_item = it;
2560                        sd->wd->anchor_y = -(itb->y + it->y - y);
2561                        goto done;
2562                     }
2563                }
2564           }
2565      }
2566 done:
2567    if (!sd->wd->reorder_move_animator) evas_object_smart_changed(obj);
2568 }
2569
2570 static void
2571 _pan_get(Evas_Object *obj,
2572          Evas_Coord  *x,
2573          Evas_Coord  *y)
2574 {
2575    Pan *sd = evas_object_smart_data_get(obj);
2576
2577    if (x) *x = sd->wd->pan_x;
2578    if (y) *y = sd->wd->pan_y;
2579 }
2580
2581 static void
2582 _pan_max_get(Evas_Object *obj,
2583              Evas_Coord  *x,
2584              Evas_Coord  *y)
2585 {
2586    Pan *sd = evas_object_smart_data_get(obj);
2587    Evas_Coord ow, oh;
2588
2589    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
2590    ow = sd->wd->minw - ow;
2591    if (ow < 0) ow = 0;
2592    oh = sd->wd->minh - oh;
2593    if (oh < 0) oh = 0;
2594    if (x) *x = ow;
2595    if (y) *y = oh;
2596 }
2597
2598 static void
2599 _pan_min_get(Evas_Object *obj __UNUSED__,
2600              Evas_Coord  *x,
2601              Evas_Coord  *y)
2602 {
2603    if (x) *x = 0;
2604    if (y) *y = 0;
2605 }
2606
2607 static void
2608 _pan_child_size_get(Evas_Object *obj,
2609                     Evas_Coord  *w,
2610                     Evas_Coord  *h)
2611 {
2612    Pan *sd = evas_object_smart_data_get(obj);
2613
2614    if (w) *w = sd->wd->minw;
2615    if (h) *h = sd->wd->minh;
2616 }
2617
2618 static void
2619 _pan_add(Evas_Object *obj)
2620 {
2621    Pan *sd;
2622    Evas_Object_Smart_Clipped_Data *cd;
2623
2624    _pan_sc.add(obj);
2625    cd = evas_object_smart_data_get(obj);
2626    sd = ELM_NEW(Pan);
2627    if (!sd) return;
2628    sd->__clipped_data = *cd;
2629    free(cd);
2630    evas_object_smart_data_set(obj, sd);
2631 }
2632
2633 static void
2634 _pan_del(Evas_Object *obj)
2635 {
2636    Pan *sd = evas_object_smart_data_get(obj);
2637
2638    if (!sd) return;
2639    if (sd->resize_job)
2640      {
2641         ecore_job_del(sd->resize_job);
2642         sd->resize_job = NULL;
2643      }
2644    _pan_sc.del(obj);
2645 }
2646
2647 static void
2648 _pan_resize_job(void *data)
2649 {
2650    Pan *sd = data;
2651    _sizing_eval(sd->wd->obj);
2652    sd->resize_job = NULL;
2653 }
2654
2655 static void
2656 _pan_resize(Evas_Object *obj,
2657             Evas_Coord   w,
2658             Evas_Coord   h)
2659 {
2660    Pan *sd = evas_object_smart_data_get(obj);
2661    Evas_Coord ow, oh;
2662
2663    evas_object_geometry_get(obj, NULL, NULL, &ow, &oh);
2664    if ((ow == w) && (oh == h)) return;
2665    if ((sd->wd->height_for_width) && (ow != w))
2666      {
2667         if (sd->resize_job) ecore_job_del(sd->resize_job);
2668         sd->resize_job = ecore_job_add(_pan_resize_job, sd);
2669      }
2670    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
2671    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
2672 }
2673
2674 static void
2675 _pan_calculate(Evas_Object *obj)
2676 {
2677    Pan *sd = evas_object_smart_data_get(obj);
2678    Item_Block *itb;
2679    Evas_Coord ox, oy, ow, oh, cvx, cvy, cvw, cvh;
2680    int in = 0;
2681    Elm_Genlist_Item *git;
2682    Eina_List *l;
2683
2684    evas_event_freeze(evas_object_evas_get(obj));
2685    evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
2686    evas_output_viewport_get(evas_object_evas_get(obj), &cvx, &cvy, &cvw, &cvh);
2687    EINA_LIST_FOREACH(sd->wd->group_items, l, git)
2688      {
2689         git->want_realize = EINA_FALSE;
2690      }
2691    EINA_INLIST_FOREACH(sd->wd->blocks, itb)
2692      {
2693         itb->w = sd->wd->minw;
2694         if (ELM_RECTS_INTERSECT(itb->x - sd->wd->pan_x + ox,
2695                                 itb->y - sd->wd->pan_y + oy,
2696                                 itb->w, itb->h,
2697                                 cvx, cvy, cvw, cvh))
2698           {
2699              if ((!itb->realized) || (itb->changed))
2700                _item_block_realize(itb);
2701              _item_block_position(itb, in);
2702           }
2703         else
2704           {
2705              if (itb->realized) _item_block_unrealize(itb);
2706           }
2707         in += itb->count;
2708      }
2709    if ((!sd->wd->reorder_it) || (sd->wd->reorder_pan_move))
2710       _group_items_recalc(sd->wd);
2711    if ((sd->wd->reorder_mode) && (sd->wd->reorder_it))
2712      {
2713         if (sd->wd->pan_y != sd->wd->old_pan_y)
2714            sd->wd->reorder_pan_move = EINA_TRUE;
2715         else sd->wd->reorder_pan_move = EINA_FALSE;
2716         evas_object_raise(sd->wd->reorder_it->base.view);
2717         sd->wd->old_pan_y = sd->wd->pan_y;
2718         sd->wd->start_time = ecore_loop_time_get();
2719      }
2720    _item_auto_scroll(sd->wd);
2721    evas_event_thaw(evas_object_evas_get(obj));
2722    evas_event_thaw_eval(evas_object_evas_get(obj));
2723 }
2724
2725 static void
2726 _pan_move(Evas_Object *obj,
2727           Evas_Coord   x __UNUSED__,
2728           Evas_Coord   y __UNUSED__)
2729 {
2730    Pan *sd = evas_object_smart_data_get(obj);
2731
2732    if (sd->wd->calc_job) ecore_job_del(sd->wd->calc_job);
2733    sd->wd->calc_job = ecore_job_add(_calc_job, sd->wd);
2734 }
2735
2736 static void
2737 _hold_on(void        *data __UNUSED__,
2738          Evas_Object *obj,
2739          void        *event_info __UNUSED__)
2740 {
2741    Widget_Data *wd = elm_widget_data_get(obj);
2742    if (!wd) return;
2743    elm_smart_scroller_hold_set(wd->scr, 1);
2744 }
2745
2746 static void
2747 _hold_off(void        *data __UNUSED__,
2748           Evas_Object *obj,
2749           void        *event_info __UNUSED__)
2750 {
2751    Widget_Data *wd = elm_widget_data_get(obj);
2752    if (!wd) return;
2753    elm_smart_scroller_hold_set(wd->scr, 0);
2754 }
2755
2756 static void
2757 _freeze_on(void        *data __UNUSED__,
2758            Evas_Object *obj,
2759            void        *event_info __UNUSED__)
2760 {
2761    Widget_Data *wd = elm_widget_data_get(obj);
2762    if (!wd) return;
2763    elm_smart_scroller_freeze_set(wd->scr, 1);
2764 }
2765
2766 static void
2767 _freeze_off(void        *data __UNUSED__,
2768             Evas_Object *obj,
2769             void        *event_info __UNUSED__)
2770 {
2771    Widget_Data *wd = elm_widget_data_get(obj);
2772    if (!wd) return;
2773    elm_smart_scroller_freeze_set(wd->scr, 0);
2774 }
2775
2776 static void
2777 _scr_anim_start(void        *data,
2778                 Evas_Object *obj __UNUSED__,
2779                 void        *event_info __UNUSED__)
2780 {
2781    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_START, NULL);
2782 }
2783
2784 static void
2785 _scr_anim_stop(void        *data,
2786                Evas_Object *obj __UNUSED__,
2787                void        *event_info __UNUSED__)
2788 {
2789    evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_STOP, NULL);
2790 }
2791
2792 static void
2793 _scr_drag_start(void            *data,
2794                 Evas_Object     *obj __UNUSED__,
2795                 void            *event_info __UNUSED__)
2796 {
2797    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
2798 }
2799
2800 static void
2801 _scr_drag_stop(void            *data,
2802                Evas_Object     *obj __UNUSED__,
2803                void            *event_info __UNUSED__)
2804 {
2805    evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
2806 }
2807
2808 static void
2809 _scroll_edge_left(void        *data,
2810                   Evas_Object *scr __UNUSED__,
2811                   void        *event_info __UNUSED__)
2812 {
2813    Evas_Object *obj = data;
2814    evas_object_smart_callback_call(obj, SIG_SCROLL_EDGE_LEFT, NULL);
2815 }
2816
2817 static void
2818 _scroll_edge_right(void        *data,
2819                    Evas_Object *scr __UNUSED__,
2820                    void        *event_info __UNUSED__)
2821 {
2822    Evas_Object *obj = data;
2823    evas_object_smart_callback_call(obj, SIG_SCROLL_EDGE_RIGHT, NULL);
2824 }
2825
2826 static void
2827 _scroll_edge_top(void        *data,
2828                  Evas_Object *scr __UNUSED__,
2829                  void        *event_info __UNUSED__)
2830 {
2831    Evas_Object *obj = data;
2832    evas_object_smart_callback_call(obj, SIG_SCROLL_EDGE_TOP, NULL);
2833 }
2834
2835 static void
2836 _scroll_edge_bottom(void        *data,
2837                     Evas_Object *scr __UNUSED__,
2838                     void        *event_info __UNUSED__)
2839 {
2840    Evas_Object *obj = data;
2841    evas_object_smart_callback_call(obj, SIG_SCROLL_EDGE_BOTTOM, NULL);
2842 }
2843
2844 static void
2845 _mode_item_realize(Elm_Genlist_Item *it)
2846 {
2847    char buf[1024];
2848
2849    if ((it->mode_view) || (it->delete_me)) return;
2850
2851    evas_event_freeze(evas_object_evas_get(it->wd->obj));
2852    it->mode_view = edje_object_add(evas_object_evas_get(it->base.widget));
2853    edje_object_scale_set(it->mode_view,
2854                          elm_widget_scale_get(it->base.widget) *
2855                          _elm_config->scale);
2856    evas_object_smart_member_add(it->mode_view, it->wd->pan_smart);
2857    elm_widget_sub_object_add(it->base.widget, it->mode_view);
2858
2859    strncpy(buf, "item", sizeof(buf));
2860    if (it->wd->compress)
2861      strncat(buf, "_compress", sizeof(buf) - strlen(buf));
2862
2863    if (it->order_num_in & 0x1) strncat(buf, "_odd", sizeof(buf) - strlen(buf));
2864    strncat(buf, "/", sizeof(buf) - strlen(buf));
2865    strncat(buf, it->itc->mode_item_style, sizeof(buf) - strlen(buf));
2866
2867    _elm_theme_object_set(it->base.widget, it->mode_view, "genlist", buf,
2868                          elm_widget_style_get(it->base.widget));
2869    edje_object_mirrored_set(it->mode_view,
2870                             elm_widget_mirrored_get(it->base.widget));
2871
2872    /* signal callback add */
2873    evas_object_event_callback_add(it->mode_view, EVAS_CALLBACK_MOUSE_DOWN,
2874                                   _mouse_down, it);
2875    evas_object_event_callback_add(it->mode_view, EVAS_CALLBACK_MOUSE_UP,
2876                                   _mouse_up, it);
2877    evas_object_event_callback_add(it->mode_view, EVAS_CALLBACK_MOUSE_MOVE,
2878                                   _mouse_move, it);
2879
2880    /* label_get, icon_get, state_get */
2881    /* FIXME: If you see that assert, please notify us and we
2882       will clean our mess */
2883    assert(eina_list_count(it->mode_icon_objs) == 0);
2884
2885    _item_label_realize(it, it->mode_view, &it->mode_labels);
2886    it->mode_icon_objs = _item_icon_realize(it,
2887                                            it->mode_view,
2888                                            &it->mode_icons);
2889    _item_state_realize(it, it->mode_view, &it->mode_states);
2890
2891    edje_object_part_swallow(it->mode_view,
2892                             edje_object_data_get(it->mode_view, "mode_part"),
2893                             it->base.view);
2894
2895    it->want_unrealize = EINA_FALSE;
2896    evas_event_thaw(evas_object_evas_get(it->wd->obj));
2897    evas_event_thaw_eval(evas_object_evas_get(it->wd->obj));
2898 }
2899
2900 static void
2901 _mode_item_unrealize(Elm_Genlist_Item *it)
2902 {
2903    Widget_Data *wd = it->wd;
2904    Evas_Object *icon;
2905    if (!it->mode_view) return;
2906
2907    evas_event_freeze(evas_object_evas_get(it->wd->obj));
2908    elm_widget_stringlist_free(it->mode_labels);
2909    it->mode_labels = NULL;
2910    elm_widget_stringlist_free(it->mode_icons);
2911    it->mode_icons = NULL;
2912    elm_widget_stringlist_free(it->mode_states);
2913
2914    EINA_LIST_FREE(it->mode_icon_objs, icon)
2915      evas_object_del(icon);
2916
2917    edje_object_part_unswallow(it->mode_view, it->base.view);
2918    evas_object_smart_member_add(it->base.view, wd->pan_smart);
2919    evas_object_del(it->mode_view);
2920    it->mode_view = NULL;
2921
2922    if (wd->mode_item == it)
2923      wd->mode_item = NULL;
2924    evas_event_thaw(evas_object_evas_get(it->wd->obj));
2925    evas_event_thaw_eval(evas_object_evas_get(it->wd->obj));
2926 }
2927
2928 static void
2929 _item_mode_set(Elm_Genlist_Item *it)
2930 {
2931    if (!it) return;
2932    Widget_Data *wd = it->wd;
2933    if (!wd) return;
2934    char buf[1024];
2935
2936    wd->mode_item = it;
2937    it->nocache = EINA_TRUE;
2938
2939    if (wd->scr_hold_timer)
2940      {
2941         ecore_timer_del(wd->scr_hold_timer);
2942         wd->scr_hold_timer = NULL;
2943      }
2944    elm_smart_scroller_hold_set(wd->scr, EINA_TRUE);
2945    wd->scr_hold_timer = ecore_timer_add(0.1, _scr_hold_timer_cb, wd);
2946
2947    evas_event_freeze(evas_object_evas_get(it->wd->obj));
2948    _mode_item_realize(it);
2949    _item_position(it, it->mode_view, it->scrl_x, it->scrl_y);
2950    evas_event_thaw(evas_object_evas_get(it->wd->obj));
2951    evas_event_thaw_eval(evas_object_evas_get(it->wd->obj));
2952
2953    snprintf(buf, sizeof(buf), "elm,state,%s,active", wd->mode_type);
2954    edje_object_signal_emit(it->mode_view, buf, "elm");
2955 }
2956
2957 static void
2958 _item_mode_unset(Widget_Data *wd)
2959 {
2960    if (!wd) return;
2961    if (!wd->mode_item) return;
2962    char buf[1024], buf2[1024];
2963    Elm_Genlist_Item *it;
2964
2965    it = wd->mode_item;
2966    it->nocache = EINA_TRUE;
2967
2968    snprintf(buf, sizeof(buf), "elm,state,%s,passive", wd->mode_type);
2969    snprintf(buf2, sizeof(buf2), "elm,state,%s,passive,finished", wd->mode_type);
2970
2971    edje_object_signal_emit(it->mode_view, buf, "elm");
2972    edje_object_signal_callback_add(it->mode_view, buf2, "elm", _mode_finished_signal_cb, it);
2973
2974    wd->mode_item = NULL;
2975 }
2976
2977 static void
2978 _item_auto_scroll(Widget_Data *wd)
2979 {
2980    if (!wd) return;
2981    Elm_Genlist_Item  *it;
2982    Eina_List *l;
2983    Evas_Coord ox, oy, ow, oh;
2984
2985    if ((wd->expanded_item) && (wd->auto_scroll_enabled))
2986      {
2987         evas_object_geometry_get(wd->obj, &ox, &oy, &ow, &oh);
2988         if (wd->expanded_item->scrl_y > (oh + oy) / 2)
2989           {
2990              EINA_LIST_FOREACH(wd->expanded_item->items, l, it)
2991                 elm_genlist_item_bring_in(it);
2992           }
2993         wd->auto_scroll_enabled = EINA_FALSE;
2994      }
2995 }
2996
2997 EAPI Evas_Object *
2998 elm_genlist_add(Evas_Object *parent)
2999 {
3000    Evas_Object *obj;
3001    Evas *e;
3002    Widget_Data *wd;
3003    Evas_Coord minw, minh;
3004    static Evas_Smart *smart = NULL;
3005
3006    if (!smart)
3007      {
3008         static Evas_Smart_Class sc;
3009
3010         evas_object_smart_clipped_smart_set(&_pan_sc);
3011         sc = _pan_sc;
3012         sc.name = "elm_genlist_pan";
3013         sc.version = EVAS_SMART_CLASS_VERSION;
3014         sc.add = _pan_add;
3015         sc.del = _pan_del;
3016         sc.resize = _pan_resize;
3017         sc.move = _pan_move;
3018         sc.calculate = _pan_calculate;
3019         if (!(smart = evas_smart_class_new(&sc))) return NULL;
3020      }
3021
3022    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
3023
3024    ELM_SET_WIDTYPE(widtype, "genlist");
3025    elm_widget_type_set(obj, "genlist");
3026    elm_widget_sub_object_add(parent, obj);
3027    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
3028    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
3029    elm_widget_data_set(obj, wd);
3030    elm_widget_del_hook_set(obj, _del_hook);
3031    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
3032    elm_widget_theme_hook_set(obj, _theme_hook);
3033    elm_widget_can_focus_set(obj, EINA_TRUE);
3034    elm_widget_event_hook_set(obj, _event_hook);
3035    elm_widget_on_show_region_hook_set(obj, _show_region_hook, obj);
3036
3037    wd->scr = elm_smart_scroller_add(e);
3038    elm_smart_scroller_widget_set(wd->scr, obj);
3039    elm_smart_scroller_object_theme_set(obj, wd->scr, "genlist", "base",
3040                                        elm_widget_style_get(obj));
3041    elm_smart_scroller_bounce_allow_set(wd->scr, EINA_FALSE,
3042                                        _elm_config->thumbscroll_bounce_enable);
3043    elm_widget_resize_object_set(obj, wd->scr);
3044
3045    evas_object_smart_callback_add(wd->scr, "animate,start", _scr_anim_start, obj);
3046    evas_object_smart_callback_add(wd->scr, "animate,stop", _scr_anim_stop, obj);
3047    evas_object_smart_callback_add(wd->scr, "drag,start", _scr_drag_start, obj);
3048    evas_object_smart_callback_add(wd->scr, "drag,stop", _scr_drag_stop, obj);
3049    evas_object_smart_callback_add(wd->scr, "edge,left", _scroll_edge_left, obj);
3050    evas_object_smart_callback_add(wd->scr, "edge,right", _scroll_edge_right,
3051                                   obj);
3052    evas_object_smart_callback_add(wd->scr, "edge,top", _scroll_edge_top, obj);
3053    evas_object_smart_callback_add(wd->scr, "edge,bottom", _scroll_edge_bottom,
3054                                   obj);
3055
3056    wd->obj = obj;
3057    wd->mode = ELM_LIST_SCROLL;
3058    wd->max_items_per_block = MAX_ITEMS_PER_BLOCK;
3059    wd->item_cache_max = wd->max_items_per_block * 2;
3060    wd->longpress_timeout = _elm_config->longpress_timeout;
3061
3062    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
3063    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
3064    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
3065    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
3066
3067    wd->pan_smart = evas_object_smart_add(e, smart);
3068    wd->pan = evas_object_smart_data_get(wd->pan_smart);
3069    wd->pan->wd = wd;
3070
3071    elm_smart_scroller_extern_pan_set(wd->scr, wd->pan_smart,
3072                                      _pan_set, _pan_get, _pan_max_get,
3073                                      _pan_min_get, _pan_child_size_get);
3074
3075    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
3076                              &minw, &minh);
3077    evas_object_size_hint_min_set(obj, minw, minh);
3078
3079    evas_object_smart_callbacks_descriptions_set(obj, _signals);
3080
3081    _mirrored_set(obj, elm_widget_mirrored_get(obj));
3082    _sizing_eval(obj);
3083    return obj;
3084 }
3085
3086 static Elm_Genlist_Item *
3087 _item_new(Widget_Data                  *wd,
3088           const Elm_Genlist_Item_Class *itc,
3089           const void                   *data,
3090           Elm_Genlist_Item             *parent,
3091           Elm_Genlist_Item_Flags        flags,
3092           Evas_Smart_Cb                 func,
3093           const void                   *func_data)
3094 {
3095    Elm_Genlist_Item *it;
3096
3097    it = elm_widget_item_new(wd->obj, Elm_Genlist_Item);
3098    if (!it) return NULL;
3099    it->wd = wd;
3100    it->itc = itc;
3101    it->base.data = data;
3102    it->parent = parent;
3103    it->flags = flags;
3104    it->func.func = func;
3105    it->func.data = func_data;
3106    it->mouse_cursor = NULL;
3107    it->expanded_depth = 0;
3108    elm_widget_item_text_get_hook_set(it, _item_label_hook);
3109
3110    if (it->parent)
3111      {
3112         if (it->parent->flags & ELM_GENLIST_ITEM_GROUP)
3113           it->group_item = parent;
3114         else if (it->parent->group_item)
3115           it->group_item = it->parent->group_item;
3116      }
3117    return it;
3118 }
3119
3120 static void
3121 _item_block_add(Widget_Data      *wd,
3122                 Elm_Genlist_Item *it)
3123 {
3124    Item_Block *itb = NULL;
3125
3126    if (!it->rel)
3127      {
3128 newblock:
3129         if (it->rel)
3130           {
3131              itb = calloc(1, sizeof(Item_Block));
3132              if (!itb) return;
3133              itb->wd = wd;
3134              if (!it->rel->block)
3135                {
3136                   wd->blocks =
3137                     eina_inlist_append(wd->blocks, EINA_INLIST_GET(itb));
3138                   itb->items = eina_list_append(itb->items, it);
3139                }
3140              else
3141                {
3142                   if (it->before)
3143                     {
3144                        wd->blocks = eina_inlist_prepend_relative
3145                            (wd->blocks, EINA_INLIST_GET(itb),
3146                            EINA_INLIST_GET(it->rel->block));
3147                        itb->items =
3148                          eina_list_prepend_relative(itb->items, it, it->rel);
3149                     }
3150                   else
3151                     {
3152                        wd->blocks = eina_inlist_append_relative
3153                            (wd->blocks, EINA_INLIST_GET(itb),
3154                            EINA_INLIST_GET(it->rel->block));
3155                        itb->items =
3156                          eina_list_append_relative(itb->items, it, it->rel);
3157                     }
3158                }
3159           }
3160         else
3161           {
3162              if (it->before)
3163                {
3164                   if (wd->blocks)
3165                     {
3166                        itb = (Item_Block *)(wd->blocks);
3167                        if (itb->count >= wd->max_items_per_block)
3168                          {
3169                             itb = calloc(1, sizeof(Item_Block));
3170                             if (!itb) return;
3171                             itb->wd = wd;
3172                             wd->blocks =
3173                               eina_inlist_prepend(wd->blocks,
3174                                                   EINA_INLIST_GET(itb));
3175                          }
3176                     }
3177                   else
3178                     {
3179                        itb = calloc(1, sizeof(Item_Block));
3180                        if (!itb) return;
3181                        itb->wd = wd;
3182                        wd->blocks =
3183                          eina_inlist_prepend(wd->blocks, EINA_INLIST_GET(itb));
3184                     }
3185                   itb->items = eina_list_prepend(itb->items, it);
3186                }
3187              else
3188                {
3189                   if (wd->blocks)
3190                     {
3191                        itb = (Item_Block *)(wd->blocks->last);
3192                        if (itb->count >= wd->max_items_per_block)
3193                          {
3194                             itb = calloc(1, sizeof(Item_Block));
3195                             if (!itb) return;
3196                             itb->wd = wd;
3197                             wd->blocks =
3198                               eina_inlist_append(wd->blocks,
3199                                                  EINA_INLIST_GET(itb));
3200                          }
3201                     }
3202                   else
3203                     {
3204                        itb = calloc(1, sizeof(Item_Block));
3205                        if (!itb) return;
3206                        itb->wd = wd;
3207                        wd->blocks =
3208                          eina_inlist_append(wd->blocks, EINA_INLIST_GET(itb));
3209                     }
3210                   itb->items = eina_list_append(itb->items, it);
3211                }
3212           }
3213      }
3214    else
3215      {
3216         itb = it->rel->block;
3217         if (!itb) goto newblock;
3218         if (it->before)
3219           itb->items = eina_list_prepend_relative(itb->items, it, it->rel);
3220         else
3221           itb->items = eina_list_append_relative(itb->items, it, it->rel);
3222      }
3223    itb->count++;
3224    itb->changed = EINA_TRUE;
3225    it->block = itb;
3226    if (itb->wd->calc_job) ecore_job_del(itb->wd->calc_job);
3227    itb->wd->calc_job = ecore_job_add(_calc_job, itb->wd);
3228    if (it->rel)
3229      {
3230         it->rel->relcount--;
3231         if ((it->rel->delete_me) && (!it->rel->relcount))
3232           _item_del(it->rel);
3233         it->rel = NULL;
3234      }
3235    if (itb->count > itb->wd->max_items_per_block)
3236      {
3237         int newc;
3238         Item_Block *itb2;
3239         Elm_Genlist_Item *it2;
3240
3241         newc = itb->count / 2;
3242         itb2 = calloc(1, sizeof(Item_Block));
3243         if (!itb2) return;
3244         itb2->wd = wd;
3245         wd->blocks =
3246           eina_inlist_append_relative(wd->blocks, EINA_INLIST_GET(itb2),
3247                                       EINA_INLIST_GET(itb));
3248         itb2->changed = EINA_TRUE;
3249         while ((itb->count > newc) && (itb->items))
3250           {
3251              Eina_List *l;
3252
3253              l = eina_list_last(itb->items);
3254              it2 = l->data;
3255              itb->items = eina_list_remove_list(itb->items, l);
3256              itb->count--;
3257
3258              itb2->items = eina_list_prepend(itb2->items, it2);
3259              it2->block = itb2;
3260              itb2->count++;
3261           }
3262      }
3263 }
3264
3265 static int
3266 _queue_process(Widget_Data *wd)
3267 {
3268    int n;
3269    Eina_Bool showme = EINA_FALSE;
3270    double t0, t;
3271
3272    t0 = ecore_time_get();
3273    //evas_event_freeze(evas_object_evas_get(wd->obj));
3274    for (n = 0; (wd->queue) && (n < 128); n++)
3275      {
3276         Elm_Genlist_Item *it;
3277
3278         it = wd->queue->data;
3279         wd->queue = eina_list_remove_list(wd->queue, wd->queue);
3280         it->queued = EINA_FALSE;
3281         _item_block_add(wd, it);
3282         t = ecore_time_get();
3283         if (it->block->changed)
3284           {
3285              showme = _item_block_recalc(it->block, it->block->num, EINA_TRUE);
3286              it->block->changed = 0;
3287           }
3288         if (showme) it->block->showme = EINA_TRUE;
3289         if (eina_inlist_count(wd->blocks) > 1)
3290           {
3291              if ((t - t0) > (ecore_animator_frametime_get())) break;
3292           }
3293      }
3294    //evas_event_thaw(evas_object_evas_get(wd->obj));
3295    //evas_event_thaw_eval(evas_object_evas_get(wd->obj));
3296    return n;
3297 }
3298
3299 static Eina_Bool
3300 _idle_process(void *data, Eina_Bool *wakeup)
3301 {
3302    Widget_Data *wd = data;
3303
3304    //xxx
3305    //static double q_start = 0.0;
3306    //if (q_start == 0.0) q_start = ecore_time_get();
3307    //xxx
3308    if (_queue_process(wd) > 0) *wakeup = EINA_TRUE;
3309    if (!wd->queue)
3310      {
3311         //xxx
3312         //printf("PROCESS TIME: %3.3f\n", ecore_time_get() - q_start);
3313         //xxx
3314         return ECORE_CALLBACK_CANCEL;
3315      }
3316    return ECORE_CALLBACK_RENEW;
3317 }
3318
3319 static Eina_Bool
3320 _item_idle_enterer(void *data)
3321 {
3322    Widget_Data *wd = data;
3323    Eina_Bool wakeup = EINA_FALSE;
3324    Eina_Bool ok = _idle_process(data, &wakeup);
3325
3326    if (wakeup)
3327      {
3328         // wake up mainloop
3329         if (wd->calc_job) ecore_job_del(wd->calc_job);
3330         wd->calc_job = ecore_job_add(_calc_job, wd);
3331      }
3332    if (ok == ECORE_CALLBACK_CANCEL) wd->queue_idle_enterer = NULL;
3333    return ok;
3334 }
3335
3336 static void
3337 _item_queue(Widget_Data      *wd,
3338             Elm_Genlist_Item *it)
3339 {
3340    if (it->queued) return;
3341    it->queued = EINA_TRUE;
3342    wd->queue = eina_list_append(wd->queue, it);
3343 // FIXME: why does a freeze then thaw here cause some genlist
3344 // elm_genlist_item_append() to be much much slower?
3345 //   evas_event_freeze(evas_object_evas_get(wd->obj));
3346    while ((wd->queue) && ((!wd->blocks) || (!wd->blocks->next)))
3347      {
3348         if (wd->queue_idle_enterer)
3349           {
3350              ecore_idle_enterer_del(wd->queue_idle_enterer);
3351              wd->queue_idle_enterer = NULL;
3352           }
3353         _queue_process(wd);
3354      }
3355 //   evas_event_thaw(evas_object_evas_get(wd->obj));
3356 //   evas_event_thaw_eval(evas_object_evas_get(wd->obj));
3357    if (!wd->queue_idle_enterer)
3358      wd->queue_idle_enterer = ecore_idle_enterer_add(_item_idle_enterer, wd);
3359 }
3360
3361 static int
3362 _elm_genlist_item_compare_data(const void *data, const void *data1)
3363 {
3364    const Elm_Genlist_Item *item = data;
3365    const Elm_Genlist_Item *item1 = data1;
3366
3367    return _elm_genlist_item_compare_data_cb(item->base.data, item1->base.data);
3368 }
3369
3370 static int
3371 _elm_genlist_item_compare(const void *data, const void *data1)
3372 {
3373    const Elm_Genlist_Item *item, *item1;
3374    item = ELM_GENLIST_ITEM_FROM_INLIST(data);
3375    item1 = ELM_GENLIST_ITEM_FROM_INLIST(data1);
3376    return _elm_genlist_item_compare_cb(item, item1);
3377 }
3378
3379 static int
3380 _elm_genlist_item_list_compare(const void *data, const void *data1)
3381 {
3382    const Elm_Genlist_Item *item = data;
3383    const Elm_Genlist_Item *item1 = data1;
3384    return _elm_genlist_item_compare_cb(item, item1);
3385 }
3386
3387 static void
3388 _item_move_after(Elm_Genlist_Item *it, Elm_Genlist_Item *after)
3389 {
3390    if (!it) return;
3391    if (!after) return;
3392
3393    it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
3394    _item_block_del(it);
3395
3396    it->wd->items = eina_inlist_append_relative(it->wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(after));
3397    it->rel = after;
3398    it->rel->relcount++;
3399    it->before = EINA_FALSE;
3400    if (after->group_item) it->group_item = after->group_item;
3401    _item_queue(it->wd, it);
3402
3403    // TODO: change this to smart callback
3404    if (it->itc->func.moved)
3405      it->itc->func.moved(it->base.widget, it, after, EINA_TRUE);
3406 }
3407
3408 static void
3409 _item_move_before(Elm_Genlist_Item *it, Elm_Genlist_Item *before)
3410 {
3411    if (!it) return;
3412    if (!before) return;
3413
3414    it->wd->items = eina_inlist_remove(it->wd->items, EINA_INLIST_GET(it));
3415    _item_block_del(it);
3416    it->wd->items = eina_inlist_prepend_relative(it->wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(before));
3417    it->rel = before;
3418    it->rel->relcount++;
3419    it->before = EINA_TRUE;
3420    if (before->group_item) it->group_item = before->group_item;
3421    _item_queue(it->wd, it);
3422
3423    // TODO: change this to smart callback
3424    if (it->itc->func.moved)
3425      it->itc->func.moved(it->base.widget, it, before, EINA_FALSE);
3426 }
3427
3428 EAPI Elm_Genlist_Item *
3429 elm_genlist_item_append(Evas_Object                  *obj,
3430                         const Elm_Genlist_Item_Class *itc,
3431                         const void                   *data,
3432                         Elm_Genlist_Item             *parent,
3433                         Elm_Genlist_Item_Flags        flags,
3434                         Evas_Smart_Cb                 func,
3435                         const void                   *func_data)
3436 {
3437    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3438    Widget_Data *wd = elm_widget_data_get(obj);
3439    if (!wd) return NULL;
3440    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func,
3441                                     func_data);
3442    if (!it) return NULL;
3443    if (!it->parent)
3444      {
3445         if (flags & ELM_GENLIST_ITEM_GROUP)
3446           wd->group_items = eina_list_append(wd->group_items, it);
3447         wd->items = eina_inlist_append(wd->items, EINA_INLIST_GET(it));
3448         it->rel = NULL;
3449      }
3450    else
3451      {
3452         Elm_Genlist_Item *it2 = NULL;
3453         Eina_List *ll = eina_list_last(it->parent->items);
3454         if (ll) it2 = ll->data;
3455         it->parent->items = eina_list_append(it->parent->items, it);
3456         if (!it2) it2 = it->parent;
3457         wd->items =
3458           eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it),
3459                                       EINA_INLIST_GET(it2));
3460         it->rel = it2;
3461         it->rel->relcount++;
3462      }
3463    it->before = EINA_FALSE;
3464    _item_queue(wd, it);
3465    return it;
3466 }
3467
3468 EAPI Elm_Genlist_Item *
3469 elm_genlist_item_prepend(Evas_Object                  *obj,
3470                          const Elm_Genlist_Item_Class *itc,
3471                          const void                   *data,
3472                          Elm_Genlist_Item             *parent,
3473                          Elm_Genlist_Item_Flags        flags,
3474                          Evas_Smart_Cb                 func,
3475                          const void                   *func_data)
3476 {
3477    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3478    Widget_Data *wd = elm_widget_data_get(obj);
3479    if (!wd) return NULL;
3480    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func,
3481                                     func_data);
3482    if (!it) return NULL;
3483    if (!it->parent)
3484      {
3485         if (flags & ELM_GENLIST_ITEM_GROUP)
3486           wd->group_items = eina_list_prepend(wd->group_items, it);
3487         wd->items = eina_inlist_prepend(wd->items, EINA_INLIST_GET(it));
3488         it->rel = NULL;
3489      }
3490    else
3491      {
3492         Elm_Genlist_Item *it2 = NULL;
3493         Eina_List *ll = it->parent->items;
3494         if (ll) it2 = ll->data;
3495         it->parent->items = eina_list_prepend(it->parent->items, it);
3496         if (!it2) it2 = it->parent;
3497         wd->items =
3498           eina_inlist_prepend_relative(wd->items, EINA_INLIST_GET(it),
3499                                        EINA_INLIST_GET(it2));
3500         it->rel = it2;
3501         it->rel->relcount++;
3502      }
3503    it->before = EINA_TRUE;
3504    _item_queue(wd, it);
3505    return it;
3506 }
3507
3508 EAPI Elm_Genlist_Item *
3509 elm_genlist_item_insert_after(Evas_Object                  *obj,
3510                               const Elm_Genlist_Item_Class *itc,
3511                               const void                   *data,
3512                               Elm_Genlist_Item             *parent,
3513                               Elm_Genlist_Item             *after,
3514                               Elm_Genlist_Item_Flags        flags,
3515                               Evas_Smart_Cb                 func,
3516                               const void                   *func_data)
3517 {
3518    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3519    EINA_SAFETY_ON_NULL_RETURN_VAL(after, NULL);
3520    Widget_Data *wd = elm_widget_data_get(obj);
3521    if (!wd) return NULL;
3522    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func,
3523                                     func_data);
3524    if (!it) return NULL;
3525    /* It makes no sense to insert after in an empty list with after != NULL, something really bad is happening in your app. */
3526    EINA_SAFETY_ON_NULL_RETURN_VAL(wd->items, NULL);
3527
3528    if (!it->parent)
3529      {
3530         if ((flags & ELM_GENLIST_ITEM_GROUP) &&
3531             (after->flags & ELM_GENLIST_ITEM_GROUP))
3532           {
3533              Elm_Genlist_Item *it2 = NULL;
3534              Eina_List *ll = eina_list_last(after->items);
3535              if (ll) it2 = ll->data;
3536              else it2 = after;
3537
3538              wd->items =
3539                 eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it),
3540                                             EINA_INLIST_GET(it2));
3541              it->rel = it2;
3542              wd->group_items = eina_list_append_relative(wd->group_items, it,
3543                                                          after);
3544           }
3545      }
3546    else
3547      {
3548         it->parent->items = eina_list_append_relative(it->parent->items, it,
3549                                                       after);
3550         wd->items = eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it),
3551                                                 EINA_INLIST_GET(after));
3552         it->rel = after;
3553      }
3554    it->rel->relcount++;
3555    it->before = EINA_FALSE;
3556    _item_queue(wd, it);
3557    return it;
3558 }
3559
3560 EAPI Elm_Genlist_Item *
3561 elm_genlist_item_insert_before(Evas_Object                  *obj,
3562                                const Elm_Genlist_Item_Class *itc,
3563                                const void                   *data,
3564                                Elm_Genlist_Item             *parent,
3565                                Elm_Genlist_Item             *before,
3566                                Elm_Genlist_Item_Flags        flags,
3567                                Evas_Smart_Cb                 func,
3568                                const void                   *func_data)
3569 {
3570    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3571    EINA_SAFETY_ON_NULL_RETURN_VAL(before, NULL);
3572    Widget_Data *wd = elm_widget_data_get(obj);
3573    if (!wd) return NULL;
3574    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func,
3575                                     func_data);
3576    if (!it) return NULL;
3577    /* It makes no sense to insert before in an empty list with before != NULL, something really bad is happening in your app. */
3578    EINA_SAFETY_ON_NULL_RETURN_VAL(wd->items, NULL);
3579
3580    if (!it->parent)
3581      {
3582         if ((flags & ELM_GENLIST_ITEM_GROUP) &&
3583             (before->flags & ELM_GENLIST_ITEM_GROUP))
3584           wd->group_items = eina_list_prepend_relative(wd->group_items, it,
3585                                                        before);
3586      }
3587    else
3588      {
3589         it->parent->items = eina_list_prepend_relative(it->parent->items, it,
3590                                                        before);
3591      }
3592    wd->items = eina_inlist_prepend_relative(wd->items, EINA_INLIST_GET(it),
3593                                             EINA_INLIST_GET(before));
3594    it->rel = before;
3595    it->rel->relcount++;
3596    it->before = EINA_TRUE;
3597    _item_queue(wd, it);
3598    return it;
3599 }
3600
3601 EAPI Elm_Genlist_Item *
3602 elm_genlist_item_direct_sorted_insert(Evas_Object                  *obj,
3603                                       const Elm_Genlist_Item_Class *itc,
3604                                       const void                   *data,
3605                                       Elm_Genlist_Item             *parent,
3606                                       Elm_Genlist_Item_Flags        flags,
3607                                       Eina_Compare_Cb               comp,
3608                                       Evas_Smart_Cb                 func,
3609                                       const void                   *func_data)
3610 {
3611    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3612    Widget_Data *wd = elm_widget_data_get(obj);
3613    if (!wd) return NULL;
3614    Elm_Genlist_Item *rel = NULL;
3615    Elm_Genlist_Item *it = _item_new(wd, itc, data, parent, flags, func,
3616                                     func_data);
3617    if (!it) return NULL;
3618
3619    _elm_genlist_item_compare_cb = comp;
3620
3621    if (it->parent)
3622      {
3623         Eina_List *l;
3624         int cmp_result;
3625
3626         l = eina_list_search_sorted_near_list(it->parent->items,
3627                                               _elm_genlist_item_list_compare, it,
3628                                               &cmp_result);
3629         if (l)
3630           rel = eina_list_data_get(l);
3631         else
3632           rel = it->parent;
3633
3634         if (cmp_result >= 0)
3635           {
3636              it->parent->items = eina_list_prepend_relative_list(it->parent->items, it, l);
3637              wd->items = eina_inlist_prepend_relative(wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(rel));
3638              it->before = EINA_FALSE;
3639           }
3640         else if (cmp_result < 0)
3641           {
3642              it->parent->items = eina_list_append_relative_list(it->parent->items, it, l);
3643              wd->items = eina_inlist_append_relative(wd->items, EINA_INLIST_GET(it), EINA_INLIST_GET(rel));
3644              it->before = EINA_TRUE;
3645           }
3646      }
3647    else
3648      {
3649         if (flags & ELM_GENLIST_ITEM_GROUP)
3650           wd->group_items = eina_list_append(wd->group_items, it);
3651
3652         wd->items = eina_inlist_sorted_insert(wd->items, EINA_INLIST_GET(it),
3653                                               _elm_genlist_item_compare);
3654
3655         if (EINA_INLIST_GET(it)->next)
3656           {
3657              rel = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
3658              it->before = EINA_TRUE;
3659           }
3660         else if (EINA_INLIST_GET(it)->prev)
3661           {
3662              rel = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
3663              it->before = EINA_FALSE;
3664           }
3665      }
3666
3667    if (rel)
3668      {
3669         it->rel = rel;
3670         it->rel->relcount++;
3671      }
3672
3673    _item_queue(wd, it);
3674
3675    return it;
3676 }
3677
3678 EAPI Elm_Genlist_Item *
3679 elm_genlist_item_sorted_insert(Evas_Object                  *obj,
3680                                const Elm_Genlist_Item_Class *itc,
3681                                const void                   *data,
3682                                Elm_Genlist_Item             *parent,
3683                                Elm_Genlist_Item_Flags        flags,
3684                                Eina_Compare_Cb               comp,
3685                                Evas_Smart_Cb                 func,
3686                                const void                   *func_data)
3687 {
3688    _elm_genlist_item_compare_data_cb = comp;
3689
3690    return elm_genlist_item_direct_sorted_insert(obj, itc, data, parent, flags,
3691                                                 _elm_genlist_item_compare_data, func, func_data);
3692 }
3693
3694 EAPI void
3695 elm_genlist_clear(Evas_Object *obj)
3696 {
3697    ELM_CHECK_WIDTYPE(obj, widtype);
3698    Widget_Data *wd = elm_widget_data_get(obj);
3699    if (!wd) return;
3700    if (wd->walking > 0)
3701      {
3702         Elm_Genlist_Item *it;
3703
3704         wd->clear_me = EINA_TRUE;
3705         EINA_INLIST_FOREACH(wd->items, it)
3706           {
3707              it->delete_me = EINA_TRUE;
3708           }
3709         return;
3710      }
3711    evas_event_freeze(evas_object_evas_get(wd->obj));
3712    while (wd->items)
3713      {
3714         Elm_Genlist_Item *it = ELM_GENLIST_ITEM_FROM_INLIST(wd->items);
3715
3716         if (wd->anchor_item == it)
3717           {
3718              wd->anchor_item = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
3719              if (!wd->anchor_item)
3720                wd->anchor_item =
3721                  ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
3722           }
3723         wd->items = eina_inlist_remove(wd->items, wd->items);
3724         if (it->flags & ELM_GENLIST_ITEM_GROUP)
3725           it->wd->group_items = eina_list_remove(it->wd->group_items, it);
3726         elm_widget_item_pre_notify_del(it);
3727         if (it->realized) _item_unrealize(it, EINA_FALSE);
3728         if (((wd->clear_me) || (!it->delete_me)) && (it->itc->func.del))
3729           it->itc->func.del((void *)it->base.data, it->base.widget);
3730         if (it->long_timer) ecore_timer_del(it->long_timer);
3731         if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
3732         elm_widget_item_del(it);
3733      }
3734    wd->clear_me = EINA_FALSE;
3735    wd->anchor_item = NULL;
3736    while (wd->blocks)
3737      {
3738         Item_Block *itb = (Item_Block *)(wd->blocks);
3739
3740         wd->blocks = eina_inlist_remove(wd->blocks, wd->blocks);
3741         if (itb->items) eina_list_free(itb->items);
3742         free(itb);
3743      }
3744    if (wd->calc_job)
3745      {
3746         ecore_job_del(wd->calc_job);
3747         wd->calc_job = NULL;
3748      }
3749    if (wd->queue_idle_enterer)
3750      {
3751         ecore_idle_enterer_del(wd->queue_idle_enterer);
3752         wd->queue_idle_enterer = NULL;
3753      }
3754    if (wd->must_recalc_idler)
3755      {
3756         ecore_idler_del(wd->must_recalc_idler);
3757         wd->must_recalc_idler = NULL;
3758      }
3759    if (wd->queue)
3760      {
3761         eina_list_free(wd->queue);
3762         wd->queue = NULL;
3763      }
3764    if (wd->selected)
3765      {
3766         eina_list_free(wd->selected);
3767         wd->selected = NULL;
3768      }
3769    if (wd->reorder_move_animator)
3770      {
3771         ecore_animator_del(wd->reorder_move_animator);
3772         wd->reorder_move_animator = NULL;
3773      }
3774    wd->show_item = NULL;
3775    wd->pan_x = 0;
3776    wd->pan_y = 0;
3777    wd->old_pan_y = 0;
3778    wd->minw = 0;
3779    wd->minh = 0;
3780    if (wd->pan_smart)
3781      {
3782         evas_object_size_hint_min_set(wd->pan_smart, wd->minw, wd->minh);
3783         evas_object_smart_callback_call(wd->pan_smart, "changed", NULL);
3784      }
3785    _sizing_eval(obj);
3786    evas_event_thaw(evas_object_evas_get(wd->obj));
3787    evas_event_thaw_eval(evas_object_evas_get(wd->obj));
3788 }
3789
3790 EAPI void
3791 elm_genlist_multi_select_set(Evas_Object *obj,
3792                              Eina_Bool    multi)
3793 {
3794    ELM_CHECK_WIDTYPE(obj, widtype);
3795    Widget_Data *wd = elm_widget_data_get(obj);
3796    if (!wd) return;
3797    wd->multi = multi;
3798 }
3799
3800 EAPI Eina_Bool
3801 elm_genlist_multi_select_get(const Evas_Object *obj)
3802 {
3803    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
3804    Widget_Data *wd = elm_widget_data_get(obj);
3805    if (!wd) return EINA_FALSE;
3806    return wd->multi;
3807 }
3808
3809 EAPI Elm_Genlist_Item *
3810 elm_genlist_selected_item_get(const Evas_Object *obj)
3811 {
3812    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3813    Widget_Data *wd = elm_widget_data_get(obj);
3814    if (!wd) return NULL;
3815    if (wd->selected) return wd->selected->data;
3816    return NULL;
3817 }
3818
3819 EAPI const Eina_List *
3820 elm_genlist_selected_items_get(const Evas_Object *obj)
3821 {
3822    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3823    Widget_Data *wd = elm_widget_data_get(obj);
3824    if (!wd) return NULL;
3825    return wd->selected;
3826 }
3827
3828 EAPI Eina_List *
3829 elm_genlist_realized_items_get(const Evas_Object *obj)
3830 {
3831    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3832    Widget_Data *wd = elm_widget_data_get(obj);
3833    Eina_List *list = NULL;
3834    Item_Block *itb;
3835    Eina_Bool done = EINA_FALSE;
3836    if (!wd) return NULL;
3837    EINA_INLIST_FOREACH(wd->blocks, itb)
3838      {
3839         if (itb->realized)
3840           {
3841              Eina_List *l;
3842              Elm_Genlist_Item *it;
3843
3844              done = 1;
3845              EINA_LIST_FOREACH(itb->items, l, it)
3846                {
3847                   if (it->realized) list = eina_list_append(list, it);
3848                }
3849           }
3850         else
3851           {
3852              if (done) break;
3853           }
3854      }
3855    return list;
3856 }
3857
3858 EAPI Elm_Genlist_Item *
3859 elm_genlist_at_xy_item_get(const Evas_Object *obj,
3860                            Evas_Coord         x,
3861                            Evas_Coord         y,
3862                            int               *posret)
3863 {
3864    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3865    Widget_Data *wd = elm_widget_data_get(obj);
3866    Evas_Coord ox, oy, ow, oh;
3867    Item_Block *itb;
3868    Evas_Coord lasty;
3869    if (!wd) return NULL;
3870    evas_object_geometry_get(wd->pan_smart, &ox, &oy, &ow, &oh);
3871    lasty = oy;
3872    EINA_INLIST_FOREACH(wd->blocks, itb)
3873      {
3874         Eina_List *l;
3875         Elm_Genlist_Item *it;
3876
3877         if (!ELM_RECTS_INTERSECT(ox + itb->x - itb->wd->pan_x,
3878                                  oy + itb->y - itb->wd->pan_y,
3879                                  itb->w, itb->h, x, y, 1, 1))
3880           continue;
3881         EINA_LIST_FOREACH(itb->items, l, it)
3882           {
3883              Evas_Coord itx, ity;
3884
3885              itx = ox + itb->x + it->x - itb->wd->pan_x;
3886              ity = oy + itb->y + it->y - itb->wd->pan_y;
3887              if (ELM_RECTS_INTERSECT(itx, ity, it->w, it->h, x, y, 1, 1))
3888                {
3889                   if (posret)
3890                     {
3891                        if (y <= (ity + (it->h / 4))) *posret = -1;
3892                        else if (y >= (ity + it->h - (it->h / 4)))
3893                          *posret = 1;
3894                        else *posret = 0;
3895                     }
3896                   return it;
3897                }
3898              lasty = ity + it->h;
3899           }
3900      }
3901    if (posret)
3902      {
3903         if (y > lasty) *posret = 1;
3904         else *posret = -1;
3905      }
3906    return NULL;
3907 }
3908
3909 EAPI Elm_Genlist_Item *
3910 elm_genlist_first_item_get(const Evas_Object *obj)
3911 {
3912    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3913    Widget_Data *wd = elm_widget_data_get(obj);
3914    if (!wd) return NULL;
3915    if (!wd->items) return NULL;
3916    Elm_Genlist_Item *it = ELM_GENLIST_ITEM_FROM_INLIST(wd->items);
3917    while ((it) && (it->delete_me))
3918      it = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
3919    return it;
3920 }
3921
3922 EAPI Elm_Genlist_Item *
3923 elm_genlist_last_item_get(const Evas_Object *obj)
3924 {
3925    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
3926    Widget_Data *wd = elm_widget_data_get(obj);
3927    if (!wd) return NULL;
3928    if (!wd->items) return NULL;
3929    Elm_Genlist_Item *it = ELM_GENLIST_ITEM_FROM_INLIST(wd->items->last);
3930    while ((it) && (it->delete_me))
3931      it = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
3932    return it;
3933 }
3934
3935 EAPI Elm_Genlist_Item *
3936 elm_genlist_item_next_get(const Elm_Genlist_Item *it)
3937 {
3938    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
3939    while (it)
3940      {
3941         it = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->next);
3942         if ((it) && (!it->delete_me)) break;
3943      }
3944    return (Elm_Genlist_Item *)it;
3945 }
3946
3947 EAPI Elm_Genlist_Item *
3948 elm_genlist_item_prev_get(const Elm_Genlist_Item *it)
3949 {
3950    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
3951    while (it)
3952      {
3953         it = ELM_GENLIST_ITEM_FROM_INLIST(EINA_INLIST_GET(it)->prev);
3954         if ((it) && (!it->delete_me)) break;
3955      }
3956    return (Elm_Genlist_Item *)it;
3957 }
3958
3959 EAPI Evas_Object *
3960 elm_genlist_item_genlist_get(const Elm_Genlist_Item *it)
3961 {
3962    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
3963    return it->base.widget;
3964 }
3965
3966 EAPI Elm_Genlist_Item *
3967 elm_genlist_item_parent_get(const Elm_Genlist_Item *it)
3968 {
3969    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
3970    return it->parent;
3971 }
3972
3973 EAPI void
3974 elm_genlist_item_subitems_clear(Elm_Genlist_Item *it)
3975 {
3976    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
3977    Eina_List *tl = NULL, *l;
3978    Elm_Genlist_Item *it2;
3979
3980    EINA_LIST_FOREACH(it->items, l, it2)
3981      tl = eina_list_append(tl, it2);
3982    EINA_LIST_FREE(tl, it2)
3983      elm_genlist_item_del(it2);
3984 }
3985
3986 EAPI void
3987 elm_genlist_item_selected_set(Elm_Genlist_Item *it,
3988                               Eina_Bool         selected)
3989 {
3990    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
3991    Widget_Data *wd = elm_widget_data_get(it->base.widget);
3992    if (!wd) return;
3993    if ((it->delete_me) || (it->disabled)) return;
3994    selected = !!selected;
3995    if (it->selected == selected) return;
3996
3997    if (selected)
3998      {
3999         if (!wd->multi)
4000           {
4001              while (wd->selected)
4002                {
4003                   _item_unhighlight(wd->selected->data);
4004                   _item_unselect(wd->selected->data);
4005                }
4006           }
4007         _item_highlight(it);
4008         _item_select(it);
4009      }
4010    else
4011      {
4012         _item_unhighlight(it);
4013         _item_unselect(it);
4014      }
4015 }
4016
4017 EAPI Eina_Bool
4018 elm_genlist_item_selected_get(const Elm_Genlist_Item *it)
4019 {
4020    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
4021    return it->selected;
4022 }
4023
4024 EAPI void
4025 elm_genlist_item_expanded_set(Elm_Genlist_Item *it,
4026                               Eina_Bool         expanded)
4027 {
4028    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4029    if (it->expanded == expanded) return;
4030    it->expanded = expanded;
4031    it->wd->expanded_item = it;
4032    if (it->expanded)
4033      {
4034         if (it->realized)
4035           edje_object_signal_emit(it->base.view, "elm,state,expanded", "elm");
4036         evas_object_smart_callback_call(it->base.widget, SIG_EXPANDED, it);
4037         it->wd->auto_scroll_enabled = EINA_TRUE;
4038      }
4039    else
4040      {
4041         if (it->realized)
4042           edje_object_signal_emit(it->base.view, "elm,state,contracted", "elm");
4043         evas_object_smart_callback_call(it->base.widget, SIG_CONTRACTED, it);
4044         it->wd->auto_scroll_enabled = EINA_FALSE;
4045      }
4046 }
4047
4048 EAPI Eina_Bool
4049 elm_genlist_item_expanded_get(const Elm_Genlist_Item *it)
4050 {
4051    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
4052    return it->expanded;
4053 }
4054
4055 EAPI int
4056 elm_genlist_item_expanded_depth_get(const Elm_Genlist_Item *it)
4057 {
4058    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, 0);
4059    return it->expanded_depth;
4060 }
4061
4062 EAPI void
4063 elm_genlist_item_disabled_set(Elm_Genlist_Item *it,
4064                               Eina_Bool         disabled)
4065 {
4066    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4067    Eina_List *l;
4068    Evas_Object *obj;
4069    if (it->disabled == disabled) return;
4070    if (it->delete_me) return;
4071    it->disabled = !!disabled;
4072    if (it->selected)
4073      elm_genlist_item_selected_set(it, EINA_FALSE);
4074    if (it->realized)
4075      {
4076         if (it->disabled)
4077           edje_object_signal_emit(it->base.view, "elm,state,disabled", "elm");
4078         else
4079           edje_object_signal_emit(it->base.view, "elm,state,enabled", "elm");
4080         EINA_LIST_FOREACH(it->icon_objs, l, obj)
4081           elm_widget_disabled_set(obj, disabled);
4082      }
4083 }
4084
4085 EAPI Eina_Bool
4086 elm_genlist_item_disabled_get(const Elm_Genlist_Item *it)
4087 {
4088    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
4089    if (it->delete_me) return EINA_FALSE;
4090    return it->disabled;
4091 }
4092
4093 EAPI void
4094 elm_genlist_item_display_only_set(Elm_Genlist_Item *it,
4095                                   Eina_Bool         display_only)
4096 {
4097    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4098    if (it->display_only == display_only) return;
4099    if (it->delete_me) return;
4100    it->display_only = display_only;
4101    it->mincalcd = EINA_FALSE;
4102    it->updateme = EINA_TRUE;
4103    if (it->block) it->block->updateme = EINA_TRUE;
4104    if (it->wd->update_job) ecore_job_del(it->wd->update_job);
4105    it->wd->update_job = ecore_job_add(_update_job, it->wd);
4106 }
4107
4108 EAPI Eina_Bool
4109 elm_genlist_item_display_only_get(const Elm_Genlist_Item *it)
4110 {
4111    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, EINA_FALSE);
4112    if (it->delete_me) return EINA_FALSE;
4113    return it->display_only;
4114 }
4115
4116 EAPI void
4117 elm_genlist_item_show(Elm_Genlist_Item *it)
4118 {
4119    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4120    Evas_Coord gith = 0;
4121    if (it->delete_me) return;
4122    if ((it->queued) || (!it->mincalcd))
4123      {
4124         it->wd->show_item = it;
4125         it->wd->bring_in = EINA_TRUE;
4126         it->showme = EINA_TRUE;
4127         return;
4128      }
4129    if (it->wd->show_item)
4130      {
4131         it->wd->show_item->showme = EINA_FALSE;
4132         it->wd->show_item = NULL;
4133      }
4134    if ((it->group_item) && (it->wd->pan_y > (it->y + it->block->y)))
4135      gith = it->group_item->h;
4136    elm_smart_scroller_child_region_show(it->wd->scr,
4137                                         it->x + it->block->x,
4138                                         it->y + it->block->y - gith,
4139                                         it->block->w, it->h);
4140 }
4141
4142 EAPI void
4143 elm_genlist_item_bring_in(Elm_Genlist_Item *it)
4144 {
4145    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4146    Evas_Coord gith = 0;
4147    if (it->delete_me) return;
4148    if ((it->queued) || (!it->mincalcd))
4149      {
4150         it->wd->show_item = it;
4151         it->wd->bring_in = EINA_TRUE;
4152         it->showme = EINA_TRUE;
4153         return;
4154      }
4155    if (it->wd->show_item)
4156      {
4157         it->wd->show_item->showme = EINA_FALSE;
4158         it->wd->show_item = NULL;
4159      }
4160    if ((it->group_item) && (it->wd->pan_y > (it->y + it->block->y)))
4161      gith = it->group_item->h;
4162    elm_smart_scroller_region_bring_in(it->wd->scr,
4163                                       it->x + it->block->x,
4164                                       it->y + it->block->y - gith,
4165                                       it->block->w, it->h);
4166 }
4167
4168 EAPI void
4169 elm_genlist_item_top_show(Elm_Genlist_Item *it)
4170 {
4171    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4172    Evas_Coord ow, oh;
4173    Evas_Coord gith = 0;
4174
4175    if (it->delete_me) return;
4176    if ((it->queued) || (!it->mincalcd))
4177      {
4178         it->wd->show_item = it;
4179         it->wd->bring_in = EINA_TRUE;
4180         it->showme = EINA_TRUE;
4181         return;
4182      }
4183    if (it->wd->show_item)
4184      {
4185         it->wd->show_item->showme = EINA_FALSE;
4186         it->wd->show_item = NULL;
4187      }
4188    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
4189    if (it->group_item) gith = it->group_item->h;
4190    elm_smart_scroller_child_region_show(it->wd->scr,
4191                                         it->x + it->block->x,
4192                                         it->y + it->block->y - gith,
4193                                         it->block->w, oh);
4194 }
4195
4196 EAPI void
4197 elm_genlist_item_top_bring_in(Elm_Genlist_Item *it)
4198 {
4199    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4200    Evas_Coord ow, oh;
4201    Evas_Coord gith = 0;
4202
4203    if (it->delete_me) return;
4204    if ((it->queued) || (!it->mincalcd))
4205      {
4206         it->wd->show_item = it;
4207         it->wd->bring_in = EINA_TRUE;
4208         it->showme = EINA_TRUE;
4209         return;
4210      }
4211    if (it->wd->show_item)
4212      {
4213         it->wd->show_item->showme = EINA_FALSE;
4214         it->wd->show_item = NULL;
4215      }
4216    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
4217    if (it->group_item) gith = it->group_item->h;
4218    elm_smart_scroller_region_bring_in(it->wd->scr,
4219                                       it->x + it->block->x,
4220                                       it->y + it->block->y - gith,
4221                                       it->block->w, oh);
4222 }
4223
4224 EAPI void
4225 elm_genlist_item_middle_show(Elm_Genlist_Item *it)
4226 {
4227    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4228    Evas_Coord ow, oh;
4229
4230    if (it->delete_me) return;
4231    if ((it->queued) || (!it->mincalcd))
4232      {
4233         it->wd->show_item = it;
4234         it->wd->bring_in = EINA_TRUE;
4235         it->showme = EINA_TRUE;
4236         return;
4237      }
4238    if (it->wd->show_item)
4239      {
4240         it->wd->show_item->showme = EINA_FALSE;
4241         it->wd->show_item = NULL;
4242      }
4243    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
4244    elm_smart_scroller_child_region_show(it->wd->scr,
4245                                         it->x + it->block->x,
4246                                         it->y + it->block->y - oh / 2 +
4247                                         it->h / 2, it->block->w, oh);
4248 }
4249
4250 EAPI void
4251 elm_genlist_item_middle_bring_in(Elm_Genlist_Item *it)
4252 {
4253    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4254    Evas_Coord ow, oh;
4255
4256    if (it->delete_me) return;
4257    if ((it->queued) || (!it->mincalcd))
4258      {
4259         it->wd->show_item = it;
4260         it->wd->bring_in = EINA_TRUE;
4261         it->showme = EINA_TRUE;
4262         return;
4263      }
4264    if (it->wd->show_item)
4265      {
4266         it->wd->show_item->showme = EINA_FALSE;
4267         it->wd->show_item = NULL;
4268      }
4269    evas_object_geometry_get(it->wd->pan_smart, NULL, NULL, &ow, &oh);
4270    elm_smart_scroller_region_bring_in(it->wd->scr,
4271                                       it->x + it->block->x,
4272                                       it->y + it->block->y - oh / 2 + it->h / 2,
4273                                       it->block->w, oh);
4274 }
4275
4276 EAPI void
4277 elm_genlist_item_del(Elm_Genlist_Item *it)
4278 {
4279    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4280    if ((it->relcount > 0) || (it->walking > 0))
4281      {
4282         elm_widget_item_pre_notify_del(it);
4283         elm_genlist_item_subitems_clear(it);
4284         it->delete_me = EINA_TRUE;
4285         if (it->wd->show_item == it) it->wd->show_item = NULL;
4286         if (it->selected)
4287           it->wd->selected = eina_list_remove(it->wd->selected,
4288                                               it);
4289         if (it->block)
4290           {
4291              if (it->realized) _item_unrealize(it, EINA_FALSE);
4292              it->block->changed = EINA_TRUE;
4293              if (it->wd->calc_job) ecore_job_del(it->wd->calc_job);
4294              it->wd->calc_job = ecore_job_add(_calc_job, it->wd);
4295           }
4296         if (it->itc->func.del)
4297           it->itc->func.del((void *)it->base.data, it->base.widget);
4298         return;
4299      }
4300    _item_del(it);
4301 }
4302
4303 EAPI void
4304 elm_genlist_item_data_set(Elm_Genlist_Item *it,
4305                           const void       *data)
4306 {
4307    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4308    elm_widget_item_data_set(it, data);
4309 }
4310
4311 EAPI void *
4312 elm_genlist_item_data_get(const Elm_Genlist_Item *it)
4313 {
4314    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
4315    return elm_widget_item_data_get(it);
4316 }
4317
4318 EAPI void
4319 elm_genlist_item_icons_orphan(Elm_Genlist_Item *it)
4320 {
4321    Evas_Object *icon;
4322    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4323    EINA_LIST_FREE(it->icon_objs, icon)
4324      {
4325         elm_widget_sub_object_del(it->base.widget, icon);
4326         evas_object_smart_member_del(icon);
4327         evas_object_hide(icon);
4328      }
4329 }
4330
4331 EAPI const Evas_Object *
4332 elm_genlist_item_object_get(const Elm_Genlist_Item *it)
4333 {
4334    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
4335    return it->base.view;
4336 }
4337
4338 EAPI void
4339 elm_genlist_item_update(Elm_Genlist_Item *it)
4340 {
4341    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4342    if (!it->block) return;
4343    if (it->delete_me) return;
4344    it->mincalcd = EINA_FALSE;
4345    it->updateme = EINA_TRUE;
4346    it->block->updateme = EINA_TRUE;
4347    if (it->wd->update_job) ecore_job_del(it->wd->update_job);
4348    it->wd->update_job = ecore_job_add(_update_job, it->wd);
4349 }
4350
4351 EAPI void
4352 elm_genlist_item_item_class_update(Elm_Genlist_Item             *it,
4353                                    const Elm_Genlist_Item_Class *itc)
4354 {
4355    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4356    if (!it->block) return;
4357    EINA_SAFETY_ON_NULL_RETURN(itc);
4358    if (it->delete_me) return;
4359    it->itc = itc;
4360    it->nocache = EINA_TRUE;
4361    elm_genlist_item_update(it);
4362 }
4363
4364 EAPI const Elm_Genlist_Item_Class *
4365 elm_genlist_item_item_class_get(const Elm_Genlist_Item *it)
4366 {
4367    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
4368    if (it->delete_me) return NULL;
4369    return it->itc;
4370 }
4371
4372 static Evas_Object *
4373 _elm_genlist_item_label_create(void        *data,
4374                                Evas_Object *obj __UNUSED__,
4375                                Evas_Object *tooltip,
4376                                void        *item __UNUSED__)
4377 {
4378    Evas_Object *label = elm_label_add(tooltip);
4379    if (!label)
4380      return NULL;
4381    elm_object_style_set(label, "tooltip");
4382    elm_object_text_set(label, data);
4383    return label;
4384 }
4385
4386 static void
4387 _elm_genlist_item_label_del_cb(void        *data,
4388                                Evas_Object *obj __UNUSED__,
4389                                void        *event_info __UNUSED__)
4390 {
4391    eina_stringshare_del(data);
4392 }
4393
4394 EAPI void
4395 elm_genlist_item_tooltip_text_set(Elm_Genlist_Item *item,
4396                                   const char       *text)
4397 {
4398    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4399    text = eina_stringshare_add(text);
4400    elm_genlist_item_tooltip_content_cb_set(item, _elm_genlist_item_label_create,
4401                                            text,
4402                                            _elm_genlist_item_label_del_cb);
4403 }
4404
4405 EAPI void
4406 elm_genlist_item_tooltip_content_cb_set(Elm_Genlist_Item           *item,
4407                                         Elm_Tooltip_Item_Content_Cb func,
4408                                         const void                 *data,
4409                                         Evas_Smart_Cb               del_cb)
4410 {
4411    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_GOTO(item, error);
4412
4413    if ((item->tooltip.content_cb == func) && (item->tooltip.data == data))
4414      return;
4415
4416    if (item->tooltip.del_cb)
4417      item->tooltip.del_cb((void *)item->tooltip.data,
4418                           item->base.widget, item);
4419
4420    item->tooltip.content_cb = func;
4421    item->tooltip.data = data;
4422    item->tooltip.del_cb = del_cb;
4423
4424    if (item->base.view)
4425      {
4426         elm_widget_item_tooltip_content_cb_set(item,
4427                                                item->tooltip.content_cb,
4428                                                item->tooltip.data, NULL);
4429         elm_widget_item_tooltip_style_set(item, item->tooltip.style);
4430         elm_widget_item_tooltip_size_restrict_disable(item, item->tooltip.free_size);
4431      }
4432
4433    return;
4434
4435 error:
4436    if (del_cb) del_cb((void *)data, NULL, NULL);
4437 }
4438
4439 EAPI void
4440 elm_genlist_item_tooltip_unset(Elm_Genlist_Item *item)
4441 {
4442    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4443    if ((item->base.view) && (item->tooltip.content_cb))
4444      elm_widget_item_tooltip_unset(item);
4445
4446    if (item->tooltip.del_cb)
4447      item->tooltip.del_cb((void *)item->tooltip.data, item->base.widget, item);
4448    item->tooltip.del_cb = NULL;
4449    item->tooltip.content_cb = NULL;
4450    item->tooltip.data = NULL;
4451    item->tooltip.free_size = EINA_FALSE;
4452    if (item->tooltip.style)
4453      elm_genlist_item_tooltip_style_set(item, NULL);
4454 }
4455
4456 EAPI void
4457 elm_genlist_item_tooltip_style_set(Elm_Genlist_Item *item,
4458                                    const char       *style)
4459 {
4460    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4461    eina_stringshare_replace(&item->tooltip.style, style);
4462    if (item->base.view) elm_widget_item_tooltip_style_set(item, style);
4463 }
4464
4465 EAPI const char *
4466 elm_genlist_item_tooltip_style_get(const Elm_Genlist_Item *item)
4467 {
4468    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
4469    return item->tooltip.style;
4470 }
4471
4472 EAPI Eina_Bool
4473 elm_genlist_item_tooltip_size_restrict_disable(Elm_Genlist_Item *item, Eina_Bool disable)
4474 {
4475    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, EINA_FALSE);
4476    item->tooltip.free_size = disable;
4477    if (item->base.view) return elm_widget_item_tooltip_size_restrict_disable(item, disable);
4478    return EINA_TRUE;
4479 }
4480
4481 EAPI Eina_Bool
4482 elm_genlist_item_tooltip_size_restrict_disabled_get(const Elm_Genlist_Item *item)
4483 {
4484    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, EINA_FALSE);
4485    return item->tooltip.free_size;
4486 }
4487
4488 EAPI void
4489 elm_genlist_item_cursor_set(Elm_Genlist_Item *item,
4490                             const char       *cursor)
4491 {
4492    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4493    eina_stringshare_replace(&item->mouse_cursor, cursor);
4494    if (item->base.view) elm_widget_item_cursor_set(item, cursor);
4495 }
4496
4497 EAPI const char *
4498 elm_genlist_item_cursor_get(const Elm_Genlist_Item *item)
4499 {
4500    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
4501    return elm_widget_item_cursor_get(item);
4502 }
4503
4504 EAPI void
4505 elm_genlist_item_cursor_unset(Elm_Genlist_Item *item)
4506 {
4507    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4508    if (!item->mouse_cursor)
4509      return;
4510
4511    if (item->base.view)
4512      elm_widget_item_cursor_unset(item);
4513
4514    eina_stringshare_del(item->mouse_cursor);
4515    item->mouse_cursor = NULL;
4516 }
4517
4518 EAPI void
4519 elm_genlist_item_cursor_style_set(Elm_Genlist_Item *item,
4520                                   const char       *style)
4521 {
4522    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4523    elm_widget_item_cursor_style_set(item, style);
4524 }
4525
4526 EAPI const char *
4527 elm_genlist_item_cursor_style_get(const Elm_Genlist_Item *item)
4528 {
4529    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, NULL);
4530    return elm_widget_item_cursor_style_get(item);
4531 }
4532
4533 EAPI void
4534 elm_genlist_item_cursor_engine_only_set(Elm_Genlist_Item *item,
4535                                         Eina_Bool         engine_only)
4536 {
4537    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item);
4538    elm_widget_item_cursor_engine_only_set(item, engine_only);
4539 }
4540
4541 EAPI Eina_Bool
4542 elm_genlist_item_cursor_engine_only_get(const Elm_Genlist_Item *item)
4543 {
4544    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(item, EINA_FALSE);
4545    return elm_widget_item_cursor_engine_only_get(item);
4546 }
4547
4548 EAPI void
4549 elm_genlist_horizontal_set(Evas_Object  *obj,
4550                                 Elm_List_Mode mode)
4551 {
4552    ELM_CHECK_WIDTYPE(obj, widtype);
4553    Widget_Data *wd = elm_widget_data_get(obj);
4554    if (!wd) return;
4555    if (wd->mode == mode) return;
4556    wd->mode = mode;
4557    _sizing_eval(obj);
4558 }
4559
4560 EAPI void
4561 elm_genlist_horizontal_mode_set(Evas_Object  *obj,
4562                                 Elm_List_Mode mode)
4563 {
4564    elm_genlist_horizontal_set(obj, mode);
4565 }
4566
4567 EAPI Elm_List_Mode
4568 elm_genlist_horizontal_get(const Evas_Object *obj)
4569 {
4570    ELM_CHECK_WIDTYPE(obj, widtype) ELM_LIST_LAST;
4571    Widget_Data *wd = elm_widget_data_get(obj);
4572    if (!wd) return ELM_LIST_LAST;
4573    return wd->mode;
4574 }
4575
4576 EAPI Elm_List_Mode
4577 elm_genlist_horizontal_mode_get(const Evas_Object *obj)
4578 {
4579    return elm_genlist_horizontal_get(obj);
4580 }
4581
4582 EAPI void
4583 elm_genlist_always_select_mode_set(Evas_Object *obj,
4584                                    Eina_Bool    always_select)
4585 {
4586    ELM_CHECK_WIDTYPE(obj, widtype);
4587    Widget_Data *wd = elm_widget_data_get(obj);
4588    if (!wd) return;
4589    wd->always_select = always_select;
4590 }
4591
4592 EAPI Eina_Bool
4593 elm_genlist_always_select_mode_get(const Evas_Object *obj)
4594 {
4595    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
4596    Widget_Data *wd = elm_widget_data_get(obj);
4597    if (!wd) return EINA_FALSE;
4598    return wd->always_select;
4599 }
4600
4601 EAPI void
4602 elm_genlist_no_select_mode_set(Evas_Object *obj,
4603                                Eina_Bool    no_select)
4604 {
4605    ELM_CHECK_WIDTYPE(obj, widtype);
4606    Widget_Data *wd = elm_widget_data_get(obj);
4607    if (!wd) return;
4608    wd->no_select = no_select;
4609 }
4610
4611 EAPI Eina_Bool
4612 elm_genlist_no_select_mode_get(const Evas_Object *obj)
4613 {
4614    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
4615    Widget_Data *wd = elm_widget_data_get(obj);
4616    if (!wd) return EINA_FALSE;
4617    return wd->no_select;
4618 }
4619
4620 EAPI void
4621 elm_genlist_compress_mode_set(Evas_Object *obj,
4622                               Eina_Bool    compress)
4623 {
4624    ELM_CHECK_WIDTYPE(obj, widtype);
4625    Widget_Data *wd = elm_widget_data_get(obj);
4626    if (!wd) return;
4627    wd->compress = compress;
4628    if (!compress) elm_genlist_homogeneous_set(obj, EINA_FALSE);
4629 }
4630
4631 EAPI Eina_Bool
4632 elm_genlist_compress_mode_get(const Evas_Object *obj)
4633 {
4634    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
4635    Widget_Data *wd = elm_widget_data_get(obj);
4636    if (!wd) return EINA_FALSE;
4637    return wd->compress;
4638 }
4639
4640 EAPI void
4641 elm_genlist_height_for_width_mode_set(Evas_Object *obj,
4642                                       Eina_Bool    height_for_width)
4643 {
4644    ELM_CHECK_WIDTYPE(obj, widtype);
4645    Widget_Data *wd = elm_widget_data_get(obj);
4646    if (!wd) return;
4647    wd->height_for_width = !!height_for_width;
4648    if (wd->height_for_width)
4649      {
4650         elm_genlist_homogeneous_set(obj, EINA_FALSE);
4651         elm_genlist_compress_mode_set(obj, EINA_TRUE);
4652      }
4653 }
4654
4655 EAPI Eina_Bool
4656 elm_genlist_height_for_width_mode_get(const Evas_Object *obj)
4657 {
4658    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
4659    Widget_Data *wd = elm_widget_data_get(obj);
4660    if (!wd) return EINA_FALSE;
4661    return wd->height_for_width;
4662 }
4663
4664 EAPI void
4665 elm_genlist_bounce_set(Evas_Object *obj,
4666                        Eina_Bool    h_bounce,
4667                        Eina_Bool    v_bounce)
4668 {
4669    ELM_CHECK_WIDTYPE(obj, widtype);
4670    Widget_Data *wd = elm_widget_data_get(obj);
4671    if (!wd) return;
4672    elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
4673 }
4674
4675 EAPI void
4676 elm_genlist_bounce_get(const Evas_Object *obj,
4677                        Eina_Bool         *h_bounce,
4678                        Eina_Bool         *v_bounce)
4679 {
4680    ELM_CHECK_WIDTYPE(obj, widtype);
4681    Widget_Data *wd = elm_widget_data_get(obj);
4682    if (!wd) return;
4683    elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce);
4684 }
4685
4686 EAPI void
4687 elm_genlist_homogeneous_set(Evas_Object *obj,
4688                             Eina_Bool    homogeneous)
4689 {
4690    ELM_CHECK_WIDTYPE(obj, widtype);
4691    Widget_Data *wd = elm_widget_data_get(obj);
4692    if (!wd) return;
4693    if (homogeneous) elm_genlist_compress_mode_set(obj, EINA_TRUE);
4694    wd->homogeneous = homogeneous;
4695 }
4696
4697 EAPI Eina_Bool
4698 elm_genlist_homogeneous_get(const Evas_Object *obj)
4699 {
4700    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
4701    Widget_Data *wd = elm_widget_data_get(obj);
4702    if (!wd) return EINA_FALSE;
4703    return wd->homogeneous;
4704 }
4705
4706 EAPI void
4707 elm_genlist_block_count_set(Evas_Object *obj,
4708                             int          n)
4709 {
4710    ELM_CHECK_WIDTYPE(obj, widtype);
4711    Widget_Data *wd = elm_widget_data_get(obj);
4712    if (!wd) return;
4713    wd->max_items_per_block = n;
4714    wd->item_cache_max = wd->max_items_per_block * 2;
4715    _item_cache_clean(wd);
4716 }
4717
4718 EAPI int
4719 elm_genlist_block_count_get(const Evas_Object *obj)
4720 {
4721    ELM_CHECK_WIDTYPE(obj, widtype) 0;
4722    Widget_Data *wd = elm_widget_data_get(obj);
4723    if (!wd) return 0;
4724    return wd->max_items_per_block;
4725 }
4726
4727 EAPI void
4728 elm_genlist_longpress_timeout_set(Evas_Object *obj,
4729                                   double       timeout)
4730 {
4731    ELM_CHECK_WIDTYPE(obj, widtype);
4732    Widget_Data *wd = elm_widget_data_get(obj);
4733    if (!wd) return;
4734    wd->longpress_timeout = timeout;
4735 }
4736
4737 EAPI double
4738 elm_genlist_longpress_timeout_get(const Evas_Object *obj)
4739 {
4740    ELM_CHECK_WIDTYPE(obj, widtype) 0;
4741    Widget_Data *wd = elm_widget_data_get(obj);
4742    if (!wd) return 0;
4743    return wd->longpress_timeout;
4744 }
4745
4746 EAPI void
4747 elm_genlist_scroller_policy_set(Evas_Object        *obj,
4748                                 Elm_Scroller_Policy policy_h,
4749                                 Elm_Scroller_Policy policy_v)
4750 {
4751    ELM_CHECK_WIDTYPE(obj, widtype);
4752    Widget_Data *wd = elm_widget_data_get(obj);
4753    if (!wd) return;
4754    if ((policy_h >= ELM_SCROLLER_POLICY_LAST) ||
4755        (policy_v >= ELM_SCROLLER_POLICY_LAST))
4756      return;
4757    if (wd->scr)
4758      elm_smart_scroller_policy_set(wd->scr, policy_h, policy_v);
4759 }
4760
4761 EAPI void
4762 elm_genlist_scroller_policy_get(const Evas_Object   *obj,
4763                                 Elm_Scroller_Policy *policy_h,
4764                                 Elm_Scroller_Policy *policy_v)
4765 {
4766    ELM_CHECK_WIDTYPE(obj, widtype);
4767    Widget_Data *wd = elm_widget_data_get(obj);
4768    Elm_Smart_Scroller_Policy s_policy_h, s_policy_v;
4769    if ((!wd) || (!wd->scr)) return;
4770    elm_smart_scroller_policy_get(wd->scr, &s_policy_h, &s_policy_v);
4771    if (policy_h) *policy_h = (Elm_Scroller_Policy)s_policy_h;
4772    if (policy_v) *policy_v = (Elm_Scroller_Policy)s_policy_v;
4773 }
4774
4775 EAPI void
4776 elm_genlist_realized_items_update(Evas_Object *obj)
4777 {
4778    ELM_CHECK_WIDTYPE(obj, widtype);
4779
4780    Eina_List *list, *l;
4781    Elm_Genlist_Item *it;
4782
4783    list = elm_genlist_realized_items_get(obj);
4784    EINA_LIST_FOREACH(list, l, it)
4785      elm_genlist_item_update(it);
4786 }
4787
4788 EAPI void
4789 elm_genlist_item_mode_set(Elm_Genlist_Item *it,
4790                           const char       *mode_type,
4791                           Eina_Bool         mode_set)
4792 {
4793    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
4794    Widget_Data *wd = it->wd;
4795    Eina_List *l;
4796    Elm_Genlist_Item *it2;
4797
4798    if (!wd) return;
4799    if (!mode_type) return;
4800    if ((it->delete_me) || (it->disabled)) return;
4801
4802    if ((wd->mode_item == it) &&
4803        (!strcmp(mode_type, wd->mode_type)) &&
4804        (mode_set))
4805       return;
4806    if (!it->itc->mode_item_style) return;
4807
4808    if (wd->multi)
4809      {
4810         EINA_LIST_FOREACH(wd->selected, l, it2)
4811           if (it2->realized)
4812             elm_genlist_item_selected_set(it2, EINA_FALSE);
4813      }
4814    else
4815      {
4816         it2 = elm_genlist_selected_item_get(wd->obj);
4817         if ((it2) && (it2->realized))
4818           elm_genlist_item_selected_set(it2, EINA_FALSE);
4819      }
4820
4821    if (((wd->mode_type) && (strcmp(mode_type, wd->mode_type))) ||
4822        (mode_set) ||
4823        ((it == wd->mode_item) && (!mode_set)))
4824      _item_mode_unset(wd);
4825
4826    eina_stringshare_replace(&wd->mode_type, mode_type);
4827    if (mode_set) _item_mode_set(it);
4828 }
4829
4830 EAPI const char *
4831 elm_genlist_mode_get(const Evas_Object *obj)
4832 {
4833    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
4834    Widget_Data *wd = elm_widget_data_get(obj);
4835    if (!wd) return NULL;
4836    return wd->mode_type;
4837 }
4838
4839 EAPI const Elm_Genlist_Item *
4840 elm_genlist_mode_item_get(const Evas_Object *obj)
4841 {
4842    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
4843    Widget_Data *wd = elm_widget_data_get(obj);
4844    if (!wd) return NULL;
4845    return wd->mode_item;
4846 }
4847
4848 EAPI void
4849 elm_genlist_reorder_mode_set(Evas_Object *obj,
4850                              Eina_Bool    reorder_mode)
4851 {
4852    ELM_CHECK_WIDTYPE(obj, widtype);
4853    Widget_Data *wd = elm_widget_data_get(obj);
4854    if (!wd) return;
4855    wd->reorder_mode = reorder_mode;
4856 }
4857
4858 EAPI Eina_Bool
4859 elm_genlist_reorder_mode_get(const Evas_Object *obj)
4860 {
4861    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
4862    Widget_Data *wd = elm_widget_data_get(obj);
4863    if (!wd) return EINA_FALSE;
4864    return wd->reorder_mode;
4865 }