================================================================
[framework/uifw/elementary.git] / src / lib / elm_list.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 #define SWIPE_MOVES 12
5
6 /**
7  * @defgroup List List
8  * @ingroup Elementary
9  *
10  * A list is a very simple type of list widget.  For more robust
11  * lists, @ref Genlist should probably be used.
12  */
13
14 typedef struct _Widget_Data Widget_Data;
15
16 struct _Widget_Data
17 {
18    Evas_Object *scr, *box, *self;
19    Eina_List *items, *selected, *to_delete;
20    Elm_List_Item *last_selected_item;
21    Elm_List_Mode mode;
22    Elm_List_Mode h_mode;
23    Evas_Coord minw[2], minh[2];
24    Eina_Bool scr_minw : 1;
25    Eina_Bool scr_minh : 1;
26    int walking;
27    int movements;
28    struct
29    {
30       Evas_Coord x, y;
31    } history[SWIPE_MOVES];
32    Eina_Bool swipe : 1;
33    Eina_Bool fix_pending : 1;
34    Eina_Bool on_hold : 1;
35    Eina_Bool multi : 1;
36    Eina_Bool always_select : 1;
37    Eina_Bool longpressed : 1;
38    Eina_Bool wasselected : 1;
39 };
40
41 struct _Elm_List_Item
42 {
43    Elm_Widget_Item base;
44    Widget_Data *wd;
45    Eina_List *node;
46    const char *label;
47    Evas_Object *icon, *end;
48    Evas_Smart_Cb func;
49    Ecore_Timer *long_timer;
50    Ecore_Timer *swipe_timer;
51    Eina_Bool deleted : 1;
52    Eina_Bool disabled : 1;
53    Eina_Bool even : 1;
54    Eina_Bool is_even : 1;
55    Eina_Bool is_separator : 1;
56    Eina_Bool fixed : 1;
57    Eina_Bool selected : 1;
58    Eina_Bool hilighted : 1;
59    Eina_Bool dummy_icon : 1;
60    Eina_Bool dummy_end : 1;
61 };
62
63 static const char *widtype = NULL;
64 static void _del_hook(Evas_Object *obj);
65 static void _theme_hook(Evas_Object *obj);
66 static void _sizing_eval(Evas_Object *obj);
67 static void _disable_hook(Evas_Object *obj);
68 static void _on_focus_hook(void *data, Evas_Object *obj);
69 static void _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source);
70 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
71 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
72 static void _fix_items(Evas_Object *obj);
73 static void _mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
74 static void _mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info);
75 static void _mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info);
76 static void _scroll_edge_left(void *data, Evas_Object *scr, void *event_info);
77 static void _scroll_edge_right(void *data, Evas_Object *scr, void *event_info);
78 static void _scroll_edge_top(void *data, Evas_Object *scr, void *event_info);
79 static void _scroll_edge_bottom(void *data, Evas_Object *scr, void *event_info);
80 static Eina_Bool _item_multi_select_up(Widget_Data *wd);
81 static Eina_Bool _item_multi_select_down(Widget_Data *wd);
82 static Eina_Bool _item_single_select_up(Widget_Data *wd);
83 static Eina_Bool _item_single_select_down(Widget_Data *wd);
84 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
85                              Evas_Callback_Type type, void *event_info);
86 static Eina_Bool _deselect_all_items(Widget_Data *wd);
87
88 #define ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ...)                     \
89   ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, __VA_ARGS__);             \
90   if (it->deleted)                                                      \
91     {                                                                   \
92        ERR("ERROR: "#it" has been DELETED.\n");                         \
93        return __VA_ARGS__;                                              \
94     }
95
96 static inline void
97 _elm_list_item_free(Elm_List_Item *it)
98 {
99    evas_object_event_callback_del_full
100      (it->base.view, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, it);
101    evas_object_event_callback_del_full
102      (it->base.view, EVAS_CALLBACK_MOUSE_UP, _mouse_up, it);
103    evas_object_event_callback_del_full
104      (it->base.view, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, it);
105
106    if (it->icon)
107      evas_object_event_callback_del_full
108        (it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
109         _changed_size_hints, it->base.widget);
110
111    if (it->end)
112      evas_object_event_callback_del_full
113        (it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
114         _changed_size_hints, it->base.widget);
115
116    eina_stringshare_del(it->label);
117
118    if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
119    if (it->long_timer) ecore_timer_del(it->long_timer);
120    if (it->icon) evas_object_del(it->icon);
121    if (it->end) evas_object_del(it->end);
122
123    elm_widget_item_del(it);
124 }
125
126 static Eina_Bool
127 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
128 {
129    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
130    Evas_Event_Key_Down *ev = event_info;
131    Widget_Data *wd = elm_widget_data_get(obj);
132    if (!wd) return EINA_FALSE;
133    if (!wd->items) return EINA_FALSE;
134    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
135    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
136
137    Elm_List_Item *it = NULL;
138    Evas_Coord x = 0;
139    Evas_Coord y = 0;
140    Evas_Coord step_x = 0;
141    Evas_Coord step_y = 0;
142    Evas_Coord v_w = 0;
143    Evas_Coord v_h = 0;
144    Evas_Coord page_x = 0;
145    Evas_Coord page_y = 0;
146
147    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
148    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
149    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
150    elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
151
152    /* TODO: fix logic for horizontal mode */
153    if ((!strcmp(ev->keyname, "Left")) ||
154        (!strcmp(ev->keyname, "KP_Left")))
155      {
156         if ((wd->h_mode) &&
157             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
158               (_item_multi_select_up(wd)))
159              || (_item_single_select_up(wd))))
160           {
161              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
162              return EINA_TRUE;
163           }
164         else
165           x -= step_x;
166      }
167    else if ((!strcmp(ev->keyname, "Right")) ||
168             (!strcmp(ev->keyname, "KP_Right")))
169      {
170         if ((wd->h_mode) &&
171             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
172               (_item_multi_select_down(wd)))
173              || (_item_single_select_down(wd))))
174           {
175              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
176              return EINA_TRUE;
177           }
178         else
179           x += step_x;
180      }
181    else if ((!strcmp(ev->keyname, "Up"))  ||
182             (!strcmp(ev->keyname, "KP_Up")))
183      {
184         if ((!wd->h_mode) &&
185             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
186               (_item_multi_select_up(wd)))
187              || (_item_single_select_up(wd))))
188           {
189              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
190              return EINA_TRUE;
191           }
192         else
193           y -= step_y;
194      }
195    else if ((!strcmp(ev->keyname, "Down")) ||
196             (!strcmp(ev->keyname, "KP_Down")))
197      {
198         if ((!wd->h_mode) &&
199             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
200               (_item_multi_select_down(wd)))
201              || (_item_single_select_down(wd))))
202           {
203              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
204              return EINA_TRUE;
205           }
206         else
207           y += step_y;
208      }
209    else if ((!strcmp(ev->keyname, "Home")) ||
210             (!strcmp(ev->keyname, "KP_Home")))
211      {
212         it = eina_list_data_get(wd->items);
213         elm_list_item_bring_in(it);
214         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
215         return EINA_TRUE;
216      }
217    else if ((!strcmp(ev->keyname, "End")) ||
218             (!strcmp(ev->keyname, "KP_End")))
219      {
220         it = eina_list_data_get(eina_list_last(wd->items));
221         elm_list_item_bring_in(it);
222         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
223         return EINA_TRUE;
224      }
225    else if ((!strcmp(ev->keyname, "Prior")) ||
226             (!strcmp(ev->keyname, "KP_Prior")))
227      {
228         if (wd->h_mode)
229           {
230              if (page_x < 0)
231                x -= -(page_x * v_w) / 100;
232              else
233                x -= page_x;
234           }
235         else
236           {
237              if (page_y < 0)
238                y -= -(page_y * v_h) / 100;
239              else
240                y -= page_y;
241           }
242      }
243    else if ((!strcmp(ev->keyname, "Next")) ||
244             (!strcmp(ev->keyname, "KP_Next")))
245      {
246         if (wd->h_mode)
247           {
248              if (page_x < 0)
249                x += -(page_x * v_w) / 100;
250              else
251                x += page_x;
252           }
253         else
254           {
255              if (page_y < 0)
256                y += -(page_y * v_h) / 100;
257              else
258                y += page_y;
259           }
260      }
261    else if (!strcmp(ev->keyname, "Escape"))
262      {
263        if (!_deselect_all_items(wd)) return EINA_FALSE;
264        ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
265        return EINA_TRUE;
266      }
267    else return EINA_FALSE;
268
269    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
270    elm_smart_scroller_child_pos_set(wd->scr, x, y);
271    return EINA_TRUE;
272 }
273
274 static Eina_Bool
275 _deselect_all_items(Widget_Data *wd)
276 {
277    if (!wd->selected) return EINA_FALSE;
278    while(wd->selected)
279      elm_list_item_selected_set(wd->selected->data, EINA_FALSE);
280
281    return EINA_TRUE;
282 }
283
284 static Eina_Bool
285 _item_multi_select_up(Widget_Data *wd)
286 {
287    if (!wd->selected) return EINA_FALSE;
288    if (!wd->multi) return EINA_FALSE;
289
290    Elm_List_Item *prev = elm_list_item_prev(wd->last_selected_item);
291    if (!prev) return EINA_TRUE;
292
293    if (elm_list_item_selected_get(prev))
294      {
295         elm_list_item_selected_set(wd->last_selected_item, EINA_FALSE);
296         wd->last_selected_item = prev;
297         elm_list_item_show(wd->last_selected_item);
298      }
299    else
300      {
301         elm_list_item_selected_set(prev, EINA_TRUE);
302         elm_list_item_show(prev);
303      }
304    return EINA_TRUE;
305 }
306
307 static Eina_Bool
308 _item_multi_select_down(Widget_Data *wd)
309 {
310    if (!wd->selected) return EINA_FALSE;
311    if (!wd->multi) return EINA_FALSE;
312
313    Elm_List_Item *next = elm_list_item_next(wd->last_selected_item);
314    if (!next) return EINA_TRUE;
315
316    if (elm_list_item_selected_get(next))
317      {
318         elm_list_item_selected_set(wd->last_selected_item, EINA_FALSE);
319         wd->last_selected_item = next;
320         elm_list_item_show(wd->last_selected_item);
321      }
322    else
323      {
324         elm_list_item_selected_set(next, EINA_TRUE);
325         elm_list_item_show(next);
326      }
327    return EINA_TRUE;
328 }
329
330 static Eina_Bool
331 _item_single_select_up(Widget_Data *wd)
332 {
333    Elm_List_Item *prev;
334
335    if (!wd->selected) prev = eina_list_data_get(eina_list_last(wd->items));
336    else prev = elm_list_item_prev(wd->last_selected_item);
337
338    if (!prev) return EINA_FALSE;
339
340    _deselect_all_items(wd);
341
342    elm_list_item_selected_set(prev, EINA_TRUE);
343    elm_list_item_show(prev);
344    return EINA_TRUE;
345 }
346
347 static Eina_Bool
348 _item_single_select_down(Widget_Data *wd)
349 {
350    Elm_List_Item *next;
351
352    if (!wd->selected) next = eina_list_data_get(wd->items);
353    else next = elm_list_item_next(wd->last_selected_item);
354
355    if (!next) return EINA_FALSE;
356
357    _deselect_all_items(wd);
358
359    elm_list_item_selected_set(next, EINA_TRUE);
360    elm_list_item_show(next);
361    return EINA_TRUE;
362 }
363
364 static void
365 _elm_list_process_deletions(Widget_Data *wd)
366 {
367    Elm_List_Item *it;
368
369    wd->walking++; // avoid nested deletion and also _sub_del() fix_items
370
371    EINA_LIST_FREE(wd->to_delete, it)
372      {
373         elm_widget_item_pre_notify_del(it);
374
375         wd->items = eina_list_remove_list(wd->items, it->node);
376         _elm_list_item_free(it);
377      }
378
379    wd->walking--;
380 }
381
382 static inline void
383 _elm_list_walk(Widget_Data *wd)
384 {
385    if (wd->walking < 0)
386      {
387         ERR("ERROR: walking was negative. fixed!\n");
388         wd->walking = 0;
389      }
390    wd->walking++;
391 }
392
393 static inline void
394 _elm_list_unwalk(Widget_Data *wd)
395 {
396    wd->walking--;
397    if (wd->walking < 0)
398      {
399         ERR("ERROR: walking became negative. fixed!\n");
400         wd->walking = 0;
401      }
402
403    if (wd->walking)
404      return;
405
406    if (wd->to_delete)
407      _elm_list_process_deletions(wd);
408
409    if (wd->fix_pending)
410      {
411         wd->fix_pending = EINA_FALSE;
412         _fix_items(wd->self);
413         _sizing_eval(wd->self);
414      }
415 }
416
417 static void
418 _del_hook(Evas_Object *obj)
419 {
420    Widget_Data *wd = elm_widget_data_get(obj);
421    Elm_List_Item *it;
422    Eina_List *n;
423
424    if (!wd) return;
425    if (wd->walking)
426      ERR("ERROR: list deleted while walking.\n");
427
428    _elm_list_walk(wd);
429    EINA_LIST_FOREACH(wd->items, n, it) elm_widget_item_pre_notify_del(it);
430    _elm_list_unwalk(wd);
431    if (wd->to_delete)
432      ERR("ERROR: leaking nodes!\n");
433
434    EINA_LIST_FREE(wd->items, it) _elm_list_item_free(it);
435    eina_list_free(wd->selected);
436    free(wd);
437 }
438
439 static void
440 _show_region_hook(void *data, Evas_Object *obj)
441 {
442    Widget_Data *wd = elm_widget_data_get(data);
443    Evas_Coord x, y, w, h;
444    elm_widget_show_region_get(obj, &x, &y, &w, &h);
445    elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
446 }
447
448 static void
449 _disable_hook(Evas_Object *obj)
450 {
451    Widget_Data *wd = elm_widget_data_get(obj);
452    if (!wd) return;
453    if (elm_widget_disabled_get(obj))
454      {
455         _signal_emit_hook(obj, "elm,state,disabled", "elm");
456         elm_widget_scroll_freeze_push(obj);
457         elm_widget_scroll_hold_push(obj);
458         /* FIXME: if we get to have a way to only un-hilight items
459          * in the future, keeping them selected... */
460         _deselect_all_items(wd);
461      }
462    else
463      {
464         _signal_emit_hook(obj, "elm,state,enabled", "elm");
465         elm_widget_scroll_freeze_pop(obj);
466         elm_widget_scroll_hold_pop(obj);
467      }
468 }
469
470 static void
471 _sizing_eval(Evas_Object *obj)
472 {
473
474    Widget_Data *wd = elm_widget_data_get(obj);
475    if (!wd) return;
476    Evas_Coord  vw, vh, minw, minh, maxw, maxh, w, h, vmw, vmh;
477    double xw, yw;
478
479    evas_object_size_hint_min_get(wd->box, &minw, &minh);
480    evas_object_size_hint_max_get(wd->box, &maxw, &maxh);
481    evas_object_size_hint_weight_get(wd->box, &xw, &yw);
482    if (!wd->scr) return;
483    elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
484    if (xw > 0.0)
485      {
486         if ((minw > 0) && (vw < minw)) vw = minw;
487         else if ((maxw > 0) && (vw > maxw)) vw = maxw;
488      }
489    else if (minw > 0) vw = minw;
490    if (yw > 0.0)
491      {
492         if ((minh > 0) && (vh < minh)) vh = minh;
493         else if ((maxh > 0) && (vh > maxh)) vh = maxh;
494      }
495    else if (minh > 0) vh = minh;
496    evas_object_resize(wd->box, vw, vh);
497    w = -1;
498    h = -1;
499    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
500                              &vmw, &vmh);
501    if (wd->scr_minw) w = vmw + minw;
502    if (wd->scr_minh) h = vmh + minh;
503
504    evas_object_size_hint_max_get(obj, &maxw, &maxh);
505    if ((maxw > 0) && (w > maxw))
506      w = maxw;
507    if ((maxh > 0) && (h > maxh))
508      h = maxh;
509
510    evas_object_size_hint_min_set(obj, w, h);
511 }
512
513 static void
514 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
515 {
516    Widget_Data *wd = elm_widget_data_get(obj);
517    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
518                            emission, source);
519 }
520
521 static void
522 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
523 {
524    Widget_Data *wd = elm_widget_data_get(obj);
525    edje_object_signal_callback_add(elm_smart_scroller_edje_object_get(wd->scr),
526                                    emission, source, func_cb, data);
527 }
528
529 static void
530 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, void (*func_cb) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
531 {
532    Widget_Data *wd = elm_widget_data_get(obj);
533    edje_object_signal_callback_del_full(
534                               elm_smart_scroller_edje_object_get(wd->scr),
535                               emission, source, func_cb, data);
536 }
537
538 static void
539 _theme_hook(Evas_Object *obj)
540 {
541    Widget_Data *wd = elm_widget_data_get(obj);
542    Elm_List_Item *it;
543    Eina_List *n;
544
545    if (!wd) return;
546    if (wd->scr)
547      {
548         Evas_Object *edj;
549         const char *str;
550
551         elm_smart_scroller_object_theme_set(obj, wd->scr, "list", "base",
552                                             elm_widget_style_get(obj));
553 //        edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
554         edj = elm_smart_scroller_edje_object_get(wd->scr);
555         str = edje_object_data_get(edj, "focus_highlight");
556         if ((str) && (!strcmp(str, "on")))
557           elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
558         else
559           elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
560         elm_object_style_set(wd->scr, elm_widget_style_get(obj));
561      }
562    EINA_LIST_FOREACH(wd->items, n, it)
563      {
564         edje_object_scale_set(it->base.view, elm_widget_scale_get(obj) * _elm_config->scale);
565         it->fixed = 0;
566      }
567    _fix_items(obj);
568    _sizing_eval(obj);
569 }
570
571 static void
572 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
573 {
574    Widget_Data *wd = elm_widget_data_get(obj);
575    if (!wd) return;
576    if (elm_widget_focus_get(obj))
577      {
578         edje_object_signal_emit(wd->self, "elm,action,focus", "elm");
579         evas_object_focus_set(wd->self, EINA_TRUE);
580
581         if ((wd->selected) && (!wd->last_selected_item))
582           wd->last_selected_item = eina_list_data_get(wd->selected);
583      }
584    else
585      {
586         edje_object_signal_emit(wd->self, "elm,action,unfocus", "elm");
587         evas_object_focus_set(wd->self, EINA_FALSE);
588      }
589 }
590
591 static void
592 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
593 {
594    Widget_Data *wd = elm_widget_data_get(data);
595    if (!wd) return;
596    _fix_items(data);
597    _sizing_eval(data);
598 }
599
600 static void
601 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
602 {
603    Widget_Data *wd = elm_widget_data_get(obj);
604    Evas_Object *sub = event_info;
605    const Eina_List *l;
606    Elm_List_Item *it;
607
608    if (!wd) return;
609    if (!sub) abort();
610    if (sub == wd->scr)
611      wd->scr = NULL;
612    else
613      {
614         EINA_LIST_FOREACH(wd->items, l, it)
615           {
616              if ((sub == it->icon) || (sub == it->end))
617                {
618                   if (it->icon == sub) it->icon = NULL;
619                   if (it->end == sub) it->end = NULL;
620                   evas_object_event_callback_del_full
621                     (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints,
622                      obj);
623                   if (!wd->walking)
624                     {
625                        _fix_items(obj);
626                        _sizing_eval(obj);
627                     }
628                   else
629                     wd->fix_pending = EINA_TRUE;
630                   break;
631                }
632           }
633      }
634 }
635
636 static void
637 _item_hilight(Elm_List_Item *it)
638 {
639    Widget_Data *wd = elm_widget_data_get(it->base.widget);
640    const char *selectraise;
641
642    if (!wd) return;
643    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
644    if (it->hilighted) return;
645    _elm_list_walk(wd);
646
647    edje_object_signal_emit(it->base.view, "elm,state,selected", "elm");
648    selectraise = edje_object_data_get(it->base.view, "selectraise");
649    if ((selectraise) && (!strcmp(selectraise, "on")))
650      evas_object_raise(it->base.view);
651    it->hilighted = EINA_TRUE;
652
653    _elm_list_unwalk(wd);
654 }
655
656 static void
657 _item_select(Elm_List_Item *it)
658 {
659    Widget_Data *wd = elm_widget_data_get(it->base.widget);
660
661    if (!wd) return;
662    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
663    if (it->selected)
664      {
665         if (wd->always_select) goto call;
666         return;
667      }
668    it->selected = EINA_TRUE;
669    wd->selected = eina_list_append(wd->selected, it);
670    call:
671    _elm_list_walk(wd);
672
673    if (it->func) it->func((void *)it->base.data, it->base.widget, it);
674    evas_object_smart_callback_call(it->base.widget, "selected", it);
675
676    _elm_list_unwalk(wd);
677    it->wd->last_selected_item = it;
678 }
679
680 static void
681 _item_unselect(Elm_List_Item *it)
682 {
683    Widget_Data *wd = elm_widget_data_get(it->base.widget);
684    const char *stacking, *selectraise;
685
686    if (!wd) return;
687    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
688    if (!it->hilighted) return;
689    _elm_list_walk(wd);
690
691    edje_object_signal_emit(it->base.view, "elm,state,unselected", "elm");
692    stacking = edje_object_data_get(it->base.view, "stacking");
693    selectraise = edje_object_data_get(it->base.view, "selectraise");
694    if ((selectraise) && (!strcmp(selectraise, "on")))
695      {
696         if ((stacking) && (!strcmp(stacking, "below")))
697            evas_object_lower(it->base.view);
698      }
699    it->hilighted = EINA_FALSE;
700    if (it->selected)
701      {
702         it->selected = EINA_FALSE;
703         wd->selected = eina_list_remove(wd->selected, it);
704         evas_object_smart_callback_call(it->base.widget, "unselected", it);
705      }
706
707    _elm_list_unwalk(wd);
708 }
709
710 static Eina_Bool
711 _swipe_cancel(void *data)
712 {
713    Elm_List_Item *it = data;
714    Widget_Data *wd = elm_widget_data_get(it->base.widget);
715
716    if (!wd) return ECORE_CALLBACK_CANCEL;
717    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ECORE_CALLBACK_CANCEL);
718    wd->swipe = EINA_FALSE;
719    wd->movements = 0;
720    return ECORE_CALLBACK_RENEW;
721 }
722
723 static void
724 _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
725 {
726    Elm_List_Item *it = data;
727    Widget_Data *wd = elm_widget_data_get(it->base.widget);
728    Evas_Event_Mouse_Move *ev = event_info;
729
730    if (!wd) return;
731    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
732    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
733      {
734         if (!wd->on_hold)
735           {
736              wd->on_hold = EINA_TRUE;
737              if (it->long_timer)
738                {
739                   ecore_timer_del(it->long_timer);
740                   it->long_timer = NULL;
741                }
742              if (!wd->wasselected)
743                _item_unselect(it);
744           }
745         if (wd->movements == SWIPE_MOVES) wd->swipe = EINA_TRUE;
746         else
747           {
748              wd->history[wd->movements].x = ev->cur.canvas.x;
749              wd->history[wd->movements].y = ev->cur.canvas.y;
750              if (abs((wd->history[wd->movements].x - wd->history[0].x)) > 40)
751                 wd->swipe = EINA_TRUE;
752              else
753                 wd->movements++;
754           }
755      }
756 }
757
758 static void
759 _scroll_edge_left(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__)
760 {
761    Evas_Object *obj = data;
762    evas_object_smart_callback_call(obj, "scroll,edge,left", NULL);
763 }
764
765 static void
766 _scroll_edge_right(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__)
767 {
768    Evas_Object *obj = data;
769    evas_object_smart_callback_call(obj, "scroll,edge,right", NULL);
770 }
771
772 static void
773 _scroll_edge_top(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__)
774 {
775    Evas_Object *obj = data;
776    evas_object_smart_callback_call(obj, "scroll,edge,top", NULL);
777 }
778
779 static void
780 _scroll_edge_bottom(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__)
781 {
782    Evas_Object *obj = data;
783    evas_object_smart_callback_call(obj, "scroll,edge,bottom", NULL);
784 }
785
786 static Eina_Bool
787 _long_press(void *data)
788 {
789    Elm_List_Item *it = data;
790    Widget_Data *wd = elm_widget_data_get(it->base.widget);
791
792    if (!wd)
793      goto end;
794
795    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ECORE_CALLBACK_CANCEL);
796
797    it->long_timer = NULL;
798
799    if (it->disabled)
800      goto end;
801
802    wd->longpressed = EINA_TRUE;
803    evas_object_smart_callback_call(it->base.widget, "longpressed", it);
804
805  end:
806    return ECORE_CALLBACK_CANCEL;
807 }
808
809 static void
810 _swipe(Elm_List_Item *it)
811 {
812    int i, sum = 0;
813    Widget_Data *wd = elm_widget_data_get(it->base.widget);
814
815    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
816    if (!wd) return;
817    wd->swipe = EINA_FALSE;
818    for (i = 0; i < wd->movements; i++)
819      {
820         sum += wd->history[i].x;
821         if (abs(wd->history[0].y - wd->history[i].y) > 10) return;
822      }
823
824    sum /= wd->movements;
825    if (abs(sum - wd->history[0].x) <= 10) return;
826    evas_object_smart_callback_call(it->base.widget, "swipe", it);
827 }
828
829 static void
830 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
831 {
832    Elm_List_Item *it = data;
833    Widget_Data *wd = elm_widget_data_get(it->base.widget);
834    Evas_Event_Mouse_Down *ev = event_info;
835
836    if (!wd) return;
837    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
838    if (ev->button != 1) return;
839    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
840    else wd->on_hold = EINA_FALSE;
841    if (wd->on_hold) return;
842    wd->wasselected = it->selected;
843    _item_hilight(it);
844    wd->longpressed = EINA_FALSE;
845    if (it->long_timer) ecore_timer_del(it->long_timer);
846    it->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, it);
847    if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
848    it->swipe_timer = ecore_timer_add(0.4, _swipe_cancel, it);
849    /* Always call the callbacks last - the user may delete our context! */
850    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
851      evas_object_smart_callback_call(it->base.widget, "clicked", it);
852    wd->swipe = EINA_FALSE;
853    wd->movements = 0;
854 }
855
856 static void
857 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
858 {
859    Elm_List_Item *it = data;
860    Widget_Data *wd = elm_widget_data_get(it->base.widget);
861    Evas_Event_Mouse_Up *ev = event_info;
862
863    if (!wd) return;
864    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
865    if (ev->button != 1) return;
866    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
867    else wd->on_hold = EINA_FALSE;
868    wd->longpressed = EINA_FALSE;
869    if (it->long_timer)
870      {
871         ecore_timer_del(it->long_timer);
872         it->long_timer = NULL;
873      }
874    if (it->swipe_timer)
875      {
876         ecore_timer_del(it->swipe_timer);
877         it->swipe_timer = NULL;
878      }
879    if (wd->on_hold)
880      {
881         if (wd->swipe) _swipe(data);
882         wd->on_hold = EINA_FALSE;
883         return;
884      }
885    if (wd->longpressed)
886      {
887         if (!wd->wasselected) _item_unselect(it);
888         wd->wasselected = 0;
889         return;
890      }
891
892    if (it->disabled)
893      return;
894    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
895   
896    _elm_list_walk(wd); // watch out "return" before unwalk!
897
898    if (wd->multi)
899      {
900         if (!it->selected)
901           {
902              _item_hilight(it);
903              _item_select(it);
904           }
905         else _item_unselect(it);
906      }
907    else
908      {
909         if (!it->selected)
910           {
911              while (wd->selected)
912                 _item_unselect(wd->selected->data);
913              _item_hilight(it);
914              _item_select(it);
915           }
916         else
917           {
918              const Eina_List *l, *l_next;
919              Elm_List_Item *it2;
920
921              EINA_LIST_FOREACH_SAFE(wd->selected, l, l_next, it2)
922                 if (it2 != it) _item_unselect(it2);
923              _item_hilight(it);
924              _item_select(it);
925           }
926      }
927
928    _elm_list_unwalk(wd);
929 }
930
931 static Elm_List_Item *
932 _item_new(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
933 {
934    Widget_Data *wd = elm_widget_data_get(obj);
935    Elm_List_Item *it;
936
937    if (!wd) return NULL;
938    it = elm_widget_item_new(obj, Elm_List_Item);
939    it->wd = wd;
940    it->label = eina_stringshare_add(label);
941    it->icon = icon;
942    it->end = end;
943    it->func = func;
944    it->base.data = data;
945    it->base.view = edje_object_add(evas_object_evas_get(obj));
946    evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_DOWN,
947                                   _mouse_down, it);
948    evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_UP,
949                                   _mouse_up, it);
950    evas_object_event_callback_add(it->base.view, EVAS_CALLBACK_MOUSE_MOVE,
951                                   _mouse_move, it);
952    evas_object_size_hint_weight_set(it->base.view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
953    evas_object_size_hint_align_set(it->base.view, EVAS_HINT_FILL, EVAS_HINT_FILL);
954    if (it->icon)
955      {
956         elm_widget_sub_object_add(obj, it->icon);
957         evas_object_event_callback_add(it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
958                                        _changed_size_hints, obj);
959      }
960    if (it->end)
961      {
962         elm_widget_sub_object_add(obj, it->end);
963         evas_object_event_callback_add(it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
964                                        _changed_size_hints, obj);
965      }
966    return it;
967 }
968
969 static void
970 _elm_list_mode_set_internal(Widget_Data *wd)
971 {
972    if (!wd->scr)
973      return;
974
975    if (wd->mode == ELM_LIST_LIMIT)
976      {
977         if (!wd->h_mode)
978           {
979              wd->scr_minw = EINA_TRUE;
980              wd->scr_minh = EINA_FALSE;
981           }
982         else
983           {
984              wd->scr_minw = EINA_FALSE;
985              wd->scr_minh = EINA_TRUE;
986           }
987      }
988    else if (wd->mode == ELM_LIST_EXPAND)
989      {
990         wd->scr_minw = EINA_TRUE;
991         wd->scr_minh = EINA_TRUE;
992      }
993    else
994      {
995         wd->scr_minw = EINA_FALSE;
996         wd->scr_minh = EINA_FALSE;
997      }
998
999    _sizing_eval(wd->self);
1000 }
1001
1002 static void
1003 _fix_items(Evas_Object *obj)
1004 {
1005    Widget_Data *wd = elm_widget_data_get(obj);
1006    const Eina_List *l;
1007    Elm_List_Item *it;
1008    Evas_Coord minw[2] = { 0, 0 }, minh[2] = { 0, 0 };
1009    Evas_Coord mw, mh;
1010    int i, redo = 0;
1011    const char *style = elm_widget_style_get(obj);
1012    const char *it_plain = wd->h_mode ? "h_item" : "item";
1013    const char *it_odd = wd->h_mode ? "h_item_odd" : "item_odd";
1014    const char *it_compress = wd->h_mode ? "h_item_compress" : "item_compress";
1015    const char *it_compress_odd = wd->h_mode ? "h_item_compress_odd" : "item_compress_odd";
1016
1017    if (!wd) return;
1018    if (wd->walking)
1019      {
1020         wd->fix_pending = EINA_TRUE;
1021         return;
1022      }
1023
1024    _elm_list_walk(wd); // watch out "return" before unwalk!
1025
1026    EINA_LIST_FOREACH(wd->items, l, it)
1027      {
1028         if (it->deleted) continue;
1029         if (it->icon)
1030           {
1031              evas_object_size_hint_min_get(it->icon, &mw, &mh);
1032              if (mw > minw[0]) minw[0] = mw;
1033              if (mh > minh[0]) minh[0] = mh;
1034           }
1035         if (it->end)
1036           {
1037              evas_object_size_hint_min_get(it->end, &mw, &mh);
1038              if (mw > minw[1]) minw[1] = mw;
1039              if (mh > minh[1]) minh[1] = mh;
1040           }
1041      }
1042
1043    if ((minw[0] != wd->minw[0]) || (minw[1] != wd->minw[1]) ||
1044        (minw[0] != wd->minh[0]) || (minh[1] != wd->minh[1]))
1045      {
1046         wd->minw[0] = minw[0];
1047         wd->minw[1] = minw[1];
1048         wd->minh[0] = minh[0];
1049         wd->minh[1] = minh[1];
1050         redo = 1;
1051      }
1052    i = 0;
1053    EINA_LIST_FOREACH(wd->items, l, it)
1054      {
1055         if (it->deleted)
1056           continue;
1057
1058         it->even = i & 0x1;
1059         if ((it->even != it->is_even) || (!it->fixed) || (redo))
1060           {
1061              const char *stacking;
1062
1063              /* FIXME: separators' themes seem to be b0rked */
1064              if (it->is_separator)
1065                _elm_theme_object_set(obj, it->base.view, "separator",
1066                                      wd->h_mode ? "horizontal" : "vertical",
1067                                      style);
1068              else if (wd->mode == ELM_LIST_COMPRESS)
1069                {
1070                   if (it->even)
1071                     _elm_theme_object_set(obj, it->base.view, "list",
1072                                           it_compress, style);
1073                   else
1074                     _elm_theme_object_set(obj, it->base.view, "list",
1075                                           it_compress_odd, style);
1076                }
1077              else
1078                {
1079                   if (it->even)
1080                     _elm_theme_object_set(obj, it->base.view, "list", it_plain,
1081                                           style);
1082                   else
1083                     _elm_theme_object_set(obj, it->base.view, "list", it_odd,
1084                                           style);
1085                }
1086              stacking = edje_object_data_get(it->base.view, "stacking");
1087              if (stacking)
1088                {
1089                   if (!strcmp(stacking, "below"))
1090                     evas_object_lower(it->base.view);
1091                   else if (!strcmp(stacking, "above"))
1092                     evas_object_raise(it->base.view);
1093                }
1094              edje_object_part_text_set(it->base.view, "elm.text", it->label);
1095
1096              if ((!it->icon) && (minh[0] > 0))
1097                {
1098                   it->icon = evas_object_rectangle_add(evas_object_evas_get(it->base.view));
1099                   evas_object_color_set(it->icon, 0, 0, 0, 0);
1100                   it->dummy_icon = EINA_TRUE;
1101                }
1102              if ((!it->end) && (minh[1] > 0))
1103                {
1104                   it->end = evas_object_rectangle_add(evas_object_evas_get(it->base.view));
1105                   evas_object_color_set(it->end, 0, 0, 0, 0);
1106                   it->dummy_end = EINA_TRUE;
1107                }
1108              if (it->icon)
1109                {
1110                   evas_object_size_hint_min_set(it->icon, minw[0], minh[0]);
1111                   evas_object_size_hint_max_set(it->icon, 99999, 99999);
1112                   edje_object_part_swallow(it->base.view, "elm.swallow.icon", it->icon);
1113                }
1114              if (it->end)
1115                {
1116                   evas_object_size_hint_min_set(it->end, minw[1], minh[1]);
1117                   evas_object_size_hint_max_set(it->end, 99999, 99999);
1118                   edje_object_part_swallow(it->base.view, "elm.swallow.end", it->end);
1119                }
1120              if (!it->fixed)
1121                {
1122                   // this may call up user and it may modify the list item
1123                   // but we're safe as we're flagged as walking.
1124                   // just don't process further
1125                   edje_object_message_signal_process(it->base.view);
1126                   if (it->deleted)
1127                     continue;
1128                   mw = mh = -1;
1129                   elm_coords_finger_size_adjust(1, &mw, 1, &mh);
1130                   edje_object_size_min_restricted_calc(it->base.view, &mw, &mh, mw, mh);
1131                   elm_coords_finger_size_adjust(1, &mw, 1, &mh);
1132                   evas_object_size_hint_min_set(it->base.view, mw, mh);
1133                   evas_object_show(it->base.view);
1134                }
1135              if ((it->selected) || (it->hilighted))
1136                {
1137                   const char *selectraise;
1138
1139                   // this may call up user and it may modify the list item
1140                   // but we're safe as we're flagged as walking.
1141                   // just don't process further
1142                   edje_object_signal_emit(it->base.view, "elm,state,selected", "elm");
1143                   if (it->deleted)
1144                     continue;
1145
1146                   selectraise = edje_object_data_get(it->base.view, "selectraise");
1147                   if ((selectraise) && (!strcmp(selectraise, "on")))
1148                     evas_object_raise(it->base.view);
1149                }
1150              if (it->disabled)
1151                edje_object_signal_emit(it->base.view, "elm,state,disabled",
1152                                        "elm");
1153
1154              it->fixed = EINA_TRUE;
1155              it->is_even = it->even;
1156           }
1157         i++;
1158      }
1159
1160    _elm_list_unwalk(wd);
1161
1162    mw = 0; mh = 0;
1163    evas_object_size_hint_min_get(wd->box, &mw, &mh);
1164
1165    _elm_list_mode_set_internal(wd);
1166 }
1167
1168 static void
1169 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1170 {
1171    Widget_Data *wd = elm_widget_data_get(obj);
1172    if (!wd) return;
1173    if (wd->scr)
1174      elm_smart_scroller_hold_set(wd->scr, EINA_TRUE);
1175 }
1176
1177 static void
1178 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1179 {
1180    Widget_Data *wd = elm_widget_data_get(obj);
1181    if (!wd) return;
1182    if (wd->scr)
1183      elm_smart_scroller_hold_set(wd->scr, EINA_FALSE);
1184 }
1185
1186 static void
1187 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1188 {
1189    Widget_Data *wd = elm_widget_data_get(obj);
1190    if (!wd) return;
1191    if (wd->scr)
1192      elm_smart_scroller_freeze_set(wd->scr, EINA_TRUE);
1193 }
1194
1195 static void
1196 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1197 {
1198    Widget_Data *wd = elm_widget_data_get(obj);
1199    if (!wd) return;
1200    if (wd->scr)
1201      elm_smart_scroller_freeze_set(wd->scr, EINA_FALSE);
1202 }
1203
1204 static void
1205 _resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1206 {
1207    _sizing_eval(data);
1208 }
1209
1210 /**
1211  * Adds a list object.
1212  *
1213  * @param parent The parent object
1214  * @return The created object or NULL upon failure
1215  *
1216  * @ingroup List
1217  */
1218 EAPI Evas_Object *
1219 elm_list_add(Evas_Object *parent)
1220 {
1221    Evas_Object *obj;
1222    Evas *e;
1223    Widget_Data *wd;
1224    Evas_Coord minw, minh;
1225
1226    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1227
1228    wd = ELM_NEW(Widget_Data);
1229    e = evas_object_evas_get(parent);
1230    if (!e) return NULL;
1231    wd->self = obj = elm_widget_add(e);
1232    ELM_SET_WIDTYPE(widtype, "list");
1233    elm_widget_type_set(obj, "list");
1234    elm_widget_sub_object_add(parent, obj);
1235    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1236    elm_widget_data_set(obj, wd);
1237    elm_widget_del_hook_set(obj, _del_hook);
1238    elm_widget_theme_hook_set(obj, _theme_hook);
1239    elm_widget_disable_hook_set(obj, _disable_hook);
1240    elm_widget_can_focus_set(obj, EINA_TRUE);
1241    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
1242    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
1243    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
1244    elm_widget_event_hook_set(obj, _event_hook);
1245
1246    wd->scr = elm_smart_scroller_add(e);
1247    elm_smart_scroller_widget_set(wd->scr, obj);
1248    _theme_hook(obj);
1249    elm_widget_resize_object_set(obj, wd->scr);
1250    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1251                                   _changed_size_hints, obj);
1252    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh);
1253    evas_object_size_hint_min_set(obj, minw, minh);
1254    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, obj);
1255
1256    elm_smart_scroller_bounce_allow_set(wd->scr, EINA_FALSE,
1257                                        _elm_config->thumbscroll_bounce_enable);
1258
1259    wd->box = elm_box_add(parent);
1260    elm_box_homogenous_set(wd->box, 1);
1261    evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND, 0.0);
1262    evas_object_size_hint_align_set(wd->box, EVAS_HINT_FILL, 0.0);
1263    elm_widget_on_show_region_hook_set(wd->box, _show_region_hook, obj);
1264    elm_widget_sub_object_add(obj, wd->box);
1265    elm_smart_scroller_child_set(wd->scr, wd->box);
1266    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1267                                   _changed_size_hints, obj);
1268
1269    evas_object_show(wd->box);
1270
1271    wd->mode = ELM_LIST_SCROLL;
1272
1273    evas_object_smart_callback_add(wd->scr, "edge,left", _scroll_edge_left, obj);
1274    evas_object_smart_callback_add(wd->scr, "edge,right", _scroll_edge_right, obj);
1275    evas_object_smart_callback_add(wd->scr, "edge,top", _scroll_edge_top, obj);
1276    evas_object_smart_callback_add(wd->scr, "edge,bottom", _scroll_edge_bottom, obj);
1277
1278    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
1279    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
1280    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
1281    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
1282    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
1283
1284    _sizing_eval(obj);
1285    return obj;
1286 }
1287
1288 /**
1289  * Appends an item to the list object.
1290  *
1291  * @param obj The list object
1292  * @param label The label of the list item
1293  * @param icon The icon object to use for the left side of the item
1294  * @param end The icon object to use for the right side of the item
1295  * @param func The function to call when the item is clicked
1296  * @param data The data to associate with the item for related callbacks
1297  *
1298  * @return The created item or NULL upon failure
1299  *
1300  * @ingroup List
1301  */
1302 EAPI Elm_List_Item *
1303 elm_list_item_append(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
1304 {
1305    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1306    Widget_Data *wd = elm_widget_data_get(obj);
1307    Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
1308
1309    wd->items = eina_list_append(wd->items, it);
1310    it->node = eina_list_last(wd->items);
1311    elm_box_pack_end(wd->box, it->base.view);
1312    return it;
1313 }
1314
1315 /**
1316  * Prepends an item to the list object.
1317  *
1318  * @param obj The list object
1319  * @param label The label of the list item
1320  * @param icon The icon object to use for the left side of the item
1321  * @param end The icon object to use for the right side of the item
1322  * @param func The function to call when the item is clicked
1323  * @param data The data to associate with the item for related callbacks
1324  *
1325  * @return The created item or NULL upon failure
1326  *
1327  * @ingroup List
1328  */
1329 EAPI Elm_List_Item *
1330 elm_list_item_prepend(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
1331 {
1332    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1333    Widget_Data *wd = elm_widget_data_get(obj);
1334    Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
1335
1336    wd->items = eina_list_prepend(wd->items, it);
1337    it->node = wd->items;
1338    elm_box_pack_start(wd->box, it->base.view);
1339    return it;
1340 }
1341
1342 /**
1343  * Inserts an item into the list object before @p before.
1344  *
1345  * @param obj The list object
1346  * @param before The list item to insert before
1347  * @param label The label of the list item
1348  * @param icon The icon object to use for the left side of the item
1349  * @param end The icon object to use for the right side of the item
1350  * @param func The function to call when the item is clicked
1351  * @param data The data to associate with the item for related callbacks
1352  *
1353  * @return The created item or NULL upon failure
1354  *
1355  * @ingroup List
1356  */
1357 EAPI Elm_List_Item *
1358 elm_list_item_insert_before(Evas_Object *obj, Elm_List_Item *before, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
1359 {
1360    Widget_Data *wd;
1361    Elm_List_Item *it;
1362
1363    EINA_SAFETY_ON_NULL_RETURN_VAL(before, NULL);
1364    if (!before->node) return NULL;
1365    ELM_LIST_ITEM_CHECK_DELETED_RETURN(before, NULL);
1366
1367    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1368    wd = elm_widget_data_get(obj);
1369    if (!wd) return NULL;
1370    it = _item_new(obj, label, icon, end, func, data);
1371    wd->items = eina_list_prepend_relative_list(wd->items, it, before->node);
1372    it->node = before->node->prev;
1373    elm_box_pack_before(wd->box, it->base.view, before->base.view);
1374    return it;
1375 }
1376
1377 /**
1378  * Inserts an item into the list object after @p after.
1379  *
1380  * @param obj The list object
1381  * @param after The list item to insert after
1382  * @param label The label of the list item
1383  * @param icon The icon object to use for the left side of the item
1384  * @param end The icon object to use for the right side of the item
1385  * @param func The function to call when the item is clicked
1386  * @param data The data to associate with the item for related callbacks
1387  *
1388  * @return The created item or NULL upon failure
1389  *
1390  * @ingroup List
1391  */
1392 EAPI Elm_List_Item *
1393 elm_list_item_insert_after(Evas_Object *obj, Elm_List_Item *after, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
1394 {
1395    Widget_Data *wd;
1396    Elm_List_Item *it;
1397
1398    EINA_SAFETY_ON_NULL_RETURN_VAL(after, NULL);
1399    if (!after->node) return NULL;
1400    ELM_LIST_ITEM_CHECK_DELETED_RETURN(after, NULL);
1401
1402    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1403    wd = elm_widget_data_get(obj);
1404    if (!wd) return NULL;
1405    it = _item_new(obj, label, icon, end, func, data);
1406    wd->items = eina_list_append_relative_list(wd->items, it, after->node);
1407    it->node = after->node->next;
1408    elm_box_pack_after(wd->box, it->base.view, after->base.view);
1409    return it;
1410 }
1411
1412 /**
1413  * Insert a new item into the sorted list object.
1414  *
1415  * @param obj The list object
1416  * @param label The label of the list item
1417  * @param icon The icon object to use for the left side of the item
1418  * @param end The icon object to use for the right side of the item
1419  * @param func The function to call when the item is clicked
1420  * @param data The data to associate with the item for related callbacks
1421  * @param cmp_func The function called for the sort.
1422  *
1423  * @return The created item or NULL upon failure
1424  *
1425  * @ingroup List
1426  */
1427 EAPI Elm_List_Item *
1428 elm_list_item_sorted_insert(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data, Eina_Compare_Cb cmp_func)
1429 {
1430    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1431    Widget_Data *wd = elm_widget_data_get(obj);
1432    Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
1433    Eina_List *l;
1434
1435    wd->items = eina_list_sorted_insert(wd->items, cmp_func, it);
1436    l = eina_list_data_find_list(wd->items, it);
1437    l = eina_list_next(l);
1438    if (!l)
1439      {
1440         it->node = eina_list_last(wd->items);
1441         elm_box_pack_end(wd->box, it->base.view);
1442      }
1443    else
1444      {
1445         Elm_List_Item *before = eina_list_data_get(l);
1446         it->node = before->node->prev;
1447         elm_box_pack_before(wd->box, it->base.view, before->base.view);
1448      }
1449    return it;
1450 }
1451
1452 /**
1453  * Clears a list of all items.
1454  *
1455  * @param obj The list object
1456  *
1457  * @ingroup List
1458  */
1459 EAPI void
1460 elm_list_clear(Evas_Object *obj)
1461 {
1462    ELM_CHECK_WIDTYPE(obj, widtype);
1463    Widget_Data *wd = elm_widget_data_get(obj);
1464    Elm_List_Item *it;
1465
1466    if (!wd) return;
1467    if (!wd->items) return;
1468
1469    eina_list_free(wd->selected);
1470    wd->selected = NULL;
1471
1472    if (wd->walking > 0)
1473      {
1474         Eina_List *n;
1475
1476         EINA_LIST_FOREACH(wd->items, n, it)
1477           {
1478              if (it->deleted) continue;
1479              it->deleted = EINA_TRUE;
1480              wd->to_delete = eina_list_append(wd->to_delete, it);
1481           }
1482         return;
1483      }
1484
1485    _elm_list_walk(wd);
1486
1487    EINA_LIST_FREE(wd->items, it)
1488      {
1489         elm_widget_item_pre_notify_del(it);
1490         _elm_list_item_free(it);
1491      }
1492
1493    _elm_list_unwalk(wd);
1494
1495    _fix_items(obj);
1496    _sizing_eval(obj);
1497 }
1498
1499 /**
1500  * Starts the list.  Call before running show() on the list object.
1501  *
1502  * @param obj The list object
1503  *
1504  * @ingroup List
1505  */
1506 EAPI void
1507 elm_list_go(Evas_Object *obj)
1508 {
1509    ELM_CHECK_WIDTYPE(obj, widtype);
1510    Widget_Data *wd = elm_widget_data_get(obj);
1511    if (!wd) return;
1512    _fix_items(obj);
1513 }
1514
1515 /**
1516  * Enables/disables the state of multi-select on the list object.
1517  *
1518  * @param obj The list object
1519  * @param multi If true, multi-select is enabled
1520  *
1521  * @ingroup List
1522  */
1523 EAPI void
1524 elm_list_multi_select_set(Evas_Object *obj, Eina_Bool multi)
1525 {
1526    ELM_CHECK_WIDTYPE(obj, widtype);
1527    Widget_Data *wd = elm_widget_data_get(obj);
1528    if (!wd) return;
1529    wd->multi = multi;
1530 }
1531
1532 /**
1533  * Gets the state of multi-select on the list object.
1534  *
1535  * @param obj The list object
1536  * @return If true, multi-select is enabled
1537  *
1538  * @ingroup List
1539  */
1540 EAPI Eina_Bool
1541 elm_list_multi_select_get(const Evas_Object *obj)
1542 {
1543    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1544    Widget_Data *wd = elm_widget_data_get(obj);
1545    if (!wd) return EINA_FALSE;
1546    return wd->multi;
1547 }
1548
1549 /**
1550  * Set which mode to use for the list with.
1551  *
1552  * @param obj The list object
1553  * @param mode One of @c ELM_LIST_COMPRESS, @c ELM_LIST_SCROLL, @c
1554  *             ELM_LIST_LIMIT or @c ELM_LIST_EXPAND.
1555  *
1556  * @note Default value is @c ELM_LIST_SCROLL. At this mode, the list
1557  * object won't set any of its size hints to inform how a possible
1558  * container should resize it. Then, if it's not created as a "resize
1559  * object", it might end with zero dimensions. The list will respect
1560  * the container's geometry and, if any of its items won't fit into
1561  * its transverse axis, one will be able to scroll it in that
1562  * direction. @c ELM_LIST_COMPRESS is the same as the previous, except
1563  * that it <b>won't</b> let one scroll in the transverse axis, on
1564  * those cases (large items will get cropped). @c ELM_LIST_LIMIT will
1565  * actually set a minimun size hint on the list object, so that
1566  * containers may respect it (and resize itself to fit the child
1567  * properly). More specifically, a minimum size hint will be set for
1568  * its transverse axis, so that the <b>largest</b> item in that
1569  * direction fits well. @c ELM_LIST_EXPAND, besides setting a minimum
1570  * size on the transverse axis, just like the previous mode, will set
1571  * a minimum size on the longitudinal axis too, trying to reserve
1572  * space to all its children to be visible at a time. The last two
1573  * modes can always have effects bounded by setting the list object's
1574  * maximum size hints, though.
1575  *
1576  * @ingroup List
1577  */
1578 EAPI void
1579 elm_list_mode_set(Evas_Object *obj, Elm_List_Mode mode)
1580 {
1581    ELM_CHECK_WIDTYPE(obj, widtype);
1582
1583    Widget_Data *wd;
1584
1585    wd = elm_widget_data_get(obj);
1586    if (!wd)
1587      return;
1588    if (wd->mode == mode)
1589      return;
1590    wd->mode = mode;
1591
1592    _elm_list_mode_set_internal(wd);
1593 }
1594
1595 /**
1596  * Get the mode the list is at.
1597  *
1598  * @param obj The list object
1599  * @return mode One of @c ELM_LIST_COMPRESS, @c ELM_LIST_SCROLL or @c
1600  *         ELM_LIST_LIMIT (@c ELM_LIST_LAST on errors).
1601  *
1602  * @note see elm_list_mode_set() for more information.
1603  *
1604  * @ingroup List
1605  */
1606 EAPI Elm_List_Mode
1607 elm_list_mode_get(const Evas_Object *obj)
1608 {
1609    ELM_CHECK_WIDTYPE(obj, widtype) ELM_LIST_LAST;
1610    Widget_Data *wd = elm_widget_data_get(obj);
1611    if (!wd) return ELM_LIST_LAST;
1612    return wd->mode;
1613 }
1614
1615 /**
1616  * Enables/disables horizontal mode of the list.
1617  *
1618  * @param obj The list object
1619  * @param mode If true, horizontale mode is enabled
1620  *
1621  * @note Bounce options for the list will be reset to default values
1622  * with this funcion. Re-call elm_list_bounce_set() once more after
1623  * this one, if you had custom values.
1624  *
1625  * @ingroup List
1626  */
1627 EAPI void
1628 elm_list_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
1629 {
1630    ELM_CHECK_WIDTYPE(obj, widtype);
1631
1632    Widget_Data *wd;
1633    Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
1634
1635    wd = elm_widget_data_get(obj);
1636    if (!wd)
1637      return;
1638
1639    if (wd->h_mode == horizontal)
1640      return;
1641
1642    wd->h_mode = horizontal;
1643    elm_box_horizontal_set(wd->box, horizontal);
1644
1645    if (horizontal)
1646      {
1647         evas_object_size_hint_weight_set(wd->box, 0.0, EVAS_HINT_EXPAND);
1648         evas_object_size_hint_align_set(wd->box, 0.0, EVAS_HINT_FILL);
1649         elm_smart_scroller_bounce_allow_set(wd->scr, bounce, EINA_FALSE);
1650      }
1651    else
1652      {
1653         evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND, 0.0);
1654         evas_object_size_hint_align_set(wd->box, EVAS_HINT_FILL, 0.0);
1655         elm_smart_scroller_bounce_allow_set(wd->scr, EINA_FALSE, bounce);
1656      }
1657
1658    _elm_list_mode_set_internal(wd);
1659 }
1660
1661 /**
1662  * Retrieve whether horizontal mode is enabled for a list.
1663  *
1664  * @param obj The list object
1665  * @return @c EINA_TRUE, if horizontal mode is enabled and @c
1666  *            EINA_FALSE, otherwise.
1667  *
1668  * @note see elm_list_horizontal_set() for more information.
1669  *
1670  * @ingroup List
1671  */
1672 EAPI Eina_Bool
1673 elm_list_horizontal_get(const Evas_Object *obj)
1674 {
1675    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1676
1677    Widget_Data *wd;
1678
1679    wd = elm_widget_data_get(obj);
1680    if (!wd)
1681      return EINA_FALSE;
1682
1683    return wd->h_mode;
1684 }
1685
1686 /**
1687  * Enables/disables the state of always_select, meaning that
1688  * an item will always be selected.
1689  *
1690  * @param obj The list object
1691  * @param always_select If true, always_select is enabled
1692  *
1693  * @ingroup List
1694  */
1695 EAPI void
1696 elm_list_always_select_mode_set(Evas_Object *obj, Eina_Bool always_select)
1697 {
1698    ELM_CHECK_WIDTYPE(obj, widtype);
1699    Widget_Data *wd = elm_widget_data_get(obj);
1700    if (!wd) return;
1701    wd->always_select = always_select;
1702 }
1703
1704 /**
1705  * Gets the state of always_select.
1706  * See also elm_list_always_select_mode_set()
1707  *
1708  * @param obj The list object
1709  * @return If true, always_select is enabled
1710  *
1711  * @ingroup List
1712  */
1713 EAPI Eina_Bool
1714 elm_list_always_select_mode_get(const Evas_Object *obj)
1715 {
1716    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1717    Widget_Data *wd = elm_widget_data_get(obj);
1718    if (!wd) return EINA_FALSE;
1719    return wd->always_select;
1720 }
1721
1722 /**
1723  * Returns a list of all the list items.
1724  *
1725  * @param obj The list object
1726  * @return An Eina_List* of the list items, or NULL on failure
1727  *
1728  * @ingroup List
1729  */
1730 EAPI const Eina_List *
1731 elm_list_items_get(const Evas_Object *obj)
1732 {
1733    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1734    Widget_Data *wd = elm_widget_data_get(obj);
1735    if (!wd) return NULL;
1736    return wd->items;
1737 }
1738
1739 /**
1740  * Returns the currently selected list item.
1741  *
1742  * @param obj The list object
1743  * @return The selected list item, or NULL on failure
1744  *
1745  * @ingroup List
1746  */
1747 EAPI Elm_List_Item *
1748 elm_list_selected_item_get(const Evas_Object *obj)
1749 {
1750    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1751    Widget_Data *wd = elm_widget_data_get(obj);
1752    if (!wd) return NULL;
1753    if (wd->selected) return wd->selected->data;
1754    return NULL;
1755 }
1756
1757 /**
1758  * Returns a list of the currently selected list items.
1759  *
1760  * @param obj The list object
1761  * @return An Eina_List* of the selected list items, or NULL on failure
1762  *
1763  * @ingroup List
1764  */
1765 EAPI const Eina_List *
1766 elm_list_selected_items_get(const Evas_Object *obj)
1767 {
1768    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1769    Widget_Data *wd = elm_widget_data_get(obj);
1770    if (!wd) return NULL;
1771    return wd->selected;
1772 }
1773
1774 /**
1775  * Sets if item is a separator.
1776  *
1777  * @param it The list item object
1778  * @param setting
1779  */
1780 EAPI void
1781 elm_list_item_separator_set(Elm_List_Item *it, Eina_Bool setting)
1782 {
1783    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1784    it->is_separator = !!setting;
1785 }
1786
1787 /**
1788  * Returns EINA_TRUE if Elm_List_Item is a separator.
1789  *
1790  * @param it The list item object
1791  */
1792 EAPI Eina_Bool
1793 elm_list_item_separator_get(const Elm_List_Item *it)
1794 {
1795    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE);
1796    return it->is_separator;
1797 }
1798
1799
1800 /**
1801  * Sets the selected state of @p it.
1802  *
1803  * @param it The list item
1804  * @param selected Enables/disables the selected state
1805  *
1806  * @ingroup List
1807  */
1808 EAPI void
1809 elm_list_item_selected_set(Elm_List_Item *it, Eina_Bool selected)
1810 {
1811    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1812
1813    Widget_Data *wd = elm_widget_data_get(it->base.widget);
1814    if (!wd) return;
1815
1816    selected = !!selected;
1817    if (it->selected == selected) return;
1818
1819    _elm_list_walk(wd);
1820
1821    if (selected)
1822      {
1823         if (!wd->multi)
1824           {
1825              while (wd->selected)
1826                 _item_unselect(wd->selected->data);
1827           }
1828         _item_hilight(it);
1829         _item_select(it);
1830      }
1831    else
1832       _item_unselect(it);
1833
1834    _elm_list_unwalk(wd);
1835 }
1836
1837 /**
1838  * Gets the selected state of @p it.
1839  *
1840  * @param it The list item
1841  * @return If true, the item is selected
1842  *
1843  * @ingroup List
1844  */
1845 EAPI Eina_Bool
1846 elm_list_item_selected_get(const Elm_List_Item *it)
1847 {
1848    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE);
1849    return it->selected;
1850 }
1851
1852 /**
1853  * Brings @p it to the center of the list view.
1854  *
1855  * @param it The list item
1856  *
1857  * @ingroup List
1858  */
1859 EAPI void
1860 elm_list_item_show(Elm_List_Item *it)
1861 {
1862    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1863    Widget_Data *wd = elm_widget_data_get(it->base.widget);
1864    Evas_Coord bx, by, bw, bh;
1865    Evas_Coord x, y, w, h;
1866
1867    evas_object_geometry_get(wd->box, &bx, &by, &bw, &bh);
1868    evas_object_geometry_get(it->base.view, &x, &y, &w, &h);
1869    x -= bx;
1870    y -= by;
1871    if (wd->scr)
1872      elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
1873 }
1874
1875 /**
1876  * Bring in the given item
1877  *
1878  * This causes list to jump to the given item @p it and show it (by scrolling),
1879  * if it is not fully visible. This may use animation to do so and take a
1880  * period of time
1881  *
1882  * @param it The item
1883  *
1884  * @ingroup List
1885  */
1886 EAPI void
1887 elm_list_item_bring_in(Elm_List_Item *it)
1888 {
1889    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1890    Widget_Data *wd = elm_widget_data_get(it->base.widget);
1891    Evas_Coord bx, by, bw, bh;
1892    Evas_Coord x, y, w, h;
1893
1894    evas_object_geometry_get(wd->box, &bx, &by, &bw, &bh);
1895    evas_object_geometry_get(it->base.view, &x, &y, &w, &h);
1896    x -= bx;
1897    y -= by;
1898    if (wd->scr)
1899      elm_smart_scroller_region_bring_in(wd->scr, x, y, w, h);
1900 }
1901
1902 /**
1903  * Deletes item @p it from the list.
1904  *
1905  * @param it The list item to delete
1906  *
1907  * @ingroup List
1908  */
1909 EAPI void
1910 elm_list_item_del(Elm_List_Item *it)
1911 {
1912    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1913    Widget_Data *wd = elm_widget_data_get(it->base.widget);
1914    if (!wd) return;
1915
1916    if (it->selected) _item_unselect(it);
1917
1918    if (wd->walking > 0)
1919      {
1920         if (it->deleted) return;
1921         it->deleted = EINA_TRUE;
1922         wd->to_delete = eina_list_append(wd->to_delete, it);
1923         return;
1924      }
1925
1926    wd->items = eina_list_remove_list(wd->items, it->node);
1927
1928    _elm_list_walk(wd);
1929
1930    elm_widget_item_pre_notify_del(it);
1931    _elm_list_item_free(it);
1932
1933    _elm_list_unwalk(wd);
1934 }
1935
1936 /**
1937  * Set the function called when a list item is freed.
1938  *
1939  * @param it The item to set the callback on
1940  * @param func The function called
1941  *
1942  * @ingroup List
1943  */
1944 EAPI void
1945 elm_list_item_del_cb_set(Elm_List_Item *it, Evas_Smart_Cb func)
1946 {
1947    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1948    elm_widget_item_del_cb_set(it, func);
1949 }
1950
1951 /**
1952  * Returns the data associated with the item.
1953  *
1954  * @param it The list item
1955  * @return The data associated with @p it
1956  *
1957  * @ingroup List
1958  */
1959 EAPI void *
1960 elm_list_item_data_get(const Elm_List_Item *it)
1961 {
1962    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1963    return elm_widget_item_data_get(it);
1964 }
1965
1966 /**
1967  * Returns the left side icon associated with the item.
1968  *
1969  * @param it The list item
1970  * @return The left side icon associated with @p it
1971  *
1972  * @ingroup List
1973  */
1974 EAPI Evas_Object *
1975 elm_list_item_icon_get(const Elm_List_Item *it)
1976 {
1977    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1978    if (it->dummy_icon) return NULL;
1979    return it->icon;
1980 }
1981
1982 /**
1983  * Sets the left side icon associated with the item.
1984  *
1985  * Once the icon object is set, a previously set one will be deleted.
1986  * You probably don't want, then, to have the <b>same</b> icon object set
1987  * for more than one item of the list.
1988  *
1989  * @param it The list item
1990  * @param icon The left side icon object to associate with @p it
1991  *
1992  * @ingroup List
1993  */
1994 EAPI void
1995 elm_list_item_icon_set(Elm_List_Item *it, Evas_Object *icon)
1996 {
1997    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1998    if (it->icon == icon) return;
1999    if ((it->dummy_icon) && (!icon)) return;
2000    if (it->dummy_icon)
2001      {
2002         evas_object_del(it->icon);
2003         it->dummy_icon = EINA_FALSE;
2004      }
2005    if (!icon)
2006      {
2007         icon = evas_object_rectangle_add(evas_object_evas_get(it->base.widget));
2008         evas_object_color_set(icon, 0, 0, 0, 0);
2009         it->dummy_icon = EINA_TRUE;
2010      }
2011    if (it->icon)
2012      {
2013         evas_object_del(it->icon);
2014         it->icon = NULL;
2015      }
2016    it->icon = icon;
2017    if (it->base.view)
2018      edje_object_part_swallow(it->base.view, "elm.swallow.icon", icon);
2019 }
2020
2021 /**
2022  * Gets the right side icon associated with the item.
2023  *
2024  * @param it The list item
2025  * @return The right side icon object associated with @p it
2026  *
2027  * @ingroup List
2028  */
2029 EAPI Evas_Object *
2030 elm_list_item_end_get(const Elm_List_Item *it)
2031 {
2032    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
2033    if (it->dummy_end) return NULL;
2034    return it->end;
2035 }
2036
2037 /**
2038  * Sets the right side icon associated with the item.
2039  *
2040  * Once the icon object is set, a previously set one will be deleted.
2041  * You probably don't want, then, to have the <b>same</b> icon object set
2042  * for more than one item of the list.
2043  *
2044  * @param it The list item
2045  * @param icon The right side icon object to associate with @p it
2046  *
2047  * @ingroup List
2048  */
2049 EAPI void
2050 elm_list_item_end_set(Elm_List_Item *it, Evas_Object *end)
2051 {
2052    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
2053    if (it->end == end) return;
2054    if ((it->dummy_end) && (!end)) return;
2055    if (it->dummy_end)
2056      {
2057         evas_object_del(it->end);
2058         it->dummy_icon = EINA_FALSE;
2059      }
2060    if (!end)
2061      {
2062         end = evas_object_rectangle_add(evas_object_evas_get(it->base.widget));
2063         evas_object_color_set(end, 0, 0, 0, 0);
2064         it->dummy_end = EINA_TRUE;
2065      }
2066    if (it->end)
2067      {
2068         evas_object_del(it->end);
2069         it->end = NULL;
2070      }
2071    it->end = end;
2072    if (it->base.view)
2073      edje_object_part_swallow(it->base.view, "elm.swallow.end", end);
2074 }
2075
2076 /**
2077  * Gets the base object of the item.
2078  *
2079  * @param it The list item
2080  * @return The base object associated with @p it
2081  *
2082  * @ingroup List
2083  */
2084 EAPI Evas_Object *
2085 elm_list_item_base_get(const Elm_List_Item *it)
2086 {
2087    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
2088    return it->base.view;
2089 }
2090
2091 /**
2092  * Gets the label of the item.
2093  *
2094  * @param it The list item
2095  * @return The label of @p it
2096  *
2097  * @ingroup List
2098  */
2099 EAPI const char *
2100 elm_list_item_label_get(const Elm_List_Item *it)
2101 {
2102    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
2103    return it->label;
2104 }
2105
2106 /**
2107  * Sets the label of the item.
2108  *
2109  * @param it The list item
2110  * @param text The label of @p it
2111  *
2112  * @ingroup List
2113  */
2114 EAPI void
2115 elm_list_item_label_set(Elm_List_Item *it, const char *text)
2116 {
2117    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
2118    if (!eina_stringshare_replace(&it->label, text)) return;
2119    if (it->base.view)
2120      edje_object_part_text_set(it->base.view, "elm.text", it->label);
2121 }
2122
2123 /**
2124  * Gets the item before @p it in the list.
2125  *
2126  * @param it The list item
2127  * @return The item before @p it, or NULL on failure
2128  *
2129  * @ingroup List
2130  */
2131 EAPI Elm_List_Item *
2132 elm_list_item_prev(const Elm_List_Item *it)
2133 {
2134    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
2135    if (it->node->prev) return it->node->prev->data;
2136    else return NULL;
2137 }
2138
2139 /**
2140  * Gets the item after @p it in the list.
2141  *
2142  * @param it The list item
2143  * @return The item after @p it, or NULL on failure
2144  *
2145  * @ingroup List
2146  */
2147 EAPI Elm_List_Item *
2148 elm_list_item_next(const Elm_List_Item *it)
2149 {
2150    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
2151    if (it->node->next) return it->node->next->data;
2152    else return NULL;
2153 }
2154
2155 /**
2156  * Set the text to be shown in the list item.
2157  *
2158  * @param item Target item
2159  * @param text The text to set in the content
2160  *
2161  * Setup the text as tooltip to object. The item can have only one tooltip,
2162  * so any previous tooltip data is removed.
2163  *
2164  * @ingroup List
2165  */
2166 EAPI void
2167 elm_list_item_tooltip_text_set(Elm_List_Item *item, const char *text)
2168 {
2169    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item);
2170    elm_widget_item_tooltip_text_set(item, text);
2171 }
2172
2173 /**
2174  * Set the content to be shown in the tooltip item
2175  *
2176  * Setup the tooltip to item. The item can have only one tooltip,
2177  * so any previous tooltip data is removed. @p func(with @p data) will
2178  * be called every time that need show the tooltip and it should
2179  * return a valid Evas_Object. This object is then managed fully by
2180  * tooltip system and is deleted when the tooltip is gone.
2181  *
2182  * @param item the list item being attached a tooltip.
2183  * @param func the function used to create the tooltip contents.
2184  * @param data what to provide to @a func as callback data/context.
2185  * @param del_cb called when data is not needed anymore, either when
2186  *        another callback replaces @func, the tooltip is unset with
2187  *        elm_list_item_tooltip_unset() or the owner @a item
2188  *        dies. This callback receives as the first parameter the
2189  *        given @a data, and @c event_info is the item.
2190  *
2191  * @ingroup List
2192  */
2193 EAPI void
2194 elm_list_item_tooltip_content_cb_set(Elm_List_Item *item, Elm_Tooltip_Item_Content_Cb func, const void *data, Evas_Smart_Cb del_cb)
2195 {
2196    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item);
2197    elm_widget_item_tooltip_content_cb_set(item, func, data, del_cb);
2198 }
2199
2200 /**
2201  * Unset tooltip from item
2202  *
2203  * @param item list item to remove previously set tooltip.
2204  *
2205  * Remove tooltip from item. The callback provided as del_cb to
2206  * elm_list_item_tooltip_content_cb_set() will be called to notify
2207  * it is not used anymore.
2208  *
2209  * @see elm_list_item_tooltip_content_cb_set()
2210  *
2211  * @ingroup List
2212  */
2213 EAPI void
2214 elm_list_item_tooltip_unset(Elm_List_Item *item)
2215 {
2216    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item);
2217    elm_widget_item_tooltip_unset(item);
2218 }
2219
2220 /**
2221  * Sets a different style for this item tooltip.
2222  *
2223  * @note before you set a style you should define a tooltip with
2224  *       elm_list_item_tooltip_content_cb_set() or
2225  *       elm_list_item_tooltip_text_set()
2226  *
2227  * @param item list item with tooltip already set.
2228  * @param style the theme style to use (default, transparent, ...)
2229  *
2230  * @ingroup List
2231  */
2232 EAPI void
2233 elm_list_item_tooltip_style_set(Elm_List_Item *item, const char *style)
2234 {
2235    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item);
2236    elm_widget_item_tooltip_style_set(item, style);
2237 }
2238
2239 /**
2240  * Get the style for this item tooltip.
2241  *
2242  * @param item list item with tooltip already set.
2243  * @return style the theme style in use, defaults to "default". If the
2244  *         object does not have a tooltip set, then NULL is returned.
2245  *
2246  * @ingroup List
2247  */
2248 EAPI const char *
2249 elm_list_item_tooltip_style_get(const Elm_List_Item *item)
2250 {
2251    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item, NULL);
2252    return elm_widget_item_tooltip_style_get(item);
2253 }
2254
2255 /**
2256  * Set the cursor to be shown when mouse is over the list item
2257  *
2258  * @param item Target item
2259  * @param cursor the cursor name to be used.
2260  *
2261  * @see elm_object_cursor_set()
2262  * @ingroup List
2263  */
2264 EAPI void
2265 elm_list_item_cursor_set(Elm_List_Item *item, const char *cursor)
2266 {
2267    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item);
2268    elm_widget_item_cursor_set(item, cursor);
2269 }
2270
2271 /**
2272  * Get the cursor to be shown when mouse is over the list item
2273  *
2274  * @param item list item with cursor already set.
2275  * @return the cursor name.
2276  *
2277  * @ingroup List
2278  */
2279 EAPI const char *
2280 elm_list_item_cursor_get(const Elm_List_Item *item)
2281 {
2282    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item, NULL);
2283    return elm_widget_item_cursor_get(item);
2284 }
2285
2286 /**
2287  * Unset the cursor to be shown when mouse is over the list item
2288  *
2289  * @param item Target item
2290  *
2291  * @see elm_object_cursor_unset()
2292  * @ingroup List
2293  */
2294 EAPI void
2295 elm_list_item_cursor_unset(Elm_List_Item *item)
2296 {
2297    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item);
2298    elm_widget_item_cursor_unset(item);
2299 }
2300
2301 /**
2302  * Sets a different style for this item cursor.
2303  *
2304  * @note before you set a style you should define a cursor with
2305  *       elm_list_item_cursor_set()
2306  *
2307  * @param item list item with cursor already set.
2308  * @param style the theme style to use (default, transparent, ...)
2309  *
2310  * @ingroup List
2311  */
2312 EAPI void
2313 elm_list_item_cursor_style_set(Elm_List_Item *item, const char *style)
2314 {
2315    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item);
2316    elm_widget_item_cursor_style_set(item, style);
2317 }
2318
2319 /**
2320  * Get the style for this item cursor.
2321  *
2322  * @param item list item with cursor already set.
2323  * @return style the theme style in use, defaults to "default". If the
2324  *         object does not have a cursor set, then NULL is returned.
2325  *
2326  * @ingroup List
2327  */
2328 EAPI const char *
2329 elm_list_item_cursor_style_get(const Elm_List_Item *item)
2330 {
2331    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item, NULL);
2332    return elm_widget_item_cursor_style_get(item);
2333 }
2334
2335 /**
2336  * Set if the cursor set should be searched on the theme or should use
2337  * the provided by the engine, only.
2338  *
2339  * @note before you set if should look on theme you should define a cursor
2340  * with elm_object_cursor_set(). By default it will only look for cursors
2341  * provided by the engine.
2342  *
2343  * @param item widget item with cursor already set.
2344  * @param engine_only boolean to define it cursors should be looked only
2345  * between the provided by the engine or searched on widget's theme as well.
2346  *
2347  * @ingroup List
2348  */
2349 EAPI void
2350 elm_list_item_cursor_engine_only_set(Elm_List_Item *item, Eina_Bool engine_only)
2351 {
2352    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item);
2353    elm_widget_item_cursor_engine_only_set(item, engine_only);
2354 }
2355
2356 /**
2357  * Get the cursor engine only usage for this item cursor.
2358  *
2359  * @param item widget item with cursor already set.
2360  * @return engine_only boolean to define it cursors should be looked only
2361  * between the provided by the engine or searched on widget's theme as well. If
2362  *         the object does not have a cursor set, then EINA_FALSE is returned.
2363  *
2364  * @ingroup List
2365  */
2366 EAPI Eina_Bool
2367 elm_list_item_cursor_engine_only_get(const Elm_List_Item *item)
2368 {
2369    ELM_LIST_ITEM_CHECK_DELETED_RETURN(item, EINA_FALSE);
2370    return elm_widget_item_cursor_engine_only_get(item);
2371 }
2372
2373 /**
2374  * Set bounce mode
2375  *
2376  * This will enable or disable the scroller bounce mode for the list. See
2377  * elm_scroller_bounce_set() for details
2378  *
2379  * @param obj The list object
2380  * @param h_bounce Allow bounce horizontally
2381  * @param v_bounce Allow bounce vertically
2382  *
2383  * @ingroup List
2384  */
2385 EAPI void
2386 elm_list_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
2387 {
2388    ELM_CHECK_WIDTYPE(obj, widtype);
2389    Widget_Data *wd = elm_widget_data_get(obj);
2390    if (!wd) return;
2391    if (wd->scr)
2392      elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
2393 }
2394
2395 /**
2396  * Get the bounce mode
2397  *
2398  * @param obj The List object
2399  * @param h_bounce Allow bounce horizontally
2400  * @param v_bounce Allow bounce vertically
2401  *
2402  * @ingroup List
2403  */
2404 EAPI void
2405 elm_list_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce)
2406 {
2407    ELM_CHECK_WIDTYPE(obj, widtype);
2408    Widget_Data *wd = elm_widget_data_get(obj);
2409    if (!wd) return;
2410    elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce);
2411 }
2412
2413 /**
2414  * Set the scrollbar policy
2415  *
2416  * This sets the scrollbar visibility policy for the given list scroller.
2417  * ELM_SMART_SCROLLER_POLICY_AUTO means the scrollber is made visible if it
2418  * is needed, and otherwise kept hidden. ELM_SMART_SCROLLER_POLICY_ON turns
2419  * it on all the time, and ELM_SMART_SCROLLER_POLICY_OFF always keeps it off.
2420  * This applies respectively for the horizontal and vertical scrollbars.
2421  *
2422  * @param obj The list object
2423  * @param policy_h Horizontal scrollbar policy
2424  * @param policy_v Vertical scrollbar policy
2425  *
2426  * @ingroup List
2427  */
2428 EAPI void
2429 elm_list_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
2430 {
2431    ELM_CHECK_WIDTYPE(obj, widtype);
2432    Widget_Data *wd = elm_widget_data_get(obj);
2433    if (!wd) return;
2434    if ((policy_h >= ELM_SCROLLER_POLICY_LAST) ||
2435        (policy_v >= ELM_SCROLLER_POLICY_LAST))
2436    if (wd->scr)
2437      elm_smart_scroller_policy_set(wd->scr, policy_h, policy_v);
2438 }
2439
2440 EAPI void
2441 elm_list_scroller_policy_get(const Evas_Object *obj, Elm_Scroller_Policy *policy_h, Elm_Scroller_Policy *policy_v)
2442 {
2443    ELM_CHECK_WIDTYPE(obj, widtype);
2444    Widget_Data *wd = elm_widget_data_get(obj);
2445    Elm_Smart_Scroller_Policy s_policy_h, s_policy_v;
2446    if ((!wd) || (!wd->scr)) return;
2447    elm_smart_scroller_policy_get(wd->scr, &s_policy_h, &s_policy_v);
2448    if (policy_h) *policy_h = (Elm_Scroller_Policy) s_policy_h;
2449    if (policy_v) *policy_v = (Elm_Scroller_Policy) s_policy_v;
2450 }
2451
2452 /**
2453  * Sets the disabled/enabled state of a list item.
2454  *
2455  * A disabled item cannot be selected or unselected. It will also
2456  * change its appearance (generally greyed out). This sets the
2457  * disabled state (@c EINA_TRUE for disabled, @c EINA_FALSE for
2458  * enabled).
2459  *
2460  * @param it The item
2461  * @param disabled The disabled state
2462  *
2463  * @ingroup List
2464  */
2465 EAPI void
2466 elm_list_item_disabled_set(Elm_List_Item *it, Eina_Bool disabled)
2467 {
2468    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
2469
2470    if (it->disabled == disabled)
2471      return;
2472
2473    it->disabled = !!disabled;
2474
2475    if (it->disabled)
2476      edje_object_signal_emit(it->base.view, "elm,state,disabled", "elm");
2477    else
2478      edje_object_signal_emit(it->base.view, "elm,state,enabled", "elm");
2479 }
2480
2481 /**
2482  * Get the disabled/enabled state of a list item
2483  *
2484  * @param it The item
2485  * @return The disabled state
2486  *
2487  * See elm_list_item_disabled_set().
2488  *
2489  * @ingroup List
2490  */
2491 EAPI Eina_Bool
2492 elm_list_item_disabled_get(const Elm_List_Item *it)
2493 {
2494    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE);
2495
2496    return it->disabled;
2497 }
2498
2499 EAPI void
2500 elm_list_horizontal_mode_set(Evas_Object *obj, Elm_List_Mode mode)
2501 {
2502    elm_list_mode_set(obj, mode);   
2503 }
2504
2505 EAPI Elm_List_Mode
2506 elm_list_horizontal_mode_get(const Evas_Object *obj)
2507 {
2508    return elm_list_mode_get(obj);
2509 }