Merge branch 'master' of 165.213.180.234:/git/slp/pkgs/elementary
[framework/uifw/elementary.git] / src / lib / elm_list.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup List List
6  * @ingroup Elementary
7  *
8  * A list is a very simple type of list widget.  For more robust
9  * lists, @ref Genlist should probably be used.
10  */
11
12 typedef struct _Widget_Data Widget_Data;
13
14 struct _Widget_Data
15 {
16    Evas_Object *scr, *box, *self;
17    Eina_List *items, *selected, *to_delete;
18    Elm_List_Mode mode;
19    Evas_Coord minw[2], minh[2];
20    int walking;
21    Eina_Bool fix_pending : 1;
22    Eina_Bool on_hold : 1;
23    Eina_Bool multi : 1;
24    Eina_Bool always_select : 1;
25    Eina_Bool longpressed : 1;
26    Eina_Bool wasselected : 1;
27 };
28
29 struct _Elm_List_Item
30 {
31    Eina_List *node;
32    Evas_Object *obj, *base;
33    const char *label;
34    Evas_Object *icon, *end;
35    Evas_Smart_Cb func;
36    Evas_Smart_Cb del_cb;
37    const void *data;
38    Ecore_Timer *long_timer;
39    Eina_Bool deleted : 1;
40    Eina_Bool even : 1;
41    Eina_Bool is_even : 1;
42    Eina_Bool is_separator : 1;
43    Eina_Bool fixed : 1;
44    Eina_Bool selected : 1;
45    Eina_Bool hilighted : 1;
46    Eina_Bool dummy_icon : 1;
47    Eina_Bool dummy_end : 1;
48 };
49
50 static const char *widtype = NULL;
51 static void _del_hook(Evas_Object *obj);
52 static void _theme_hook(Evas_Object *obj);
53 static void _sizing_eval(Evas_Object *obj);
54 static void _on_focus_hook(void *data, Evas_Object *obj);
55 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
56 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
57 static void _fix_items(Evas_Object *obj);
58 static void _mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
59 static void _mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info);
60 static void _mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info);
61
62 #define ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ...)                     \
63   if (!it)                                                              \
64     {                                                                   \
65        fprintf(stderr, "ERROR: %s:%d:%s() "#it" is NULL.\n",            \
66                __FILE__, __LINE__, __FUNCTION__);                       \
67        return __VA_ARGS__;                                              \
68     }                                                                   \
69   else if (it->deleted)                                         \
70     {                                                                   \
71        fprintf(stderr, "ERROR: %s:%d:%s() "#it" has been DELETED.\n",   \
72                __FILE__, __LINE__, __FUNCTION__);                       \
73        return __VA_ARGS__;                                              \
74     }
75
76
77
78 static inline void
79 _elm_list_item_call_del_cb(Elm_List_Item *it)
80 {
81    if (it->del_cb) it->del_cb((void *)it->data, it->obj, it);
82 }
83
84 static inline void
85 _elm_list_item_free(Elm_List_Item *it)
86 {
87    evas_object_event_callback_del_full
88      (it->base, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, it);
89    evas_object_event_callback_del_full
90      (it->base, EVAS_CALLBACK_MOUSE_UP, _mouse_up, it);
91    evas_object_event_callback_del_full
92      (it->base, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, it);
93
94    if (it->icon)
95      evas_object_event_callback_del_full
96        (it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
97         _changed_size_hints, it->obj);
98
99    if (it->end)
100      evas_object_event_callback_del_full
101        (it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
102         _changed_size_hints, it->obj);
103
104    eina_stringshare_del(it->label);
105
106    if (it->long_timer) ecore_timer_del(it->long_timer);
107    if (it->icon) evas_object_del(it->icon);
108    if (it->end) evas_object_del(it->end);
109    if (it->base) evas_object_del(it->base);
110    free(it);
111 }
112
113 static void
114 _elm_list_process_deletions(Widget_Data *wd)
115 {
116    Elm_List_Item *it;
117
118    wd->walking++; // avoid nested deletion and also _sub_del() fix_items
119
120    EINA_LIST_FREE(wd->to_delete, it)
121      {
122         _elm_list_item_call_del_cb(it);
123
124         wd->items = eina_list_remove_list(wd->items, it->node);
125         _elm_list_item_free(it);
126      }
127
128    wd->walking--;
129 }
130
131 static inline void
132 _elm_list_walk(Widget_Data *wd)
133 {
134    if (wd->walking < 0)
135      {
136         fprintf(stderr, "ERROR: walking was negative. fixed!\n");
137         wd->walking = 0;
138      }
139    wd->walking++;
140 }
141
142 static inline void
143 _elm_list_unwalk(Widget_Data *wd)
144 {
145    wd->walking--;
146    if (wd->walking < 0)
147      {
148         fprintf(stderr, "ERROR: walking became negative. fixed!\n");
149         wd->walking = 0;
150      }
151
152    if (wd->walking)
153      return;
154
155    if (wd->to_delete)
156      _elm_list_process_deletions(wd);
157
158    if (wd->fix_pending)
159      {
160         wd->fix_pending = EINA_FALSE;
161         _fix_items(wd->self);
162         _sizing_eval(wd->self);
163      }
164 }
165
166 static void
167 _del_hook(Evas_Object *obj)
168 {
169    Widget_Data *wd = elm_widget_data_get(obj);
170    Elm_List_Item *it;
171    Eina_List *n;
172
173    if (!wd) return;
174    if (wd->walking != 0)
175      fprintf(stderr, "ERROR: list deleted while walking.\n");
176
177    _elm_list_walk(wd);
178    EINA_LIST_FOREACH(wd->items, n, it) _elm_list_item_call_del_cb(it);
179    _elm_list_unwalk(wd);
180    if (wd->to_delete) fprintf(stderr, "ERROR: leaking nodes!\n");
181
182    EINA_LIST_FREE(wd->items, it) _elm_list_item_free(it);
183    eina_list_free(wd->selected);
184    free(wd);
185 }
186
187 static void
188 _sizing_eval(Evas_Object *obj)
189 {
190    Widget_Data *wd = elm_widget_data_get(obj);
191    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
192    if (!wd) return;
193    if (wd->scr)
194      {
195         evas_object_size_hint_min_get(wd->scr, &minw, &minh);
196         evas_object_size_hint_max_get(wd->scr, &maxw, &maxh);
197         evas_object_size_hint_min_set(obj, minw, minh);
198         evas_object_size_hint_max_set(obj, maxw, maxh);
199      }
200 }
201
202 static void
203 _theme_hook(Evas_Object *obj)
204 {
205    Widget_Data *wd = elm_widget_data_get(obj);
206    Elm_List_Item *it;
207    Eina_List *n;
208
209    if (!wd) return;
210    if (wd->scr)
211      {
212         elm_scroller_custom_widget_base_theme_set(wd->scr, "list", "base");
213         elm_object_style_set(wd->scr, elm_widget_style_get(obj));
214 //        edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
215      }
216    EINA_LIST_FOREACH(wd->items, n, it)
217      {
218         it->fixed = 0;
219      }
220    _fix_items(obj);
221    _sizing_eval(obj);
222 }
223
224 static void
225 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
226 {
227    Widget_Data *wd = elm_widget_data_get(obj);
228    if (!wd) return;
229    if (elm_widget_focus_get(obj))
230      evas_object_focus_set(wd->scr, 1);
231    else
232      evas_object_focus_set(wd->scr, 0);
233 }
234
235 static void
236 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
237 {
238    Widget_Data *wd = elm_widget_data_get(data);
239    if (!wd) return;
240 //   _fix_items(data);
241 //   _sizing_eval(data);
242 }
243
244 static void
245 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
246 {
247    Widget_Data *wd = elm_widget_data_get(obj);
248    Evas_Object *sub = event_info;
249    const Eina_List *l;
250    Elm_List_Item *it;
251
252    if (!wd) return;
253    if (!sub) abort();
254    if (sub == wd->scr)
255      wd->scr = NULL;
256    else
257      {
258         EINA_LIST_FOREACH(wd->items, l, it)
259           {
260              if ((sub == it->icon) || (sub == it->end))
261                {
262                   if (it->icon == sub) it->icon = NULL;
263                   if (it->end == sub) it->end = NULL;
264                   evas_object_event_callback_del_full
265                     (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints,
266                      obj);
267                   if (!wd->walking)
268                     {
269                        _fix_items(obj);
270                        _sizing_eval(obj);
271                     }
272                   else
273                     wd->fix_pending = EINA_TRUE;
274                   break;
275                }
276           }
277      }
278 }
279
280 static void
281 _item_hilight(Elm_List_Item *it)
282 {
283    Widget_Data *wd = elm_widget_data_get(it->obj);
284    const char *selectraise;
285
286    if (!wd) return;
287    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
288    if (it->hilighted) return;
289    _elm_list_walk(wd);
290
291    edje_object_signal_emit(it->base, "elm,state,selected", "elm");
292    selectraise = edje_object_data_get(it->base, "selectraise");
293    if ((selectraise) && (!strcmp(selectraise, "on")))
294      evas_object_raise(it->base);
295    it->hilighted = EINA_TRUE;
296
297    _elm_list_unwalk(wd);
298 }
299
300 static void
301 _item_select(Elm_List_Item *it)
302 {
303    Widget_Data *wd = elm_widget_data_get(it->obj);
304
305    if (!wd) return;
306    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
307    if (it->selected)
308      {
309         if (wd->always_select) goto call;
310         return;
311      }
312    it->selected = EINA_TRUE;
313    wd->selected = eina_list_append(wd->selected, it);
314    call:
315    _elm_list_walk(wd);
316
317    if (it->func) it->func((void *)it->data, it->obj, it);
318    evas_object_smart_callback_call(it->obj, "selected", it);
319
320    _elm_list_unwalk(wd);
321 }
322
323 static void
324 _item_unselect(Elm_List_Item *it)
325 {
326    Widget_Data *wd = elm_widget_data_get(it->obj);
327    const char *stacking, *selectraise;
328
329    if (!wd) return;
330    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
331    if (!it->hilighted) return;
332    _elm_list_walk(wd);
333
334    edje_object_signal_emit(it->base, "elm,state,unselected", "elm");
335    stacking = edje_object_data_get(it->base, "stacking");
336    selectraise = edje_object_data_get(it->base, "selectraise");
337    if ((selectraise) && (!strcmp(selectraise, "on")))
338      {
339         if ((stacking) && (!strcmp(stacking, "below")))
340           evas_object_lower(it->base);
341      }
342    it->hilighted = EINA_FALSE;
343    if (it->selected)
344      {
345         it->selected = EINA_FALSE;
346         wd->selected = eina_list_remove(wd->selected, it);
347         evas_object_smart_callback_call(it->obj, "unselected", it);
348      }
349
350    _elm_list_unwalk(wd);
351 }
352
353 static void
354 _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
355 {
356    Elm_List_Item *it = data;
357    Widget_Data *wd = elm_widget_data_get(it->obj);
358    Evas_Event_Mouse_Move *ev = event_info;
359
360    if (!wd) return;
361    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
362    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
363      {
364         if (!wd->on_hold)
365           {
366              wd->on_hold = EINA_TRUE;
367              if (it->long_timer)
368                {
369                   ecore_timer_del(it->long_timer);
370                   it->long_timer = NULL;
371                }
372              if (!wd->wasselected)
373                _item_unselect(it);
374           }
375      }
376 }
377
378 static Eina_Bool
379 _long_press(void *data)
380 {
381    Elm_List_Item *it = data;
382    Widget_Data *wd = elm_widget_data_get(it->obj);
383
384    if (!wd) return ECORE_CALLBACK_CANCEL;
385    it->long_timer = NULL;
386    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, 0);
387    wd->longpressed = EINA_TRUE;
388    evas_object_smart_callback_call(it->obj, "longpressed", it);
389    return ECORE_CALLBACK_CANCEL;
390 }
391
392 static void
393 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
394 {
395    Elm_List_Item *it = data;
396    Widget_Data *wd = elm_widget_data_get(it->obj);
397    Evas_Event_Mouse_Down *ev = event_info;
398
399    if (!wd) return;
400    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
401    if (ev->button != 1) return;
402    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
403    else wd->on_hold = EINA_FALSE;
404    if (wd->on_hold) return;
405    wd->wasselected = it->selected;
406    _item_hilight(it);
407    wd->longpressed = EINA_FALSE;
408    if (it->long_timer) ecore_timer_del(it->long_timer);
409    it->long_timer = ecore_timer_add(1.0, _long_press, it);
410    /* Always call the callbacks last - the user may delete our context! */
411    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
412      evas_object_smart_callback_call(it->obj, "clicked", it);
413 }
414
415 static void
416 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
417 {
418    Elm_List_Item *it = data;
419    Widget_Data *wd = elm_widget_data_get(it->obj);
420    Evas_Event_Mouse_Up *ev = event_info;
421
422    if (!wd) return;
423    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
424    if (ev->button != 1) return;
425    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
426    else wd->on_hold = EINA_FALSE;
427    wd->longpressed = EINA_FALSE;
428    if (it->long_timer)
429      {
430         ecore_timer_del(it->long_timer);
431         it->long_timer = NULL;
432      }
433    if (wd->on_hold)
434      {
435         wd->on_hold = EINA_FALSE;
436         return;
437      }
438    if (wd->longpressed)
439      {
440         if (!wd->wasselected) _item_unselect(it);
441         wd->wasselected = 0;
442         return;
443      }
444
445    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return; 
446
447    _elm_list_walk(wd); // watch out "return" before unwalk!
448
449    if (wd->multi)
450      {
451         if (!it->selected)
452           {
453              _item_hilight(it);
454              _item_select(it);
455           }
456         else _item_unselect(it);
457      }
458    else
459      {
460         if (!it->selected)
461           {
462              while (wd->selected)
463                _item_unselect(wd->selected->data);
464              _item_hilight(it);
465              _item_select(it);
466           }
467         else
468           {
469              const Eina_List *l, *l_next;
470              Elm_List_Item *it2;
471
472              EINA_LIST_FOREACH_SAFE(wd->selected, l, l_next, it2)
473                if (it2 != it) _item_unselect(it2);
474              _item_hilight(it);
475              _item_select(it);
476           }
477      }
478
479    _elm_list_unwalk(wd);
480 }
481
482 static Elm_List_Item *
483 _item_new(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
484 {
485    Widget_Data *wd = elm_widget_data_get(obj);
486    Elm_List_Item *it;
487
488    if (!wd) return NULL;
489    it = calloc(1, sizeof(Elm_List_Item));
490    it->obj = obj;
491    it->label = eina_stringshare_add(label);
492    it->icon = icon;
493    it->end = end;
494    it->func = func;
495    it->data = data;
496    it->base = edje_object_add(evas_object_evas_get(obj));
497    evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_DOWN,
498                                   _mouse_down, it);
499    evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_UP,
500                                   _mouse_up, it);
501    evas_object_event_callback_add(it->base, EVAS_CALLBACK_MOUSE_MOVE,
502                                   _mouse_move, it);
503    evas_object_size_hint_weight_set(it->base, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
504    evas_object_size_hint_align_set(it->base, EVAS_HINT_FILL, EVAS_HINT_FILL);
505    if (it->icon)
506      {
507         elm_widget_sub_object_add(obj, it->icon);
508         evas_object_event_callback_add(it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
509                                        _changed_size_hints, obj);
510      }
511    if (it->end)
512      {
513         elm_widget_sub_object_add(obj, it->end);
514         evas_object_event_callback_add(it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
515                                        _changed_size_hints, obj);
516      }
517    return it;
518 }
519
520 static void
521 _fix_items(Evas_Object *obj)
522 {
523    Widget_Data *wd = elm_widget_data_get(obj);
524    const Eina_List *l;
525    Elm_List_Item *it;
526    Evas_Coord minw[2] = { 0, 0 }, minh[2] = { 0, 0 };
527    Evas_Coord mw, mh;
528    int i, redo = 0;
529    const char *style = elm_widget_style_get(obj);
530
531    if (!wd) return;
532    if (wd->walking)
533      {
534         wd->fix_pending = EINA_TRUE;
535         return;
536      }
537
538    _elm_list_walk(wd); // watch out "return" before unwalk!
539
540    EINA_LIST_FOREACH(wd->items, l, it)
541      {
542         if (it->deleted) continue;
543         if (it->icon)
544           {
545              evas_object_size_hint_min_get(it->icon, &mw, &mh);
546              if (mw > minw[0]) minw[0] = mw;
547              if (mh > minh[0]) minh[0] = mh;
548           }
549         if (it->end)
550           {
551              evas_object_size_hint_min_get(it->end, &mw, &mh);
552              if (mw > minw[1]) minw[1] = mw;
553              if (mh > minh[1]) minh[1] = mh;
554           }
555      }
556    if ((minw[0] != wd->minw[0]) || (minw[1] != wd->minw[1]) ||
557        (minw[0] != wd->minh[0]) || (minh[1] != wd->minh[1]))
558      {
559         wd->minw[0] = minw[0];
560         wd->minw[1] = minw[1];
561         wd->minh[0] = minh[0];
562         wd->minh[1] = minh[1];
563         redo = 1;
564      }
565    i = 0;
566    EINA_LIST_FOREACH(wd->items, l, it)
567      {
568         if (it->deleted) continue;
569         it->even = i & 0x1;
570         if ((it->even != it->is_even) || (!it->fixed) || (redo))
571           {
572              const char *stacking;
573
574              if (it->is_separator)
575                _elm_theme_object_set(obj, it->base, "list", "separator", style);
576              else if (wd->mode == ELM_LIST_COMPRESS)
577                {
578                   if (it->even)
579                     _elm_theme_object_set(obj, it->base, "list", "item_compress", style);
580                   else
581                     _elm_theme_object_set(obj, it->base, "list", "item_compress_odd", style);
582                }
583              else
584                {
585                   if (it->even)
586                     _elm_theme_object_set(obj, it->base, "list", "item", style);
587                   else
588                     _elm_theme_object_set(obj, it->base, "list", "item_odd", style);
589                }
590              stacking = edje_object_data_get(it->base, "stacking");
591              if (stacking)
592                {
593                   if (!strcmp(stacking, "below"))
594                     evas_object_lower(it->base);
595                   else if (!strcmp(stacking, "above"))
596                     evas_object_raise(it->base);
597                }
598              edje_object_part_text_set(it->base, "elm.text", it->label);
599              if ((!it->icon) && (minh[0] > 0))
600                {
601                   it->icon = evas_object_rectangle_add(evas_object_evas_get(it->base));
602                   evas_object_color_set(it->icon, 0, 0, 0, 0);
603                   it->dummy_icon = EINA_TRUE;
604                }
605              if ((!it->end) && (minh[1] > 0))
606                {
607                   it->end = evas_object_rectangle_add(evas_object_evas_get(it->base));
608                   evas_object_color_set(it->end, 0, 0, 0, 0);
609                   it->dummy_end = EINA_TRUE;
610                }
611              if (it->icon)
612                {
613                   evas_object_size_hint_min_set(it->icon, minw[0], minh[0]);
614                   evas_object_size_hint_max_set(it->icon, 99999, 99999);
615                   edje_object_part_swallow(it->base, "elm.swallow.icon", it->icon);
616                }
617              if (it->end)
618                {
619                   evas_object_size_hint_min_set(it->end, minw[1], minh[1]);
620                   evas_object_size_hint_max_set(it->end, 99999, 99999);
621                   edje_object_part_swallow(it->base, "elm.swallow.end", it->end);
622                }
623              if (!it->fixed)
624                {
625                   // this may call up user and it may modify the list item
626                   // but we're safe as we're flagged as walking.
627                   // just don't process further
628                   edje_object_message_signal_process(it->base);
629                   if (it->deleted)
630                     continue;
631                   mw = mh = -1;
632                   elm_coords_finger_size_adjust(1, &mw, 1, &mh);
633                   edje_object_size_min_restricted_calc(it->base, &mw, &mh, mw, mh);
634                   elm_coords_finger_size_adjust(1, &mw, 1, &mh);
635                   evas_object_size_hint_min_set(it->base, mw, mh);
636                   evas_object_show(it->base);
637                }
638              if ((it->selected) || (it->hilighted))
639                {
640                   const char *selectraise;
641
642                   // this may call up user and it may modify the list item
643                   // but we're safe as we're flagged as walking.
644                   // just don't process further
645                   edje_object_signal_emit(it->base, "elm,state,selected", "elm");
646                   if (it->deleted)
647                     continue;
648
649                   selectraise = edje_object_data_get(it->base, "selectraise");
650                   if ((selectraise) && (!strcmp(selectraise, "on")))
651                     evas_object_raise(it->base);
652                   stacking = edje_object_data_get(it->base, "stacking");
653                }
654              it->fixed = EINA_TRUE;
655              it->is_even = it->even;
656           }
657         i++;
658      }
659
660    _elm_list_unwalk(wd);
661
662    mw = 0; mh = 0;
663    evas_object_size_hint_min_get(wd->box, &mw, &mh);
664    if (wd->scr)
665      {
666         if (wd->mode == ELM_LIST_LIMIT)
667           elm_scroller_content_min_limit(wd->scr, 1, 0);
668         else
669           elm_scroller_content_min_limit(wd->scr, 0, 0);
670      }
671    _sizing_eval(obj);
672 }
673
674 static void
675 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
676 {
677    Widget_Data *wd = elm_widget_data_get(obj);
678    if (!wd) return;
679    if (wd->scr)
680      elm_widget_scroll_hold_push(wd->scr);
681 }
682
683 static void
684 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
685 {
686    Widget_Data *wd = elm_widget_data_get(obj);
687    if (!wd) return;
688    if (wd->scr)
689      elm_widget_scroll_hold_pop(wd->scr);
690 }
691
692 static void
693 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
694 {
695    Widget_Data *wd = elm_widget_data_get(obj);
696    if (!wd) return;
697    if (wd->scr)
698      elm_widget_scroll_hold_push(wd->scr);
699 }
700
701 static void
702 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
703 {
704    Widget_Data *wd = elm_widget_data_get(obj);
705    if (!wd) return;
706    if (wd->scr)
707      elm_widget_scroll_hold_pop(wd->scr);
708 }
709
710 /**
711  * Adds a list object.
712  *
713  * @param parent The parent object
714  * @return The created object or NULL upon failure
715  *
716  * @ingroup List
717  */
718 EAPI Evas_Object *
719 elm_list_add(Evas_Object *parent)
720 {
721    Evas_Object *obj;
722    Evas *e;
723    Widget_Data *wd;
724
725    wd = ELM_NEW(Widget_Data);
726    e = evas_object_evas_get(parent);
727    wd->self = obj = elm_widget_add(e);
728    ELM_SET_WIDTYPE(widtype, "list");
729    elm_widget_type_set(obj, "list");
730    elm_widget_sub_object_add(parent, obj);
731    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
732    elm_widget_data_set(obj, wd);
733    elm_widget_del_hook_set(obj, _del_hook);
734    elm_widget_theme_hook_set(obj, _theme_hook);
735    elm_widget_can_focus_set(obj, 1);
736
737    wd->scr = elm_scroller_add(parent);
738    elm_scroller_custom_widget_base_theme_set(wd->scr, "list", "base");
739    elm_widget_resize_object_set(obj, wd->scr);
740
741    elm_scroller_bounce_set(wd->scr, 0, 1);
742
743    wd->box = elm_box_add(parent);
744    elm_box_homogenous_set(wd->box, 1);
745    evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND, 0.0);
746    evas_object_size_hint_align_set(wd->box, EVAS_HINT_FILL, 0.0);
747    elm_scroller_content_set(wd->scr, wd->box);
748    evas_object_show(wd->box);
749
750    wd->mode = ELM_LIST_SCROLL;
751
752    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
753    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
754    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
755    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
756    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
757
758    _sizing_eval(obj);
759    return obj;
760 }
761
762 /**
763  * Appends an item to the list object.
764  *
765  * @param obj The list object
766  * @param label The label of the list item
767  * @param icon The icon object to use for the left side of the item
768  * @param end The icon object to use for the right side of the item
769  * @param func The function to call when the item is clicked
770  * @param data The data to associate with the item for related callbacks
771  *
772  * @return The created item or NULL upon failure
773  *
774  * @ingroup List
775  */
776 EAPI Elm_List_Item *
777 elm_list_item_append(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
778 {
779    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
780    Widget_Data *wd = elm_widget_data_get(obj);
781    Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
782
783    wd->items = eina_list_append(wd->items, it);
784    it->node = eina_list_last(wd->items);
785    elm_box_pack_end(wd->box, it->base);
786    return it;
787 }
788
789 /**
790  * Prepends an item to the list object.
791  *
792  * @param obj The list object
793  * @param label The label of the list item
794  * @param icon The icon object to use for the left side of the item
795  * @param end The icon object to use for the right side of the item
796  * @param func The function to call when the item is clicked
797  * @param data The data to associate with the item for related callbacks
798  *
799  * @return The created item or NULL upon failure
800  *
801  * @ingroup List
802  */
803 EAPI Elm_List_Item *
804 elm_list_item_prepend(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
805 {
806    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
807    Widget_Data *wd = elm_widget_data_get(obj);
808    Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
809
810    wd->items = eina_list_prepend(wd->items, it);
811    it->node = wd->items;
812    elm_box_pack_start(wd->box, it->base);
813    return it;
814 }
815
816 /**
817  * Inserts an item into the list object before @p before.
818  *
819  * @param obj The list object
820  * @param before The list item to insert before
821  * @param label The label of the list item
822  * @param icon The icon object to use for the left side of the item
823  * @param end The icon object to use for the right side of the item
824  * @param func The function to call when the item is clicked
825  * @param data The data to associate with the item for related callbacks
826  *
827  * @return The created item or NULL upon failure
828  *
829  * @ingroup List
830  */
831 EAPI Elm_List_Item *
832 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)
833 {
834    Widget_Data *wd;
835    Elm_List_Item *it;
836
837    if ((!before) || (!before->node)) return NULL;
838    ELM_LIST_ITEM_CHECK_DELETED_RETURN(before, NULL);
839
840    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
841    wd = elm_widget_data_get(obj);
842    if (!wd) return NULL;
843    it = _item_new(obj, label, icon, end, func, data);
844    wd->items = eina_list_prepend_relative_list(wd->items, it, before->node);
845    it->node = before->node->prev;
846    elm_box_pack_before(wd->box, it->base, before->base);
847    return it;
848 }
849
850 /**
851  * Inserts an item into the list object after @p after.
852  *
853  * @param obj The list object
854  * @param after The list item to insert after
855  * @param label The label of the list item
856  * @param icon The icon object to use for the left side of the item
857  * @param end The icon object to use for the right side of the item
858  * @param func The function to call when the item is clicked
859  * @param data The data to associate with the item for related callbacks
860  *
861  * @return The created item or NULL upon failure
862  *
863  * @ingroup List
864  */
865 EAPI Elm_List_Item *
866 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)
867 {
868    Widget_Data *wd;
869    Elm_List_Item *it;
870
871    if ((!after) || (!after->node)) return NULL;
872    ELM_LIST_ITEM_CHECK_DELETED_RETURN(after, NULL);
873
874    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
875    wd = elm_widget_data_get(obj);
876    if (!wd) return NULL;
877    it = _item_new(obj, label, icon, end, func, data);
878    wd->items = eina_list_append_relative_list(wd->items, it, after->node);
879    it->node = after->node->next;
880    elm_box_pack_after(wd->box, it->base, after->base);
881    return it;
882 }
883
884 /**
885  * Insert a new item into the sorted list object.
886  *
887  * @param obj The list object
888  * @param label The label of the list item
889  * @param icon The icon object to use for the left side of the item
890  * @param end The icon object to use for the right side of the item
891  * @param func The function to call when the item is clicked
892  * @param data The data to associate with the item for related callbacks
893  * @param cmp_func The function called for the sort.
894  *
895  * @return The created item or NULL upon failure
896  *
897  * @ingroup List
898  */
899 EAPI Elm_List_Item *
900 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)
901 {
902    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
903    Widget_Data *wd = elm_widget_data_get(obj);
904    Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
905    Eina_List *l;
906
907    wd->items = eina_list_sorted_insert(wd->items, cmp_func, it);
908    l = eina_list_data_find_list(wd->items, it);
909    l = eina_list_next(l);
910    if (!l)
911      {
912         it->node = eina_list_last(wd->items);
913         elm_box_pack_end(wd->box, it->base);
914      }
915    else
916      {
917         Elm_List_Item *before = eina_list_data_get(l);
918         it->node = before->node->prev;
919         elm_box_pack_before(wd->box, it->base, before->base);
920      }
921    return it;
922 }
923
924 /**
925  * Clears a list of all items.
926  *
927  * @param obj The list object
928  *
929  * @ingroup List
930  */
931 EAPI void
932 elm_list_clear(Evas_Object *obj)
933 {
934    ELM_CHECK_WIDTYPE(obj, widtype);
935    Widget_Data *wd = elm_widget_data_get(obj);
936    Elm_List_Item *it;
937
938    if (!wd) return;
939    if (!wd->items) return;
940
941    eina_list_free(wd->selected);
942    wd->selected = NULL;
943
944    if (wd->walking > 0)
945      {
946         Eina_List *n;
947
948         EINA_LIST_FOREACH(wd->items, n, it)
949           {
950              if (it->deleted) continue;
951              it->deleted = EINA_TRUE;
952              wd->to_delete = eina_list_append(wd->to_delete, it);
953           }
954         return;
955      }
956
957    _elm_list_walk(wd);
958
959    EINA_LIST_FREE(wd->items, it)
960      {
961         _elm_list_item_call_del_cb(it);
962         _elm_list_item_free(it);
963      }
964
965    _elm_list_unwalk(wd);
966
967    _fix_items(obj);
968    _sizing_eval(obj);
969 }
970
971 /**
972  * Starts the list.  Call before running show() on the list object.
973  *
974  * @param obj The list object
975  *
976  * @ingroup List
977  */
978 EAPI void
979 elm_list_go(Evas_Object *obj)
980 {
981    ELM_CHECK_WIDTYPE(obj, widtype);
982    Widget_Data *wd = elm_widget_data_get(obj);
983    if (!wd) return;
984    _fix_items(obj);
985 }
986
987 /**
988  * Enables/disables the state of multi-select on the list object.
989  *
990  * @param obj The list object
991  * @param multi If true, multi-select is enabled
992  *
993  * @ingroup List
994  */
995 EAPI void
996 elm_list_multi_select_set(Evas_Object *obj, Eina_Bool multi)
997 {
998    ELM_CHECK_WIDTYPE(obj, widtype);
999    Widget_Data *wd = elm_widget_data_get(obj);
1000    if (!wd) return;
1001    wd->multi = multi;
1002 }
1003
1004 /**
1005  * Gets the state of multi-select on the list object.
1006  *
1007  * @param obj The list object
1008  * @return If true, multi-select is enabled
1009  *
1010  * @ingroup List
1011  */
1012 EAPI Eina_Bool
1013 elm_list_multi_select_get(const Evas_Object *obj)
1014 {
1015    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1016    Widget_Data *wd = elm_widget_data_get(obj);
1017    if (!wd) return EINA_FALSE;
1018    return wd->multi;
1019 }
1020
1021 /**
1022  * Enables/disables horizontal mode of the list
1023  *
1024  * @param obj The list object
1025  * @param mode If true, horizontale mode is enabled
1026  *
1027  * @ingroup List
1028  */
1029 EAPI void
1030 elm_list_horizontal_mode_set(Evas_Object *obj, Elm_List_Mode mode)
1031 {
1032    ELM_CHECK_WIDTYPE(obj, widtype);
1033    Widget_Data *wd = elm_widget_data_get(obj);
1034    if (!wd) return;
1035    if (wd->mode == mode) return;
1036    wd->mode = mode;
1037    if (wd->scr)
1038      {
1039         if (wd->mode == ELM_LIST_LIMIT)
1040           elm_scroller_content_min_limit(wd->scr, 1, 0);
1041         else
1042           elm_scroller_content_min_limit(wd->scr, 0, 0);
1043      }
1044 }
1045
1046 /**
1047  * Gets the state of horizontal mode of the list
1048  *
1049  * @param obj The list object
1050  * @return If true, horizontale mode is enabled
1051  *
1052  * @ingroup List
1053  */
1054 EAPI Elm_List_Mode
1055 elm_list_horizontal_mode_get(const Evas_Object *obj)
1056 {
1057    ELM_CHECK_WIDTYPE(obj, widtype) ELM_LIST_SCROLL;
1058    Widget_Data *wd = elm_widget_data_get(obj);
1059    if (!wd) return ELM_LIST_SCROLL;
1060    return wd->mode;
1061 }
1062
1063 /**
1064  * Enables/disables the state of always_select, meaning that
1065  * an item will always be selected.
1066  *
1067  * @param obj The list object
1068  * @param always_select If true, always_select is enabled
1069  *
1070  * @ingroup List
1071  */
1072 EAPI void
1073 elm_list_always_select_mode_set(Evas_Object *obj, Eina_Bool always_select)
1074 {
1075    ELM_CHECK_WIDTYPE(obj, widtype);
1076    Widget_Data *wd = elm_widget_data_get(obj);
1077    if (!wd) return;
1078    wd->always_select = always_select;
1079 }
1080
1081 /**
1082  * Gets the state of always_select.
1083  * See also elm_list_always_select_mode_set()
1084  *
1085  * @param obj The list object
1086  * @return If true, always_select is enabled
1087  *
1088  * @ingroup List
1089  */
1090 EAPI Eina_Bool
1091 elm_list_always_select_mode_get(const Evas_Object *obj)
1092 {
1093    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1094    Widget_Data *wd = elm_widget_data_get(obj);
1095    if (!wd) return EINA_FALSE;
1096    return wd->always_select;
1097 }
1098
1099 /**
1100  * Returns a list of all the list items.
1101  *
1102  * @param obj The list object
1103  * @return An Eina_List* of the list items, or NULL on failure
1104  *
1105  * @ingroup List
1106  */
1107 EAPI const Eina_List *
1108 elm_list_items_get(const Evas_Object *obj)
1109 {
1110    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1111    Widget_Data *wd = elm_widget_data_get(obj);
1112    if (!wd) return NULL;
1113    return wd->items;
1114 }
1115
1116 /**
1117  * Returns the currently selected list item.
1118  *
1119  * @param obj The list object
1120  * @return The selected list item, or NULL on failure
1121  *
1122  * @ingroup List
1123  */
1124 EAPI Elm_List_Item *
1125 elm_list_selected_item_get(const Evas_Object *obj)
1126 {
1127    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1128    Widget_Data *wd = elm_widget_data_get(obj);
1129    if (!wd) return NULL;
1130    if (wd->selected) return wd->selected->data;
1131    return NULL;
1132 }
1133
1134 /**
1135  * Returns a list of the currently selected list items.
1136  *
1137  * @param obj The list object
1138  * @return An Eina_List* of the selected list items, or NULL on failure
1139  *
1140  * @ingroup List
1141  */
1142 EAPI const Eina_List *
1143 elm_list_selected_items_get(const Evas_Object *obj)
1144 {
1145    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1146    Widget_Data *wd = elm_widget_data_get(obj);
1147    if (!wd) return NULL;
1148    return wd->selected;
1149 }
1150
1151 /**
1152  * Sets if item is a separator.
1153  *
1154  * @param it The list item object
1155  * @param setting
1156  */
1157 EAPI void
1158 elm_list_item_separator_set(Elm_List_Item *it, Eina_Bool setting)
1159 {
1160    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1161    it->is_separator = !!setting;
1162 }
1163
1164 /**
1165  * Returns EINA_TRUE if Elm_List_Item is a separator.
1166  *
1167  * @param it The list item object
1168  */
1169 EAPI Eina_Bool
1170 elm_list_item_separator_get(const Elm_List_Item *it)
1171 {
1172    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE);
1173    return it->is_separator;
1174 }
1175
1176
1177 /**
1178  * Sets the selected state of @p it.
1179  *
1180  * @param it The list item
1181  * @param selected Enables/disables the selected state
1182  *
1183  * @ingroup List
1184  */
1185 EAPI void
1186 elm_list_item_selected_set(Elm_List_Item *it, Eina_Bool selected)
1187 {
1188    Widget_Data *wd = elm_widget_data_get(it->obj);
1189    if (!wd) return;
1190    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1191    selected = !!selected;
1192    if (it->selected == selected) return;
1193
1194    _elm_list_walk(wd);
1195
1196    if (selected)
1197      {
1198         if (!wd->multi)
1199           {
1200              while (wd->selected)
1201                _item_unselect(wd->selected->data);
1202           }
1203         _item_hilight(it);
1204         _item_select(it);
1205      }
1206    else
1207      _item_unselect(it);
1208
1209    _elm_list_unwalk(wd);
1210 }
1211
1212 /**
1213  * Gets the selected state of @p it.
1214  *
1215  * @param it The list item
1216  * @return If true, the item is selected
1217  *
1218  * @ingroup List
1219  */
1220 EAPI Eina_Bool
1221 elm_list_item_selected_get(Elm_List_Item *it)
1222 {
1223    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE);
1224    return it->selected;
1225 }
1226
1227 /**
1228  * Brings @p it to the center of the list view.
1229  *
1230  * @param it The list item
1231  *
1232  * @ingroup List
1233  */
1234 EAPI void
1235 elm_list_item_show(Elm_List_Item *it)
1236 {
1237    Widget_Data *wd = elm_widget_data_get(it->obj);
1238    Evas_Coord bx, by, bw, bh;
1239    Evas_Coord x, y, w, h;
1240
1241    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1242    evas_object_geometry_get(wd->box, &bx, &by, &bw, &bh);
1243    evas_object_geometry_get(it->base, &x, &y, &w, &h);
1244    x -= bx;
1245    y -= by;
1246    if (wd->scr)
1247      elm_scroller_region_show(wd->scr, x, y, w, h);
1248 }
1249
1250 /**
1251  * Deletes item @p it from the list.
1252  *
1253  * @param it The list item to delete
1254  *
1255  * @ingroup List
1256  */
1257 EAPI void
1258 elm_list_item_del(Elm_List_Item *it)
1259 {
1260    Widget_Data *wd = elm_widget_data_get(it->obj);
1261    if (!wd) return;
1262    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1263
1264    if (it->selected) _item_unselect(it);
1265
1266    if (wd->walking > 0)
1267      {
1268         if (it->deleted) return;
1269         it->deleted = EINA_TRUE;
1270         wd->to_delete = eina_list_append(wd->to_delete, it);
1271         return;
1272      }
1273
1274    wd->items = eina_list_remove_list(wd->items, it->node);
1275
1276    _elm_list_walk(wd);
1277
1278    _elm_list_item_call_del_cb(it);
1279    _elm_list_item_free(it);
1280
1281    _elm_list_unwalk(wd);
1282 }
1283
1284 /**
1285  * Set the function called when a list item is freed.
1286  *
1287  * @param it The item to set the callback on
1288  * @param func The function called
1289  *
1290  * @ingroup List
1291  */
1292 EAPI void
1293 elm_list_item_del_cb_set(Elm_List_Item *it, Evas_Smart_Cb func)
1294 {
1295    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1296    it->del_cb = func;
1297 }
1298
1299 /**
1300  * Returns the data associated with the item.
1301  *
1302  * @param it The list item
1303  * @return The data associated with @p it
1304  *
1305  * @ingroup List
1306  */
1307 EAPI void *
1308 elm_list_item_data_get(const Elm_List_Item *it)
1309 {
1310    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1311    return (void *)it->data;
1312 }
1313
1314 /**
1315  * Returns the left side icon associated with the item.
1316  *
1317  * @param it The list item
1318  * @return The left side icon associated with @p it
1319  *
1320  * @ingroup List
1321  */
1322 EAPI Evas_Object *
1323 elm_list_item_icon_get(const Elm_List_Item *it)
1324 {
1325    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1326    if (it->dummy_icon) return NULL;
1327    return it->icon;
1328 }
1329
1330 /**
1331  * Sets the left side icon associated with the item.
1332  *
1333  * Once the icon object is set, a previously set one will be deleted.
1334  * You probably don't want, then, to have the <b>same</b> icon object set
1335  * for more than one item of the list.
1336  *
1337  * @param it The list item
1338  * @param icon The left side icon object to associate with @p it
1339  *
1340  * @ingroup List
1341  */
1342 EAPI void
1343 elm_list_item_icon_set(Elm_List_Item *it, Evas_Object *icon)
1344 {
1345    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1346    if (it->icon == icon) return;
1347    if (it->dummy_icon && !icon) return;
1348    if (it->dummy_icon)
1349      {
1350         evas_object_del(it->icon);
1351         it->dummy_icon = EINA_FALSE;
1352      }
1353    if (!icon)
1354      {
1355         icon = evas_object_rectangle_add(evas_object_evas_get(it->obj));
1356         evas_object_color_set(icon, 0, 0, 0, 0);
1357         it->dummy_icon = EINA_TRUE;
1358      }
1359    if (it->icon)
1360      {
1361         evas_object_del(it->icon);
1362         it->icon = NULL;
1363      }
1364    it->icon = icon;
1365    if (it->base)
1366      edje_object_part_swallow(it->base, "elm.swallow.icon", icon);
1367 }
1368
1369 /**
1370  * Gets the right side icon associated with the item.
1371  *
1372  * @param it The list item
1373  * @return The right side icon object associated with @p it
1374  *
1375  * @ingroup List
1376  */
1377 EAPI Evas_Object *
1378 elm_list_item_end_get(const Elm_List_Item *it)
1379 {
1380    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1381    if (it->dummy_end) return NULL;
1382    return it->end;
1383 }
1384
1385 /**
1386  * Sets the right side icon associated with the item.
1387  *
1388  * Once the icon object is set, a previously set one will be deleted.
1389  * You probably don't want, then, to have the <b>same</b> icon object set
1390  * for more than one item of the list.
1391  *
1392  * @param it The list item
1393  * @param icon The right side icon object to associate with @p it
1394  *
1395  * @ingroup List
1396  */
1397 EAPI void
1398 elm_list_item_end_set(Elm_List_Item *it, Evas_Object *end)
1399 {
1400    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1401    if (it->end == end) return;
1402    if (it->dummy_end && !end) return;
1403    if (it->dummy_end)
1404      {
1405         evas_object_del(it->end);
1406         it->dummy_icon = EINA_FALSE;
1407      }
1408    if (!end)
1409      {
1410         end = evas_object_rectangle_add(evas_object_evas_get(it->obj));
1411         evas_object_color_set(end, 0, 0, 0, 0);
1412         it->dummy_end = EINA_TRUE;
1413      }
1414    if (it->end)
1415      {
1416         evas_object_del(it->end);
1417         it->end = NULL;
1418      }
1419    it->end = end;
1420    if (it->base)
1421      edje_object_part_swallow(it->base, "elm.swallow.end", end);
1422 }
1423
1424 /**
1425  * Gets the base object of the item.
1426  *
1427  * @param it The list item
1428  * @return The base object associated with @p it
1429  *
1430  * @ingroup List
1431  */
1432 EAPI Evas_Object *
1433 elm_list_item_base_get(const Elm_List_Item *it)
1434 {
1435    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1436    return it->base;
1437 }
1438
1439 /**
1440  * Gets the label of the item.
1441  *
1442  * @param it The list item
1443  * @return The label of @p it
1444  *
1445  * @ingroup List
1446  */
1447 EAPI const char *
1448 elm_list_item_label_get(const Elm_List_Item *it)
1449 {
1450    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1451    return it->label;
1452 }
1453
1454 /**
1455  * Sets the label of the item.
1456  *
1457  * @param it The list item
1458  * @param text The label of @p it
1459  *
1460  * @ingroup List
1461  */
1462 EAPI void
1463 elm_list_item_label_set(Elm_List_Item *it, const char *text)
1464 {
1465    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1466    if (!eina_stringshare_replace(&it->label, text)) return;
1467    if (it->base)
1468      edje_object_part_text_set(it->base, "elm.text", it->label);
1469 }
1470
1471 /**
1472  * Gets the item before @p it in the list.
1473  *
1474  * @param it The list item
1475  * @return The item before @p it, or NULL on failure
1476  *
1477  * @ingroup List
1478  */
1479 EAPI Elm_List_Item *
1480 elm_list_item_prev(const Elm_List_Item *it)
1481 {
1482    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1483    if (it->node->prev) return it->node->prev->data;
1484    else return NULL;
1485 }
1486
1487 /**
1488  * Gets the item after @p it in the list.
1489  *
1490  * @param it The list item
1491  * @return The item after @p it, or NULL on failure
1492  *
1493  * @ingroup List
1494  */
1495 EAPI Elm_List_Item *
1496 elm_list_item_next(const Elm_List_Item *it)
1497 {
1498    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1499    if (it->node->next) return it->node->next->data;
1500    else return NULL;
1501 }
1502
1503 /**
1504  * Set bounce mode
1505  *
1506  * This will enable or disable the scroller bounce mode for the list. See
1507  * elm_scroller_bounce_set() for details
1508  *
1509  * @param obj The list object
1510  * @param h_bounce Allow bounce horizontally
1511  * @param v_bounce Allow bounce vertically
1512  *
1513  * @ingroup List
1514  */
1515 EAPI void
1516 elm_list_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
1517 {
1518    ELM_CHECK_WIDTYPE(obj, widtype);
1519    Widget_Data *wd = elm_widget_data_get(obj);
1520    if (!wd) return;
1521    if (wd->scr)
1522      elm_scroller_bounce_set(wd->scr, h_bounce, v_bounce);
1523 }
1524
1525 /**
1526  * Set the scrollbar policy
1527  *
1528  * This sets the scrollbar visibility policy for the given scroller.
1529  * ELM_SMART_SCROLLER_POLICY_AUTO means the scrollber is made visible if it
1530  * is needed, and otherwise kept hidden. ELM_SMART_SCROLLER_POLICY_ON turns
1531  * it on all the time, and ELM_SMART_SCROLLER_POLICY_OFF always keeps it off.
1532  * This applies respectively for the horizontal and vertical scrollbars.
1533  *
1534  * @param obj The list object
1535  * @param policy_h Horizontal scrollbar policy
1536  * @param policy_v Vertical scrollbar policy
1537  *
1538  * @ingroup List
1539  */
1540 EAPI void
1541 elm_list_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
1542 {
1543    ELM_CHECK_WIDTYPE(obj, widtype);
1544    Widget_Data *wd = elm_widget_data_get(obj);
1545    if (!wd) return;
1546    if (wd->scr)
1547      elm_scroller_policy_set(wd->scr, policy_h, policy_v);
1548 }
1549
1550 EAPI void
1551 elm_list_scroller_policy_get(const Evas_Object *obj, Elm_Scroller_Policy *policy_h, Elm_Scroller_Policy *policy_v)
1552 {
1553    ELM_CHECK_WIDTYPE(obj, widtype);
1554    Widget_Data *wd = elm_widget_data_get(obj);
1555    if (!wd) return;
1556    if (wd->scr)
1557      elm_scroller_policy_get(wd->scr, policy_h, policy_v);
1558 }