Merge "Region show on item elements fixed" into tizen
[platform/upstream/elementary.git] / src / lib / elm_list.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
6 #define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED
7 #define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED
8 #define ELM_INTERFACE_ATSPI_SELECTION_PROTECTED
9 //TIZEN_ONLY(20160329): list: enhance accessibility scroll and highlight (02c20ee39a0ebbe67b9e1491ccfc46dd681821c9)
10 #define ELM_INTERFACE_ATSPI_COMPONENT_PROTECTED
11 //
12 #define ELM_WIDGET_ITEM_PROTECTED
13
14 #include <Elementary.h>
15
16 #include "elm_priv.h"
17 #include "elm_widget_list.h"
18 #include "elm_interface_scrollable.h"
19
20 #define MY_CLASS ELM_LIST_CLASS
21
22 #define MY_CLASS_NAME "Elm_List"
23 #define MY_CLASS_NAME_LEGACY "elm_list"
24
25 #define ELM_LIST_SWIPE_TIME 0.4
26
27 static const char SIG_ACTIVATED[] = "activated";
28 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
29 static const char SIG_CLICKED_RIGHT[] = "clicked,right";
30 static const char SIG_SELECTED[] = "selected";
31 static const char SIG_UNSELECTED[] = "unselected";
32 static const char SIG_LONGPRESSED[] = "longpressed";
33 static const char SIG_EDGE_TOP[] = "edge,top";
34 static const char SIG_EDGE_BOTTOM[] = "edge,bottom";
35 static const char SIG_EDGE_LEFT[] = "edge,left";
36 static const char SIG_EDGE_RIGHT[] = "edge,right";
37 static const char SIG_SWIPE[] = "swipe";
38 static const char SIG_HIGHLIGHTED[] = "highlighted";
39 static const char SIG_UNHIGHLIGHTED[] = "unhighlighted";
40 static const char SIG_ITEM_FOCUSED[] = "item,focused";
41 static const char SIG_ITEM_UNFOCUSED[] = "item,unfocused";
42 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
43    {SIG_ACTIVATED, ""},
44    {SIG_CLICKED_DOUBLE, ""},
45    {SIG_CLICKED_RIGHT, ""},
46    {SIG_SELECTED, ""},
47    {SIG_UNSELECTED, ""},
48    {SIG_LONGPRESSED, ""},
49    {SIG_EDGE_TOP, ""},
50    {SIG_EDGE_BOTTOM, ""},
51    {SIG_EDGE_LEFT, ""},
52    {SIG_EDGE_RIGHT, ""},
53    {SIG_SWIPE, ""},
54    {SIG_HIGHLIGHTED, ""},
55    {SIG_UNHIGHLIGHTED, ""},
56    {SIG_ITEM_FOCUSED, ""},
57    {SIG_ITEM_UNFOCUSED, ""},
58    {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
59    {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
60    {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
61    {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
62    {NULL, NULL}
63 };
64
65 static void _size_hints_changed_cb(void *, Evas *, Evas_Object *, void *);
66 static void _mouse_up_cb(void *, Evas *, Evas_Object *, void *);
67 static void _mouse_down_cb(void *, Evas *, Evas_Object *, void *);
68 static void _mouse_move_cb(void *, Evas *, Evas_Object *, void *);
69 static void _mouse_in_cb(void *, Evas *, Evas_Object *, void *);
70 static void _items_fix(Evas_Object *);
71
72 static Eina_Bool _key_action_move(Evas_Object *obj, const char *params);
73 static Eina_Bool _key_action_select(Evas_Object *obj, const char *params);
74 static Eina_Bool _key_action_escape(Evas_Object *obj, const char *params);
75
76
77 static const Elm_Action key_actions[] = {
78    {"move", _key_action_move},
79    {"select", _key_action_select},
80    {"escape", _key_action_escape},
81    {NULL, NULL}
82 };
83
84 static Eina_Bool
85 _is_no_select(Elm_List_Item_Data *it)
86 {
87    ELM_LIST_DATA_GET_FROM_ITEM(it, sd);
88
89    if ((sd->select_mode == ELM_OBJECT_SELECT_MODE_NONE) ||
90        (sd->select_mode == ELM_OBJECT_SELECT_MODE_DISPLAY_ONLY))
91      return EINA_TRUE;
92    return EINA_FALSE;
93 }
94
95 static inline void
96 _elm_list_item_free(Elm_List_Item_Data *it)
97 {
98    ELM_LIST_DATA_GET_FROM_ITEM(it, sd);
99    Elm_Object_Item *eo_it = it?EO_OBJ(it):NULL;
100
101    if (sd->focused_item == eo_it)
102      sd->focused_item = NULL;
103    if (sd->last_focused_item == eo_it)
104      sd->last_focused_item = NULL;
105    if (sd->last_selected_item == eo_it)
106      sd->last_selected_item = NULL;
107
108
109    evas_object_event_callback_del_full
110      (VIEW(it), EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, it);
111    evas_object_event_callback_del_full
112      (VIEW(it), EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, it);
113    evas_object_event_callback_del_full
114      (VIEW(it), EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, it);
115    evas_object_event_callback_del_full
116      (VIEW(it), EVAS_CALLBACK_MOUSE_IN, _mouse_in_cb, it);
117
118    if (it->icon)
119      evas_object_event_callback_del_full
120        (it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
121        _size_hints_changed_cb, WIDGET(it));
122
123    if (it->end)
124      evas_object_event_callback_del_full
125        (it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
126        _size_hints_changed_cb, WIDGET(it));
127
128    ELM_SAFE_FREE(it->label, eina_stringshare_del);
129    ELM_SAFE_FREE(it->swipe_timer, ecore_timer_del);
130    ELM_SAFE_FREE(it->long_timer, ecore_timer_del);
131    ELM_SAFE_FREE(it->icon, evas_object_del);
132    ELM_SAFE_FREE(it->end, evas_object_del);
133 }
134
135 static Eina_Bool
136 _item_multi_select_up(Elm_List_Data *sd)
137 {
138    Elm_Object_Item *prev;
139
140    if (!sd->selected) return EINA_FALSE;
141    if (!sd->multi) return EINA_FALSE;
142
143    prev = elm_list_item_prev(sd->last_selected_item);
144    while (prev)
145      {
146         if (!elm_object_item_disabled_get(prev)) break;
147         prev = elm_list_item_prev(prev);
148      }
149    if (!prev) return EINA_TRUE;
150
151    if (elm_list_item_selected_get(prev))
152      {
153         elm_list_item_selected_set(sd->last_selected_item, EINA_FALSE);
154         sd->last_selected_item = prev;
155      }
156    else
157      {
158         elm_list_item_selected_set(prev, EINA_TRUE);
159      }
160    return EINA_TRUE;
161 }
162
163 static Eina_Bool
164 _item_multi_select_down(Elm_List_Data *sd)
165 {
166    Elm_Object_Item *next;
167
168    if (!sd->selected) return EINA_FALSE;
169    if (!sd->multi) return EINA_FALSE;
170
171    next = elm_list_item_next(sd->last_selected_item);
172    while (next)
173      {
174         if (!elm_object_item_disabled_get(next)) break;
175         next = elm_list_item_next(next);
176      }
177    if (!next) return EINA_TRUE;
178
179    if (elm_list_item_selected_get(next))
180      {
181         elm_list_item_selected_set(sd->last_selected_item, EINA_FALSE);
182         sd->last_selected_item = next;
183      }
184    else
185      {
186         elm_list_item_selected_set(next, EINA_TRUE);
187      }
188    return EINA_TRUE;
189 }
190
191 static Eina_Bool
192 _all_items_unselect(Elm_List_Data *sd)
193 {
194    if (!sd->selected) return EINA_FALSE;
195
196    while (sd->selected)
197      elm_list_item_selected_set
198        (sd->selected->data, EINA_FALSE);
199
200    return EINA_TRUE;
201 }
202
203 static Eina_Bool
204 _item_single_select_up(Elm_List_Data *sd)
205 {
206    Elm_Object_Item *prev;
207
208    if (!sd->selected)
209      prev = eina_list_data_get(eina_list_last(sd->items));
210    else
211      prev = elm_list_item_prev(sd->last_selected_item);
212
213    while (prev)
214      {
215         if (!elm_object_item_disabled_get(prev)) break;
216         prev = elm_list_item_prev(prev);
217      }
218
219    if (!prev) return EINA_FALSE;
220
221    _all_items_unselect(sd);
222
223    elm_list_item_selected_set(prev, EINA_TRUE);
224
225    return EINA_TRUE;
226 }
227
228 static Eina_Bool
229 _item_single_select_down(Elm_List_Data *sd)
230 {
231    Elm_Object_Item *next;
232
233    if (!sd->selected)
234      next = eina_list_data_get(sd->items);
235    else
236      next = elm_list_item_next(sd->last_selected_item);
237
238    while (next)
239      {
240         if (!elm_object_item_disabled_get(next)) break;
241         next = elm_list_item_next(next);
242      }
243
244    if (!next) return EINA_FALSE;
245
246    _all_items_unselect(sd);
247
248    elm_list_item_selected_set(next, EINA_TRUE);
249
250    return EINA_TRUE;
251 }
252
253 static Eina_Bool
254 _elm_list_item_content_focus_set(Elm_List_Item_Data *it, Elm_Focus_Direction dir,
255                                  Eina_Bool h_mode)
256 {
257    if (!it) return EINA_FALSE;
258    ELM_LIST_DATA_GET_FROM_ITEM(it, sd);
259
260    if (!sd->focus_on_selection_enabled) return EINA_FALSE;
261    if ((h_mode && (dir != ELM_FOCUS_UP) && (dir != ELM_FOCUS_DOWN)) ||
262        (!h_mode && (dir != ELM_FOCUS_LEFT) && (dir != ELM_FOCUS_RIGHT)))
263      return EINA_FALSE;
264
265    int focus_objs = 0;
266    Evas_Object *focus_chain[2];
267    Evas_Object *focused = NULL;
268    int idx;
269    
270    if (it->icon && elm_object_widget_check(it->icon) && elm_object_focus_allow_get(it->icon))
271      focus_chain[focus_objs++] = it->icon;
272    if (it->end && elm_object_widget_check(it->end) && elm_object_focus_allow_get(it->end))
273      focus_chain[focus_objs++] = it->end;
274
275    if (!focus_objs)
276      return EINA_FALSE;
277
278    for (idx = 0; idx < focus_objs; idx++)
279      {
280         if (elm_object_focus_get(focus_chain[idx]))
281           {
282              focused = focus_chain[idx];
283              break;
284           }
285      }
286
287    if (!focused)
288      {
289         elm_object_focus_set(focus_chain[0], EINA_TRUE);
290         return EINA_TRUE;
291      }
292
293    if (dir != ELM_FOCUS_PREVIOUS)
294      {
295         Evas_Object *nextfocus;
296         Elm_Object_Item *nextfocus_item;
297         if (elm_widget_focus_next_get(focused, dir, &nextfocus, &nextfocus_item))
298           {
299              if (nextfocus_item)
300                elm_object_item_focus_set(nextfocus_item, EINA_TRUE);
301              else
302                elm_object_focus_set(nextfocus, EINA_TRUE);
303              return EINA_TRUE;
304           }
305
306         idx += ((dir == ELM_FOCUS_UP) || (dir == ELM_FOCUS_LEFT)) ? -1 : 1;
307         if (idx < 0) idx = focus_objs - 1;
308         if (idx >= focus_objs) idx = 0;
309         focused = focus_chain[idx];
310      }
311
312    elm_object_focus_set(focused, EINA_TRUE);
313    return EINA_TRUE;
314 }
315
316 static Elm_Object_Item *
317 _next_item_get(Elm_List_Data *sd, Elm_Object_Item *eo_cur, Elm_Focus_Direction dir)
318 {
319    Eina_List *list = NULL;
320    Elm_Object_Item *eo_it = NULL;
321
322    list = eina_list_data_find_list(sd->items, eo_cur);
323    if (!list) return NULL;
324    if ((!sd->h_mode && (dir == ELM_FOCUS_UP)) ||
325        ((sd->h_mode) && (dir == ELM_FOCUS_LEFT)))
326      eo_it = eina_list_data_get(eina_list_prev(list));
327    else if (((!sd->h_mode) && (dir == ELM_FOCUS_DOWN)) ||
328             ((sd->h_mode) && (dir == ELM_FOCUS_RIGHT)))
329      eo_it = eina_list_data_get(eina_list_next(list));
330
331    return eo_it;
332 }
333
334 static Eina_Bool
335 _item_focused_next(Evas_Object *obj, Elm_Focus_Direction dir)
336 {
337    ELM_LIST_DATA_GET_OR_RETURN_VAL(obj, sd, EINA_FALSE);
338    Elm_Object_Item *eo_it = NULL;
339
340    if (sd->focused_item)
341      eo_it = _next_item_get(sd, sd->focused_item, dir);
342
343    while (eo_it &&
344           elm_object_item_disabled_get(eo_it))
345      {
346         eo_it = _next_item_get(sd, eo_it, dir);
347      }
348
349    if (eo_it)
350      {
351         elm_object_item_focus_set(eo_it, EINA_TRUE);
352         return EINA_TRUE;
353      }
354
355    return EINA_FALSE;
356 }
357
358 static Eina_Bool
359 _elm_list_elm_widget_event_direction(Evas_Object *obj, Elm_Focus_Direction dir, Eina_Bool multi)
360 {
361    Elm_Object_Item *eo_it = NULL;
362    ELM_LIST_DATA_GET(obj, sd);
363    Eina_Bool ret = EINA_FALSE;
364    Evas_Coord v = 0;
365    Evas_Coord min = 0;
366    Eina_Bool focus_only = EINA_FALSE;
367
368    // check if the content can get the focus by direction key
369    ELM_LIST_ITEM_DATA_GET(elm_object_focused_item_get(obj) , it);
370    if (_elm_list_item_content_focus_set(it, dir, sd->h_mode))
371      return EINA_TRUE;
372
373    if ((sd->h_mode && (dir != ELM_FOCUS_LEFT) && (dir != ELM_FOCUS_RIGHT)) ||
374        (!sd->h_mode && (dir != ELM_FOCUS_UP) && (dir != ELM_FOCUS_DOWN)))
375      return EINA_FALSE;
376
377    // get content size and viewport size
378    if ((dir == ELM_FOCUS_LEFT) || (dir == ELM_FOCUS_RIGHT))
379      {
380         eo_do(obj,
381               elm_interface_scrollable_content_viewport_geometry_get
382               (NULL, NULL, &v, NULL),
383               elm_interface_scrollable_content_size_get(&min, NULL));
384      }
385    else
386      {
387         eo_do(obj,
388               elm_interface_scrollable_content_viewport_geometry_get
389               (NULL, NULL, NULL, &v),
390               elm_interface_scrollable_content_size_get(NULL, &min));
391      }
392
393    // move focus or selection according to the configuration
394    focus_only = _elm_config->item_select_on_focus_disable;
395    if (focus_only)
396      ret = _item_focused_next(obj, dir);
397    else
398      {
399         if (multi)
400           {
401              if ((dir == ELM_FOCUS_LEFT) || (dir == ELM_FOCUS_UP))
402                ret = _item_multi_select_up(sd);
403              else
404                ret = _item_multi_select_down(sd);
405           }
406         else
407           {
408              if ((dir == ELM_FOCUS_LEFT) || (dir == ELM_FOCUS_UP))
409                ret = _item_single_select_up(sd);
410              else
411                ret = _item_single_select_down(sd);
412           }
413      }
414    if (ret)
415      return EINA_TRUE;
416
417    // handle item loop feature
418    if (sd->item_loop_enable && !sd->item_looping_on)
419      {
420         if (min > v)
421           {
422              if (dir == ELM_FOCUS_LEFT)
423                {
424                   elm_layout_signal_emit(obj, "elm,action,looping,left", "elm");
425                   sd->item_looping_on = EINA_TRUE;
426                }
427              else if (dir == ELM_FOCUS_RIGHT)
428                {
429                   elm_layout_signal_emit(obj, "elm,action,looping,right", "elm");
430                   sd->item_looping_on = EINA_TRUE;
431                }
432              else if (dir == ELM_FOCUS_UP)
433                {
434                   elm_layout_signal_emit(obj, "elm,action,looping,up", "elm");
435                   sd->item_looping_on = EINA_TRUE;
436                }
437              else if (dir == ELM_FOCUS_DOWN)
438                {
439                   elm_layout_signal_emit(obj, "elm,action,looping,down", "elm");
440                   sd->item_looping_on = EINA_TRUE;
441                }
442           }
443         else
444           {
445              if ((dir == ELM_FOCUS_LEFT) || (dir == ELM_FOCUS_UP))
446                eo_it = elm_list_last_item_get(obj);
447              else
448                eo_it = elm_list_first_item_get(obj);
449
450              if (focus_only)
451                elm_object_item_focus_set(eo_it, EINA_TRUE);
452              else
453                elm_list_item_selected_set(eo_it, EINA_TRUE);
454           }
455         return EINA_TRUE;
456      }
457    else if (sd->item_looping_on)
458      return EINA_TRUE;
459
460    return EINA_FALSE;
461 }
462
463 static Eina_Bool _key_action_move(Evas_Object *obj, const char *params)
464 {
465    ELM_LIST_DATA_GET(obj, sd);
466    const char *dir = params;
467
468    Evas_Coord x = 0;
469    Evas_Coord y = 0;
470    Evas_Coord v_w = 0;
471    Evas_Coord v_h = 0;
472    Evas_Coord step_x = 0;
473    Evas_Coord step_y = 0;
474    Evas_Coord page_x = 0;
475    Evas_Coord page_y = 0;
476    Elm_Object_Item *it = NULL;
477
478    eo_do(obj,
479          elm_interface_scrollable_content_pos_get(&x, &y),
480          elm_interface_scrollable_step_size_get(&step_x, &step_y),
481          elm_interface_scrollable_page_size_get(&page_x, &page_y),
482          elm_interface_scrollable_content_viewport_geometry_get
483          (NULL, NULL, &v_w, &v_h));
484
485    _elm_widget_focus_auto_show(obj);
486    /* TODO: fix logic for horizontal mode */
487    if (!strcmp(dir, "left"))
488      {
489         if (_elm_list_elm_widget_event_direction(obj, ELM_FOCUS_LEFT, EINA_FALSE))
490           return EINA_TRUE;
491         else
492           return EINA_FALSE;
493      }
494    else if (!strcmp(dir, "left_multi"))
495      {
496         if (_elm_list_elm_widget_event_direction(obj, ELM_FOCUS_LEFT, EINA_TRUE))
497           return EINA_TRUE;
498         else
499           return EINA_FALSE;
500      }
501    else if (!strcmp(dir, "right"))
502      {
503         if (_elm_list_elm_widget_event_direction(obj, ELM_FOCUS_RIGHT, EINA_FALSE))
504           return EINA_TRUE;
505         else
506           return EINA_FALSE;
507      }
508    else if (!strcmp(dir, "right_multi"))
509      {
510         if (_elm_list_elm_widget_event_direction(obj, ELM_FOCUS_RIGHT, EINA_TRUE))
511           return EINA_TRUE;
512         else
513           return EINA_FALSE;
514      }
515    else if (!strcmp(dir, "up"))
516      {
517         if (_elm_list_elm_widget_event_direction(obj, ELM_FOCUS_UP, EINA_FALSE))
518           return EINA_TRUE;
519         else
520           return EINA_FALSE;
521      }
522    else if (!strcmp(dir, "up_multi"))
523      {
524         if (_elm_list_elm_widget_event_direction(obj, ELM_FOCUS_UP, EINA_TRUE))
525           return EINA_TRUE;
526         else
527           return EINA_FALSE;
528      }
529    else if (!strcmp(dir, "down"))
530      {
531         if (_elm_list_elm_widget_event_direction(obj, ELM_FOCUS_DOWN, EINA_FALSE))
532           return EINA_TRUE;
533         else
534           return EINA_FALSE;
535      }
536    else if (!strcmp(dir, "down_multi"))
537      {
538         if (_elm_list_elm_widget_event_direction(obj, ELM_FOCUS_DOWN, EINA_TRUE))
539           return EINA_TRUE;
540         else
541           return EINA_FALSE;
542      }
543    else if (!strcmp(dir, "first"))
544      {
545         it = eina_list_data_get(sd->items);
546         if (it)
547           {
548              elm_list_item_selected_set(it, EINA_TRUE);
549              return EINA_TRUE;
550           }
551         else
552           return EINA_FALSE;
553      }
554    else if (!strcmp(dir, "last"))
555      {
556         it = eina_list_data_get(eina_list_last(sd->items));
557         if (it)
558           {
559              elm_list_item_selected_set(it, EINA_TRUE);
560              return EINA_TRUE;
561           }
562         else
563           return EINA_FALSE;
564      }
565    else if (!strcmp(dir, "prior"))
566      {
567         if (sd->h_mode)
568           {
569              if (page_x < 0)
570                x -= -(page_x * v_w) / 100;
571              else
572                x -= page_x;
573           }
574         else
575           {
576              if (page_y < 0)
577                y -= -(page_y * v_h) / 100;
578              else
579                y -= page_y;
580           }
581      }
582    else if (!strcmp(dir, "next"))
583      {
584         if (sd->h_mode)
585           {
586              if (page_x < 0)
587                x += -(page_x * v_w) / 100;
588              else
589                x += page_x;
590           }
591         else
592           {
593              if (page_y < 0)
594                y += -(page_y * v_h) / 100;
595              else
596                y += page_y;
597           }
598      }
599    else return EINA_FALSE;
600
601    eo_do(obj, elm_interface_scrollable_content_pos_set(x, y, EINA_TRUE));
602    return EINA_TRUE;
603 }
604
605 static Eina_Bool _key_action_select(Evas_Object *obj, const char *params EINA_UNUSED)
606 {
607    ELM_LIST_DATA_GET(obj, sd);
608    Elm_Object_Item *eo_it = NULL;
609
610    if (!_elm_config->item_select_on_focus_disable &&
611        (!sd->multi) && (sd->selected))
612      eo_it = elm_list_selected_item_get(obj);
613    else
614      eo_it = elm_object_focused_item_get(obj);
615    elm_list_item_selected_set(eo_it, EINA_TRUE);
616    if (eo_it)
617      {
618         ELM_LIST_ITEM_DATA_GET(eo_it, it);
619         eo_do(WIDGET(it), eo_event_callback_call
620           (ELM_LIST_EVENT_ACTIVATED, eo_it));
621      }
622
623    return EINA_TRUE;
624 }
625
626 static Eina_Bool _key_action_escape(Evas_Object *obj, const char *params EINA_UNUSED)
627 {
628    ELM_LIST_DATA_GET(obj, sd);
629
630    if (!_all_items_unselect(sd)) return EINA_FALSE;
631    return EINA_TRUE;
632 }
633
634 EOLIAN static Eina_Bool
635 _elm_list_elm_widget_event(Eo *obj, Elm_List_Data *sd, Evas_Object *src, Evas_Callback_Type type, void *event_info)
636 {
637    (void) src;
638    Evas_Event_Key_Down *ev = event_info;
639
640    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
641    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
642    if (!sd->items) return EINA_FALSE;
643
644    if (!_elm_config_key_binding_call(obj, ev, key_actions))
645      return EINA_FALSE;
646
647    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
648    return EINA_TRUE;
649 }
650
651 EOLIAN static Eina_Bool
652 _elm_list_elm_widget_translate(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
653 {
654    Elm_Object_Item *it;
655    Eina_List *l;
656
657    EINA_LIST_FOREACH(sd->items, l, it)
658      eo_do(it, elm_wdg_item_translate());
659
660    eo_do_super(obj, MY_CLASS, elm_obj_widget_translate());
661
662    return EINA_TRUE;
663 }
664
665 static void
666 _elm_list_deletions_process(Elm_List_Data *sd)
667 {
668    Elm_List_Item_Data *it;
669
670    sd->walking++; // avoid nested deletion and also _sub_del() items_fix
671
672    EINA_LIST_FREE(sd->to_delete, it)
673      {
674         sd->items = eina_list_remove_list(sd->items, it->node);
675
676         /* issuing free because of "locking" item del pre hook */
677         _elm_list_item_free(it);
678         eo_del(EO_OBJ(it));
679      }
680
681    sd->walking--;
682 }
683
684 EOLIAN static void
685 _elm_list_elm_layout_sizing_eval(Eo *obj, Elm_List_Data *sd)
686 {
687    Evas_Coord vw = 0, vh = 0;
688    Evas_Coord minw = 0, minh = 0, maxw = 0, maxh = 0, w = 0, h = 0, vmw = 0, vmh = 0;
689    double xw = 0.0, yw = 0.0;
690
691    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
692
693    evas_object_size_hint_min_get(sd->box, &minw, &minh);
694    evas_object_size_hint_max_get(sd->box, &maxw, &maxh);
695    evas_object_size_hint_weight_get(sd->box, &xw, &yw);
696
697    eo_do(obj, elm_interface_scrollable_content_viewport_geometry_get
698          (NULL, NULL, &vw, &vh));
699    if (xw > 0.0)
700      {
701         if ((minw > 0) && (vw < minw)) vw = minw;
702         else if ((maxw > 0) && (vw > maxw))
703           vw = maxw;
704      }
705    else if (minw > 0)
706      vw = minw;
707    if (yw > 0.0)
708      {
709         if ((minh > 0) && (vh < minh)) vh = minh;
710         else if ((maxh > 0) && (vh > maxh))
711           vh = maxh;
712      }
713    else if (minh > 0)
714      vh = minh;
715
716    evas_object_resize(sd->box, vw, vh);
717    w = -1;
718    h = -1;
719
720    edje_object_size_min_calc
721      (wd->resize_obj, &vmw, &vmh);
722
723    if (sd->scr_minw) w = vmw + minw;
724    if (sd->scr_minh) h = vmh + minh;
725
726    evas_object_size_hint_max_get(obj, &maxw, &maxh);
727    if ((maxw > 0) && (w > maxw))
728      w = maxw;
729    if ((maxh > 0) && (h > maxh))
730      h = maxh;
731
732    evas_object_size_hint_min_set(obj, w, h);
733 }
734
735 static void
736 _elm_list_content_min_limit_cb(Evas_Object *obj,
737                                Eina_Bool w,
738                                Eina_Bool h)
739 {
740    ELM_LIST_DATA_GET(obj, sd);
741
742    if ((sd->mode == ELM_LIST_LIMIT) ||
743        (sd->mode == ELM_LIST_EXPAND)) return;
744    sd->scr_minw = !!w;
745    sd->scr_minh = !!h;
746
747    elm_layout_sizing_eval(obj);
748 }
749
750 static void
751 _elm_list_mode_set_internal(Evas_Object *obj)
752 {
753    Elm_List_Data *sd = eo_data_scope_get(obj, MY_CLASS);
754    if (sd->mode == ELM_LIST_LIMIT)
755      {
756         if (!sd->h_mode)
757           {
758              sd->scr_minw = EINA_TRUE;
759              sd->scr_minh = EINA_FALSE;
760           }
761         else
762           {
763              sd->scr_minw = EINA_FALSE;
764              sd->scr_minh = EINA_TRUE;
765           }
766      }
767    else if (sd->mode == ELM_LIST_EXPAND)
768      {
769         sd->scr_minw = EINA_TRUE;
770         sd->scr_minh = EINA_TRUE;
771      }
772    else
773      {
774         sd->scr_minw = EINA_FALSE;
775         sd->scr_minh = EINA_FALSE;
776      }
777
778    elm_layout_sizing_eval(obj);
779 }
780
781 static inline void
782 _elm_list_walk(Elm_List_Data *sd)
783 {
784    if (sd->walking < 0)
785      {
786         ERR("ERROR: walking was negative. fixed!\n");
787         sd->walking = 0;
788      }
789    sd->walking++;
790 }
791
792 static inline void
793 _elm_list_unwalk(Evas_Object *obj, Elm_List_Data *sd)
794 {
795    sd->walking--;
796    if (sd->walking < 0)
797      {
798         ERR("ERROR: walking became negative. fixed!\n");
799         sd->walking = 0;
800      }
801
802    if (sd->walking)
803      return;
804
805    if (sd->to_delete)
806      _elm_list_deletions_process(sd);
807
808    if (sd->fix_pending)
809      {
810         sd->fix_pending = EINA_FALSE;
811         _items_fix(obj);
812         elm_layout_sizing_eval(obj);
813      }
814 }
815
816 static void
817 _items_fix(Evas_Object *obj)
818 {
819    Evas_Coord minw[2] = { 0, 0 }, minh[2] = { 0, 0 };
820    const Eina_List *l;
821    Elm_Object_Item *eo_it;
822    Evas_Coord mw, mh;
823    int i, redo = 0;
824
825    const char *style;
826    const char *it_odd;
827    const char *it_plain;
828    const char *it_compress;
829    const char *it_compress_odd;
830
831    ELM_LIST_DATA_GET(obj, sd);
832
833    style = elm_widget_style_get(obj);
834    it_plain = sd->h_mode ? "h_item" : "item";
835    it_odd = sd->h_mode ? "h_item_odd" : "item_odd";
836    it_compress = sd->h_mode ? "h_item_compress" : "item_compress";
837    it_compress_odd = sd->h_mode ? "h_item_compress_odd" : "item_compress_odd";
838
839    if (sd->walking)
840      {
841         sd->fix_pending = EINA_TRUE;
842         return;
843      }
844
845    evas_object_ref(obj);
846    _elm_list_walk(sd); // watch out "return" before unwalk!
847
848    EINA_LIST_FOREACH(sd->items, l, eo_it)
849      {
850         ELM_LIST_ITEM_DATA_GET(eo_it, it);
851         if (!it) continue;
852         if (it->deleted) continue;
853         if (it->icon)
854           {
855              evas_object_size_hint_min_get(it->icon, &mw, &mh);
856              if (mw > minw[0]) minw[0] = mw;
857              if (mh > minh[0]) minh[0] = mh;
858           }
859         if (it->end)
860           {
861              evas_object_size_hint_min_get(it->end, &mw, &mh);
862              if (mw > minw[1]) minw[1] = mw;
863              if (mh > minh[1]) minh[1] = mh;
864           }
865      }
866
867    if ((minw[0] != sd->minw[0]) || (minw[1] != sd->minw[1]) ||
868        (minh[0] != sd->minh[0]) || (minh[1] != sd->minh[1]))
869      {
870         sd->minw[0] = minw[0];
871         sd->minw[1] = minw[1];
872         sd->minh[0] = minh[0];
873         sd->minh[1] = minh[1];
874         redo = 1;
875      }
876
877    i = 0;
878    EINA_LIST_FOREACH(sd->items, l, eo_it)
879      {
880         ELM_LIST_ITEM_DATA_GET(eo_it, it);
881         if (!it) continue;
882         if (it->deleted)
883           continue;
884
885         it->even = i & 0x1;
886         if ((it->even != it->is_even) || (!it->fixed) || (redo))
887           {
888              const char *stacking;
889
890              if (it->is_separator)
891                elm_widget_theme_object_set
892                  (obj, VIEW(it), "separator", sd->h_mode ?
893                      "vertical" : "horizontal", style);
894              else if (sd->mode == ELM_LIST_COMPRESS)
895                {
896                   if (it->even)
897                     elm_widget_theme_object_set
898                       (obj, VIEW(it), "list", it_compress, style);
899                   else
900                     elm_widget_theme_object_set
901                       (obj, VIEW(it), "list", it_compress_odd, style);
902                }
903              else
904                {
905                   if (it->even)
906                     elm_widget_theme_object_set
907                       (obj, VIEW(it), "list", it_plain, style);
908                   else
909                     elm_widget_theme_object_set
910                       (obj, VIEW(it), "list", it_odd, style);
911                }
912              stacking = edje_object_data_get(VIEW(it), "stacking");
913              if (stacking)
914                {
915                   if (!strcmp(stacking, "below"))
916                     evas_object_lower(VIEW(it));
917                   else if (!strcmp(stacking, "above"))
918                     evas_object_raise(VIEW(it));
919                }
920
921              if (!it->is_separator)
922                {
923                   edje_object_part_text_escaped_set
924                      (VIEW(it), "elm.text", it->label);
925                   eo_do(EO_OBJ(it), elm_wdg_item_part_text_custom_update());
926
927                   if ((!it->icon) && (minh[0] > 0))
928                     {
929                        it->icon = evas_object_rectangle_add
930                           (evas_object_evas_get(VIEW(it)));
931                        evas_object_color_set(it->icon, 0, 0, 0, 0);
932                        it->dummy_icon = EINA_TRUE;
933                     }
934                   if ((!it->end) && (minh[1] > 0))
935                     {
936                        it->end = evas_object_rectangle_add
937                           (evas_object_evas_get(VIEW(it)));
938                        evas_object_color_set(it->end, 0, 0, 0, 0);
939                        it->dummy_end = EINA_TRUE;
940                     }
941                   if (it->icon)
942                     {
943                        evas_object_size_hint_min_set(it->icon, minw[0], minh[0]);
944                        evas_object_size_hint_max_set(it->icon, 99999, 99999);
945                        edje_object_part_swallow
946                           (VIEW(it), "elm.swallow.icon", it->icon);
947                     }
948                   if (it->end)
949                     {
950                        evas_object_size_hint_min_set(it->end, minw[1], minh[1]);
951                        evas_object_size_hint_max_set(it->end, 99999, 99999);
952                        edje_object_part_swallow
953                           (VIEW(it), "elm.swallow.end", it->end);
954                     }
955                   if (eina_list_count(sd->items) == 1)
956                     {
957                        edje_object_signal_emit
958                            (VIEW(it), "elm,state,list,single", "elm");
959                     }
960                   else if (l == sd->items) //1st item
961                     {
962                        edje_object_signal_emit
963                            (VIEW(it), "elm,state,list,first", "elm");
964                     }
965                   else if (l == eina_list_last(sd->items))
966                     {
967                        edje_object_signal_emit
968                            (VIEW(it), "elm,state,list,last", "elm");
969                     }
970                   else
971                    {
972                        edje_object_signal_emit
973                            (VIEW(it), "elm,state,list,middle", "elm");
974                    }
975                }
976              if (!it->fixed)
977                {
978                   // this may call up user and it may modify the list item
979                   // but we're safe as we're flagged as walking.
980                   // just don't process further
981                   edje_object_message_signal_process(VIEW(it));
982                   if (it->deleted)
983                     continue;
984                   mw = mh = -1;
985                   if (!it->is_separator)
986                     elm_coords_finger_size_adjust(1, &mw, 1, &mh);
987                   edje_object_size_min_restricted_calc
988                     (VIEW(it), &mw, &mh, mw, mh);
989                   /*
990                   FIXME: this fixed T179 but introduced T286.
991                   Temporarily disable these lines until it gets fixed correctly.
992                   Evas_Coord ew, eh;
993                   edje_object_parts_extends_calc
994                     (VIEW(it), NULL, NULL, &ew, &eh);
995                   mw = mw > ew ? mw : ew;
996                   mh = mh > eh ? mh : eh;
997                   */
998                   evas_object_size_hint_min_set(VIEW(it), mw, mh);
999                   evas_object_show(VIEW(it));
1000                }
1001              if ((it->selected) || (it->highlighted))
1002                {
1003                   const char *select_raise;
1004
1005                   // this may call up user and it may modify the list item
1006                   // but we're safe as we're flagged as walking.
1007                   // just don't process further
1008                   edje_object_signal_emit
1009                     (VIEW(it), "elm,state,selected", "elm");
1010                   if (it->deleted)
1011                     continue;
1012
1013                   select_raise = edje_object_data_get(VIEW(it), "selectraise");
1014                   if ((select_raise) && (!strcmp(select_raise, "on")))
1015                     evas_object_raise(VIEW(it));
1016                }
1017              if (it->base->disabled)
1018                edje_object_signal_emit(VIEW(it), "elm,state,disabled", "elm");
1019
1020              it->fixed = EINA_TRUE;
1021              it->is_even = it->even;
1022           }
1023
1024         if (!it->is_separator)
1025           i++;
1026      }
1027
1028    _elm_list_mode_set_internal(obj);
1029    _elm_list_unwalk(obj, sd);
1030
1031    //focus highlight in_theme is set by list item theme.
1032    _elm_widget_item_highlight_in_theme(
1033          obj, elm_list_first_item_get(obj));
1034
1035    evas_object_unref(obj);
1036 }
1037
1038 static void
1039 _size_hints_changed_cb(void *data,
1040                        Evas *e EINA_UNUSED,
1041                        Evas_Object *obj EINA_UNUSED,
1042                        void *event_info EINA_UNUSED)
1043 {
1044    ELM_LIST_DATA_GET(data, sd);
1045    if (sd->delete_me) return;
1046
1047    _items_fix(data);
1048    elm_layout_sizing_eval(data);
1049 }
1050
1051 /* FIXME: take off later. maybe this show region coords belong in the
1052  * interface (new api functions, set/get)? */
1053 static void
1054 _show_region_hook(void *data EINA_UNUSED,
1055                   Evas_Object *obj)
1056 {
1057    Evas_Coord x, y, w, h;
1058
1059    elm_widget_show_region_get(obj, &x, &y, &w, &h);
1060    eo_do(obj, elm_interface_scrollable_content_region_set(x, y, w, h));
1061 }
1062
1063 EOLIAN static Eina_Bool
1064 _elm_list_elm_widget_disable(Eo *obj, Elm_List_Data *sd)
1065 {
1066    Eina_Bool int_ret = EINA_FALSE;
1067    eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_disable());
1068    if (!int_ret) return EINA_FALSE;
1069
1070    if (elm_widget_disabled_get(obj))
1071      {
1072         elm_widget_scroll_freeze_push(obj);
1073         elm_widget_scroll_hold_push(obj);
1074         /* FIXME: if we get to have a way to only un-highlight items
1075          * in the future, keeping them selected... */
1076         _all_items_unselect(sd);
1077      }
1078    else
1079      {
1080         elm_widget_scroll_freeze_pop(obj);
1081         elm_widget_scroll_hold_pop(obj);
1082      }
1083
1084    return EINA_TRUE;
1085 }
1086
1087 static void
1088 _mirrored_set(Evas_Object *obj,
1089               Eina_Bool rtl)
1090 {
1091    Elm_Object_Item *eo_it;
1092    Eina_List *n;
1093
1094    ELM_LIST_DATA_GET(obj, sd);
1095
1096    eo_do(obj, elm_interface_scrollable_mirrored_set(rtl));
1097
1098    EINA_LIST_FOREACH(sd->items, n, eo_it)
1099      {
1100         ELM_LIST_ITEM_DATA_GET(eo_it, it);
1101         edje_object_mirrored_set(VIEW(it), rtl);
1102      }
1103 }
1104
1105 EOLIAN static Eina_Bool
1106 _elm_list_elm_widget_theme_apply(Eo *obj, Elm_List_Data *sd)
1107 {
1108    Elm_Object_Item *eo_it;
1109    Eina_List *n;
1110
1111    Eina_Bool int_ret = EINA_FALSE;
1112    eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_theme_apply());
1113    if (!int_ret) return EINA_FALSE;
1114
1115    _mirrored_set(obj, elm_widget_mirrored_get(obj));
1116
1117    EINA_LIST_FOREACH(sd->items, n, eo_it)
1118      {
1119         ELM_LIST_ITEM_DATA_GET(eo_it, it);
1120         edje_object_scale_set
1121           (VIEW(it), elm_widget_scale_get(obj) * elm_config_scale_get());
1122         it->fixed = EINA_FALSE;
1123      }
1124
1125    _items_fix(obj);
1126
1127    elm_layout_sizing_eval(obj);
1128
1129    return EINA_TRUE;
1130 }
1131
1132 static void
1133 _elm_list_item_focused(Elm_Object_Item *eo_it)
1134 {
1135    ELM_LIST_ITEM_DATA_GET(eo_it, it);
1136    ELM_LIST_DATA_GET_FROM_ITEM(it, sd);
1137    Evas_Coord x, y, w, h, sx, sy, sw, sh;
1138    const char *focus_raise;
1139
1140    if ((!sd) || _is_no_select(it) ||
1141        (eo_it == sd->focused_item))
1142      return;
1143    evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
1144    evas_object_geometry_get(sd->hit_rect, &sx, &sy, &sw, &sh);
1145    if (!ELM_RECTS_INCLUDE(sx, sy, sw, sh, x, y, w, h))
1146      {
1147         switch (_elm_config->focus_autoscroll_mode)
1148           {
1149            case ELM_FOCUS_AUTOSCROLL_MODE_SHOW:
1150               elm_list_item_show(eo_it);
1151               break;
1152            case ELM_FOCUS_AUTOSCROLL_MODE_BRING_IN:
1153               elm_list_item_bring_in(eo_it);
1154               break;
1155            default:
1156               break;
1157           }
1158      }
1159    sd->focused_item = eo_it;
1160    if (elm_widget_focus_highlight_enabled_get(WIDGET(it)) || _elm_config->win_auto_focus_enable)
1161      {
1162         edje_object_signal_emit
1163            (VIEW(it), "elm,state,focused", "elm");
1164      }
1165    focus_raise = edje_object_data_get(VIEW(it), "focusraise");
1166    if ((focus_raise) && (!strcmp(focus_raise, "on")))
1167      evas_object_raise(VIEW(it));
1168    eo_do(WIDGET(it), eo_event_callback_call
1169      (ELM_LIST_EVENT_ITEM_FOCUSED, eo_it));
1170    if (_elm_config->atspi_mode)
1171      elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_FOCUSED, EINA_TRUE);
1172 }
1173
1174 static void
1175 _elm_list_item_unfocused(Elm_Object_Item *eo_it)
1176 {
1177    ELM_LIST_ITEM_DATA_GET(eo_it, it);
1178    Evas_Object *obj = WIDGET(it);
1179    ELM_LIST_DATA_GET(obj, sd);
1180
1181    if ((!sd) || (!sd->focused_item) ||
1182        (eo_it != sd->focused_item))
1183      return;
1184
1185    if (_is_no_select(it))
1186      return;
1187
1188    if (elm_widget_focus_highlight_enabled_get(obj) || _elm_config->win_auto_focus_enable)
1189      {
1190         ELM_LIST_ITEM_DATA_GET(sd->focused_item, focus_it);
1191         edje_object_signal_emit
1192            (VIEW(focus_it), "elm,state,unfocused", "elm");
1193      }
1194
1195    sd->focused_item = NULL;
1196    eo_do(obj, eo_event_callback_call(ELM_LIST_EVENT_ITEM_UNFOCUSED, eo_it));
1197    if (_elm_config->atspi_mode)
1198      elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_FOCUSED, EINA_FALSE);
1199 }
1200
1201 /*
1202  * This function searches the nearest visible item based on the given item.
1203  * If the given item is in the list viewport, this returns the given item.
1204  * Or this searches other items and checks the nearest fully visible item
1205  * according to the given item's position.
1206  */
1207 static Elm_List_Item_Data *
1208 _elm_list_nearest_visible_item_get(Evas_Object *obj, Elm_List_Item_Data *it)
1209 {
1210    Evas_Coord vx = 0, vy = 0, vw = 0, vh = 0; // list viewport geometry
1211    Evas_Coord ix = 0, iy = 0, iw = 0, ih = 0; // given item geometry
1212    Evas_Coord cx = 0, cy = 0, cw = 0, ch = 0; // candidate item geometry
1213    Eina_List *item_list = NULL;
1214    Elm_List_Item_Data *item = NULL;
1215    ELM_LIST_DATA_GET(obj, sd);
1216    Eina_Bool search_next = EINA_FALSE;
1217
1218    if (!it) return NULL;
1219
1220    evas_object_geometry_get(obj, &vx, &vy, &vw, &vh);
1221    evas_object_geometry_get(VIEW(it), &ix, &iy, &iw, &ih);
1222
1223    if (ELM_RECTS_INCLUDE(vx, vy, vw, vh, ix, iy, iw, ih))
1224      {
1225         if (!elm_object_item_disabled_get(EO_OBJ(it)))
1226           return it;
1227         else
1228           search_next = EINA_TRUE;
1229      }
1230
1231    item_list = eina_list_data_find_list(sd->items, EO_OBJ(it));
1232
1233    if ((!sd->h_mode && (iy < vy)) ||
1234        (sd->h_mode && (iw < vw)) ||
1235        search_next)
1236      {
1237         while ((item_list = eina_list_next(item_list)))
1238           {
1239              item = eo_data_scope_get(eina_list_data_get(item_list), ELM_LIST_ITEM_CLASS);
1240              if (!item) continue;
1241              evas_object_geometry_get(VIEW(item), &cx, &cy, &cw, &ch);
1242              if (ELM_RECTS_INCLUDE(vx, vy, vw, vh, cx, cy, cw, ch) &&
1243                  !elm_object_item_disabled_get(EO_OBJ(item)))
1244                {
1245                   return item;
1246                }
1247           }
1248      }
1249    else
1250      {
1251         while ((item_list = eina_list_prev(item_list)))
1252           {
1253              item = eo_data_scope_get(eina_list_data_get(item_list), ELM_LIST_ITEM_CLASS);
1254              if (!item) continue;
1255              evas_object_geometry_get(VIEW(item), &cx, &cy, &cw, &ch);
1256              if (ELM_RECTS_INCLUDE(vx, vy, vw, vh, cx, cy, cw, ch) &&
1257                  !elm_object_item_disabled_get(EO_OBJ(item)))
1258                {
1259                   return item;
1260                }
1261           }
1262      }
1263
1264    return it;
1265 }
1266
1267 EOLIAN static Eina_Bool
1268 _elm_list_elm_widget_on_focus(Eo *obj, Elm_List_Data *sd, Elm_Object_Item *item EINA_UNUSED)
1269 {
1270    Eina_Bool int_ret = EINA_FALSE;
1271    Elm_Object_Item *eo_it = NULL;
1272    Eina_Bool is_sel = EINA_FALSE;
1273
1274    eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_on_focus(NULL));
1275    if (!int_ret) return EINA_FALSE;
1276
1277    if (elm_widget_focus_get(obj) && sd->selected && !sd->last_selected_item)
1278      {
1279         Elm_Object_Item *sel = eina_list_data_get(sd->selected);
1280         sd->last_selected_item = eo_data_scope_get(sel, ELM_LIST_ITEM_CLASS);
1281      }
1282
1283    if (!sd->items) return EINA_FALSE;
1284
1285    if (elm_widget_focus_get(obj) && !sd->mouse_down)
1286      {
1287         if (sd->last_focused_item)
1288           eo_it = sd->last_focused_item;
1289         else if (sd->last_selected_item)
1290           eo_it = sd->last_selected_item;
1291         else if (_elm_config->first_item_focus_on_first_focus_in)
1292           {
1293              eo_it = elm_list_first_item_get(obj);
1294              is_sel = EINA_TRUE;
1295           }
1296
1297         if (eo_it)
1298           {
1299              ELM_LIST_ITEM_DATA_GET(eo_it, it);
1300              it = _elm_list_nearest_visible_item_get(obj, it);
1301              if (it)
1302                {
1303                   if (!_elm_config->item_select_on_focus_disable && is_sel)
1304                     elm_list_item_selected_set(EO_OBJ(it), EINA_TRUE);
1305                   else
1306                     elm_object_item_focus_set(EO_OBJ(it), EINA_TRUE);
1307                }
1308           }
1309      }
1310    else
1311      {
1312         sd->last_focused_item = sd->focused_item;
1313         if (sd->focused_item)
1314           _elm_list_item_unfocused(sd->focused_item);
1315      }
1316    return EINA_TRUE;
1317 }
1318
1319 EOLIAN static Eina_Bool
1320 _elm_list_elm_widget_sub_object_del(Eo *obj, Elm_List_Data *sd, Evas_Object *sobj)
1321 {
1322    const Eina_List *l;
1323    Elm_Object_Item *eo_it;
1324
1325    Eina_Bool int_ret = EINA_FALSE;
1326    eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_sub_object_del(sobj));
1327    if (!int_ret) return EINA_FALSE;
1328
1329    if ((sobj == sd->box) || (sobj == obj)) goto end;
1330
1331    EINA_LIST_FOREACH(sd->items, l, eo_it)
1332      {
1333         ELM_LIST_ITEM_DATA_GET(eo_it, it);
1334         if ((sobj == it->icon) || (sobj == it->end))
1335           {
1336              if (it->icon == sobj) it->icon = NULL;
1337              if (it->end == sobj) it->end = NULL;
1338              evas_object_event_callback_del_full
1339                (sobj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _size_hints_changed_cb,
1340                obj);
1341              if (!sd->walking)
1342                {
1343                   _items_fix(obj);
1344                   elm_layout_sizing_eval(obj);
1345                }
1346              else
1347                sd->fix_pending = EINA_TRUE;
1348              break;
1349           }
1350      }
1351
1352 end:
1353    return EINA_TRUE;
1354 }
1355
1356 static void
1357 _item_highlight(Elm_List_Item_Data *it)
1358 {
1359    Evas_Object *obj;
1360    const char *select_raise;
1361
1362    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
1363    obj = WIDGET(it);
1364    ELM_LIST_DATA_GET(obj, sd);
1365
1366    if (_is_no_select(it) ||
1367        (it->highlighted) || (it->base->disabled))
1368        return;
1369
1370    evas_object_ref(obj);
1371    _elm_list_walk(sd);
1372
1373    edje_object_signal_emit(VIEW(it), "elm,state,selected", "elm");
1374    eo_do(obj, eo_event_callback_call(ELM_LIST_EVENT_HIGHLIGHTED, EO_OBJ(it)));
1375    select_raise = edje_object_data_get(VIEW(it), "selectraise");
1376    if ((select_raise) && (!strcmp(select_raise, "on")))
1377      evas_object_raise(VIEW(it));
1378    it->highlighted = EINA_TRUE;
1379    _elm_list_unwalk(obj, sd);
1380    evas_object_unref(obj);
1381 }
1382
1383 static void
1384 _item_select(Elm_List_Item_Data *it)
1385 {
1386    Evas_Object *obj;
1387
1388    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
1389    obj = WIDGET(it);
1390    ELM_LIST_DATA_GET(obj, sd);
1391    Elm_Object_Item *eo_it = EO_OBJ(it);
1392
1393    if (it->base->disabled || _is_no_select(it))
1394      return;
1395    if (!sd->focus_on_selection_enabled)
1396      {
1397         if (it->icon && elm_object_widget_check(it->icon) &&
1398             elm_object_focus_get(it->icon))
1399           {
1400              elm_object_focus_set(obj, EINA_FALSE);
1401              elm_object_focus_set(obj, EINA_TRUE);
1402           }
1403         else if (it->end && elm_object_widget_check(it->end) &&
1404                  elm_object_focus_get(it->end))
1405           {
1406              elm_object_focus_set(obj, EINA_FALSE);
1407              elm_object_focus_set(obj, EINA_TRUE);
1408           }
1409      }
1410    if (it->selected)
1411      {
1412         if (sd->select_mode == ELM_OBJECT_SELECT_MODE_ALWAYS) goto call;
1413         return;
1414      }
1415
1416    _elm_list_item_content_focus_set(it, ELM_FOCUS_PREVIOUS, sd->h_mode);
1417
1418    it->selected = EINA_TRUE;
1419    sd->selected = eina_list_append(sd->selected, eo_it);
1420
1421 call:
1422    evas_object_ref(obj);
1423    _elm_list_walk(sd);
1424
1425    if (it->func) it->func((void *)WIDGET_ITEM_DATA_GET(eo_it), WIDGET(it), eo_it);
1426    eo_do(obj, eo_event_callback_call(EVAS_SELECTABLE_INTERFACE_EVENT_SELECTED, eo_it));
1427      if (_elm_config->atspi_mode)
1428        elm_interface_atspi_accessible_state_changed_signal_emit(eo_it, ELM_ATSPI_STATE_SELECTED, EINA_TRUE);
1429    sd->last_selected_item = eo_it;
1430
1431    _elm_list_unwalk(obj, sd);
1432    evas_object_unref(obj);
1433 }
1434
1435 static void
1436 _item_unhighlight(Elm_List_Item_Data *it)
1437 {
1438    Evas_Object *obj;
1439    const char *stacking, *select_raise;
1440
1441    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
1442    obj = WIDGET(it);
1443    ELM_LIST_DATA_GET(obj, sd);
1444
1445 //   if ((!it->highlighted) || (it->base->disabled) ||
1446 //       (sd->select_mode == ELM_OBJECT_SELECT_MODE_NONE)) return;
1447    if (!it->highlighted) return;
1448
1449    evas_object_ref(obj);
1450    _elm_list_walk(sd);
1451
1452    edje_object_signal_emit(VIEW(it), "elm,state,unselected", "elm");
1453    eo_do(obj, eo_event_callback_call
1454      (ELM_LIST_EVENT_UNHIGHLIGHTED, EO_OBJ(it)));
1455    stacking = edje_object_data_get(VIEW(it), "stacking");
1456    select_raise = edje_object_data_get(VIEW(it), "selectraise");
1457    if ((select_raise) && (!strcmp(select_raise, "on")))
1458      {
1459         if ((stacking) && (!strcmp(stacking, "below")))
1460           evas_object_lower(VIEW(it));
1461      }
1462    it->highlighted = EINA_FALSE;
1463
1464    _elm_list_unwalk(obj, sd);
1465    evas_object_unref(obj);
1466 }
1467
1468 static void
1469 _item_unselect(Elm_List_Item_Data *it)
1470 {
1471    Evas_Object *obj;
1472
1473    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
1474    obj = WIDGET(it);
1475    ELM_LIST_DATA_GET(obj, sd);
1476
1477 //   if (it->base->disabled || (sd->select_mode == ELM_OBJECT_SELECT_MODE_NONE))
1478 //     return;
1479
1480    evas_object_ref(obj);
1481    _elm_list_walk(sd);
1482
1483    if (sd->focus_on_selection_enabled)
1484      {
1485         if (it->icon) elm_object_focus_set(it->icon, EINA_FALSE);
1486         if (it->end) elm_object_focus_set(it->end, EINA_FALSE);
1487      }
1488
1489    if (it->selected)
1490      {
1491         it->selected = EINA_FALSE;
1492         sd->selected = eina_list_remove(sd->selected, EO_OBJ(it));
1493         if (!(it->base->disabled ||
1494               (sd->select_mode == ELM_OBJECT_SELECT_MODE_NONE)))
1495           eo_do(WIDGET(it), eo_event_callback_call
1496             (EVAS_SELECTABLE_INTERFACE_EVENT_UNSELECTED, EO_OBJ(it)));
1497         if (_elm_config->atspi_mode)
1498           elm_interface_atspi_accessible_state_changed_signal_emit(EO_OBJ(it), ELM_ATSPI_STATE_SELECTED, EINA_FALSE);
1499      }
1500
1501    _elm_list_unwalk(obj, sd);
1502    evas_object_unref(obj);
1503 }
1504
1505 static Eina_Bool
1506 _swipe_cancel(void *data)
1507 {
1508    Elm_List_Item_Data *it = data;
1509
1510    ELM_LIST_ITEM_CHECK_OR_RETURN(it, ECORE_CALLBACK_CANCEL);
1511    ELM_LIST_DATA_GET_FROM_ITEM(it, sd);
1512
1513    sd->swipe = EINA_FALSE;
1514    sd->movements = 0;
1515
1516    return ECORE_CALLBACK_RENEW;
1517 }
1518
1519 static void
1520 _edge_left_cb(Evas_Object *obj,
1521               void *data EINA_UNUSED)
1522 {
1523    eo_do(obj, eo_event_callback_call(ELM_LIST_EVENT_EDGE_LEFT, NULL));
1524 }
1525
1526 static void
1527 _edge_right_cb(Evas_Object *obj,
1528                void *data EINA_UNUSED)
1529 {
1530    eo_do(obj, eo_event_callback_call(ELM_LIST_EVENT_EDGE_RIGHT, NULL));
1531 }
1532
1533 static void
1534 _edge_top_cb(Evas_Object *obj,
1535              void *data EINA_UNUSED)
1536 {
1537    eo_do(obj, eo_event_callback_call(ELM_LIST_EVENT_EDGE_TOP, NULL));
1538 }
1539
1540 static void
1541 _edge_bottom_cb(Evas_Object *obj,
1542                 void *data EINA_UNUSED)
1543 {
1544    eo_do(obj, eo_event_callback_call(ELM_LIST_EVENT_EDGE_BOTTOM, NULL));
1545 }
1546
1547 static Eina_Bool
1548 _long_press_cb(void *data)
1549 {
1550    Elm_List_Item_Data *it = data;
1551    Evas_Object *obj;
1552
1553    ELM_LIST_ITEM_CHECK_OR_RETURN(it, ECORE_CALLBACK_CANCEL);
1554    obj = WIDGET(it);
1555    ELM_LIST_DATA_GET(obj, sd);
1556
1557    it->long_timer = NULL;
1558    if (it->base->disabled) goto end;
1559
1560    sd->longpressed = EINA_TRUE;
1561    eo_do(WIDGET(it), eo_event_callback_call
1562      (EVAS_CLICKABLE_INTERFACE_EVENT_LONGPRESSED, EO_OBJ(it)));
1563
1564 end:
1565    return ECORE_CALLBACK_CANCEL;
1566 }
1567
1568 static void
1569 _swipe_do(Elm_List_Item_Data *it)
1570 {
1571    int i, sum = 0;
1572
1573    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
1574    ELM_LIST_DATA_GET_FROM_ITEM(it, sd);
1575
1576    sd->swipe = EINA_FALSE;
1577    for (i = 0; i < sd->movements; i++)
1578      {
1579         sum += sd->history[i].x;
1580         if (abs(sd->history[0].y - sd->history[i].y) > 10) return;
1581      }
1582
1583    sum /= sd->movements;
1584    if (abs(sum - sd->history[0].x) <= 10) return;
1585
1586    eo_do(WIDGET(it), eo_event_callback_call
1587      (ELM_LIST_EVENT_SWIPE, EO_OBJ(it)));
1588 }
1589
1590 static void
1591 _mouse_in_cb(void *data,
1592              Evas *evas EINA_UNUSED,
1593              Evas_Object *o EINA_UNUSED,
1594              void *event_info EINA_UNUSED)
1595 {
1596    Elm_List_Item_Data *it = data;
1597    if (!elm_object_item_disabled_get(EO_OBJ(it)) &&
1598        (_elm_config->focus_move_policy == ELM_FOCUS_MOVE_POLICY_IN))
1599      elm_object_item_focus_set(EO_OBJ(it), EINA_TRUE);
1600 }
1601
1602 static void
1603 _mouse_move_cb(void *data,
1604                Evas *evas EINA_UNUSED,
1605                Evas_Object *o,
1606                void *event_info)
1607 {
1608    Evas_Object *obj;
1609    Elm_List_Item_Data *it = data;
1610    Evas_Event_Mouse_Move *ev = event_info;
1611    Evas_Coord x = 0, y = 0, w = 0, h = 0;
1612
1613    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
1614    obj = WIDGET(it);
1615    ELM_LIST_DATA_GET(obj, sd);
1616
1617    evas_object_ref(obj);
1618    _elm_list_walk(sd);
1619
1620    evas_object_geometry_get(o, &x, &y, &w, &h);
1621
1622    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
1623      {
1624         if (!sd->on_hold)
1625           {
1626              sd->on_hold = EINA_TRUE;
1627              ELM_SAFE_FREE(it->long_timer, ecore_timer_del);
1628              if (!sd->was_selected)
1629                {
1630                   _item_unhighlight(it);
1631                   _item_unselect(it);
1632                }
1633           }
1634      }
1635    else if (ELM_RECTS_POINT_OUT(x, y, w, h, ev->cur.canvas.x, ev->cur.canvas.y))
1636      {
1637         ELM_SAFE_FREE(it->long_timer, ecore_timer_del);
1638         if (!sd->was_selected)
1639           {
1640              _item_unhighlight(it);
1641              _item_unselect(it);
1642           }
1643         it->base->still_in = EINA_FALSE;
1644      }
1645
1646    if (sd->movements == ELM_LIST_SWIPE_MOVES)
1647      {
1648         sd->swipe = EINA_TRUE;
1649      }
1650    else
1651      {
1652         sd->history[sd->movements].x = ev->cur.canvas.x;
1653         sd->history[sd->movements].y = ev->cur.canvas.y;
1654         if (abs((sd->history[sd->movements].x - sd->history[0].x)) > 40)
1655           {
1656              sd->swipe = EINA_TRUE;
1657           }
1658         else
1659           sd->movements++;
1660      }
1661    if (sd->swipe)
1662      ELM_SAFE_FREE(it->long_timer, ecore_timer_del);
1663    _elm_list_unwalk(obj, sd);
1664    evas_object_unref(obj);
1665 }
1666
1667 static void
1668 _mouse_down_cb(void *data,
1669                Evas *evas EINA_UNUSED,
1670                Evas_Object *o EINA_UNUSED,
1671                void *event_info)
1672 {
1673    Evas_Event_Mouse_Down *ev = event_info;
1674    Elm_List_Item_Data *it = data;
1675    Evas_Object *obj;
1676    Evas_Coord x, y;
1677
1678    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
1679    obj = WIDGET(it);
1680    ELM_LIST_DATA_GET(obj, sd);
1681
1682    if (ev->button == 3)
1683      {
1684         evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1685         sd->dx = ev->canvas.x - x;
1686         sd->dy = ev->canvas.y - y;
1687         return;
1688      }
1689
1690    if (ev->button != 1) return;
1691    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) sd->on_hold = EINA_TRUE;
1692    else sd->on_hold = EINA_FALSE;
1693
1694    if (sd->on_hold) return;
1695    sd->mouse_down = EINA_TRUE;
1696    sd->was_selected = it->selected;
1697
1698    evas_object_ref(obj);
1699    _elm_list_walk(sd);
1700
1701    _item_highlight(it);
1702    sd->longpressed = EINA_FALSE;
1703    ecore_timer_del(it->long_timer);
1704    it->long_timer = ecore_timer_add
1705        (_elm_config->longpress_timeout, _long_press_cb, it);
1706    ecore_timer_del(it->swipe_timer);
1707    it->swipe_timer = ecore_timer_add(ELM_LIST_SWIPE_TIME, _swipe_cancel, it);
1708
1709    /* Always call the callbacks last - the user may delete our context! */
1710    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
1711      {
1712         eo_do(WIDGET(it), eo_event_callback_call
1713           (EVAS_CLICKABLE_INTERFACE_EVENT_CLICKED_DOUBLE, EO_OBJ(it)));
1714         eo_do(WIDGET(it), eo_event_callback_call
1715           (ELM_LIST_EVENT_ACTIVATED, EO_OBJ(it)));
1716      }
1717    sd->swipe = EINA_FALSE;
1718    sd->movements = 0;
1719    it->base->still_in = EINA_TRUE;
1720
1721    _elm_list_unwalk(obj, sd);
1722    evas_object_unref(obj);
1723 }
1724
1725 static void
1726 _mouse_up_cb(void *data,
1727              Evas *evas EINA_UNUSED,
1728              Evas_Object *o EINA_UNUSED,
1729              void *event_info)
1730 {
1731    Evas_Object *obj;
1732    Elm_List_Item_Data *it = data;
1733    Evas_Event_Mouse_Up *ev = event_info;
1734    Evas_Coord x, y, dx, dy;
1735
1736    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
1737    obj = WIDGET(it);
1738    ELM_LIST_DATA_GET(obj, sd);
1739
1740    if (ev->button == 3)
1741      {
1742         evas_object_geometry_get(obj, &x, &y, NULL, NULL);
1743         dx = sd->dx - (ev->canvas.x - x);
1744         dy = sd->dy - (ev->canvas.y - y);
1745         if (dx < 0) dx = -dx;
1746         if (dy < 0) dy = -dy;
1747         if ((dx < 5) && (dy < 5))
1748           eo_do(obj, eo_event_callback_call
1749             (EVAS_CLICKABLE_INTERFACE_EVENT_CLICKED_RIGHT, EO_OBJ(it)));
1750         return;
1751      }
1752
1753    if (ev->button != 1) return;
1754    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) sd->on_hold = EINA_TRUE;
1755    else sd->on_hold = EINA_FALSE;
1756
1757    sd->mouse_down = EINA_FALSE;
1758    ELM_SAFE_FREE(it->long_timer, ecore_timer_del);
1759    ELM_SAFE_FREE(it->swipe_timer, ecore_timer_del);
1760    if (sd->swipe)
1761      {
1762         if (!sd->was_selected)
1763           {
1764              _item_unhighlight(it);
1765              _item_unselect(it);
1766           }
1767         _swipe_do(data);
1768         sd->swipe = EINA_FALSE;
1769         sd->was_selected = EINA_FALSE;
1770         return;
1771      }
1772    if (sd->longpressed)
1773      {
1774         if (!sd->was_selected)
1775           {
1776              _item_unhighlight(it);
1777              _item_unselect(it);
1778           }
1779         sd->longpressed = EINA_FALSE;
1780         sd->was_selected = EINA_FALSE;
1781         return;
1782      }
1783
1784    if (it->base->disabled)
1785      return;
1786    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD || !it->base->still_in)
1787      return;
1788
1789    evas_object_ref(obj);
1790    _elm_list_walk(sd);
1791
1792    if (sd->focused_item != EO_OBJ(it))
1793      elm_object_item_focus_set(EO_OBJ(it), EINA_TRUE);
1794
1795    if (sd->multi &&
1796        ((sd->multi_select_mode != ELM_OBJECT_MULTI_SELECT_MODE_WITH_CONTROL) ||
1797         (evas_key_modifier_is_set(ev->modifiers, "Control"))))
1798      {
1799         if (!it->selected)
1800           {
1801              _item_highlight(it);
1802              _item_select(it);
1803           }
1804         else
1805           {
1806              _item_unhighlight(it);
1807              _item_unselect(it);
1808           }
1809      }
1810    else
1811      {
1812         if (!it->selected)
1813           {
1814              while (sd->selected)
1815                {
1816                   Elm_Object_Item *eo_it2 = sd->selected->data;
1817                   ELM_LIST_ITEM_DATA_GET(eo_it2, it2);
1818                   sd->selected = eina_list_remove_list
1819                     (sd->selected, sd->selected);
1820                   _item_unhighlight(it2);
1821                   _item_unselect(it2);
1822                }
1823              _item_highlight(it);
1824              _item_select(it);
1825           }
1826         else
1827           {
1828              const Eina_List *l, *l_next;
1829              Elm_Object_Item *eo_it2;
1830
1831              EINA_LIST_FOREACH_SAFE(sd->selected, l, l_next, eo_it2)
1832                if (eo_it2 != EO_OBJ(it))
1833                  {
1834                     ELM_LIST_ITEM_DATA_GET(eo_it2, it2);
1835                     _item_unhighlight(it2);
1836                     _item_unselect(it2);
1837                  }
1838              _item_highlight(it);
1839              _item_select(it);
1840           }
1841      }
1842
1843    _elm_list_unwalk(obj, sd);
1844    evas_object_unref(obj);
1845 }
1846
1847 static void
1848 _elm_list_looping_left_cb(void *data,
1849                           Evas_Object *obj EINA_UNUSED,
1850                           const char *emission EINA_UNUSED,
1851                           const char *source EINA_UNUSED)
1852 {
1853    Evas_Object *list = data;
1854
1855    ELM_LIST_DATA_GET(list, sd);
1856
1857    Elm_Object_Item *it = elm_list_last_item_get(list);
1858    if (!_elm_config->item_select_on_focus_disable)
1859      elm_list_item_selected_set(it, EINA_TRUE);
1860    else
1861      elm_object_item_focus_set(it, EINA_TRUE);
1862    elm_layout_signal_emit(list, "elm,action,looping,left,end", "elm");
1863    sd->item_looping_on = EINA_FALSE;
1864 }
1865
1866 static void
1867 _elm_list_looping_right_cb(void *data,
1868                           Evas_Object *obj EINA_UNUSED,
1869                           const char *emission EINA_UNUSED,
1870                           const char *source EINA_UNUSED)
1871 {
1872    Evas_Object *list = data;
1873
1874    ELM_LIST_DATA_GET(list, sd);
1875
1876    Elm_Object_Item *it = elm_list_first_item_get(list);
1877    if (!_elm_config->item_select_on_focus_disable)
1878      elm_list_item_selected_set(it, EINA_TRUE);
1879    else
1880      elm_object_item_focus_set(it, EINA_TRUE);
1881    elm_layout_signal_emit(list, "elm,action,looping,right,end", "elm");
1882    sd->item_looping_on = EINA_FALSE;
1883 }
1884
1885 static void
1886 _elm_list_looping_up_cb(void *data,
1887                           Evas_Object *obj EINA_UNUSED,
1888                           const char *emission EINA_UNUSED,
1889                           const char *source EINA_UNUSED)
1890 {
1891    Evas_Object *list = data;
1892
1893    ELM_LIST_DATA_GET(list, sd);
1894
1895    Elm_Object_Item *it = elm_list_last_item_get(list);
1896    if (!_elm_config->item_select_on_focus_disable)
1897      elm_list_item_selected_set(it, EINA_TRUE);
1898    else
1899      elm_object_item_focus_set(it, EINA_TRUE);
1900    elm_layout_signal_emit(list, "elm,action,looping,up,end", "elm");
1901    sd->item_looping_on = EINA_FALSE;
1902 }
1903
1904 static void
1905 _elm_list_looping_down_cb(void *data,
1906                           Evas_Object *obj EINA_UNUSED,
1907                           const char *emission EINA_UNUSED,
1908                           const char *source EINA_UNUSED)
1909 {
1910    Evas_Object *list = data;
1911
1912    ELM_LIST_DATA_GET(list, sd);
1913
1914    Elm_Object_Item *it = elm_list_first_item_get(list);
1915    if (!_elm_config->item_select_on_focus_disable)
1916      elm_list_item_selected_set(it, EINA_TRUE);
1917    else
1918      elm_object_item_focus_set(it, EINA_TRUE);
1919    elm_layout_signal_emit(list, "elm,action,looping,down,end", "elm");
1920    sd->item_looping_on = EINA_FALSE;
1921 }
1922
1923 EOLIAN static void
1924 _elm_list_item_elm_widget_item_disable(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *item)
1925 {
1926    _item_unhighlight(item);
1927    _item_unselect(item);
1928    if (item->base->disabled)
1929      edje_object_signal_emit(VIEW(item), "elm,state,disabled", "elm");
1930    else
1931      edje_object_signal_emit(VIEW(item), "elm,state,enabled", "elm");
1932 }
1933
1934 EOLIAN static void
1935 _elm_list_item_elm_widget_item_part_content_set(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *item,
1936                        const char *part,
1937                        Evas_Object *content)
1938 {
1939    Evas_Object **icon_p = NULL;
1940    Eina_Bool dummy = EINA_FALSE;
1941
1942    if ((!part) || (!strcmp(part, "start")))
1943      {
1944         icon_p = &(item->icon);
1945         dummy = item->dummy_icon;
1946         if (!content) item->dummy_icon = EINA_TRUE;
1947         else item->dummy_icon = EINA_FALSE;
1948      }
1949    else if (!strcmp(part, "end"))
1950      {
1951         icon_p = &(item->end);
1952         dummy = item->dummy_end;
1953         if (!content) item->dummy_end = EINA_TRUE;
1954         else item->dummy_end = EINA_FALSE;
1955      }
1956    else
1957      return;
1958
1959    if (content == *icon_p) return;
1960    if ((dummy) && (!content)) return;
1961    if (dummy) evas_object_del(*icon_p);
1962    if (!content)
1963      {
1964         content =
1965           evas_object_rectangle_add(evas_object_evas_get(WIDGET(item)));
1966         evas_object_color_set(content, 0, 0, 0, 0);
1967      }
1968    evas_object_del(*icon_p);
1969    *icon_p = content;
1970
1971    if (VIEW(item))
1972      {
1973         if ((!part) || !strcmp(part, "start"))
1974           edje_object_part_swallow(VIEW(item), "elm.swallow.icon", content);
1975         else
1976           edje_object_part_swallow(VIEW(item), "elm.swallow.end", content);
1977      }
1978 }
1979
1980 EOLIAN static Evas_Object *
1981 _elm_list_item_elm_widget_item_part_content_get(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *item,
1982                        const char *part)
1983 {
1984    if ((!part) || (!strcmp(part, "start")))
1985      {
1986         if (item->dummy_icon) return NULL;
1987         return item->icon;
1988      }
1989    else if (!strcmp(part, "end"))
1990      {
1991         if (item->dummy_end) return NULL;
1992         return item->end;
1993      }
1994
1995    return NULL;
1996 }
1997
1998 EOLIAN static Evas_Object *
1999 _elm_list_item_elm_widget_item_part_content_unset(Eo *eo_it EINA_UNUSED, Elm_List_Item_Data *item,
2000                          const char *part)
2001 {
2002    if ((!part) || (!strcmp(part, "start")))
2003      {
2004         Evas_Object *obj = item->icon;
2005         eo_do(eo_it, elm_wdg_item_part_content_set(part, NULL));
2006         return obj;
2007      }
2008    else if (!strcmp(part, "end"))
2009      {
2010         Evas_Object *obj = item->end;
2011         eo_do(eo_it, elm_wdg_item_part_content_set(part, NULL));
2012         return obj;
2013      }
2014
2015    return NULL;
2016 }
2017
2018 EOLIAN static void
2019 _elm_list_item_elm_widget_item_part_text_set(Eo *eo_list_it, Elm_List_Item_Data *list_it,
2020                     const char *part,
2021                     const char *text)
2022 {
2023    if (part && strcmp(part, "default"))
2024      {
2025         eo_do(eo_list_it, elm_wdg_item_part_text_custom_set(part, text));
2026         edje_object_part_text_escaped_set(VIEW(list_it), part, text);
2027         return;
2028      }
2029    if (!eina_stringshare_replace(&list_it->label, text)) return;
2030    if (VIEW(list_it))
2031      edje_object_part_text_escaped_set(VIEW(list_it), "elm.text", text);
2032 }
2033
2034 EOLIAN static const char *
2035 _elm_list_item_elm_widget_item_part_text_get(Eo *eo_it, Elm_List_Item_Data *it,
2036                     const char *part)
2037 {
2038    const char *ret;
2039    if (part && strcmp(part, "default"))
2040      return eo_do_ret(eo_it, ret, elm_wdg_item_part_text_custom_get(part));
2041    return it->label;
2042 }
2043
2044 /* FIXME: this _item_del_pre_hook is never been called at all!
2045  To fix this,
2046  1. it->walking concept should be adopted.
2047  2. elm_widget_item_del() should be called instead of the combination of
2048  _elm_list_item_free() + elm_widget_item_free()
2049  */
2050 EOLIAN static Eina_Bool
2051 _elm_list_item_elm_widget_item_del_pre(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *item)
2052 {
2053    Evas_Object *obj = WIDGET(item);
2054
2055    ELM_LIST_DATA_GET(obj, sd);
2056
2057    if (item->selected)
2058      {
2059         _item_unhighlight(item);
2060         _item_unselect(item);
2061      }
2062
2063    if (sd->walking > 0)
2064      {
2065         if (item->deleted) return EINA_FALSE;
2066         item->deleted = EINA_TRUE;
2067         sd->to_delete = eina_list_append(sd->to_delete, item);
2068         return EINA_FALSE;
2069      }
2070
2071    sd->items = eina_list_remove_list(sd->items, item->node);
2072
2073    evas_object_ref(obj);
2074    _elm_list_walk(sd);
2075
2076    _elm_list_item_free(item);
2077
2078    _elm_list_unwalk(obj, sd);
2079    evas_object_unref(obj);
2080
2081    return EINA_TRUE;
2082 }
2083
2084 EOLIAN static void _elm_list_item_elm_widget_item_signal_emit(Eo *eo_it EINA_UNUSED, Elm_List_Item_Data *it,
2085                        const char *emission,
2086                        const char *source)
2087 {
2088    edje_object_signal_emit(VIEW(it), emission, source);
2089 }
2090
2091 EOLIAN static void
2092 _elm_list_item_elm_widget_item_focus_set(Eo *eo_it, Elm_List_Item_Data *it, Eina_Bool focused)
2093 {
2094    Evas_Object *obj = WIDGET(it);
2095    ELM_LIST_DATA_GET(obj, sd);
2096
2097    if (focused)
2098      {
2099         sd->last_focused_item = eo_it;
2100         if (!elm_object_focus_get(obj))
2101           elm_object_focus_set(obj, EINA_TRUE);
2102
2103         if (!elm_widget_focus_get(obj))
2104           return;
2105
2106         if (eo_it != sd->focused_item)
2107           {
2108              if (sd->focused_item)
2109                _elm_list_item_unfocused(sd->focused_item);
2110              _elm_list_item_focused(eo_it);
2111           }
2112      }
2113    else
2114      {
2115         if (!elm_widget_focus_get(obj))
2116           return;
2117         if (eo_it)
2118           _elm_list_item_unfocused(eo_it);
2119      }
2120    _elm_widget_focus_highlight_start(obj);
2121 }
2122
2123 EOLIAN static Eina_Bool
2124 _elm_list_item_elm_widget_item_focus_get(Eo *eo_it, Elm_List_Item_Data *it)
2125 {
2126    ELM_LIST_ITEM_CHECK_OR_RETURN(it, EINA_FALSE);
2127    Evas_Object *obj = WIDGET(it);
2128    ELM_LIST_CHECK(obj) EINA_FALSE;
2129    ELM_LIST_DATA_GET(obj, sd);
2130
2131    if (eo_it == sd->focused_item)
2132      return EINA_TRUE;
2133    return EINA_FALSE;
2134 }
2135
2136 EOLIAN static Elm_Atspi_State_Set
2137 _elm_list_item_elm_interface_atspi_accessible_state_set_get(Eo *eo_it, Elm_List_Item_Data *data EINA_UNUSED)
2138 {
2139    Elm_Atspi_State_Set ret;
2140    Eina_Bool sel;
2141
2142    eo_do_super(eo_it, ELM_LIST_ITEM_CLASS, ret = elm_interface_atspi_accessible_state_set_get());
2143
2144    if (elm_object_item_disabled_get(eo_it))
2145      return ret;
2146
2147    STATE_TYPE_SET(ret, ELM_ATSPI_STATE_SELECTABLE);
2148
2149    eo_do(eo_it, sel = elm_obj_list_item_selected_get());
2150    if (sel)
2151      STATE_TYPE_SET(ret, ELM_ATSPI_STATE_SELECTED);
2152    else
2153      STATE_TYPE_UNSET(ret, ELM_ATSPI_STATE_SELECTED);
2154
2155    return ret;
2156 }
2157
2158 EOLIAN static char*
2159 _elm_list_item_elm_interface_atspi_accessible_name_get(Eo *eo_it EINA_UNUSED, Elm_List_Item_Data *data)
2160 {
2161    return data->label ? strdup(data->label) : NULL;
2162 }
2163
2164 EOLIAN static Eina_List*
2165 _elm_list_item_elm_interface_atspi_accessible_children_get(Eo *eo_it EINA_UNUSED, Elm_List_Item_Data *data)
2166 {
2167    Eina_List *ret = NULL;
2168
2169    if (data->icon && eo_isa(data->icon, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
2170      ret = eina_list_append(ret, data->icon);
2171    if (data->end && eo_isa(data->end, ELM_INTERFACE_ATSPI_ACCESSIBLE_MIXIN))
2172      ret = eina_list_append(ret, data->end);
2173
2174    return ret;
2175 }
2176
2177 EOLIAN static Eina_Bool
2178 _elm_list_item_elm_interface_atspi_component_highlight_clear(Eo *eo_it, Elm_List_Item_Data *it)
2179 {
2180    elm_object_accessibility_highlight_set(VIEW(it), EINA_FALSE);
2181
2182    return EINA_TRUE;
2183 }
2184
2185 static char *
2186 _access_info_cb(void *data, Evas_Object *obj EINA_UNUSED)
2187 {
2188    Elm_List_Item_Data *it = (Elm_List_Item_Data *)data;
2189    const char *txt = NULL;
2190    if (!it) return NULL;
2191
2192    if (!txt) txt = it->label;
2193    if (txt) return strdup(txt);
2194
2195    return NULL;
2196 }
2197
2198 static char *
2199 _access_state_cb(void *data, Evas_Object *obj EINA_UNUSED)
2200 {
2201    Elm_List_Item_Data *it = (Elm_List_Item_Data *)data;
2202    if (!it) return NULL;
2203
2204    if (it->base->disabled)
2205      return strdup(E_("State: Disabled"));
2206
2207    return NULL;
2208 }
2209
2210 static void
2211 _access_on_highlight_cb(void *data)
2212 {
2213    Elm_Object_Item *it = data;
2214    if (!it) return;
2215
2216    elm_list_item_bring_in(it);
2217 }
2218
2219 static void
2220 _access_activate_cb(void *data EINA_UNUSED,
2221                     Evas_Object *part_obj EINA_UNUSED,
2222                     Elm_Object_Item *eo_it)
2223 {
2224    Evas_Object *obj;
2225
2226    ELM_LIST_ITEM_DATA_GET(eo_it, it);
2227    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
2228
2229    obj = WIDGET(it);
2230    ELM_LIST_DATA_GET(obj, sd);
2231
2232    evas_object_ref(obj);
2233    _elm_list_walk(sd);
2234
2235    if (sd->multi)
2236      {
2237         if (!it->selected)
2238           {
2239              _item_highlight(it);
2240              _item_select(it);
2241           }
2242         else
2243           {
2244              _item_unhighlight(it);
2245              _item_unselect(it);
2246           }
2247      }
2248    else
2249      {
2250         if (!it->selected)
2251           {
2252              while (sd->selected)
2253                {
2254                   Elm_Object_Item *eo_sel = sd->selected->data;
2255                   ELM_LIST_ITEM_DATA_GET(eo_sel, sel);
2256                   _item_unhighlight(sel);
2257                   _item_unselect(sel);
2258                }
2259              _item_highlight(it);
2260              _item_select(it);
2261           }
2262         else
2263           {
2264              const Eina_List *l, *l_next;
2265              Elm_Object_Item *eo_it2;
2266
2267              EINA_LIST_FOREACH_SAFE(sd->selected, l, l_next, eo_it2)
2268                if (eo_it2 != EO_OBJ(it))
2269                  {
2270                     ELM_LIST_ITEM_DATA_GET(eo_it2, it2);
2271                     _item_unhighlight(it2);
2272                     _item_unselect(it2);
2273                  }
2274              _item_highlight(it);
2275              _item_select(it);
2276           }
2277      }
2278
2279    _elm_list_unwalk(obj, sd);
2280    evas_object_unref(obj);
2281 }
2282
2283 static void
2284 _access_widget_item_register(Elm_List_Item_Data *it, Eina_Bool is_access)
2285 {
2286    Elm_Access_Info *ai;
2287
2288    if (!is_access) _elm_access_widget_item_unregister(it->base);
2289    else
2290      {
2291         _elm_access_widget_item_register(it->base);
2292
2293         ai = _elm_access_info_get(it->base->access_obj);
2294
2295         _elm_access_callback_set(ai, ELM_ACCESS_INFO, _access_info_cb, it);
2296         _elm_access_callback_set(ai, ELM_ACCESS_STATE, _access_state_cb, it);
2297         _elm_access_on_highlight_hook_set(ai, _access_on_highlight_cb, EO_OBJ(it));
2298         _elm_access_activate_callback_set(ai, _access_activate_cb, EO_OBJ(it));
2299      }
2300 }
2301
2302 EOLIAN static Eo *
2303 _elm_list_item_eo_base_constructor(Eo *eo_it, Elm_List_Item_Data *it)
2304 {
2305    eo_it = eo_do_super_ret(eo_it, ELM_LIST_ITEM_CLASS, eo_it, eo_constructor());
2306    it->base = eo_data_scope_get(eo_it, ELM_WIDGET_ITEM_CLASS);
2307    eo_do(eo_it, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_LIST_ITEM));
2308
2309    return eo_it;
2310 }
2311
2312 static Elm_List_Item_Data *
2313 _item_new(Evas_Object *obj,
2314           const char *label,
2315           Evas_Object *icon,
2316           Evas_Object *end,
2317           Evas_Smart_Cb func,
2318           const void *data)
2319 {
2320    Eo *eo_it = eo_add(ELM_LIST_ITEM_CLASS, obj);
2321    if (!eo_it) return NULL;
2322    ELM_LIST_ITEM_DATA_GET(eo_it, it);
2323
2324    it->label = eina_stringshare_add(label);
2325    it->icon = icon;
2326    it->end = end;
2327    it->func = func;
2328    WIDGET_ITEM_DATA_SET(EO_OBJ(it), data);
2329
2330    VIEW(it) = edje_object_add(evas_object_evas_get(obj));
2331
2332    if (_elm_config->atspi_mode)
2333      {
2334         if (it->icon) eo_do(it->icon, elm_interface_atspi_accessible_parent_set(eo_it));
2335         if (it->end) eo_do(it->end, elm_interface_atspi_accessible_parent_set(eo_it));
2336      }
2337
2338    /* access */
2339    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
2340      _access_widget_item_register(it, EINA_TRUE);
2341
2342    edje_object_mirrored_set(VIEW(it), elm_widget_mirrored_get(obj));
2343    evas_object_event_callback_add
2344      (VIEW(it), EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, it);
2345    evas_object_event_callback_add
2346      (VIEW(it), EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, it);
2347    evas_object_event_callback_add
2348      (VIEW(it), EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, it);
2349    evas_object_event_callback_add
2350      (VIEW(it), EVAS_CALLBACK_MOUSE_IN, _mouse_in_cb, it);
2351    evas_object_size_hint_weight_set
2352      (VIEW(it), EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2353    evas_object_size_hint_align_set(VIEW(it), EVAS_HINT_FILL, EVAS_HINT_FILL);
2354    edje_object_mirrored_set(VIEW(it), elm_widget_mirrored_get(obj));
2355
2356    if (it->icon)
2357      {
2358         eo_do(it->icon, elm_interface_atspi_accessible_parent_set(eo_it));
2359         elm_widget_sub_object_add(obj, it->icon);
2360         evas_object_event_callback_add
2361           (it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _size_hints_changed_cb,
2362           obj);
2363      }
2364    if (it->end)
2365      {
2366         eo_do(it->end, elm_interface_atspi_accessible_parent_set(eo_it));
2367         elm_widget_sub_object_add(obj, it->end);
2368         evas_object_event_callback_add
2369           (it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _size_hints_changed_cb,
2370           obj);
2371      }
2372
2373    if (_elm_config->atspi_mode)
2374      elm_interface_atspi_accessible_added(eo_it);
2375
2376    return it;
2377 }
2378
2379 static void
2380 _resize_cb(void *data,
2381            Evas *e EINA_UNUSED,
2382            Evas_Object *obj EINA_UNUSED,
2383            void *event_info EINA_UNUSED)
2384 {
2385    elm_layout_sizing_eval(data);
2386 }
2387
2388 static Eina_Bool _elm_list_smart_focus_next_enable = EINA_FALSE;
2389
2390 EOLIAN static Eina_Bool
2391 _elm_list_elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_List_Data *sd EINA_UNUSED)
2392 {
2393    return _elm_list_smart_focus_next_enable;
2394 }
2395
2396 EOLIAN static Eina_Bool
2397 _elm_list_elm_widget_focus_direction_manager_is(Eo *obj EINA_UNUSED, Elm_List_Data *sd EINA_UNUSED)
2398 {
2399    return EINA_FALSE;
2400 }
2401
2402 EOLIAN static Eina_Bool
2403 _elm_list_elm_widget_focus_next(Eo *obj, Elm_List_Data *sd, Elm_Focus_Direction dir, Evas_Object **next, Elm_Object_Item **next_item)
2404 {
2405    Eina_List *items = NULL;
2406    Eina_List *elist = NULL;
2407    Elm_Object_Item *eo_it;
2408
2409    if (_elm_config->access_mode != ELM_ACCESS_MODE_ON) return EINA_FALSE;
2410
2411    EINA_LIST_FOREACH(sd->items, elist, eo_it)
2412      {
2413         ELM_LIST_ITEM_DATA_GET(eo_it, it);
2414         items = eina_list_append(items, it->base->access_obj);
2415         if (it->icon) items = eina_list_append(items, it->icon);
2416         if (it->end) items = eina_list_append(items, it->end);
2417      }
2418
2419    return elm_widget_focus_list_next_get
2420             (obj, items, eina_list_data_get, dir, next, next_item);
2421 }
2422
2423 EOLIAN static void
2424 _elm_list_evas_object_smart_add(Eo *obj, Elm_List_Data *priv)
2425 {
2426    Evas_Coord minw, minh;
2427
2428    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
2429
2430    eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
2431    elm_widget_sub_object_parent_add(obj);
2432
2433    elm_widget_can_focus_set(obj, EINA_TRUE);
2434
2435    priv->mode = ELM_LIST_SCROLL;
2436
2437    if (!elm_layout_theme_set(obj, "list", "base", elm_widget_style_get(obj)))
2438      CRI("Failed to set layout!");
2439
2440    priv->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
2441    evas_object_data_set(priv->hit_rect, "_elm_leaveme", obj);
2442    evas_object_smart_member_add(priv->hit_rect, obj);
2443    elm_widget_sub_object_add(obj, priv->hit_rect);
2444
2445    /* common scroller hit rectangle setup */
2446    evas_object_color_set(priv->hit_rect, 0, 0, 0, 0);
2447    evas_object_show(priv->hit_rect);
2448    evas_object_repeat_events_set(priv->hit_rect, EINA_TRUE);
2449
2450    eo_do(obj,
2451          elm_interface_scrollable_edge_left_cb_set(_edge_left_cb),
2452          elm_interface_scrollable_edge_right_cb_set(_edge_right_cb),
2453          elm_interface_scrollable_edge_top_cb_set(_edge_top_cb),
2454          elm_interface_scrollable_edge_bottom_cb_set(_edge_bottom_cb),
2455          elm_interface_scrollable_content_min_limit_cb_set(_elm_list_content_min_limit_cb),
2456          elm_interface_scrollable_objects_set(wd->resize_obj, priv->hit_rect));
2457
2458    /* the scrollable interface may set this */
2459    evas_object_event_callback_add
2460      (wd->resize_obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
2461      _size_hints_changed_cb, obj);
2462
2463    edje_object_size_min_calc
2464      (wd->resize_obj, &minw, &minh);
2465    evas_object_size_hint_min_set(obj, minw, minh);
2466    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize_cb, obj);
2467
2468    eo_do(obj, elm_interface_scrollable_bounce_allow_set(EINA_FALSE, _elm_config->thumbscroll_bounce_enable));
2469
2470    priv->box = elm_box_add(obj);
2471    evas_object_size_hint_weight_set(priv->box, EVAS_HINT_EXPAND, 0.0);
2472    evas_object_size_hint_align_set(priv->box, EVAS_HINT_FILL, 0.0);
2473
2474    /* FIXME: change this ugly code path later */
2475    elm_widget_on_show_region_hook_set(priv->box, _show_region_hook, obj);
2476    elm_widget_sub_object_add(obj, priv->box);
2477
2478    eo_do(obj, elm_interface_scrollable_content_set(priv->box));
2479    evas_object_event_callback_add
2480      (priv->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
2481      _size_hints_changed_cb, obj);
2482
2483    edje_object_signal_callback_add(wd->resize_obj, "elm,looping,left,done", "elm", _elm_list_looping_left_cb, obj);
2484    edje_object_signal_callback_add(wd->resize_obj, "elm,looping,right,done", "elm", _elm_list_looping_right_cb, obj);
2485    edje_object_signal_callback_add(wd->resize_obj, "elm,looping,up,done", "elm", _elm_list_looping_up_cb, obj);
2486    edje_object_signal_callback_add(wd->resize_obj, "elm,looping,down,done", "elm", _elm_list_looping_down_cb, obj);
2487 }
2488
2489 EOLIAN static void
2490 _elm_list_evas_object_smart_del(Eo *obj, Elm_List_Data *sd)
2491 {
2492    const Eina_List *l;
2493    Elm_Object_Item *eo_it;
2494
2495    if (sd->walking)
2496      ERR("ERROR: list deleted while walking.\n");
2497
2498    sd->delete_me = EINA_TRUE;
2499    EINA_LIST_FOREACH(sd->items, l, eo_it)
2500      {
2501         ELM_LIST_ITEM_DATA_GET(eo_it, it);
2502         if (it->icon)
2503           evas_object_event_callback_del
2504             (it->icon, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
2505             _size_hints_changed_cb);
2506         if (it->end)
2507           evas_object_event_callback_del
2508             (it->end, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
2509             _size_hints_changed_cb);
2510      }
2511
2512    evas_object_event_callback_del
2513      (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
2514      _size_hints_changed_cb);
2515    evas_object_event_callback_del
2516      (sd->box, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _size_hints_changed_cb);
2517
2518    _elm_list_walk(sd);
2519
2520    EINA_LIST_FREE(sd->items, eo_it)
2521      {
2522         ELM_LIST_ITEM_DATA_GET(eo_it, it);
2523         /* issuing free because of "locking" item del pre hook */
2524         _elm_list_item_free(it);
2525         WIDGET(it) = NULL;
2526         eo_del(eo_it);
2527      }
2528
2529    _elm_list_unwalk(obj, sd);
2530
2531    if (sd->to_delete)
2532      ERR("ERROR: leaking nodes!\n");
2533
2534    sd->selected = eina_list_free(sd->selected);
2535
2536    eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
2537 }
2538
2539 EOLIAN static void
2540 _elm_list_evas_object_smart_move(Eo *obj, Elm_List_Data *sd, Evas_Coord x, Evas_Coord y)
2541 {
2542    eo_do_super(obj, MY_CLASS, evas_obj_smart_move(x, y));
2543
2544    evas_object_move(sd->hit_rect, x, y);
2545 }
2546
2547 EOLIAN static void
2548 _elm_list_evas_object_smart_resize(Eo *obj, Elm_List_Data *sd, Evas_Coord w, Evas_Coord h)
2549 {
2550    eo_do_super(obj, MY_CLASS, evas_obj_smart_resize(w, h));
2551
2552    evas_object_resize(sd->hit_rect, w, h);
2553 }
2554
2555 EOLIAN static void
2556 _elm_list_evas_object_smart_member_add(Eo *obj, Elm_List_Data *sd, Evas_Object *member)
2557 {
2558    eo_do_super(obj, MY_CLASS, evas_obj_smart_member_add(member));
2559
2560    if (sd->hit_rect)
2561      evas_object_raise(sd->hit_rect);
2562 }
2563
2564 EOLIAN static void
2565 _elm_list_elm_widget_access(Eo *obj EINA_UNUSED, Elm_List_Data *sd, Eina_Bool acs)
2566 {
2567    Eina_List *elist = NULL;
2568    Elm_Object_Item *eo_it;
2569    _elm_list_smart_focus_next_enable = acs;
2570
2571    EINA_LIST_FOREACH(sd->items, elist, eo_it)
2572      {
2573         ELM_LIST_ITEM_DATA_GET(eo_it, it);
2574         _access_widget_item_register(it, _elm_list_smart_focus_next_enable);
2575      }
2576 }
2577
2578 EAPI Evas_Object *
2579 elm_list_add(Evas_Object *parent)
2580 {
2581    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
2582    Evas_Object *obj = eo_add(MY_CLASS, parent);
2583    return obj;
2584 }
2585
2586 EOLIAN static Eo *
2587 _elm_list_eo_base_constructor(Eo *obj, Elm_List_Data *sd EINA_UNUSED)
2588 {
2589    obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
2590    eo_do(obj,
2591          evas_obj_type_set(MY_CLASS_NAME_LEGACY),
2592          evas_obj_smart_callbacks_descriptions_set(_smart_callbacks),
2593          elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_LIST));
2594
2595    return obj;
2596 }
2597
2598 EOLIAN static void
2599 _elm_list_go(Eo *obj, Elm_List_Data *sd EINA_UNUSED)
2600 {
2601    _items_fix(obj);
2602 }
2603
2604 EOLIAN static void
2605 _elm_list_multi_select_set(Eo *obj EINA_UNUSED, Elm_List_Data *sd, Eina_Bool multi)
2606 {
2607    sd->multi = multi;
2608 }
2609
2610 EOLIAN static Eina_Bool
2611 _elm_list_multi_select_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
2612 {
2613    return sd->multi;
2614 }
2615
2616 EOLIAN static void
2617 _elm_list_multi_select_mode_set(Eo *obj EINA_UNUSED, Elm_List_Data *sd, Elm_Object_Multi_Select_Mode mode)
2618 {
2619    if (mode >= ELM_OBJECT_MULTI_SELECT_MODE_MAX)
2620      return;
2621
2622    if (sd->multi_select_mode != mode)
2623      sd->multi_select_mode = mode;
2624 }
2625
2626 EOLIAN static Elm_Object_Multi_Select_Mode
2627 _elm_list_multi_select_mode_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
2628 {
2629    return sd->multi_select_mode;
2630 }
2631
2632 EOLIAN static void
2633 _elm_list_mode_set(Eo *obj, Elm_List_Data *sd, Elm_List_Mode mode)
2634 {
2635    Elm_Object_Item *eo_it;
2636    Eina_List *n;
2637
2638    if (sd->mode == mode)
2639      return;
2640
2641    sd->mode = mode;
2642
2643    _elm_list_mode_set_internal(obj);
2644
2645    EINA_LIST_FOREACH(sd->items, n, eo_it)
2646      {
2647         ELM_LIST_ITEM_DATA_GET(eo_it, it);
2648         it->fixed = EINA_FALSE;
2649      }
2650    _items_fix(obj);
2651 }
2652
2653 EOLIAN static Elm_List_Mode
2654 _elm_list_mode_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
2655 {
2656    return sd->mode;
2657 }
2658
2659 EOLIAN static void
2660 _elm_list_horizontal_set(Eo *obj, Elm_List_Data *sd, Eina_Bool horizontal)
2661 {
2662    Eina_Bool bounce = _elm_config->thumbscroll_bounce_enable;
2663
2664    horizontal = !!horizontal;
2665
2666    if (sd->h_mode == horizontal)
2667      return;
2668
2669    sd->h_mode = horizontal;
2670    elm_box_horizontal_set(sd->box, horizontal);
2671
2672    if (horizontal)
2673      {
2674         evas_object_size_hint_weight_set(sd->box, 0.0, EVAS_HINT_EXPAND);
2675         evas_object_size_hint_align_set(sd->box, 0.0, EVAS_HINT_FILL);
2676         eo_do(obj, elm_interface_scrollable_bounce_allow_set(bounce, EINA_FALSE));
2677      }
2678    else
2679      {
2680         evas_object_size_hint_weight_set(sd->box, EVAS_HINT_EXPAND, 0.0);
2681         evas_object_size_hint_align_set(sd->box, EVAS_HINT_FILL, 0.0);
2682         eo_do(obj, elm_interface_scrollable_bounce_allow_set(EINA_FALSE, bounce));
2683      }
2684
2685    _elm_list_mode_set_internal(obj);
2686 }
2687
2688 EOLIAN static Eina_Bool
2689 _elm_list_horizontal_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
2690 {
2691    return sd->h_mode;
2692 }
2693
2694 EOLIAN static void
2695 _elm_list_select_mode_set(Eo *obj EINA_UNUSED, Elm_List_Data *sd, Elm_Object_Select_Mode mode)
2696 {
2697    if (mode >= ELM_OBJECT_SELECT_MODE_MAX)
2698      return;
2699
2700    if (sd->select_mode != mode)
2701      sd->select_mode = mode;
2702 }
2703
2704 EOLIAN static Elm_Object_Select_Mode
2705 _elm_list_select_mode_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
2706 {
2707    return sd->select_mode;
2708 }
2709
2710 EAPI void
2711 elm_list_bounce_set(Evas_Object *obj,
2712                     Eina_Bool h_bounce,
2713                     Eina_Bool v_bounce)
2714 {
2715    ELM_LIST_CHECK(obj);
2716
2717    eo_do(obj, elm_interface_scrollable_bounce_allow_set(h_bounce, v_bounce));
2718 }
2719
2720 EAPI void
2721 elm_list_bounce_get(const Evas_Object *obj,
2722                     Eina_Bool *h_bounce,
2723                     Eina_Bool *v_bounce)
2724 {
2725    ELM_LIST_CHECK(obj);
2726
2727    eo_do((Eo *) obj, elm_interface_scrollable_bounce_allow_get(h_bounce, v_bounce));
2728 }
2729
2730 EAPI void
2731 elm_list_scroller_policy_set(Evas_Object *obj,
2732                              Elm_Scroller_Policy policy_h,
2733                              Elm_Scroller_Policy policy_v)
2734 {
2735    ELM_LIST_CHECK(obj);
2736    eo_do(obj, elm_interface_scrollable_policy_set(policy_h, policy_v));
2737 }
2738
2739 EOLIAN static void
2740 _elm_list_elm_interface_scrollable_policy_set(Eo *obj, Elm_List_Data *sd EINA_UNUSED, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
2741 {
2742    if ((policy_h >= ELM_SCROLLER_POLICY_LAST) ||
2743        (policy_v >= ELM_SCROLLER_POLICY_LAST))
2744      return;
2745
2746    eo_do_super(obj, MY_CLASS, elm_interface_scrollable_policy_set(policy_h, policy_v));
2747 }
2748
2749 EAPI void
2750 elm_list_scroller_policy_get(const Evas_Object *obj,
2751                              Elm_Scroller_Policy *policy_h,
2752                              Elm_Scroller_Policy *policy_v)
2753 {
2754    ELM_LIST_CHECK(obj);
2755    eo_do((Eo *) obj, elm_interface_scrollable_policy_get(policy_h, policy_v));
2756 }
2757
2758 EOLIAN static void
2759 _elm_list_clear(Eo *obj, Elm_List_Data *sd)
2760 {
2761    Elm_Object_Item *eo_it;
2762
2763    if (!sd->items) return;
2764
2765    sd->selected = eina_list_free(sd->selected);
2766
2767    if (sd->walking > 0)
2768      {
2769         Eina_List *n;
2770
2771         EINA_LIST_FOREACH(sd->items, n, eo_it)
2772           {
2773              ELM_LIST_ITEM_DATA_GET(eo_it, it);
2774              if (it->deleted) continue;
2775              it->deleted = EINA_TRUE;
2776              sd->to_delete = eina_list_append(sd->to_delete, it);
2777           }
2778         return;
2779      }
2780
2781    evas_object_ref(obj);
2782
2783    _elm_list_walk(sd);
2784
2785    EINA_LIST_FREE(sd->items, eo_it)
2786      {
2787         ELM_LIST_ITEM_DATA_GET(eo_it, it);
2788         /* issuing free because of "locking" item del pre hook */
2789         _elm_list_item_free(it);
2790         eo_del(eo_it);
2791      }
2792
2793    _elm_list_unwalk(obj, sd);
2794
2795    _items_fix(obj);
2796    elm_layout_sizing_eval(obj);
2797
2798    evas_object_unref(obj);
2799 }
2800
2801 EOLIAN static const Eina_List*
2802 _elm_list_items_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
2803 {
2804    return sd->items;
2805 }
2806
2807 EOLIAN static Elm_Object_Item*
2808 _elm_list_selected_item_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
2809 {
2810    if (sd->selected) return sd->selected->data;
2811    else return NULL;
2812 }
2813
2814 EOLIAN static const Eina_List*
2815 _elm_list_selected_items_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
2816 {
2817    return sd->selected;
2818 }
2819
2820 EOLIAN static Elm_Object_Item*
2821 _elm_list_item_append(Eo *obj, Elm_List_Data *sd, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
2822 {
2823    Elm_List_Item_Data *it;
2824
2825    it = _item_new(obj, label, icon, end, func, data);
2826
2827    sd->items = eina_list_append(sd->items, EO_OBJ(it));
2828    it->node = eina_list_last(sd->items);
2829    elm_box_pack_end(sd->box, VIEW(it));
2830
2831    if (_elm_config->atspi_mode)
2832      elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it));
2833
2834    return EO_OBJ(it);
2835 }
2836
2837 EOLIAN static Elm_Object_Item*
2838 _elm_list_item_prepend(Eo *obj, Elm_List_Data *sd, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
2839 {
2840    Elm_List_Item_Data *it;
2841
2842    it = _item_new(obj, label, icon, end, func, data);
2843
2844    sd->items = eina_list_prepend(sd->items, EO_OBJ(it));
2845    it->node = sd->items;
2846    elm_box_pack_start(sd->box, VIEW(it));
2847
2848    if (_elm_config->atspi_mode)
2849      elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it));
2850
2851    return EO_OBJ(it);
2852 }
2853
2854 EOLIAN static Elm_Object_Item*
2855 _elm_list_item_insert_before(Eo *obj, Elm_List_Data *sd, Elm_Object_Item *eo_before, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
2856 {
2857    Elm_List_Item_Data *it;
2858    EINA_SAFETY_ON_NULL_RETURN_VAL(eo_before, NULL);
2859    ELM_LIST_ITEM_DATA_GET(eo_before, before_it);
2860
2861    ELM_LIST_ITEM_CHECK_OR_RETURN(before_it, NULL);
2862
2863    if (!before_it->node) return NULL;
2864
2865    it = _item_new(obj, label, icon, end, func, data);
2866    sd->items = eina_list_prepend_relative_list(sd->items, EO_OBJ(it), before_it->node);
2867    it->node = before_it->node->prev;
2868    elm_box_pack_before(sd->box, VIEW(it), VIEW(before_it));
2869
2870    if (_elm_config->atspi_mode)
2871      elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it));
2872
2873    return EO_OBJ(it);
2874 }
2875
2876 EOLIAN static Elm_Object_Item*
2877 _elm_list_item_insert_after(Eo *obj, Elm_List_Data *sd, Elm_Object_Item *eo_after, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data)
2878 {
2879    Elm_List_Item_Data *it;
2880    EINA_SAFETY_ON_NULL_RETURN_VAL(eo_after, NULL);
2881    ELM_LIST_ITEM_DATA_GET(eo_after, after_it);
2882
2883    ELM_LIST_ITEM_CHECK_OR_RETURN(after_it, NULL);
2884
2885    if (!after_it->node) return NULL;
2886
2887    it = _item_new(obj, label, icon, end, func, data);
2888    sd->items = eina_list_append_relative_list(sd->items, EO_OBJ(it), after_it->node);
2889    it->node = after_it->node->next;
2890    elm_box_pack_after(sd->box, VIEW(it), VIEW(after_it));
2891
2892    if (_elm_config->atspi_mode)
2893      elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it));
2894
2895    return EO_OBJ(it);
2896 }
2897
2898 EOLIAN static Elm_Object_Item*
2899 _elm_list_item_sorted_insert(Eo *obj, Elm_List_Data *sd, const char *label, Evas_Object *icon, Evas_Object *end, Evas_Smart_Cb func, const void *data, Eina_Compare_Cb cmp_func)
2900 {
2901    Eina_List *l;
2902    Elm_List_Item_Data *it;
2903
2904    it = _item_new(obj, label, icon, end, func, data);
2905
2906    sd->items = eina_list_sorted_insert(sd->items, cmp_func, EO_OBJ(it));
2907    l = eina_list_data_find_list(sd->items, EO_OBJ(it));
2908    l = eina_list_next(l);
2909    if (!l)
2910      {
2911         it->node = eina_list_last(sd->items);
2912         elm_box_pack_end(sd->box, VIEW(it));
2913      }
2914    else
2915      {
2916         Elm_Object_Item *eo_before = eina_list_data_get(l);
2917         ELM_LIST_ITEM_DATA_GET(eo_before, before);
2918
2919         it->node = before->node->prev;
2920         elm_box_pack_before(sd->box, VIEW(it), VIEW(before));
2921      }
2922
2923    if (_elm_config->atspi_mode)
2924      elm_interface_atspi_accessible_children_changed_added_signal_emit(obj, EO_OBJ(it));
2925
2926    return EO_OBJ(it);
2927 }
2928
2929 EOLIAN static void
2930 _elm_list_item_separator_set(Eo *eo_item, Elm_List_Item_Data *it, Eina_Bool setting)
2931 {
2932    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
2933
2934    it->is_separator = !!setting;
2935
2936    if (it->is_separator)
2937       eo_do(eo_item, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_SEPARATOR));
2938    else
2939       eo_do(eo_item, elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_LIST_ITEM));
2940 }
2941
2942 EOLIAN static Eina_Bool
2943 _elm_list_item_separator_get(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *it)
2944 {
2945    ELM_LIST_ITEM_CHECK_OR_RETURN(it, EINA_FALSE);
2946
2947    return it->is_separator;
2948 }
2949
2950 EOLIAN static void
2951 _elm_list_item_selected_set(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *item,
2952       Eina_Bool selected)
2953 {
2954    Evas_Object *obj;
2955
2956    ELM_LIST_ITEM_CHECK_OR_RETURN(item);
2957    obj = WIDGET(item);
2958    ELM_LIST_DATA_GET(obj, sd);
2959
2960    selected = !!selected;
2961    if (item->selected == selected) return;
2962
2963    evas_object_ref(obj);
2964    _elm_list_walk(sd);
2965
2966    if (selected)
2967      {
2968         if (!sd->multi)
2969           {
2970              while (sd->selected)
2971                {
2972                   Elm_Object_Item *eo_sel = sd->selected->data;
2973                   ELM_LIST_ITEM_DATA_GET(eo_sel, sel);
2974                   _item_unhighlight(sel);
2975                   _item_unselect(sel);
2976                }
2977           }
2978         _item_highlight(item);
2979         elm_object_item_focus_set(EO_OBJ(item), EINA_TRUE);
2980         _item_select(item);
2981      }
2982    else
2983      {
2984         _item_unhighlight(item);
2985         _item_unselect(item);
2986      }
2987
2988    _elm_list_unwalk(obj, sd);
2989    evas_object_unref(obj);
2990 }
2991
2992 EOLIAN static Eina_Bool
2993 _elm_list_item_selected_get(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *it)
2994 {
2995    ELM_LIST_ITEM_CHECK_OR_RETURN(it, EINA_FALSE);
2996
2997    return it->selected;
2998 }
2999
3000 EOLIAN static void
3001 _elm_list_item_show(Eo *eo_it EINA_UNUSED, Elm_List_Item_Data *it)
3002 {
3003    Evas_Coord bx, by, bw, bh;
3004    Evas_Coord x, y, w, h;
3005
3006    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
3007    ELM_LIST_DATA_GET_FROM_ITEM(it, sd);
3008
3009    evas_smart_objects_calculate(evas_object_evas_get(sd->box));
3010    evas_object_geometry_get(sd->box, &bx, &by, &bw, &bh);
3011    evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
3012    x -= bx;
3013    y -= by;
3014
3015    eo_do(WIDGET(it), elm_interface_scrollable_content_region_show(x, y, w, h));
3016 }
3017
3018 EOLIAN static void
3019 _elm_list_item_bring_in(Eo *eo_it EINA_UNUSED, Elm_List_Item_Data *it)
3020 {
3021    Evas_Coord bx, by, bw, bh;
3022    Evas_Coord x, y, w, h;
3023
3024    ELM_LIST_ITEM_CHECK_OR_RETURN(it);
3025    ELM_LIST_DATA_GET_FROM_ITEM(it, sd);
3026
3027    evas_smart_objects_calculate(evas_object_evas_get(sd->box));
3028    evas_object_geometry_get(sd->box, &bx, &by, &bw, &bh);
3029    evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
3030    x -= bx;
3031    y -= by;
3032
3033    eo_do(WIDGET(it), elm_interface_scrollable_region_bring_in(x, y, w, h));
3034 }
3035
3036 EOLIAN static Evas_Object *
3037 _elm_list_item_object_get(Eo *eo_it EINA_UNUSED, Elm_List_Item_Data *it)
3038 {
3039    ELM_LIST_ITEM_CHECK_OR_RETURN(it, NULL);
3040
3041    return VIEW(it);
3042 }
3043
3044 EOLIAN static Elm_Object_Item *
3045 _elm_list_item_prev_get(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *item)
3046 {
3047    if (item->node->prev)
3048      return item->node->prev->data;
3049    return NULL;
3050 }
3051
3052 EOLIAN static Elm_Object_Item *
3053 _elm_list_item_next_get(Eo *eo_item EINA_UNUSED, Elm_List_Item_Data *item)
3054 {
3055    if (item->node->next)
3056      return item->node->next->data;
3057    return NULL;
3058 }
3059
3060 EOLIAN static Elm_Object_Item*
3061 _elm_list_first_item_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
3062 {
3063    if (!sd->items) return NULL;
3064    else
3065      return eina_list_data_get(sd->items);
3066    return NULL;
3067 }
3068
3069 EOLIAN static Elm_Object_Item*
3070 _elm_list_last_item_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
3071 {
3072    if (!sd->items) return NULL;
3073    else
3074      return eina_list_data_get(eina_list_last(sd->items));
3075    return NULL;
3076 }
3077
3078 EOLIAN static Elm_Object_Item*
3079 _elm_list_at_xy_item_get(const Eo *obj EINA_UNUSED, Elm_List_Data *sd, Evas_Coord x, Evas_Coord y, int *posret)
3080 {
3081    Eina_List *l;
3082    Elm_Object_Item *eo_it;
3083    Evas_Coord lasty;
3084    evas_object_geometry_get(sd->hit_rect, &lasty, NULL, NULL, NULL);
3085
3086    EINA_LIST_FOREACH(sd->items, l, eo_it)
3087      {
3088         ELM_LIST_ITEM_DATA_GET(eo_it, it);
3089         Evas_Coord itx, ity;
3090         Evas_Object *vit = VIEW(it);
3091         Evas_Coord vx, vy, vw, vh;
3092         evas_object_geometry_get(vit, &vx, &vy, &vw, &vh);
3093
3094         itx = vx;
3095         ity = vy;
3096         if (ELM_RECTS_INTERSECT
3097               (itx, ity, vw, vh, x, y, 1, 1))
3098           {
3099              if (posret)
3100                {
3101                   if (y <= (ity + (vh / 4))) *posret = -1;
3102                   else if (y >= (ity + vh - (vh / 4)))
3103                     *posret = 1;
3104                   else *posret = 0;
3105                }
3106
3107              return EO_OBJ(it);
3108           }
3109
3110         lasty = ity + vh;
3111      }
3112
3113    if (posret)
3114      {
3115         if (y > lasty) *posret = 1;
3116         else *posret = -1;
3117      }
3118
3119    return NULL;
3120 }
3121
3122 EOLIAN static void
3123 _elm_list_focus_on_selection_set(Eo *obj EINA_UNUSED, Elm_List_Data *sd, Eina_Bool enabled)
3124 {
3125    sd->focus_on_selection_enabled = !!enabled;
3126 }
3127
3128 EOLIAN static Eina_Bool
3129 _elm_list_focus_on_selection_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
3130 {
3131    return sd->focus_on_selection_enabled;
3132 }
3133
3134 static void
3135 _elm_list_item_coordinates_adjust(Elm_List_Item_Data *it,
3136                                   Evas_Coord *x,
3137                                   Evas_Coord *y,
3138                                   Evas_Coord *w,
3139                                   Evas_Coord *h)
3140 {
3141    ELM_LIST_DATA_GET_FROM_ITEM(it, sd);
3142
3143    Evas_Coord ix, iy, iw, ih, vx, vy, vw, vh;
3144
3145    evas_object_geometry_get(sd->hit_rect, &vx, &vy, &vw, &vh);
3146    evas_object_geometry_get(VIEW(it), &ix, &iy, &iw, &ih);
3147    *x = ix;
3148    *y = iy;
3149    *w = iw;
3150    *h = ih;
3151    if (!sd->h_mode)
3152      {
3153         if (ELM_RECTS_X_AXIS_OUT(ix, iy, iw, ih, vx, vy, vw, vh))
3154           *y = iy - ih;
3155         else if (iy < vy)
3156           *y = iy + ih;
3157      }
3158    else
3159      {
3160         if (ELM_RECTS_Y_AXIS_OUT(ix, iy, iw, ih, vx, vy, vw, vh))
3161           *x = ix - iw;
3162         else if (ix < vx)
3163           *x = ix + iw;
3164      }
3165 }
3166
3167 EOLIAN static void
3168 _elm_list_elm_widget_focus_highlight_geometry_get(const Eo *obj EINA_UNUSED, Elm_List_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
3169 {
3170    if (sd->focused_item)
3171      {
3172         ELM_LIST_ITEM_DATA_GET(sd->focused_item, focus_it);
3173         _elm_list_item_coordinates_adjust(focus_it, x, y, w, h);
3174         elm_widget_focus_highlight_focus_part_geometry_get(VIEW(focus_it), x, y, w, h);
3175      }
3176 }
3177
3178 EOLIAN static Elm_Object_Item*
3179 _elm_list_elm_widget_focused_item_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
3180 {
3181    return sd->focused_item;
3182 }
3183
3184 EOLIAN static void
3185 _elm_list_elm_widget_item_loop_enabled_set(Eo *obj EINA_UNUSED, Elm_List_Data *sd, Eina_Bool enable)
3186 {
3187    sd->item_loop_enable = !!enable;
3188 }
3189
3190 EOLIAN static Eina_Bool
3191 _elm_list_elm_widget_item_loop_enabled_get(Eo *obj EINA_UNUSED, Elm_List_Data *sd)
3192 {
3193    return sd->item_loop_enable;
3194 }
3195
3196 static void
3197 _elm_list_class_constructor(Eo_Class *klass)
3198 {
3199       if (_elm_config->access_mode)
3200         _elm_list_smart_focus_next_enable = EINA_TRUE;
3201
3202       evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
3203 }
3204
3205 EOLIAN const Elm_Atspi_Action *
3206 _elm_list_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Elm_List_Data *pd EINA_UNUSED)
3207 {
3208    static Elm_Atspi_Action atspi_actions[] = {
3209           { "move,prior", "move", "prior", _key_action_move},
3210           { "move,next", "move", "next", _key_action_move},
3211           { "move,left", "move", "left", _key_action_move},
3212           { "move,left,multi", "move", "left_multi", _key_action_move},
3213           { "move,right", "move", "right", _key_action_move},
3214           { "move,right,multi", "move", "right_multi", _key_action_move},
3215           { "move,up", "move", "up", _key_action_move},
3216           { "move,up,multi", "move", "up_multi", _key_action_move},
3217           { "move,down", "move", "down", _key_action_move},
3218           { "move,down,multi", "move", "down_multi", _key_action_move},
3219           { "move,first", "move", "first", _key_action_move},
3220           { "move,last", "move", "last", _key_action_move},
3221           { "select", "select", NULL, _key_action_select},
3222           { "escape", "escape", NULL, _key_action_escape},
3223           { NULL, NULL, NULL, NULL }
3224    };
3225    return &atspi_actions[0];
3226 }
3227
3228 EOLIAN Eina_List*
3229 _elm_list_elm_interface_atspi_accessible_children_get(Eo *eo_item EINA_UNUSED, Elm_List_Data *pd)
3230 {
3231    return eina_list_clone(pd->items);
3232 }
3233
3234 EOLIAN int
3235 _elm_list_elm_interface_atspi_selection_selected_children_count_get(Eo *objm EINA_UNUSED, Elm_List_Data *pd)
3236 {
3237    return eina_list_count(pd->selected);
3238 }
3239
3240 EOLIAN Eo*
3241 _elm_list_elm_interface_atspi_selection_selected_child_get(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_idx)
3242 {
3243    return eina_list_nth(pd->selected, child_idx);
3244 }
3245
3246 EOLIAN Eina_Bool
3247 _elm_list_elm_interface_atspi_selection_child_select(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_index)
3248 {
3249    if (pd->select_mode != ELM_OBJECT_SELECT_MODE_NONE)
3250      {
3251         Eo *item = eina_list_nth(pd->items, child_index);
3252         if (item)
3253            elm_list_item_selected_set(item, EINA_TRUE);
3254         return EINA_TRUE;
3255      }
3256    return EINA_FALSE;
3257 }
3258
3259 EOLIAN Eina_Bool
3260 _elm_list_elm_interface_atspi_selection_selected_child_deselect(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_index)
3261 {
3262    Eo *item = eina_list_nth(pd->selected, child_index);
3263    if (item)
3264      {
3265         elm_list_item_selected_set(item, EINA_FALSE);
3266         return EINA_TRUE;
3267      }
3268    return EINA_FALSE;
3269 }
3270
3271 EOLIAN Eina_Bool
3272 _elm_list_elm_interface_atspi_selection_is_child_selected(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_index)
3273 {
3274    Eo *item = eina_list_nth(pd->items, child_index);
3275    if (item)
3276      return elm_list_item_selected_get(item);
3277
3278    return EINA_FALSE;
3279 }
3280
3281 EOLIAN Eina_Bool
3282 _elm_list_elm_interface_atspi_selection_all_children_select(Eo *obj EINA_UNUSED, Elm_List_Data *pd)
3283 {
3284    Eo *it;
3285    Eina_List *l;
3286
3287    if (pd->select_mode == ELM_OBJECT_SELECT_MODE_NONE)
3288      return EINA_FALSE;
3289
3290    EINA_LIST_FOREACH(pd->items, l, it)
3291       elm_list_item_selected_set(it, EINA_TRUE);
3292
3293    return EINA_TRUE;
3294 }
3295
3296 EOLIAN Eina_Bool
3297 _elm_list_elm_interface_atspi_selection_clear(Eo *obj EINA_UNUSED, Elm_List_Data *pd)
3298 {
3299    Eo *it;
3300    Eina_List *l;
3301
3302    if (pd->select_mode == ELM_OBJECT_SELECT_MODE_NONE)
3303      return EINA_FALSE;
3304
3305    EINA_LIST_FOREACH(pd->items, l, it)
3306       elm_list_item_selected_set(it, EINA_FALSE);
3307
3308    return EINA_TRUE;
3309 }
3310
3311 EOLIAN Eina_Bool
3312 _elm_list_elm_interface_atspi_selection_child_deselect(Eo *obj EINA_UNUSED, Elm_List_Data *pd, int child_index)
3313 {
3314    Eo *item = eina_list_nth(pd->items, child_index);
3315    if (item)
3316      {
3317         elm_list_item_selected_set(item, EINA_FALSE);
3318         return EINA_TRUE;
3319      }
3320    return EINA_FALSE;
3321 }
3322
3323 //TIZEN_ONLY(20160329): list: enhance accessibility scroll and highlight (02c20ee39a0ebbe67b9e1491ccfc46dd681821c9)
3324 static int _is_item_in_viewport(int viewport_y, int viewport_h, int obj_y, int obj_h)
3325 {
3326     if ((obj_y + obj_h/2) < viewport_y)
3327       return 1;
3328     else if ((obj_y + obj_h/2) > viewport_y + viewport_h)
3329       return -1;
3330     return 0;
3331 }
3332
3333 static Eina_Bool _atspi_enabled()
3334 {
3335     Eo *bridge = NULL;
3336     Eina_Bool ret = EINA_FALSE;
3337     if (_elm_config->atspi_mode && (bridge = _elm_atspi_bridge_get()))
3338       eo_do(bridge, ret = elm_obj_atspi_bridge_connected_get());
3339     return ret;
3340 }
3341
3342 EOLIAN static void
3343 _elm_list_elm_interface_scrollable_content_pos_set(Eo *obj EINA_UNUSED, Elm_List_Data *pd, Evas_Coord x, Evas_Coord y, Eina_Bool sig)
3344 {
3345    if (!_atspi_enabled())
3346      {
3347         eo_do_super(obj, MY_CLASS, elm_interface_scrollable_content_pos_set(x,y,sig));
3348         return;
3349      }
3350
3351    int old_x, old_y, delta_y;
3352    eo_do_super(obj, MY_CLASS, elm_interface_scrollable_content_pos_get(&old_x,&old_y));
3353    eo_do_super(obj, MY_CLASS, elm_interface_scrollable_content_pos_set(x,y,sig));
3354    delta_y = old_y - y;
3355
3356    //check if highlighted item is list descendant
3357    Evas_Object *win = elm_widget_top_get(obj);
3358    Evas_Object * highlighted_obj = _elm_win_accessibility_highlight_get(win);
3359    Evas_Object * parent = highlighted_obj;
3360    if (eo_isa(highlighted_obj, ELM_WIDGET_CLASS))
3361      {
3362         while ((parent = elm_widget_parent_get(parent)))
3363           if (parent == obj)
3364             break;
3365      }
3366    else if (eo_isa(highlighted_obj, EDJE_OBJECT_CLASS))
3367      {
3368         while ((parent = evas_object_smart_parent_get(parent)))
3369           if (parent == obj)
3370             break;
3371      }
3372
3373    if (parent)
3374      {
3375         int obj_x, obj_y, w, h, hx, hy, hw, hh;
3376         evas_object_geometry_get(obj, &obj_x, &obj_y, &w, &h);
3377
3378         evas_object_geometry_get(highlighted_obj, &hx, &hy, &hw, &hh);
3379
3380         Elm_List_Item_Data *next_previous_item = NULL;
3381         int viewport_position_result = _is_item_in_viewport(obj_y, h, hy, hh);
3382         //only highlight if move direction is correct
3383         //sometimes highlighted item is brought in and it does not fit viewport
3384         //however content goes to the viewport position so soon it will
3385         //meet _is_item_in_viewport condition
3386
3387         if ((viewport_position_result < 0 && delta_y > 0) ||
3388            (viewport_position_result > 0 && delta_y < 0))
3389           {
3390              Eo *item;
3391              Eina_List *l;
3392              Eina_Bool traverse_direction = viewport_position_result > 0;
3393              l = traverse_direction ? pd->items: eina_list_last(pd->items);
3394
3395              while(l)
3396               {
3397                  item = eina_list_data_get(l);
3398                  ELM_LIST_ITEM_DATA_GET(item, it_data);
3399                  next_previous_item = it_data;
3400                  evas_object_geometry_get(VIEW(next_previous_item), &hx, &hy, &hw, &hh);
3401
3402                  if (_is_item_in_viewport(obj_y, h, hy, hh) == 0)
3403                     break;
3404
3405                  next_previous_item = NULL;
3406
3407                  l = traverse_direction ? eina_list_next(l): eina_list_prev(l);
3408               }
3409           }
3410         if (next_previous_item)
3411           eo_do(EO_OBJ(next_previous_item), elm_interface_atspi_component_highlight_grab());
3412      }
3413 }
3414
3415 EOLIAN static Eina_Bool
3416 _elm_list_item_elm_interface_atspi_component_highlight_grab(Eo *eo_it, Elm_List_Item_Data *it)
3417 {
3418    Evas_Coord wy, wh, x, y, w, h, bx, by, bw, bh;
3419    ELM_LIST_DATA_GET_OR_RETURN_VAL(WIDGET(it), sd, EINA_FALSE);
3420    Eina_Bool ret;
3421
3422    evas_object_geometry_get(WIDGET(it), NULL, &wy, NULL, &wh);
3423    evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
3424    int res = _is_item_in_viewport(wy, wh, y, h);
3425
3426    if (res != 0)
3427      {
3428         evas_object_geometry_get(sd->box, &bx, &by, &bw, &bh);
3429         evas_smart_objects_calculate(evas_object_evas_get(sd->box));
3430         x -= bx;
3431         y -= by;
3432         if (res > 0)
3433           {
3434              y -= wh - h;
3435              eo_do(WIDGET(it), elm_interface_scrollable_content_region_show(x, y, w, h));
3436           }
3437         else if (res < 0)
3438           {
3439              y += wh - h;
3440              eo_do(WIDGET(it), elm_interface_scrollable_content_region_show(x, y, w, h));
3441           }
3442      }
3443    else
3444      elm_list_item_show(eo_it);
3445
3446    eo_do_super(eo_it, ELM_LIST_ITEM_CLASS, ret = elm_interface_atspi_component_highlight_grab());
3447    return ret;
3448 }
3449 //
3450
3451 #include "elm_list.eo.c"
3452 #include "elm_list_item.eo.c"