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