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