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