[list] opensource merge (r69555)
[framework/uifw/elementary.git] / src / lib / elm_list.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "els_scroller.h"
4
5 #define SWIPE_MOVES 12
6
7 typedef struct _Widget_Data Widget_Data;
8 typedef struct _Elm_List_Item Elm_List_Item;
9
10 struct _Widget_Data
11 {
12    Evas_Object *scr, *box, *self;
13    Eina_List *items, *selected, *to_delete;
14    Elm_Object_Item *last_selected_item;
15    Elm_List_Mode mode;
16    Elm_List_Mode h_mode;
17    Evas_Coord minw[2], minh[2];
18    Elm_Object_Select_Mode select_mode;
19    int walking;
20    int movements;
21    struct {
22         Evas_Coord x, y;
23    } history[SWIPE_MOVES];
24    Eina_Bool scr_minw : 1;
25    Eina_Bool scr_minh : 1;
26    Eina_Bool swipe : 1;
27    Eina_Bool fix_pending : 1;
28    Eina_Bool on_hold : 1;
29    Eina_Bool multi : 1;
30    Eina_Bool longpressed : 1;
31    Eina_Bool wasselected : 1;
32 };
33
34 struct _Elm_List_Item
35 {
36    ELM_WIDGET_ITEM;
37    Widget_Data *wd;
38    Eina_List *node;
39    const char *label;
40    Evas_Object *icon, *end;
41    Evas_Smart_Cb func;
42    Ecore_Timer *long_timer;
43    Ecore_Timer *swipe_timer;
44    Eina_Bool deleted : 1;
45    Eina_Bool even : 1;
46    Eina_Bool is_even : 1;
47    Eina_Bool is_separator : 1;
48    Eina_Bool fixed : 1;
49    Eina_Bool selected : 1;
50    Eina_Bool highlighted : 1;
51    Eina_Bool dummy_icon : 1;
52    Eina_Bool dummy_end : 1;
53 };
54
55 static const char *widtype = NULL;
56 static void _del_hook(Evas_Object *obj);
57 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
58 static void _theme_hook(Evas_Object *obj);
59 static void _sizing_eval(Evas_Object *obj);
60 static void _disable_hook(Evas_Object *obj);
61 static void _on_focus_hook(void *data, Evas_Object *obj);
62 static void _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source);
63 static void _changed_size_hints(void *data, Evas *e, Evas_Object *obj, void *event_info);
64 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
65 static void _fix_items(Evas_Object *obj);
66 static void _mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info);
67 static void _mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info);
68 static void _mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info);
69 static void _edge_left(void *data, Evas_Object *scr, void *event_info);
70 static void _edge_right(void *data, Evas_Object *scr, void *event_info);
71 static void _edge_top(void *data, Evas_Object *scr, void *event_info);
72 static void _edge_bottom(void *data, Evas_Object *scr, void *event_info);
73 static Eina_Bool _item_multi_select_up(Widget_Data *wd);
74 static Eina_Bool _item_multi_select_down(Widget_Data *wd);
75 static Eina_Bool _item_single_select_up(Widget_Data *wd);
76 static Eina_Bool _item_single_select_down(Widget_Data *wd);
77 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
78                              Evas_Callback_Type type, void *event_info);
79 static Eina_Bool _deselect_all_items(Widget_Data *wd);
80
81 static const char SIG_ACTIVATED[] = "activated";
82 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
83 static const char SIG_SELECTED[] = "selected";
84 static const char SIG_UNSELECTED[] = "unselected";
85 static const char SIG_LONGPRESSED[] = "longpressed";
86 static const char SIG_EDGE_TOP[] = "edge,top";
87 static const char SIG_EDGE_BOTTOM[] = "edge,bottom";
88 static const char SIG_EDGE_LEFT[] = "edge,left";
89 static const char SIG_EDGE_RIGHT[] = "edge,right";
90
91 static const Evas_Smart_Cb_Description _signals[] = {
92    {SIG_ACTIVATED, ""},
93    {SIG_CLICKED_DOUBLE, ""},
94    {SIG_SELECTED, ""},
95    {SIG_UNSELECTED, ""},
96    {SIG_LONGPRESSED, ""},
97    {SIG_EDGE_TOP, ""},
98    {SIG_EDGE_BOTTOM, ""},
99    {SIG_EDGE_LEFT, ""},
100    {SIG_EDGE_RIGHT, ""},
101    {NULL, NULL}
102 };
103
104 #define ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ...)                      \
105    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, __VA_ARGS__);                        \
106 if (((Elm_List_Item *)it)->deleted)                                     \
107 {                                                                        \
108    ERR("ERROR: "#it" has been DELETED.\n");                              \
109    return __VA_ARGS__;                                                   \
110 }
111
112 static inline void
113 _elm_list_item_free(Elm_List_Item *it)
114 {
115    evas_object_event_callback_del_full
116       (VIEW(it), EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, it);
117    evas_object_event_callback_del_full
118       (VIEW(it), EVAS_CALLBACK_MOUSE_UP, _mouse_up, it);
119    evas_object_event_callback_del_full
120       (VIEW(it), EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, it);
121
122    if (it->icon)
123      evas_object_event_callback_del_full
124         (it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
125          _changed_size_hints, WIDGET(it));
126
127    if (it->end)
128      evas_object_event_callback_del_full
129         (it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
130          _changed_size_hints, WIDGET(it));
131
132    eina_stringshare_del(it->label);
133
134    if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
135    if (it->long_timer) ecore_timer_del(it->long_timer);
136    if (it->icon) evas_object_del(it->icon);
137    if (it->end) evas_object_del(it->end);
138 }
139
140 static Eina_Bool
141 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
142 {
143    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
144    Evas_Event_Key_Down *ev = event_info;
145    Widget_Data *wd = elm_widget_data_get(obj);
146    if (!wd) return EINA_FALSE;
147    if (!wd->items) return EINA_FALSE;
148    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
149    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
150
151    Elm_List_Item *it = NULL;
152    Evas_Coord x = 0;
153    Evas_Coord y = 0;
154    Evas_Coord step_x = 0;
155    Evas_Coord step_y = 0;
156    Evas_Coord v_w = 0;
157    Evas_Coord v_h = 0;
158    Evas_Coord page_x = 0;
159    Evas_Coord page_y = 0;
160
161    elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
162    elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
163    elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
164    elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
165
166    /* TODO: fix logic for horizontal mode */
167    if ((!strcmp(ev->keyname, "Left")) ||
168        (!strcmp(ev->keyname, "KP_Left")))
169      {
170         if ((wd->h_mode) &&
171             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
172               (_item_multi_select_up(wd)))
173              || (_item_single_select_up(wd))))
174           {
175              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
176              return EINA_TRUE;
177           }
178         else
179           x -= step_x;
180      }
181    else if ((!strcmp(ev->keyname, "Right")) ||
182             (!strcmp(ev->keyname, "KP_Right")))
183      {
184         if ((wd->h_mode) &&
185             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
186               (_item_multi_select_down(wd)))
187              || (_item_single_select_down(wd))))
188           {
189              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
190              return EINA_TRUE;
191           }
192         else
193           x += step_x;
194      }
195    else if ((!strcmp(ev->keyname, "Up"))  ||
196             (!strcmp(ev->keyname, "KP_Up")))
197      {
198         if ((!wd->h_mode) &&
199             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
200               (_item_multi_select_up(wd)))
201              || (_item_single_select_up(wd))))
202           {
203              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
204              return EINA_TRUE;
205           }
206         else
207           y -= step_y;
208      }
209    else if ((!strcmp(ev->keyname, "Down")) ||
210             (!strcmp(ev->keyname, "KP_Down")))
211      {
212         if ((!wd->h_mode) &&
213             (((evas_key_modifier_is_set(ev->modifiers, "Shift")) &&
214               (_item_multi_select_down(wd)))
215              || (_item_single_select_down(wd))))
216           {
217              ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
218              return EINA_TRUE;
219           }
220         else
221           y += step_y;
222      }
223    else if ((!strcmp(ev->keyname, "Home")) ||
224             (!strcmp(ev->keyname, "KP_Home")))
225      {
226         it = eina_list_data_get(wd->items);
227         elm_list_item_bring_in((Elm_Object_Item *)it);
228         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
229         return EINA_TRUE;
230      }
231    else if ((!strcmp(ev->keyname, "End")) ||
232             (!strcmp(ev->keyname, "KP_End")))
233      {
234         it = eina_list_data_get(eina_list_last(wd->items));
235         elm_list_item_bring_in((Elm_Object_Item *)it);
236         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
237         return EINA_TRUE;
238      }
239    else if ((!strcmp(ev->keyname, "Prior")) ||
240             (!strcmp(ev->keyname, "KP_Prior")))
241      {
242         if (wd->h_mode)
243           {
244              if (page_x < 0)
245                x -= -(page_x * v_w) / 100;
246              else
247                x -= page_x;
248           }
249         else
250           {
251              if (page_y < 0)
252                y -= -(page_y * v_h) / 100;
253              else
254                y -= page_y;
255           }
256      }
257    else if ((!strcmp(ev->keyname, "Next")) ||
258             (!strcmp(ev->keyname, "KP_Next")))
259      {
260         if (wd->h_mode)
261           {
262              if (page_x < 0)
263                x += -(page_x * v_w) / 100;
264              else
265                x += page_x;
266           }
267         else
268           {
269              if (page_y < 0)
270                y += -(page_y * v_h) / 100;
271              else
272                y += page_y;
273           }
274      }
275    else if (((!strcmp(ev->keyname, "Return")) ||
276             (!strcmp(ev->keyname, "KP_Enter")) ||
277             (!strcmp(ev->keyname, "space")))
278            && (!wd->multi) && (wd->selected))
279      {
280         it = (Elm_List_Item *) elm_list_selected_item_get(obj);
281         evas_object_smart_callback_call(WIDGET(it), SIG_ACTIVATED, it);
282      }
283    else if (!strcmp(ev->keyname, "Escape"))
284      {
285         if (!_deselect_all_items(wd)) return EINA_FALSE;
286         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
287         return EINA_TRUE;
288      }
289    else return EINA_FALSE;
290
291    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
292    elm_smart_scroller_child_pos_set(wd->scr, x, y);
293    return EINA_TRUE;
294 }
295
296 static void
297 _translate_hook(Evas_Object *obj)
298 {
299    evas_object_smart_callback_call(obj, "language,changed", NULL);
300 }
301
302 static Eina_Bool
303 _deselect_all_items(Widget_Data *wd)
304 {
305    if (!wd->selected) return EINA_FALSE;
306    while (wd->selected)
307      elm_list_item_selected_set((Elm_Object_Item *) wd->selected->data,
308                                 EINA_FALSE);
309
310    return EINA_TRUE;
311 }
312
313 static Eina_Bool
314 _item_multi_select_up(Widget_Data *wd)
315 {
316    if (!wd->selected) return EINA_FALSE;
317    if (!wd->multi) return EINA_FALSE;
318
319    Elm_Object_Item *prev = elm_list_item_prev(wd->last_selected_item);
320    if (!prev) return EINA_TRUE;
321
322    if (elm_list_item_selected_get(prev))
323      {
324         elm_list_item_selected_set(wd->last_selected_item, EINA_FALSE);
325         wd->last_selected_item = prev;
326         elm_list_item_show(wd->last_selected_item);
327      }
328    else
329      {
330         elm_list_item_selected_set(prev, EINA_TRUE);
331         elm_list_item_show(prev);
332      }
333    return EINA_TRUE;
334 }
335
336 static Eina_Bool
337 _item_multi_select_down(Widget_Data *wd)
338 {
339    if (!wd->selected) return EINA_FALSE;
340    if (!wd->multi) return EINA_FALSE;
341
342    Elm_Object_Item *next = elm_list_item_next(wd->last_selected_item);
343    if (!next) return EINA_TRUE;
344
345    if (elm_list_item_selected_get(next))
346      {
347         elm_list_item_selected_set(wd->last_selected_item, EINA_FALSE);
348         wd->last_selected_item = next;
349         elm_list_item_show(wd->last_selected_item);
350      }
351    else
352      {
353         elm_list_item_selected_set(next, EINA_TRUE);
354         elm_list_item_show(next);
355      }
356    return EINA_TRUE;
357 }
358
359 static Eina_Bool
360 _item_single_select_up(Widget_Data *wd)
361 {
362    Elm_Object_Item *prev;
363
364    if (!wd->selected) prev = eina_list_data_get(eina_list_last(wd->items));
365    else prev = elm_list_item_prev(wd->last_selected_item);
366    if (!prev) return EINA_FALSE;
367
368    _deselect_all_items(wd);
369
370    elm_list_item_selected_set(prev, EINA_TRUE);
371    elm_list_item_show(prev);
372    return EINA_TRUE;
373 }
374
375 static Eina_Bool
376 _item_single_select_down(Widget_Data *wd)
377 {
378    Elm_Object_Item *next;
379
380    if (!wd->selected) next = eina_list_data_get(wd->items);
381    else next = elm_list_item_next(wd->last_selected_item);
382    if (!next) return EINA_FALSE;
383
384    _deselect_all_items(wd);
385
386    elm_list_item_selected_set(next, EINA_TRUE);
387    elm_list_item_show(next);
388    return EINA_TRUE;
389 }
390
391 static void
392 _elm_list_process_deletions(Widget_Data *wd)
393 {
394    Elm_List_Item *it;
395
396    wd->walking++; // avoid nested deletion and also _sub_del() fix_items
397
398    EINA_LIST_FREE(wd->to_delete, it)
399      {
400         wd->items = eina_list_remove_list(wd->items, it->node);
401         _elm_list_item_free(it);
402         elm_widget_item_free(it);
403      }
404
405    wd->walking--;
406 }
407
408 static inline void
409 _elm_list_walk(Widget_Data *wd)
410 {
411    if (wd->walking < 0)
412      {
413         ERR("ERROR: walking was negative. fixed!\n");
414         wd->walking = 0;
415      }
416    wd->walking++;
417 }
418
419 static inline void
420 _elm_list_unwalk(Widget_Data *wd)
421 {
422    wd->walking--;
423    if (wd->walking < 0)
424      {
425         ERR("ERROR: walking became negative. fixed!\n");
426         wd->walking = 0;
427      }
428
429    if (wd->walking)
430      return;
431
432    if (wd->to_delete)
433      _elm_list_process_deletions(wd);
434
435    if (wd->fix_pending)
436      {
437         wd->fix_pending = EINA_FALSE;
438         _fix_items(wd->self);
439         _sizing_eval(wd->self);
440      }
441 }
442
443 static void
444 _del_pre_hook(Evas_Object *obj)
445 {
446    Widget_Data *wd = elm_widget_data_get(obj);
447    const Eina_List *l;
448    Elm_List_Item *it;
449
450    evas_object_smart_callback_del(obj, "sub-object-del", _sub_del);
451
452    if (!wd) return;
453
454    EINA_LIST_FOREACH(wd->items, l, it)
455      {
456         if (it->icon)
457            evas_object_event_callback_del(it->icon,
458                                           EVAS_CALLBACK_CHANGED_SIZE_HINTS,
459                                           _changed_size_hints);
460         if (it->end)
461            evas_object_event_callback_del(it->end,
462                                           EVAS_CALLBACK_CHANGED_SIZE_HINTS,
463                                           _changed_size_hints);
464      }
465
466    evas_object_event_callback_del(wd->scr,
467                                   EVAS_CALLBACK_CHANGED_SIZE_HINTS,
468                                   _changed_size_hints);
469    evas_object_event_callback_del(wd->box,
470                                   EVAS_CALLBACK_CHANGED_SIZE_HINTS,
471                                   _changed_size_hints);
472 }
473
474 static void
475 _del_hook(Evas_Object *obj)
476 {
477    Widget_Data *wd = elm_widget_data_get(obj);
478    Elm_List_Item *it;
479    Eina_List *n;
480
481    if (!wd) return;
482    if (wd->walking)
483      ERR("ERROR: list deleted while walking.\n");
484
485    _elm_list_walk(wd);
486    EINA_LIST_FOREACH(wd->items, n, it) elm_widget_item_pre_notify_del(it);
487    _elm_list_unwalk(wd);
488    if (wd->to_delete)
489      ERR("ERROR: leaking nodes!\n");
490
491    EINA_LIST_FREE(wd->items, it)
492      {
493         _elm_list_item_free(it);
494         elm_widget_item_free(it);
495      }
496    eina_list_free(wd->selected);
497    free(wd);
498 }
499
500 static void
501 _show_region_hook(void *data, Evas_Object *obj)
502 {
503    Widget_Data *wd = elm_widget_data_get(data);
504    Evas_Coord x, y, w, h;
505    if (!wd) return;
506    elm_widget_show_region_get(obj, &x, &y, &w, &h);
507    elm_smart_scroller_child_region_set(wd->scr, x, y, w, h);
508 }
509
510 static void
511 _disable_hook(Evas_Object *obj)
512 {
513    Widget_Data *wd = elm_widget_data_get(obj);
514    if (!wd) return;
515    if (elm_widget_disabled_get(obj))
516      {
517         _signal_emit_hook(obj, "elm,state,disabled", "elm");
518         elm_widget_scroll_freeze_push(obj);
519         elm_widget_scroll_hold_push(obj);
520         /* FIXME: if we get to have a way to only un-highlight items
521          * in the future, keeping them selected... */
522         _deselect_all_items(wd);
523      }
524    else
525      {
526         _signal_emit_hook(obj, "elm,state,enabled", "elm");
527         elm_widget_scroll_freeze_pop(obj);
528         elm_widget_scroll_hold_pop(obj);
529      }
530 }
531
532 static void
533 _sizing_eval(Evas_Object *obj)
534 {
535
536    Widget_Data *wd = elm_widget_data_get(obj);
537    if (!wd) return;
538    Evas_Coord  vw, vh, minw, minh, maxw, maxh, w, h, vmw, vmh;
539    double xw, yw;
540
541    evas_object_size_hint_min_get(wd->box, &minw, &minh);
542    evas_object_size_hint_max_get(wd->box, &maxw, &maxh);
543    evas_object_size_hint_weight_get(wd->box, &xw, &yw);
544    if (!wd->scr) return;
545    elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
546    if (xw > 0.0)
547      {
548         if ((minw > 0) && (vw < minw)) vw = minw;
549         else if ((maxw > 0) && (vw > maxw)) vw = maxw;
550      }
551    else if (minw > 0) vw = minw;
552    if (yw > 0.0)
553      {
554         if ((minh > 0) && (vh < minh)) vh = minh;
555         else if ((maxh > 0) && (vh > maxh)) vh = maxh;
556      }
557    else if (minh > 0) vh = minh;
558    evas_object_resize(wd->box, vw, vh);
559    w = -1;
560    h = -1;
561    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr),
562                              &vmw, &vmh);
563    if (wd->scr_minw) w = vmw + minw;
564    if (wd->scr_minh) h = vmh + minh;
565
566    evas_object_size_hint_max_get(obj, &maxw, &maxh);
567    if ((maxw > 0) && (w > maxw))
568      w = maxw;
569    if ((maxh > 0) && (h > maxh))
570      h = maxh;
571
572    evas_object_size_hint_min_set(obj, w, h);
573 }
574
575 static void
576 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
577 {
578    Widget_Data *wd = elm_widget_data_get(obj);
579    edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
580                            emission, source);
581 }
582
583 static void
584 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
585 {
586    Widget_Data *wd = elm_widget_data_get(obj);
587    edje_object_signal_callback_add(elm_smart_scroller_edje_object_get(wd->scr),
588                                    emission, source, func_cb, data);
589 }
590
591 static void
592 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
593 {
594    Widget_Data *wd = elm_widget_data_get(obj);
595    edje_object_signal_callback_del_full(
596       elm_smart_scroller_edje_object_get(wd->scr),
597       emission, source, func_cb, data);
598 }
599
600 static void
601 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
602 {
603    Widget_Data *wd = elm_widget_data_get(obj);
604    Elm_List_Item *it;
605    Eina_List *n;
606
607    if (!wd) return;
608    if (wd->scr)
609      elm_smart_scroller_mirrored_set(wd->scr, rtl);
610
611    EINA_LIST_FOREACH(wd->items, n, it)
612       edje_object_mirrored_set(VIEW(it), rtl);
613 }
614
615 static void
616 _theme_hook(Evas_Object *obj)
617 {
618    Widget_Data *wd = elm_widget_data_get(obj);
619    Elm_List_Item *it;
620    Eina_List *n;
621
622    if (!wd) return;
623    _elm_widget_mirrored_reload(obj);
624    _mirrored_set(obj, elm_widget_mirrored_get(obj));
625
626    if (wd->scr)
627      {
628         Evas_Object *edj;
629         const char *str;
630
631         elm_smart_scroller_object_theme_set(obj, wd->scr, "list", "base",
632                                             elm_widget_style_get(obj));
633         //        edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
634         edj = elm_smart_scroller_edje_object_get(wd->scr);
635         str = edje_object_data_get(edj, "focus_highlight");
636         if ((str) && (!strcmp(str, "on")))
637           elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
638         else
639           elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
640         elm_object_style_set(wd->scr, elm_widget_style_get(obj));
641      }
642    EINA_LIST_FOREACH(wd->items, n, it)
643      {
644         edje_object_scale_set(VIEW(it), elm_widget_scale_get(obj) * _elm_config->scale);
645         it->fixed = 0;
646      }
647    _fix_items(obj);
648    _sizing_eval(obj);
649 }
650
651 static void
652 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
653 {
654    Widget_Data *wd = elm_widget_data_get(obj);
655    if (!wd) return;
656    if (elm_widget_focus_get(obj))
657      {
658         edje_object_signal_emit(wd->self, "elm,action,focus", "elm");
659         evas_object_focus_set(wd->self, EINA_TRUE);
660
661         if ((wd->selected) && (!wd->last_selected_item))
662           wd->last_selected_item = eina_list_data_get(wd->selected);
663      }
664    else
665      {
666         edje_object_signal_emit(wd->self, "elm,action,unfocus", "elm");
667         evas_object_focus_set(wd->self, EINA_FALSE);
668      }
669 }
670
671 static void
672 _changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
673 {
674    Widget_Data *wd = elm_widget_data_get(data);
675    if (!wd) return;
676    _fix_items(data);
677    _sizing_eval(data);
678 }
679
680 static void
681 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
682 {
683    Widget_Data *wd = elm_widget_data_get(obj);
684    Evas_Object *sub = event_info;
685    const Eina_List *l;
686    Elm_List_Item *it;
687
688    if (!wd) return;
689    if (!sub) abort();
690    if ((sub == wd->box) || (sub == wd->scr)) return;
691
692    EINA_LIST_FOREACH(wd->items, l, it)
693      {
694         if ((sub == it->icon) || (sub == it->end))
695           {
696              if (it->icon == sub) it->icon = NULL;
697              if (it->end == sub) it->end = NULL;
698              evas_object_event_callback_del_full
699              (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints,
700               obj);
701              if (!wd->walking)
702                {
703                   _fix_items(obj);
704                   _sizing_eval(obj);
705                }
706              else
707                wd->fix_pending = EINA_TRUE;
708              break;
709           }
710      }
711 }
712
713 static void
714 _item_highlight(Elm_List_Item *it)
715 {
716    Evas_Object *obj = WIDGET(it);
717    Widget_Data *wd = elm_widget_data_get(obj);
718    const char *selectraise;
719
720    if (!wd) return;
721    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
722    if ((it->highlighted) || (it->base.disabled) ||
723        (wd->select_mode == ELM_OBJECT_SELECT_MODE_NONE)) return;
724
725    evas_object_ref(obj);
726    _elm_list_walk(wd);
727
728    edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm");
729    selectraise = edje_object_data_get(VIEW(it), "selectraise");
730    if ((selectraise) && (!strcmp(selectraise, "on")))
731      evas_object_raise(VIEW(it));
732    it->highlighted = EINA_TRUE;
733
734    _elm_list_unwalk(wd);
735    evas_object_unref(obj);
736 }
737
738 static void
739 _item_select(Elm_List_Item *it)
740 {
741    Evas_Object *obj = WIDGET(it);
742    Widget_Data *wd = elm_widget_data_get(obj);
743
744    if (!wd) return;
745    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
746    if (it->base.disabled || (wd->select_mode == ELM_OBJECT_SELECT_MODE_NONE)) return;
747    if (it->selected)
748      {
749         if (wd->select_mode == ELM_OBJECT_SELECT_MODE_ALWAYS) goto call;
750         return;
751      }
752    it->selected = EINA_TRUE;
753    wd->selected = eina_list_append(wd->selected, it);
754
755 call:
756    evas_object_ref(obj);
757    _elm_list_walk(wd);
758
759    if (it->func) it->func((void *)it->base.data, WIDGET(it), it);
760    evas_object_smart_callback_call(obj, SIG_SELECTED, it);
761    it->wd->last_selected_item = (Elm_Object_Item *)it;
762
763    _elm_list_unwalk(wd);
764    evas_object_unref(obj);
765 }
766
767 static void
768 _item_unselect(Elm_List_Item *it)
769 {
770    Evas_Object *obj = WIDGET(it);
771    Widget_Data *wd = elm_widget_data_get(obj);
772    const char *stacking, *selectraise;
773
774    if (!wd) return;
775    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
776    if (!it->highlighted) return;
777
778    evas_object_ref(obj);
779    _elm_list_walk(wd);
780
781    edje_object_signal_emit(VIEW(it), "elm,state,unselected", "elm");
782    stacking = edje_object_data_get(VIEW(it), "stacking");
783    selectraise = edje_object_data_get(VIEW(it), "selectraise");
784    if ((selectraise) && (!strcmp(selectraise, "on")))
785      {
786         if ((stacking) && (!strcmp(stacking, "below")))
787           evas_object_lower(VIEW(it));
788      }
789    it->highlighted = EINA_FALSE;
790    if (it->selected)
791      {
792         it->selected = EINA_FALSE;
793         wd->selected = eina_list_remove(wd->selected, it);
794         evas_object_smart_callback_call(WIDGET(it), SIG_UNSELECTED, it);
795      }
796
797    _elm_list_unwalk(wd);
798    evas_object_unref(obj);
799 }
800
801 static Eina_Bool
802 _swipe_cancel(void *data)
803 {
804    Elm_List_Item *it = data;
805    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
806
807    if (!wd) return ECORE_CALLBACK_CANCEL;
808    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ECORE_CALLBACK_CANCEL);
809    wd->swipe = EINA_FALSE;
810    wd->movements = 0;
811    return ECORE_CALLBACK_RENEW;
812 }
813
814 static void
815 _mouse_move(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
816 {
817    Elm_List_Item *it = data;
818    Evas_Object *obj2 = WIDGET(it);
819    Widget_Data *wd = elm_widget_data_get(obj2);
820    Evas_Event_Mouse_Move *ev = event_info;
821
822    if (!wd) return;
823    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
824
825    evas_object_ref(obj2);
826    _elm_list_walk(wd);
827
828    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
829      {
830         if (!wd->on_hold)
831           {
832              wd->on_hold = EINA_TRUE;
833              if (it->long_timer)
834                {
835                   ecore_timer_del(it->long_timer);
836                   it->long_timer = NULL;
837                }
838              if (!wd->wasselected)
839                _item_unselect(it);
840           }
841         if (wd->movements == SWIPE_MOVES) wd->swipe = EINA_TRUE;
842         else
843           {
844              wd->history[wd->movements].x = ev->cur.canvas.x;
845              wd->history[wd->movements].y = ev->cur.canvas.y;
846              if (abs((wd->history[wd->movements].x - wd->history[0].x)) > 40)
847                wd->swipe = EINA_TRUE;
848              else
849                wd->movements++;
850           }
851      }
852
853    _elm_list_unwalk(wd);
854    evas_object_unref(obj2);
855 }
856
857 static void
858 _edge_left(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__)
859 {
860    Evas_Object *obj = data;
861    evas_object_smart_callback_call(obj, SIG_EDGE_LEFT, NULL);
862 }
863
864 static void
865 _edge_right(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__)
866 {
867    Evas_Object *obj = data;
868    evas_object_smart_callback_call(obj, SIG_EDGE_RIGHT, NULL);
869 }
870
871 static void
872 _edge_top(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__)
873 {
874    Evas_Object *obj = data;
875    evas_object_smart_callback_call(obj, SIG_EDGE_TOP, NULL);
876 }
877
878 static void
879 _edge_bottom(void *data, Evas_Object *scr __UNUSED__, void *event_info __UNUSED__)
880 {
881    Evas_Object *obj = data;
882    evas_object_smart_callback_call(obj, SIG_EDGE_BOTTOM, NULL);
883 }
884
885 static Eina_Bool
886 _long_press(void *data)
887 {
888    Elm_List_Item *it = data;
889    Evas_Object *obj = WIDGET(it);
890    Widget_Data *wd = elm_widget_data_get(obj);
891
892    if (!wd) goto end;
893
894    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, ECORE_CALLBACK_CANCEL);
895    it->long_timer = NULL;
896    if (it->base.disabled) goto end;
897
898    wd->longpressed = EINA_TRUE;
899    evas_object_smart_callback_call(WIDGET(it), SIG_LONGPRESSED, it);
900
901 end:
902    return ECORE_CALLBACK_CANCEL;
903 }
904
905 static void
906 _swipe(Elm_List_Item *it)
907 {
908    int i, sum = 0;
909    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
910
911    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
912    if (!wd) return;
913    wd->swipe = EINA_FALSE;
914    for (i = 0; i < wd->movements; i++)
915      {
916         sum += wd->history[i].x;
917         if (abs(wd->history[0].y - wd->history[i].y) > 10) return;
918      }
919
920    sum /= wd->movements;
921    if (abs(sum - wd->history[0].x) <= 10) return;
922    evas_object_smart_callback_call(WIDGET(it), "swipe", it);
923 }
924
925 static void
926 _mouse_down(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
927 {
928    Elm_List_Item *it = data;
929    Evas_Object *obj2 = WIDGET(it);
930    Widget_Data *wd = elm_widget_data_get(obj2);
931    Evas_Event_Mouse_Down *ev = event_info;
932
933    if (!wd) return;
934    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
935    if (ev->button != 1) return;
936    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
937    else wd->on_hold = EINA_FALSE;
938    if (wd->on_hold) return;
939    wd->wasselected = it->selected;
940
941    evas_object_ref(obj2);
942    _elm_list_walk(wd);
943
944    _item_highlight(it);
945    wd->longpressed = EINA_FALSE;
946    if (it->long_timer) ecore_timer_del(it->long_timer);
947    it->long_timer = ecore_timer_add(_elm_config->longpress_timeout, _long_press, it);
948    if (it->swipe_timer) ecore_timer_del(it->swipe_timer);
949    it->swipe_timer = ecore_timer_add(0.4, _swipe_cancel, it);
950    /* Always call the callbacks last - the user may delete our context! */
951    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
952      {
953         evas_object_smart_callback_call(WIDGET(it), SIG_CLICKED_DOUBLE, it);
954         evas_object_smart_callback_call(WIDGET(it), SIG_ACTIVATED, it);
955      }
956    wd->swipe = EINA_FALSE;
957    wd->movements = 0;
958
959    _elm_list_unwalk(wd);
960    evas_object_unref(obj2);
961 }
962
963 static void
964 _mouse_up(void *data, Evas *evas __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
965 {
966    Elm_List_Item *it = data;
967    Evas_Object *obj2 = WIDGET(it);
968    Widget_Data *wd = elm_widget_data_get(obj2);
969    Evas_Event_Mouse_Up *ev = event_info;
970
971    if (!wd) return;
972    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
973    if (ev->button != 1) return;
974    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) wd->on_hold = EINA_TRUE;
975    else wd->on_hold = EINA_FALSE;
976    wd->longpressed = EINA_FALSE;
977    if (it->long_timer)
978      {
979         ecore_timer_del(it->long_timer);
980         it->long_timer = NULL;
981      }
982    if (it->swipe_timer)
983      {
984         ecore_timer_del(it->swipe_timer);
985         it->swipe_timer = NULL;
986      }
987    if (wd->on_hold)
988      {
989         if (wd->swipe) _swipe(data);
990         wd->on_hold = EINA_FALSE;
991         return;
992      }
993    if (wd->longpressed)
994      {
995         if (!wd->wasselected) _item_unselect(it);
996         wd->wasselected = 0;
997         return;
998      }
999
1000    if (it->base.disabled)
1001      return;
1002    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
1003
1004    evas_object_ref(obj2);
1005    _elm_list_walk(wd);
1006
1007    if (wd->multi)
1008      {
1009         if (!it->selected)
1010           {
1011              _item_highlight(it);
1012              _item_select(it);
1013           }
1014         else _item_unselect(it);
1015      }
1016    else
1017      {
1018         if (!it->selected)
1019           {
1020              while (wd->selected)
1021                _item_unselect(wd->selected->data);
1022              _item_highlight(it);
1023              _item_select(it);
1024           }
1025         else
1026           {
1027              const Eina_List *l, *l_next;
1028              Elm_List_Item *it2;
1029
1030              EINA_LIST_FOREACH_SAFE(wd->selected, l, l_next, it2)
1031                 if (it2 != it) _item_unselect(it2);
1032              _item_highlight(it);
1033              _item_select(it);
1034           }
1035      }
1036
1037    _elm_list_unwalk(wd);
1038    evas_object_unref(obj2);
1039 }
1040
1041 static void
1042 _item_disable(Elm_Object_Item *it)
1043 {
1044    Elm_List_Item *item = (Elm_List_Item *)it;
1045    if (item->base.disabled)
1046      edje_object_signal_emit(VIEW(item), "elm,state,disabled", "elm");
1047    else
1048      edje_object_signal_emit(VIEW(item), "elm,state,enabled", "elm");
1049 }
1050
1051 static void
1052 _item_content_set(Elm_Object_Item *it, const char *part, Evas_Object *content)
1053 {
1054    Elm_List_Item *item = (Elm_List_Item *)it;
1055    Evas_Object **icon_p = NULL;
1056    Eina_Bool dummy = EINA_FALSE;
1057
1058    if ((!part) || (!strcmp(part, "start")))
1059      {
1060         icon_p = &(item->icon);
1061         dummy = item->dummy_icon;
1062         if (!content) item->dummy_icon = EINA_TRUE;
1063         else item->dummy_icon = EINA_FALSE;
1064      }
1065    else if (!strcmp(part, "end"))
1066      {
1067         icon_p = &(item->end);
1068         dummy = item->dummy_end;
1069         if (!content) item->dummy_end = EINA_TRUE;
1070         else item->dummy_end = EINA_FALSE;
1071      }
1072    else
1073      return;
1074
1075    if (content == *icon_p) return;
1076    if ((dummy) && (!content)) return;
1077    if (dummy) evas_object_del(*icon_p);
1078    if (!content)
1079      {
1080         content = evas_object_rectangle_add(evas_object_evas_get(WIDGET(item)));
1081         evas_object_color_set(content, 0, 0, 0, 0);
1082      }
1083    if (*icon_p)
1084      {
1085         evas_object_del(*icon_p);
1086         *icon_p = NULL;
1087      }
1088    *icon_p = content;
1089    if (VIEW(item))
1090      edje_object_part_swallow(VIEW(item), "elm.swallow.icon", content);
1091 }
1092
1093 static Evas_Object *
1094 _item_content_get(const Elm_Object_Item *it, const char *part)
1095 {
1096    Elm_List_Item *item = (Elm_List_Item *)it;
1097
1098    if ((!part) || (!strcmp(part, "start")))
1099      {
1100         if (item->dummy_icon) return NULL;
1101         return item->icon;
1102      }
1103    else if (!strcmp(part, "end"))
1104      {
1105         if (item->dummy_end) return NULL;
1106         return item->end;
1107      }
1108    return NULL;
1109 }
1110
1111 static Evas_Object *
1112 _item_content_unset(const Elm_Object_Item *it, const char *part)
1113 {
1114    Elm_List_Item *item = (Elm_List_Item *)it;
1115
1116    if ((!part) || (!strcmp(part, "start")))
1117      {
1118         Evas_Object *obj = item->icon;
1119         _item_content_set((Elm_Object_Item *)it, part, NULL);
1120         return obj;
1121      }
1122    else if (!strcmp(part, "end"))
1123      {
1124         Evas_Object *obj = item->end;
1125         _item_content_set((Elm_Object_Item *)it, part, NULL);
1126         return obj;
1127      }
1128    return NULL;
1129 }
1130
1131 static void
1132 _item_text_set(Elm_Object_Item *it, const char *part, const char *text)
1133 {
1134    Elm_List_Item *list_it = (Elm_List_Item *)it;
1135    if (part && strcmp(part, "default")) return;
1136    if (!eina_stringshare_replace(&list_it->label, text)) return;
1137    if (VIEW(list_it))
1138      edje_object_part_text_set(VIEW(list_it), "elm.text", text);
1139 }
1140
1141 static const char *
1142 _item_text_get(const Elm_Object_Item *it, const char *part)
1143 {
1144    if (part && strcmp(part, "default")) return NULL;
1145    return ((Elm_List_Item *)it)->label;
1146 }
1147
1148 static Eina_Bool
1149 _item_del_pre_hook(Elm_Object_Item *it)
1150 {
1151    Evas_Object *obj = WIDGET(it);
1152    Elm_List_Item *item = (Elm_List_Item *)it;
1153    Widget_Data *wd = elm_widget_data_get(obj);
1154    if (!wd) return EINA_FALSE;
1155
1156    if (item->selected) _item_unselect(item);
1157
1158    if (wd->walking > 0)
1159      {
1160         if (item->deleted) return EINA_FALSE;
1161         item->deleted = EINA_TRUE;
1162         wd->to_delete = eina_list_append(wd->to_delete, item);
1163         return EINA_FALSE;
1164      }
1165
1166    wd->items = eina_list_remove_list(wd->items, item->node);
1167
1168    evas_object_ref(obj);
1169    _elm_list_walk(wd);
1170
1171    _elm_list_item_free(item);
1172
1173    _elm_list_unwalk(wd);
1174    evas_object_unref(obj);
1175
1176    return EINA_TRUE;
1177 }
1178
1179 static Elm_List_Item *
1180 _item_new(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
1181 {
1182    Widget_Data *wd = elm_widget_data_get(obj);
1183    Elm_List_Item *it;
1184
1185    if (!wd) return NULL;
1186    it = elm_widget_item_new(obj, Elm_List_Item);
1187    it->wd = wd;
1188    it->label = eina_stringshare_add(label);
1189    it->icon = icon;
1190    it->end = end;
1191    it->func = func;
1192    it->base.data = data;
1193    VIEW(it) = edje_object_add(evas_object_evas_get(obj));
1194    edje_object_mirrored_set(VIEW(it), elm_widget_mirrored_get(obj));
1195    evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_DOWN,
1196                                   _mouse_down, it);
1197    evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_UP,
1198                                   _mouse_up, it);
1199    evas_object_event_callback_add(VIEW(it), EVAS_CALLBACK_MOUSE_MOVE,
1200                                   _mouse_move, it);
1201    evas_object_size_hint_weight_set(VIEW(it), EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1202    evas_object_size_hint_align_set(VIEW(it), EVAS_HINT_FILL, EVAS_HINT_FILL);
1203    if (it->icon)
1204      {
1205         elm_widget_sub_object_add(obj, it->icon);
1206         evas_object_event_callback_add(it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1207                                        _changed_size_hints, obj);
1208      }
1209    if (it->end)
1210      {
1211         elm_widget_sub_object_add(obj, it->end);
1212         evas_object_event_callback_add(it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1213                                        _changed_size_hints, obj);
1214      }
1215    elm_widget_item_disable_hook_set(it, _item_disable);
1216    elm_widget_item_content_set_hook_set(it, _item_content_set);
1217    elm_widget_item_content_get_hook_set(it, _item_content_get);
1218    elm_widget_item_content_unset_hook_set(it, _item_content_unset);
1219    elm_widget_item_text_set_hook_set(it, _item_text_set);
1220    elm_widget_item_text_get_hook_set(it, _item_text_get);
1221    elm_widget_item_del_pre_hook_set(it, _item_del_pre_hook);
1222    return it;
1223 }
1224
1225 static void
1226 _elm_list_mode_set_internal(Widget_Data *wd)
1227 {
1228    if (!wd->scr)
1229      return;
1230
1231    if (wd->mode == ELM_LIST_LIMIT)
1232      {
1233         if (!wd->h_mode)
1234           {
1235              wd->scr_minw = EINA_TRUE;
1236              wd->scr_minh = EINA_FALSE;
1237           }
1238         else
1239           {
1240              wd->scr_minw = EINA_FALSE;
1241              wd->scr_minh = EINA_TRUE;
1242           }
1243      }
1244    else if (wd->mode == ELM_LIST_EXPAND)
1245      {
1246         wd->scr_minw = EINA_TRUE;
1247         wd->scr_minh = EINA_TRUE;
1248      }
1249    else
1250      {
1251         wd->scr_minw = EINA_FALSE;
1252         wd->scr_minh = EINA_FALSE;
1253      }
1254
1255    _sizing_eval(wd->self);
1256 }
1257
1258 static void
1259 _fix_items(Evas_Object *obj)
1260 {
1261    Widget_Data *wd = elm_widget_data_get(obj);
1262    if (!wd) return;
1263    const Eina_List *l;
1264    Elm_List_Item *it;
1265    Evas_Coord minw[2] = { 0, 0 }, minh[2] = { 0, 0 };
1266    Evas_Coord mw, mh;
1267    int i, redo = 0;
1268    const char *style = elm_widget_style_get(obj);
1269    const char *it_plain = wd->h_mode ? "h_item" : "item";
1270    const char *it_odd = wd->h_mode ? "h_item_odd" : "item_odd";
1271    const char *it_compress = wd->h_mode ? "h_item_compress" : "item_compress";
1272    const char *it_compress_odd = wd->h_mode ? "h_item_compress_odd" : "item_compress_odd";
1273
1274    if (wd->walking)
1275      {
1276         wd->fix_pending = EINA_TRUE;
1277         return;
1278      }
1279
1280    evas_object_ref(obj);
1281    _elm_list_walk(wd); // watch out "return" before unwalk!
1282
1283    EINA_LIST_FOREACH(wd->items, l, it)
1284      {
1285         if (it->deleted) continue;
1286         if (it->icon)
1287           {
1288              evas_object_size_hint_min_get(it->icon, &mw, &mh);
1289              if (mw > minw[0]) minw[0] = mw;
1290              if (mh > minh[0]) minh[0] = mh;
1291           }
1292         if (it->end)
1293           {
1294              evas_object_size_hint_min_get(it->end, &mw, &mh);
1295              if (mw > minw[1]) minw[1] = mw;
1296              if (mh > minh[1]) minh[1] = mh;
1297           }
1298      }
1299
1300    if ((minw[0] != wd->minw[0]) || (minw[1] != wd->minw[1]) ||
1301        (minw[0] != wd->minh[0]) || (minh[1] != wd->minh[1]))
1302      {
1303         wd->minw[0] = minw[0];
1304         wd->minw[1] = minw[1];
1305         wd->minh[0] = minh[0];
1306         wd->minh[1] = minh[1];
1307         redo = 1;
1308      }
1309    i = 0;
1310    EINA_LIST_FOREACH(wd->items, l, it)
1311      {
1312         if (it->deleted)
1313           continue;
1314
1315         it->even = i & 0x1;
1316         if ((it->even != it->is_even) || (!it->fixed) || (redo))
1317           {
1318              const char *stacking;
1319
1320              /* FIXME: separators' themes seem to be b0rked */
1321              if (it->is_separator)
1322                _elm_theme_object_set(obj, VIEW(it), "separator",
1323                                      wd->h_mode ? "horizontal" : "vertical",
1324                                      style);
1325              else if (wd->mode == ELM_LIST_COMPRESS)
1326                {
1327                   if (it->even)
1328                     _elm_theme_object_set(obj, VIEW(it), "list",
1329                                           it_compress, style);
1330                   else
1331                     _elm_theme_object_set(obj, VIEW(it), "list",
1332                                           it_compress_odd, style);
1333                }
1334              else
1335                {
1336                   if (it->even)
1337                     _elm_theme_object_set(obj, VIEW(it), "list", it_plain,
1338                                           style);
1339                   else
1340                     _elm_theme_object_set(obj, VIEW(it), "list", it_odd,
1341                                           style);
1342                }
1343              stacking = edje_object_data_get(VIEW(it), "stacking");
1344              if (stacking)
1345                {
1346                   if (!strcmp(stacking, "below"))
1347                     evas_object_lower(VIEW(it));
1348                   else if (!strcmp(stacking, "above"))
1349                     evas_object_raise(VIEW(it));
1350                }
1351              edje_object_part_text_set(VIEW(it), "elm.text", it->label);
1352
1353              if ((!it->icon) && (minh[0] > 0))
1354                {
1355                   it->icon = evas_object_rectangle_add(evas_object_evas_get(VIEW(it)));
1356                   evas_object_color_set(it->icon, 0, 0, 0, 0);
1357                   it->dummy_icon = EINA_TRUE;
1358                }
1359              if ((!it->end) && (minh[1] > 0))
1360                {
1361                   it->end = evas_object_rectangle_add(evas_object_evas_get(VIEW(it)));
1362                   evas_object_color_set(it->end, 0, 0, 0, 0);
1363                   it->dummy_end = EINA_TRUE;
1364                }
1365              if (it->icon)
1366                {
1367                   evas_object_size_hint_min_set(it->icon, minw[0], minh[0]);
1368                   evas_object_size_hint_max_set(it->icon, 99999, 99999);
1369                   edje_object_part_swallow(VIEW(it), "elm.swallow.icon", it->icon);
1370                }
1371              if (it->end)
1372                {
1373                   evas_object_size_hint_min_set(it->end, minw[1], minh[1]);
1374                   evas_object_size_hint_max_set(it->end, 99999, 99999);
1375                   edje_object_part_swallow(VIEW(it), "elm.swallow.end", it->end);
1376                }
1377              if (!it->fixed)
1378                {
1379                   // this may call up user and it may modify the list item
1380                   // but we're safe as we're flagged as walking.
1381                   // just don't process further
1382                   edje_object_message_signal_process(VIEW(it));
1383                   if (it->deleted)
1384                     continue;
1385                   mw = mh = -1;
1386                   elm_coords_finger_size_adjust(1, &mw, 1, &mh);
1387                   edje_object_size_min_restricted_calc(VIEW(it), &mw, &mh, mw, mh);
1388                   elm_coords_finger_size_adjust(1, &mw, 1, &mh);
1389                   evas_object_size_hint_min_set(VIEW(it), mw, mh);
1390                   evas_object_show(VIEW(it));
1391                }
1392              if ((it->selected) || (it->highlighted))
1393                {
1394                   const char *selectraise;
1395
1396                   // this may call up user and it may modify the list item
1397                   // but we're safe as we're flagged as walking.
1398                   // just don't process further
1399                   edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm");
1400                   if (it->deleted)
1401                     continue;
1402
1403                   selectraise = edje_object_data_get(VIEW(it), "selectraise");
1404                   if ((selectraise) && (!strcmp(selectraise, "on")))
1405                     evas_object_raise(VIEW(it));
1406                }
1407              if (it->base.disabled)
1408                edje_object_signal_emit(VIEW(it), "elm,state,disabled",
1409                                        "elm");
1410
1411              it->fixed = EINA_TRUE;
1412              it->is_even = it->even;
1413           }
1414         i++;
1415      }
1416
1417    mw = 0; mh = 0;
1418    evas_object_size_hint_min_get(wd->box, &mw, &mh);
1419
1420    _elm_list_mode_set_internal(wd);
1421
1422    _elm_list_unwalk(wd);
1423    evas_object_unref(obj);
1424 }
1425
1426 static void
1427 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1428 {
1429    Widget_Data *wd = elm_widget_data_get(obj);
1430    if (!wd) return;
1431    if (wd->scr)
1432      elm_smart_scroller_hold_set(wd->scr, EINA_TRUE);
1433 }
1434
1435 static void
1436 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1437 {
1438    Widget_Data *wd = elm_widget_data_get(obj);
1439    if (!wd) return;
1440    if (wd->scr)
1441      elm_smart_scroller_hold_set(wd->scr, EINA_FALSE);
1442 }
1443
1444 static void
1445 _freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1446 {
1447    Widget_Data *wd = elm_widget_data_get(obj);
1448    if (!wd) return;
1449    if (wd->scr)
1450      elm_smart_scroller_freeze_set(wd->scr, EINA_TRUE);
1451 }
1452
1453 static void
1454 _freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1455 {
1456    Widget_Data *wd = elm_widget_data_get(obj);
1457    if (!wd) return;
1458    if (wd->scr)
1459      elm_smart_scroller_freeze_set(wd->scr, EINA_FALSE);
1460 }
1461
1462 static void
1463 _resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1464 {
1465    _sizing_eval(data);
1466 }
1467
1468 EAPI Evas_Object *
1469 elm_list_add(Evas_Object *parent)
1470 {
1471    Evas_Object *obj;
1472    Evas *e;
1473    Widget_Data *wd;
1474    Evas_Coord minw, minh;
1475
1476    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1477
1478    ELM_SET_WIDTYPE(widtype, "list");
1479    elm_widget_type_set(obj, "list");
1480    elm_widget_sub_object_add(parent, obj);
1481    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1482    elm_widget_data_set(obj, wd);
1483    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1484    elm_widget_del_hook_set(obj, _del_hook);
1485    elm_widget_theme_hook_set(obj, _theme_hook);
1486    elm_widget_disable_hook_set(obj, _disable_hook);
1487    elm_widget_can_focus_set(obj, EINA_TRUE);
1488    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
1489    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
1490    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
1491    elm_widget_event_hook_set(obj, _event_hook);
1492    elm_widget_translate_hook_set(obj, _translate_hook);
1493
1494    wd->self = obj;
1495    wd->scr = elm_smart_scroller_add(e);
1496    elm_smart_scroller_widget_set(wd->scr, obj);
1497    elm_widget_resize_object_set(obj, wd->scr);
1498    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1499                                   _changed_size_hints, obj);
1500    edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh);
1501    evas_object_size_hint_min_set(obj, minw, minh);
1502    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, obj);
1503
1504    elm_smart_scroller_bounce_allow_set(wd->scr, EINA_FALSE,
1505                                        _elm_config->thumbscroll_bounce_enable);
1506
1507    wd->box = elm_box_add(parent);
1508    elm_box_homogeneous_set(wd->box, 1);
1509    evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND, 0.0);
1510    evas_object_size_hint_align_set(wd->box, EVAS_HINT_FILL, 0.0);
1511    elm_widget_on_show_region_hook_set(wd->box, _show_region_hook, obj);
1512    elm_widget_sub_object_add(obj, wd->box);
1513    elm_smart_scroller_child_set(wd->scr, wd->box);
1514    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
1515                                   _changed_size_hints, obj);
1516
1517    evas_object_show(wd->box);
1518
1519    _theme_hook(obj);
1520
1521    wd->mode = ELM_LIST_SCROLL;
1522
1523    evas_object_smart_callback_add(wd->scr, "edge,left", _edge_left, obj);
1524    evas_object_smart_callback_add(wd->scr, "edge,right", _edge_right, obj);
1525    evas_object_smart_callback_add(wd->scr, "edge,top", _edge_top, obj);
1526    evas_object_smart_callback_add(wd->scr, "edge,bottom", _edge_bottom, obj);
1527
1528    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
1529    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
1530    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
1531    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
1532    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
1533
1534    evas_object_smart_callbacks_descriptions_set(obj, _signals);
1535
1536    _mirrored_set(obj, elm_widget_mirrored_get(obj));
1537    _sizing_eval(obj);
1538    return obj;
1539 }
1540
1541 EAPI void
1542 elm_list_go(Evas_Object *obj)
1543 {
1544    ELM_CHECK_WIDTYPE(obj, widtype);
1545    Widget_Data *wd = elm_widget_data_get(obj);
1546    if (!wd) return;
1547    _fix_items(obj);
1548 }
1549
1550 EAPI void
1551 elm_list_multi_select_set(Evas_Object *obj, Eina_Bool multi)
1552 {
1553    ELM_CHECK_WIDTYPE(obj, widtype);
1554    Widget_Data *wd = elm_widget_data_get(obj);
1555    if (!wd) return;
1556    wd->multi = multi;
1557 }
1558
1559 EAPI Eina_Bool
1560 elm_list_multi_select_get(const Evas_Object *obj)
1561 {
1562    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1563    Widget_Data *wd = elm_widget_data_get(obj);
1564    if (!wd) return EINA_FALSE;
1565    return wd->multi;
1566 }
1567
1568 EAPI void
1569 elm_list_mode_set(Evas_Object *obj, Elm_List_Mode mode)
1570 {
1571    ELM_CHECK_WIDTYPE(obj, widtype);
1572
1573    Widget_Data *wd;
1574
1575    wd = elm_widget_data_get(obj);
1576    if (!wd)
1577      return;
1578    if (wd->mode == mode)
1579      return;
1580    wd->mode = mode;
1581
1582    _elm_list_mode_set_internal(wd);
1583 }
1584
1585 EAPI Elm_List_Mode
1586 elm_list_mode_get(const Evas_Object *obj)
1587 {
1588    ELM_CHECK_WIDTYPE(obj, widtype) ELM_LIST_LAST;
1589    Widget_Data *wd = elm_widget_data_get(obj);
1590    if (!wd) return ELM_LIST_LAST;
1591    return wd->mode;
1592 }
1593
1594 EAPI void
1595 elm_list_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
1596 {
1597    ELM_CHECK_WIDTYPE(obj, widtype);
1598
1599    Widget_Data *wd;
1600    Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
1601
1602    wd = elm_widget_data_get(obj);
1603    if (!wd)
1604      return;
1605
1606    if (wd->h_mode == horizontal)
1607      return;
1608
1609    wd->h_mode = horizontal;
1610    elm_box_horizontal_set(wd->box, horizontal);
1611
1612    if (horizontal)
1613      {
1614         evas_object_size_hint_weight_set(wd->box, 0.0, EVAS_HINT_EXPAND);
1615         evas_object_size_hint_align_set(wd->box, 0.0, EVAS_HINT_FILL);
1616         elm_smart_scroller_bounce_allow_set(wd->scr, bounce, EINA_FALSE);
1617      }
1618    else
1619      {
1620         evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND, 0.0);
1621         evas_object_size_hint_align_set(wd->box, EVAS_HINT_FILL, 0.0);
1622         elm_smart_scroller_bounce_allow_set(wd->scr, EINA_FALSE, bounce);
1623      }
1624
1625    _elm_list_mode_set_internal(wd);
1626 }
1627
1628 EAPI Eina_Bool
1629 elm_list_horizontal_get(const Evas_Object *obj)
1630 {
1631    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1632
1633    Widget_Data *wd;
1634
1635    wd = elm_widget_data_get(obj);
1636    if (!wd)
1637      return EINA_FALSE;
1638
1639    return wd->h_mode;
1640 }
1641
1642 EAPI void
1643 elm_list_select_mode_set(Evas_Object *obj, Elm_Object_Select_Mode mode)
1644 {
1645    ELM_CHECK_WIDTYPE(obj, widtype);
1646    Widget_Data *wd = elm_widget_data_get(obj);
1647    if (!wd) return;
1648    if (mode >= ELM_OBJECT_SELECT_MODE_MAX)
1649      return;
1650    if (wd->select_mode != mode)
1651      wd->select_mode = mode;
1652 }
1653
1654 EAPI Elm_Object_Select_Mode
1655 elm_list_select_mode_get(const Evas_Object *obj)
1656 {
1657    ELM_CHECK_WIDTYPE(obj, widtype) ELM_OBJECT_SELECT_MODE_MAX;
1658    Widget_Data *wd = elm_widget_data_get(obj);
1659    if (!wd) return ELM_OBJECT_SELECT_MODE_MAX;
1660    return wd->select_mode;
1661 }
1662
1663 EAPI void
1664 elm_list_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
1665 {
1666    ELM_CHECK_WIDTYPE(obj, widtype);
1667    Widget_Data *wd = elm_widget_data_get(obj);
1668    if (!wd) return;
1669    if (wd->scr)
1670      elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
1671 }
1672
1673 EAPI void
1674 elm_list_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce)
1675 {
1676    ELM_CHECK_WIDTYPE(obj, widtype);
1677    Widget_Data *wd = elm_widget_data_get(obj);
1678    if (!wd) return;
1679    elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce);
1680 }
1681
1682 EAPI void
1683 elm_list_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
1684 {
1685    ELM_CHECK_WIDTYPE(obj, widtype);
1686    Widget_Data *wd = elm_widget_data_get(obj);
1687    if ((!wd) || (!wd->scr)) return;
1688    if ((policy_h >= ELM_SCROLLER_POLICY_LAST) ||
1689        (policy_v >= ELM_SCROLLER_POLICY_LAST))
1690      return;
1691    elm_smart_scroller_policy_set(wd->scr, policy_h, policy_v);
1692 }
1693
1694 EAPI void
1695 elm_list_scroller_policy_get(const Evas_Object *obj, Elm_Scroller_Policy *policy_h, Elm_Scroller_Policy *policy_v)
1696 {
1697    ELM_CHECK_WIDTYPE(obj, widtype);
1698    Widget_Data *wd = elm_widget_data_get(obj);
1699    Elm_Smart_Scroller_Policy s_policy_h, s_policy_v;
1700    if ((!wd) || (!wd->scr)) return;
1701    elm_smart_scroller_policy_get(wd->scr, &s_policy_h, &s_policy_v);
1702    if (policy_h) *policy_h = (Elm_Scroller_Policy) s_policy_h;
1703    if (policy_v) *policy_v = (Elm_Scroller_Policy) s_policy_v;
1704 }
1705
1706 EAPI void
1707 elm_list_clear(Evas_Object *obj)
1708 {
1709    ELM_CHECK_WIDTYPE(obj, widtype);
1710    Widget_Data *wd = elm_widget_data_get(obj);
1711    Elm_List_Item *it;
1712
1713    if (!wd) return;
1714    if (!wd->items) return;
1715
1716    eina_list_free(wd->selected);
1717    wd->selected = NULL;
1718
1719    if (wd->walking > 0)
1720      {
1721         Eina_List *n;
1722
1723         EINA_LIST_FOREACH(wd->items, n, it)
1724           {
1725              if (it->deleted) continue;
1726              it->deleted = EINA_TRUE;
1727              wd->to_delete = eina_list_append(wd->to_delete, it);
1728           }
1729         return;
1730      }
1731
1732    evas_object_ref(obj);
1733    _elm_list_walk(wd);
1734
1735    EINA_LIST_FREE(wd->items, it)
1736      {
1737         _elm_list_item_free(it);
1738         elm_widget_item_free(it);
1739      }
1740
1741    _elm_list_unwalk(wd);
1742
1743    _fix_items(obj);
1744    _sizing_eval(obj);
1745    evas_object_unref(obj);
1746 }
1747
1748 EAPI const Eina_List *
1749 elm_list_items_get(const Evas_Object *obj)
1750 {
1751    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1752    Widget_Data *wd = elm_widget_data_get(obj);
1753    if (!wd) return NULL;
1754    return wd->items;
1755 }
1756
1757 EAPI Elm_Object_Item *
1758 elm_list_selected_item_get(const Evas_Object *obj)
1759 {
1760    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1761    Widget_Data *wd = elm_widget_data_get(obj);
1762    if (!wd) return NULL;
1763    if (wd->selected) return (Elm_Object_Item *) wd->selected->data;
1764    return NULL;
1765 }
1766
1767 EAPI const Eina_List *
1768 elm_list_selected_items_get(const Evas_Object *obj)
1769 {
1770    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1771    Widget_Data *wd = elm_widget_data_get(obj);
1772    if (!wd) return NULL;
1773    return wd->selected;
1774 }
1775
1776 EAPI Elm_Object_Item *
1777 elm_list_item_append(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
1778 {
1779    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1780    Widget_Data *wd = elm_widget_data_get(obj);
1781    Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
1782
1783    wd->items = eina_list_append(wd->items, it);
1784    it->node = eina_list_last(wd->items);
1785    elm_box_pack_end(wd->box, VIEW(it));
1786    return (Elm_Object_Item *)it;
1787 }
1788
1789 EAPI Elm_Object_Item *
1790 elm_list_item_prepend(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
1791 {
1792    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1793    Widget_Data *wd = elm_widget_data_get(obj);
1794    Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
1795
1796    wd->items = eina_list_prepend(wd->items, it);
1797    it->node = wd->items;
1798    elm_box_pack_start(wd->box, VIEW(it));
1799    return (Elm_Object_Item *)it;
1800 }
1801
1802 EAPI Elm_Object_Item *
1803 elm_list_item_insert_before(Evas_Object *obj, Elm_Object_Item *before, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
1804 {
1805    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1806    ELM_LIST_ITEM_CHECK_DELETED_RETURN(before, NULL);
1807
1808    Widget_Data *wd;
1809    Elm_List_Item *it, *before_it;
1810
1811    wd = elm_widget_data_get(obj);
1812    if (!wd) return NULL;
1813
1814    before_it = (Elm_List_Item *) before;
1815    if (!before_it->node) return NULL;
1816
1817    it = _item_new(obj, label, icon, end, func, data);
1818    wd->items = eina_list_prepend_relative_list(wd->items, it, before_it->node);
1819    it->node = before_it->node->prev;
1820    elm_box_pack_before(wd->box, VIEW(it), VIEW(before_it));
1821    return (Elm_Object_Item *)it;
1822 }
1823
1824 EAPI Elm_Object_Item *
1825 elm_list_item_insert_after(Evas_Object *obj, Elm_Object_Item *after, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
1826 {
1827    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1828    ELM_LIST_ITEM_CHECK_DELETED_RETURN(after, NULL);
1829
1830    Widget_Data *wd;
1831    Elm_List_Item *it, *after_it;
1832
1833    wd = elm_widget_data_get(obj);
1834    if (!wd) return NULL;
1835
1836    after_it = (Elm_List_Item *) after;
1837    if (!after_it->node) return NULL;
1838
1839    it = _item_new(obj, label, icon, end, func, data);
1840    wd->items = eina_list_append_relative_list(wd->items, it, after_it->node);
1841    it->node = after_it->node->next;
1842    elm_box_pack_after(wd->box, VIEW(it), VIEW(after_it));
1843    return (Elm_Object_Item *)it;
1844 }
1845
1846 EAPI Elm_Object_Item *
1847 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)
1848 {
1849    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1850    Widget_Data *wd = elm_widget_data_get(obj);
1851    Elm_List_Item *it = _item_new(obj, label, icon, end, func, data);
1852    Eina_List *l;
1853
1854    wd->items = eina_list_sorted_insert(wd->items, cmp_func, it);
1855    l = eina_list_data_find_list(wd->items, it);
1856    l = eina_list_next(l);
1857    if (!l)
1858      {
1859         it->node = eina_list_last(wd->items);
1860         elm_box_pack_end(wd->box, VIEW(it));
1861      }
1862    else
1863      {
1864         Elm_List_Item *before = eina_list_data_get(l);
1865         it->node = before->node->prev;
1866         elm_box_pack_before(wd->box, VIEW(it), VIEW(before));
1867      }
1868    return (Elm_Object_Item *)it;
1869 }
1870
1871 EAPI void
1872 elm_list_item_separator_set(Elm_Object_Item *it, Eina_Bool setting)
1873 {
1874    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1875    ((Elm_List_Item *)it)->is_separator = !!setting;
1876 }
1877
1878 EAPI Eina_Bool
1879 elm_list_item_separator_get(const Elm_Object_Item *it)
1880 {
1881    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE);
1882    return ((Elm_List_Item *)it)->is_separator;
1883 }
1884
1885 EAPI void
1886 elm_list_item_selected_set(Elm_Object_Item *it, Eina_Bool selected)
1887 {
1888    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1889    Evas_Object *obj = WIDGET(it);
1890    Widget_Data *wd = elm_widget_data_get(obj);
1891    Elm_List_Item *item = (Elm_List_Item *)it;
1892    if (!wd) return;
1893
1894    selected = !!selected;
1895    if (item->selected == selected) return;
1896
1897    evas_object_ref(obj);
1898    _elm_list_walk(wd);
1899
1900    if (selected)
1901      {
1902         if (!wd->multi)
1903           {
1904              while (wd->selected)
1905                _item_unselect(wd->selected->data);
1906           }
1907         _item_highlight(item);
1908         _item_select(item);
1909      }
1910    else
1911      _item_unselect(item);
1912
1913    _elm_list_unwalk(wd);
1914    evas_object_unref(obj);
1915 }
1916
1917 EAPI Eina_Bool
1918 elm_list_item_selected_get(const Elm_Object_Item *it)
1919 {
1920    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, EINA_FALSE);
1921    return ((Elm_List_Item *)it)->selected;
1922 }
1923
1924 EAPI void
1925 elm_list_item_show(Elm_Object_Item *it)
1926 {
1927    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1928    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
1929    if (!wd) return;
1930    Evas_Coord bx, by, bw, bh;
1931    Evas_Coord x, y, w, h;
1932
1933    evas_object_geometry_get(wd->box, &bx, &by, &bw, &bh);
1934    evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
1935    x -= bx;
1936    y -= by;
1937    if (wd->scr) elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
1938 }
1939
1940 EAPI void
1941 elm_list_item_bring_in(Elm_Object_Item *it)
1942 {
1943    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it);
1944    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
1945    if (!wd) return;
1946    Evas_Coord bx, by, bw, bh;
1947    Evas_Coord x, y, w, h;
1948
1949    evas_object_geometry_get(wd->box, &bx, &by, &bw, &bh);
1950    evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
1951    x -= bx;
1952    y -= by;
1953    if (wd->scr) elm_smart_scroller_region_bring_in(wd->scr, x, y, w, h);
1954 }
1955
1956 EAPI Evas_Object *
1957 elm_list_item_object_get(const Elm_Object_Item *it)
1958 {
1959    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1960    return VIEW(it);
1961 }
1962
1963 EAPI Elm_Object_Item *
1964 elm_list_item_prev(const Elm_Object_Item *it)
1965 {
1966    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1967    Elm_List_Item *item = (Elm_List_Item *)it;
1968    if (item->node->prev) return item->node->prev->data;
1969    else return NULL;
1970 }
1971
1972 EAPI Elm_Object_Item *
1973 elm_list_item_next(const Elm_Object_Item *it)
1974 {
1975    ELM_LIST_ITEM_CHECK_DELETED_RETURN(it, NULL);
1976    Elm_List_Item *item = (Elm_List_Item *)it;
1977    if (item->node->next) return item->node->next->data;
1978    else return NULL;
1979 }