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