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