297db2f38644ce581276aed467c8d1c4bf5cc36d
[framework/uifw/elementary.git] / src / lib / elm_index.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "els_box.h"
4 #include "elm_widget_index.h"
5
6 EAPI const char ELM_INDEX_SMART_NAME[] = "elm_index";
7
8 #define INDEX_DELAY_CHANGE_TIME 0.2
9
10 static const char SIG_CHANGED[] = "changed";
11 static const char SIG_DELAY_CHANGED[] = "delay,changed";
12 static const char SIG_SELECTED[] = "selected";
13 static const char SIG_LEVEL_UP[] = "level,up";
14 static const char SIG_LEVEL_DOWN[] = "level,down";
15 static const char SIG_LANG_CHANGED[] = "language,changed";
16
17 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
18    {SIG_CHANGED, ""},
19    {SIG_DELAY_CHANGED, ""},
20    {SIG_SELECTED, ""},
21    {SIG_LEVEL_UP, ""},
22    {SIG_LEVEL_DOWN, ""},
23    {SIG_LANG_CHANGED, ""},
24    {NULL, NULL}
25 };
26
27 EVAS_SMART_SUBCLASS_NEW
28   (ELM_INDEX_SMART_NAME, _elm_index, Elm_Index_Smart_Class,
29   Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
30
31 static Eina_Bool
32 _elm_index_smart_translate(Evas_Object *obj)
33 {
34    evas_object_smart_callback_call(obj, SIG_LANG_CHANGED, NULL);
35    return EINA_TRUE;
36 }
37
38 static void
39 _item_free(Elm_Index_Item *it)
40 {
41    ELM_INDEX_DATA_GET(WIDGET(it), sd);
42
43    sd->items = eina_list_remove(sd->items, it);
44
45    if (it->omitted)
46      it->omitted = eina_list_free(it->omitted);
47
48    if (it->letter)
49      eina_stringshare_del(it->letter);
50 }
51
52 static void
53 _box_custom_layout(Evas_Object *o,
54                    Evas_Object_Box_Data *priv,
55                    void *data)
56 {
57    Elm_Index_Smart_Data *sd = data;
58
59    _els_box_layout(o, priv, sd->horizontal, 1, 0);
60 }
61
62 static void
63 _index_box_clear(Evas_Object *obj,
64                  Evas_Object *box,
65                  int level)
66 {
67    Eina_List *l;
68    Elm_Index_Item *it;
69
70    ELM_INDEX_DATA_GET(obj, sd);
71
72    if (!sd->level_active[level]) return;
73
74    EINA_LIST_FOREACH(sd->items, l, it)
75      {
76         if (!VIEW(it)) continue;
77         if (it->level != level) continue;
78
79         evas_object_del(VIEW(it));
80         VIEW(it) = NULL;
81      }
82
83    evas_object_smart_calculate(box);
84    sd->level_active[level] = 0;
85 }
86
87 static char *
88 _access_info_cb(void *data, Evas_Object *obj __UNUSED__)
89 {
90    const char *txt = NULL;
91
92    Elm_Index_Item *it = (Elm_Index_Item *)data;
93    ELM_INDEX_ITEM_CHECK_OR_RETURN(it, NULL);
94
95    txt = elm_widget_access_info_get(obj);
96    if (!txt) txt = it->letter;
97    if (txt) return strdup(txt);
98
99    return NULL;
100 }
101
102 static void
103 _access_widget_item_activate_cb(void *data __UNUSED__,
104                                 Evas_Object *part_obj __UNUSED__,
105                                 Elm_Object_Item *it)
106 {
107    evas_object_smart_callback_call(WIDGET(it), SIG_SELECTED, it);
108 }
109
110 static void
111 _access_widget_item_register(Elm_Index_Item *it)
112 {
113    Elm_Access_Info *ai;
114
115    _elm_access_widget_item_register((Elm_Widget_Item *)it);
116
117    ai = _elm_access_object_get(it->base.access_obj);
118
119    _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("Index Item"));
120    _elm_access_callback_set(ai, ELM_ACCESS_INFO, _access_info_cb, it);
121    _elm_access_activate_callback_set
122      (ai, _access_widget_item_activate_cb, NULL);
123 }
124
125 static void
126 _omit_calc(void *data, int num_of_items, int max_num_of_items)
127 {
128    Elm_Index_Smart_Data *sd = data;
129    int max_group_num, num_of_extra_items, i, g, size, sum, start;
130    int *group_pos, *omit_info;
131    Elm_Index_Omit *o;
132
133    if ((max_num_of_items < 3) || (num_of_items <= max_num_of_items)) return;
134
135    if (sd->group_num > 0)
136      start = sd->group_num + sd->default_num - 1;
137    else start = 0;
138    max_group_num = (max_num_of_items - 1) / 2;
139    num_of_extra_items = num_of_items - max_num_of_items;
140
141    group_pos = (int *)malloc(sizeof(int) * max_group_num);
142    omit_info = (int *)malloc(sizeof(int) * max_num_of_items);
143
144    if (num_of_extra_items >= max_group_num)
145      {
146         g = 1;
147         for (i = 0; i < max_group_num; i++)
148           {
149              group_pos[i] = g;
150              g += 2;
151           }
152      }
153    else
154      {
155         size = max_num_of_items / (num_of_extra_items + 1);
156         g = size;
157         for (i = 0; i < num_of_extra_items; i++)
158           {
159              group_pos[i] = g;
160              g += size;
161           }
162      }
163    for (i = 0; i < max_num_of_items; i++)
164      omit_info[i] = 1;
165    for (i = 0; i < num_of_extra_items; i++)
166      omit_info[group_pos[i % max_group_num]]++;
167
168    sum = 0;
169    for (i = 0; i < max_num_of_items; i++)
170      {
171         if (omit_info[i] > 1)
172           {
173              o = (Elm_Index_Omit *)malloc(sizeof(Elm_Index_Omit));
174              o->offset = sum + start;
175              o->count = omit_info[i];
176              sd->omit = eina_list_append(sd->omit, o);
177           }
178         sum += omit_info[i];
179      }
180
181    free(group_pos);
182    free(omit_info);
183 }
184
185 // FIXME: always have index filled
186 static void
187 _index_box_auto_fill(Evas_Object *obj,
188                      Evas_Object *box,
189                      int level)
190 {
191    int i = 0, max_num_of_items = 0, num_of_items = 0, g = 0, skip = 0;
192    Eina_List *l;
193    Eina_Bool rtl;
194    Elm_Index_Item *it, *head = NULL, *last_it = NULL;
195    Evas_Coord mw, mh, ih;
196    Evas_Object *o;
197    Elm_Index_Omit *om;
198
199    ELM_INDEX_DATA_GET(obj, sd);
200
201    if (sd->level_active[level]) return;
202
203    edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.index.0", NULL, NULL, NULL, &ih);
204
205    rtl = elm_widget_mirrored_get(obj);
206
207    EINA_LIST_FREE(sd->omit, om)
208      free(om);
209
210    EINA_LIST_FOREACH(sd->items, l, it)
211      {
212         if (it->omitted)
213           it->omitted = eina_list_free(it->omitted);
214         if (it->head) it->head = NULL;
215      }
216
217    if (sd->omit_enabled)
218      {
219         o = edje_object_add(evas_object_evas_get(obj));
220         elm_widget_theme_object_set
221            (obj, o, "index", "item/vertical",
222             elm_widget_style_get(obj));
223
224         edje_object_size_min_restricted_calc(o, NULL, &mh, 0, 0);
225
226         EINA_LIST_FOREACH(sd->items, l, it)
227            if (it->level == level && it->priority == sd->show_group)
228              num_of_items++;
229
230         if (mh != 0)
231           max_num_of_items = ih / mh;
232         if (sd->group_num)
233           max_num_of_items -= (sd->group_num + sd->default_num - 1);
234
235         _omit_calc(sd, num_of_items, max_num_of_items);
236      }
237
238    int current_priority = -1;
239    om = eina_list_nth(sd->omit, g);
240    EINA_LIST_FOREACH(sd->items, l, it)
241      {
242         const char *stacking;
243
244         if (it->level != level) continue;
245
246         if ((current_priority != -1) && (current_priority == it->priority)
247             && (it->priority != sd->show_group)) continue;
248
249         if ((om) && (i == om->offset))
250           {
251              skip = om->count;
252              skip--;
253              head = it;
254              it->head = head;
255              head->omitted = eina_list_append(head->omitted, it);
256              om = eina_list_nth(sd->omit, ++g);
257           }
258         else if (skip > 0)
259           {
260              skip--;
261              i++;
262              if (head)
263                {
264                   it->head = head;
265                   head->omitted = eina_list_append(head->omitted, it);
266                }
267              continue;
268           }
269
270         o = edje_object_add(evas_object_evas_get(obj));
271         VIEW(it) = o;
272         edje_object_mirrored_set(VIEW(it), rtl);
273
274         if (sd->horizontal)
275           {
276              if (i & 0x1)
277                elm_widget_theme_object_set
278                  (obj, o, "index", "item_odd/horizontal",
279                  elm_widget_style_get(obj));
280              else
281                elm_widget_theme_object_set
282                  (obj, o, "index", "item/horizontal",
283                  elm_widget_style_get(obj));
284           }
285         else
286           {
287              if (i & 0x1)
288                elm_widget_theme_object_set
289                  (obj, o, "index", "item_odd/vertical",
290                  elm_widget_style_get(obj));
291              else
292                elm_widget_theme_object_set
293                  (obj, o, "index", "item/vertical",
294                  elm_widget_style_get(obj));
295           }
296
297         if (skip > 0)
298           edje_object_part_text_escaped_set(o, "elm.text", "*");
299         else
300           edje_object_part_text_escaped_set(o, "elm.text", it->letter);
301         edje_object_size_min_restricted_calc(o, &mw, &mh, 0, 0);
302         evas_object_size_hint_min_set(o, mw, mh);
303         evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
304         evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
305         elm_widget_sub_object_add(obj, o);
306         evas_object_box_append(box, o);
307         stacking = edje_object_data_get(o, "stacking");
308
309         if (stacking)
310           {
311              if (!strcmp(stacking, "below")) evas_object_lower(o);
312              else if (!strcmp(stacking, "above"))
313                evas_object_raise(o);
314           }
315
316         evas_object_show(o);
317
318         i++;
319
320         if (current_priority != it->priority) current_priority = it->priority;
321         last_it = it;
322
323         // ACCESS
324         if ((it->level == 0) && (_elm_config->access_mode))
325           _access_widget_item_register(it);
326      }
327
328    // TIZEN ONLY adjust the last item's theme according to winset gui
329    if (last_it)
330      edje_object_signal_emit(VIEW(last_it), "elm,last,item", "elm");
331    // TIZEN ONLY
332
333    evas_object_smart_calculate(box);
334    sd->level_active[level] = 1;
335 }
336
337 static void
338 _priority_change_job(void *data)
339 {
340    ELM_INDEX_DATA_GET(data, sd);
341    Elm_Object_Item *selected_it;
342
343    sd->priority_change = NULL;
344    sd->show_group = sd->next_group;
345    _index_box_clear(data, sd->bx[0], 0);
346    _index_box_auto_fill(data, sd->bx[0], 0);
347
348    selected_it = elm_index_selected_item_get(data, sd->level);
349    if (selected_it) elm_index_item_selected_set(selected_it, EINA_FALSE);
350 }
351
352 static Eina_Bool
353 _priority_up_cb(void *data)
354 {
355    _priority_change_job(data);
356    elm_layout_signal_emit(data, "elm,priority,up", "elm");
357
358    return ECORE_CALLBACK_CANCEL;
359 }
360
361 static Eina_Bool
362 _priority_down_cb(void *data)
363 {
364    _priority_change_job(data);
365    elm_layout_signal_emit(data, "elm,priority,down", "elm");
366
367    return ECORE_CALLBACK_CANCEL;
368 }
369
370 static void
371 _index_priority_change(void *data, Elm_Index_Item *it)
372 {
373    ELM_INDEX_DATA_GET(data, sd);
374
375    if (sd->priority_change)
376      {
377         ecore_timer_del(sd->priority_change);
378         sd->priority_change = NULL;
379      }
380
381    if ((it->priority != -1) && (it->priority != sd->show_group))
382      {
383         sd->next_group = it->priority;
384         if (it->priority < sd->show_group)
385           sd->priority_change = ecore_timer_add(0.3, _priority_up_cb, data);
386         else
387           sd->priority_change = ecore_timer_add(0.3, _priority_down_cb, data);
388      }
389 }
390
391 static void
392 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
393 {
394    ELM_INDEX_DATA_GET(obj, sd);
395
396    if (!sd->horizontal)
397      edje_object_mirrored_set(ELM_WIDGET_DATA(sd)->resize_obj, rtl);
398 }
399
400 static void
401 _access_activate_cb(void *data,
402                     Evas_Object *part_obj __UNUSED__,
403                     Elm_Object_Item *item __UNUSED__)
404 {
405    Elm_Index_Item *it;
406    ELM_INDEX_DATA_GET(data, sd);
407
408    it = eina_list_nth(sd->items, 0);
409    _elm_access_highlight_set(it->base.access_obj, EINA_FALSE);
410    sd->index_focus = EINA_TRUE;
411 }
412
413 static void
414 _access_index_register(Evas_Object *obj)
415 {
416    Evas_Object *ao;
417    Elm_Access_Info *ai;
418    elm_widget_can_focus_set(obj, EINA_TRUE);
419
420    ao = _elm_access_edje_object_part_object_register
421               (obj, elm_layout_edje_get(obj), "access");
422    ai = _elm_access_object_get(ao);
423
424    _elm_access_text_set
425      (ai, ELM_ACCESS_TYPE, E_("Index"));
426    _elm_access_activate_callback_set
427      (ai, _access_activate_cb, obj);
428 }
429
430 static Eina_Bool
431 _elm_index_smart_theme(Evas_Object *obj)
432 {
433    Evas_Coord minw = 0, minh = 0;
434    Elm_Index_Item *it;
435
436    ELM_INDEX_DATA_GET(obj, sd);
437
438    _index_box_clear(obj, sd->bx[0], 0);
439    _index_box_clear(obj, sd->bx[1], 1);
440
441    if (sd->horizontal)
442      eina_stringshare_replace(&ELM_LAYOUT_DATA(sd)->group, "base/horizontal");
443    else
444      {
445         eina_stringshare_replace(&ELM_LAYOUT_DATA(sd)->group, "base/vertical");
446         _mirrored_set(obj, elm_widget_mirrored_get(obj));
447      }
448
449    if (!ELM_WIDGET_CLASS(_elm_index_parent_sc)->theme(obj)) return EINA_FALSE;
450
451    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
452    evas_object_size_hint_min_set(sd->event[0], minw, minh);
453
454    if (edje_object_part_exists
455          (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.index.1"))
456      {
457         if (!sd->bx[1])
458           {
459              sd->bx[1] = evas_object_box_add(evas_object_evas_get(obj));
460              evas_object_box_layout_set
461                (sd->bx[1], _box_custom_layout, sd, NULL);
462              elm_widget_sub_object_add(obj, sd->bx[1]);
463           }
464         elm_layout_content_set(obj, "elm.swallow.index.1", sd->bx[1]);
465      }
466    else if (sd->bx[1])
467      {
468         evas_object_del(sd->bx[1]);
469         sd->bx[1] = NULL;
470      }
471    if (edje_object_part_exists
472          (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.event.1"))
473      {
474         if (!sd->event[1])
475           {
476              sd->event[1] =
477                evas_object_rectangle_add(evas_object_evas_get(obj));
478              evas_object_color_set(sd->event[1], 0, 0, 0, 0);
479              elm_widget_sub_object_add(obj, sd->event[1]);
480           }
481         elm_layout_content_set(obj, "elm.swallow.event.1", sd->event[1]);
482         evas_object_size_hint_min_set(sd->event[1], minw, minh);
483      }
484    else if (sd->event[1])
485      {
486         evas_object_del(sd->event[1]);
487         sd->event[1] = NULL;
488      }
489    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
490
491    elm_layout_sizing_eval(obj);
492    _index_box_auto_fill(obj, sd->bx[0], 0);
493
494    if (sd->autohide_disabled)
495      {
496         if (sd->level == 1) _index_box_auto_fill(obj, sd->bx[1], 1);
497         elm_layout_signal_emit(obj, "elm,state,active", "elm");
498      }
499    else elm_layout_signal_emit(obj, "elm,state,inactive", "elm");
500
501    it = (Elm_Index_Item *)elm_index_selected_item_get(obj, sd->level);
502    if (it)
503      {
504         if (it->head)
505           edje_object_signal_emit(VIEW(it->head), "elm,state,active", "elm");
506         else
507           edje_object_signal_emit(VIEW(it), "elm,state,active", "elm");
508      }
509
510    /* access */
511    if (_elm_config->access_mode)
512      {
513         elm_index_autohide_disabled_set(obj, EINA_TRUE);
514         elm_layout_signal_emit(obj, "elm,access,state,active", "elm");
515         _access_index_register(obj);
516      }
517
518    return EINA_TRUE;
519 }
520
521 static void
522 _elm_index_smart_sizing_eval(Evas_Object *obj)
523 {
524    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
525
526    ELM_INDEX_DATA_GET(obj, sd);
527
528    edje_object_size_min_calc(ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh);
529    evas_object_size_hint_min_set(obj, minw, minh);
530    evas_object_size_hint_max_set(obj, maxw, maxh);
531 }
532
533 static Eina_Bool
534 _item_del_pre_hook(Elm_Object_Item *it)
535 {
536    ELM_INDEX_DATA_GET(WIDGET(it), sd);
537
538    _item_free((Elm_Index_Item *)it);
539    _index_box_clear(WIDGET(it), sd->bx[sd->level], sd->level);
540
541    return EINA_TRUE;
542 }
543
544 static Elm_Index_Item *
545 _item_new(Evas_Object *obj,
546           const char *letter,
547           Evas_Smart_Cb func,
548           const void *data)
549 {
550    Elm_Index_Item *it;
551
552    ELM_INDEX_DATA_GET(obj, sd);
553
554    it = elm_widget_item_new(obj, Elm_Index_Item);
555    if (!it) return NULL;
556
557    elm_widget_item_del_pre_hook_set(it, _item_del_pre_hook);
558    if (letter) it->letter = eina_stringshare_add(letter);
559    it->func = func;
560    it->base.data = data;
561    it->level = sd->level;
562    it->priority = -1;
563
564    return it;
565 }
566
567 static Elm_Index_Item *
568 _item_find(Evas_Object *obj,
569            const void *data)
570 {
571    Eina_List *l;
572    Elm_Index_Item *it;
573
574    ELM_INDEX_DATA_GET(obj, sd);
575
576    EINA_LIST_FOREACH(sd->items, l, it)
577      if (it->base.data == data) return it;
578
579    return NULL;
580 }
581
582 static Eina_Bool
583 _delay_change_cb(void *data)
584 {
585    Elm_Object_Item *item;
586
587    ELM_INDEX_DATA_GET(data, sd);
588
589    sd->delay = NULL;
590    item = elm_index_selected_item_get(data, sd->level);
591    if (item)
592      {
593         evas_object_smart_callback_call(data, SIG_DELAY_CHANGED, item);
594         _index_priority_change(data, (Elm_Index_Item *)item);
595      }
596
597    return ECORE_CALLBACK_CANCEL;
598 }
599
600 static void
601 _sel_eval(Evas_Object *obj,
602           Evas_Coord evx,
603           Evas_Coord evy)
604 {
605    Evas_Coord x, y, w, h, bx, by, bw, bh, xx, yy;
606    Elm_Index_Item *it, *it_closest, *it_last, *om_closest;
607    char *label = NULL, *last = NULL;
608    double cdv = 0.5;
609    Evas_Coord dist;
610    Eina_List *l;
611    int i, j, size, dh, dx, dy;
612
613    ELM_INDEX_DATA_GET(obj, sd);
614
615    for (i = 0; i <= sd->level; i++)
616      {
617         it_last = NULL;
618         it_closest = NULL;
619         om_closest = NULL;
620         dist = 0x7fffffff;
621         evas_object_geometry_get(sd->bx[i], &bx, &by, &bw, &bh);
622
623         EINA_LIST_FOREACH(sd->items, l, it)
624           {
625              if (it->level != i) continue;
626              if (it->level != sd->level)
627                {
628                   if (it->selected)
629                     {
630                        it_closest = it;
631                        break;
632                     }
633                   continue;
634                }
635              if (it->selected)
636                {
637                   it_last = it;
638                   it->selected = 0;
639                }
640              if (VIEW(it))
641                {
642                   evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
643                   xx = x + (w / 2);
644                   yy = y + (h / 2);
645                   x = evx - xx;
646                   y = evy - yy;
647                   x = (x * x) + (y * y);
648                   if ((x < dist) || (!it_closest))
649                     {
650                        if (sd->horizontal)
651                          cdv = (double)(xx - bx) / (double)bw;
652                        else
653                          cdv = (double)(yy - by) / (double)bh;
654                        it_closest = it;
655                        dist = x;
656                     }
657                }
658           }
659         if ((i == 0) && (sd->level == 0))
660           edje_object_part_drag_value_set
661             (ELM_WIDGET_DATA(sd)->resize_obj, "elm.dragable.index.1", cdv, cdv);
662
663         if (it_closest && it_closest->omitted)
664           {
665              it = it_closest;
666              size = eina_list_count(it->omitted);
667              evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
668              dist = 0x7fffffff;
669              dh = h / size;
670              if (dh == 0)
671                printf("too many index items to omit\n"); //FIXME
672              else
673                {
674                   for (j = 0; j < size; j++)
675                     {
676                        xx = x + (w / 2);
677                        yy = y + (dh * j) + (dh / 2);
678                        dx = evx - xx;
679                        dy = evy - yy;
680                        dx = (dx * dx) + (dy * dy);
681                        if ((dx < dist) || (!om_closest))
682                          {
683                             om_closest = eina_list_nth(it->omitted, j);
684                             dist = dx;
685                          }
686                     }
687                }
688           }
689
690         if (om_closest) om_closest->selected = 1;
691         else if (it_closest) it_closest->selected = 1;
692
693         if (it_closest != it_last)
694           {
695              if (it_last)
696                {
697                   const char *stacking, *selectraise;
698
699                   it = it_last;
700                   if (it->head)
701                     {
702                        if (it->head != it_closest) it = it->head;
703                        else it = NULL;
704                     }
705                   if (it)
706                     {
707                        edje_object_signal_emit
708                           (VIEW(it), "elm,state,inactive", "elm");
709                        stacking = edje_object_data_get(VIEW(it), "stacking");
710                        selectraise = edje_object_data_get(VIEW(it), "selectraise");
711                        if ((selectraise) && (!strcmp(selectraise, "on")))
712                          {
713                             if ((stacking) && (!strcmp(stacking, "below")))
714                               evas_object_lower(VIEW(it));
715                          }
716                     }
717                }
718              if (it_closest)
719                {
720                   const char *selectraise;
721
722                   it = it_closest;
723
724                   if (!((it_last) && (it_last->head) && (it_last->head == it_closest)))
725                     {
726                        edje_object_signal_emit(VIEW(it), "elm,state,active", "elm");
727                        selectraise = edje_object_data_get(VIEW(it), "selectraise");
728                        if ((selectraise) && (!strcmp(selectraise, "on")))
729                          evas_object_raise(VIEW(it));
730                     }
731
732                   if (om_closest)
733                     evas_object_smart_callback_call
734                        (obj, SIG_CHANGED, om_closest);
735                   else
736                     evas_object_smart_callback_call
737                        (obj, SIG_CHANGED, it);
738                   if (sd->delay) ecore_timer_del(sd->delay);
739                   sd->delay = ecore_timer_add(sd->delay_change_time,
740                                               _delay_change_cb, obj);
741                }
742           }
743         if (it_closest)
744           {
745              if (om_closest) it = om_closest;
746              else it = it_closest;
747              if (!last && it->letter) last = strdup(it->letter);
748              else
749                {
750                   if (!label && last) label = strdup(last);
751                   else
752                     {
753                        if (label && last)
754                          {
755                             label = realloc(label, strlen(label) +
756                                             strlen(last) + 1);
757                             if (!label) return;
758                             strcat(label, last);
759                          }
760                     }
761                   free(last);
762                   if (it->letter) last = strdup(it->letter);
763                }
764           }
765      }
766    if (!label) label = strdup("");
767    if (!last) last = strdup("");
768
769    elm_layout_text_set(obj, "elm.text.body", label);
770    elm_layout_text_set(obj, "elm.text", last);
771
772    free(label);
773    free(last);
774 }
775
776 static void
777 _on_mouse_wheel(void *data __UNUSED__,
778                 Evas *e __UNUSED__,
779                 Evas_Object *o __UNUSED__,
780                 void *event_info __UNUSED__)
781 {
782 }
783
784 static void
785 _on_mouse_down(void *data,
786                Evas *e __UNUSED__,
787                Evas_Object *o __UNUSED__,
788                void *event_info)
789 {
790    Evas_Event_Mouse_Down *ev = event_info;
791    Evas_Coord x, y, w;
792
793    ELM_INDEX_DATA_GET(data, sd);
794
795    if (ev->button != 1) return;
796    sd->down = 1;
797    evas_object_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, &x, &y, &w, NULL);
798    sd->dx = ev->canvas.x - x;
799    sd->dy = ev->canvas.y - y;
800    if (!sd->autohide_disabled)
801      {
802         _index_box_clear(data, sd->bx[1], 1);
803         elm_layout_signal_emit(data, "elm,state,active", "elm");
804      }
805    _sel_eval(data, ev->canvas.x, ev->canvas.y);
806    edje_object_part_drag_value_set
807      (ELM_WIDGET_DATA(sd)->resize_obj, "elm.dragable.pointer",
808      (!elm_object_mirrored_get(data)) ? sd->dx : (sd->dx - w), sd->dy);
809    if (sd->items && !sd->indicator_disabled)
810      elm_layout_signal_emit(data, "elm,indicator,state,active", "elm");
811 }
812
813 static void
814 _on_mouse_up(void *data,
815              Evas *e __UNUSED__,
816              Evas_Object *o __UNUSED__,
817              void *event_info)
818 {
819    Evas_Event_Mouse_Up *ev = event_info;
820    Elm_Object_Item *item;
821    Elm_Index_Item *id_item;
822
823    ELM_INDEX_DATA_GET(data, sd);
824
825    if (ev->button != 1) return;
826    sd->down = 0;
827    item = elm_index_selected_item_get(data, sd->level);
828    if (item)
829      {
830         evas_object_smart_callback_call(data, SIG_SELECTED, item);
831         id_item = (Elm_Index_Item *)item;
832         if (id_item->func)
833           id_item->func((void *)id_item->base.data, WIDGET(id_item), id_item);
834      }
835    if (!sd->autohide_disabled)
836      elm_layout_signal_emit(data, "elm,state,inactive", "elm");
837
838    elm_layout_signal_emit(data, "elm,state,level,0", "elm");
839    if (sd->items && !sd->indicator_disabled)
840      elm_layout_signal_emit(data, "elm,indicator,state,inactive", "elm");
841 }
842
843 static void
844 _on_mouse_move(void *data,
845                Evas *e __UNUSED__,
846                Evas_Object *o __UNUSED__,
847                void *event_info)
848 {
849    Evas_Event_Mouse_Move *ev = event_info;
850    Evas_Coord minw = 0, minh = 0, x, y, dx, adx, w;
851    char buf[1024];
852
853    ELM_INDEX_DATA_GET(data, sd);
854
855    if (!sd->down) return;
856    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
857    evas_object_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, &x, &y, &w, NULL);
858    x = ev->cur.canvas.x - x;
859    y = ev->cur.canvas.y - y;
860    dx = x - sd->dx;
861    adx = dx;
862    if (adx < 0) adx = -dx;
863    edje_object_part_drag_value_set
864      (ELM_WIDGET_DATA(sd)->resize_obj, "elm.dragable.pointer",
865      (!edje_object_mirrored_get(ELM_WIDGET_DATA(sd)->resize_obj)) ?
866      x : (x - w), y);
867    if (!sd->horizontal)
868      {
869         if (adx > minw)
870           {
871              if (!sd->level)
872                {
873                   sd->level = 1;
874                   snprintf(buf, sizeof(buf), "elm,state,level,%i", sd->level);
875                   elm_layout_signal_emit(data, buf, "elm");
876                   evas_object_smart_callback_call(data, SIG_LEVEL_UP, NULL);
877                }
878           }
879         else
880           {
881              if (sd->level == 1)
882                {
883                   sd->level = 0;
884                   snprintf(buf, sizeof(buf), "elm,state,level,%i", sd->level);
885                   elm_layout_signal_emit(data, buf, "elm");
886                   evas_object_smart_callback_call(data, SIG_LEVEL_DOWN, NULL);
887                }
888           }
889      }
890    _sel_eval(data, ev->cur.canvas.x, ev->cur.canvas.y);
891 }
892
893 static void
894 _index_resize_cb(void *data,
895                  Evas *e __UNUSED__,
896                  Evas_Object *obj __UNUSED__,
897                  void *event_info __UNUSED__)
898 {
899    ELM_INDEX_DATA_GET_OR_RETURN(data, sd);
900
901    if (!sd->omit_enabled) return;
902
903    Elm_Index_Item *it;
904
905    _index_box_clear(data, sd->bx[0], 0);
906    _index_box_auto_fill(data, sd->bx[0], 0);
907
908    it = (Elm_Index_Item *)elm_index_selected_item_get(obj, sd->level);
909    if (it)
910      {
911         if (it->head)
912           edje_object_signal_emit(VIEW(it->head), "elm,state,active", "elm");
913         else
914           edje_object_signal_emit(VIEW(it), "elm,state,active", "elm");
915      }
916 }
917
918 static void
919 _elm_index_smart_add(Evas_Object *obj)
920 {
921    Evas_Object *o;
922    Evas_Coord minw, minh;
923
924    EVAS_SMART_DATA_ALLOC(obj, Elm_Index_Smart_Data);
925
926    ELM_WIDGET_CLASS(_elm_index_parent_sc)->base.add(obj);
927
928    elm_layout_theme_set
929      (obj, "index", "base/vertical", elm_widget_style_get(obj));
930
931    o = evas_object_rectangle_add(evas_object_evas_get(obj));
932    priv->event[0] = o;
933    evas_object_color_set(o, 0, 0, 0, 0);
934    minw = minh = 0;
935    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
936    evas_object_size_hint_min_set(o, minw, minh);
937    elm_layout_content_set(obj, "elm.swallow.event.0", o);
938    elm_widget_sub_object_add(obj, o);
939
940    evas_object_event_callback_add
941      (obj, EVAS_CALLBACK_RESIZE, _index_resize_cb, obj);
942    evas_object_event_callback_add
943      (o, EVAS_CALLBACK_MOUSE_WHEEL, _on_mouse_wheel, obj);
944    evas_object_event_callback_add
945      (o, EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down, obj);
946    evas_object_event_callback_add
947      (o, EVAS_CALLBACK_MOUSE_UP, _on_mouse_up, obj);
948    evas_object_event_callback_add
949      (o, EVAS_CALLBACK_MOUSE_MOVE, _on_mouse_move, obj);
950
951    if (edje_object_part_exists
952          (ELM_WIDGET_DATA(priv)->resize_obj, "elm.swallow.event.1"))
953      {
954         o = evas_object_rectangle_add(evas_object_evas_get(obj));
955         priv->event[1] = o;
956         evas_object_color_set(o, 0, 0, 0, 0);
957         evas_object_size_hint_min_set(o, minw, minh);
958         elm_layout_content_set(obj, "elm.swallow.event.1", o);
959         elm_widget_sub_object_add(obj, o);
960      }
961
962    priv->bx[0] = evas_object_box_add(evas_object_evas_get(obj));
963    evas_object_box_layout_set(priv->bx[0], _box_custom_layout, priv, NULL);
964    elm_widget_sub_object_add(obj, priv->bx[0]);
965    elm_layout_content_set(obj, "elm.swallow.index.0", priv->bx[0]);
966    evas_object_show(priv->bx[0]);
967
968    priv->delay_change_time = INDEX_DELAY_CHANGE_TIME;
969    priv->omit_enabled = 1;
970
971    if (edje_object_part_exists
972          (ELM_WIDGET_DATA(priv)->resize_obj, "elm.swallow.index.1"))
973      {
974         priv->bx[1] = evas_object_box_add(evas_object_evas_get(obj));
975         evas_object_box_layout_set
976           (priv->bx[1], _box_custom_layout, priv, NULL);
977         elm_widget_sub_object_add(obj, priv->bx[1]);
978         elm_layout_content_set(obj, "elm.swallow.index.1", priv->bx[1]);
979         evas_object_show(priv->bx[1]);
980      }
981
982    _mirrored_set(obj, elm_widget_mirrored_get(obj));
983    elm_layout_sizing_eval(obj);
984    elm_widget_can_focus_set(obj, EINA_FALSE);
985
986    // ACCESS
987    if (_elm_config->access_mode)
988      {
989         elm_index_autohide_disabled_set(obj, EINA_TRUE);
990         elm_layout_signal_emit(obj, "elm,access,state,active", "elm");
991         _access_index_register(obj);
992      }
993 }
994
995 static void
996 _elm_index_smart_del(Evas_Object *obj)
997 {
998    Elm_Index_Item *it;
999    Elm_Index_Omit *o;
1000
1001    ELM_INDEX_DATA_GET(obj, sd);
1002
1003    while (sd->items)
1004      {
1005         it = sd->items->data;
1006         elm_widget_item_del(it);
1007      }
1008
1009    EINA_LIST_FREE(sd->omit, o)
1010      free(o);
1011
1012    if (sd->delay) ecore_timer_del(sd->delay);
1013
1014    ELM_WIDGET_CLASS(_elm_index_parent_sc)->base.del(obj);
1015 }
1016
1017 static Eina_Bool
1018 _elm_index_smart_focus_next(const Evas_Object *obj,
1019                             Elm_Focus_Direction dir,
1020                             Evas_Object **next)
1021 {
1022    Eina_List *items = NULL;
1023    Eina_List *l = NULL;
1024    Elm_Index_Item *it;
1025    Evas_Object *ao;
1026    Evas_Object *po;
1027    Eina_Bool ret;
1028
1029    ELM_INDEX_CHECK(obj) EINA_FALSE;
1030    ELM_INDEX_DATA_GET(obj, sd);
1031
1032    if (!sd->autohide_disabled)
1033      elm_layout_signal_emit((Evas_Object *)obj, "elm,state,active", "elm");
1034
1035    po = (Evas_Object *)edje_object_part_object_get
1036               (elm_layout_edje_get(obj), "access");
1037    ao = evas_object_data_get(po, "_part_access_obj");
1038    items = eina_list_append(items, ao);
1039
1040    if (sd->index_focus)
1041      {
1042       EINA_LIST_FOREACH(sd->items, l, it)
1043         {
1044            if (it->level != 0) continue;
1045            items = eina_list_append(items, it->base.access_obj);
1046         }
1047      }
1048
1049    ret = elm_widget_focus_list_next_get
1050             (obj, items, eina_list_data_get, dir, next);
1051
1052    if (!ret)
1053      {
1054         sd->index_focus = EINA_FALSE;
1055
1056         Evas_Object *it_access_obj = eina_list_nth(items, eina_list_count(items) - 1);
1057
1058         items = eina_list_free(items);
1059         items = eina_list_append(items, it_access_obj);
1060         items = eina_list_append(items, ao);
1061
1062         ret = elm_widget_focus_list_next_get(obj, items, eina_list_data_get, dir, next);
1063
1064         // to hide index item, if there is nothing to focus on autohide disalbe mode
1065         if (!sd->autohide_disabled)
1066           elm_layout_signal_emit((Evas_Object *)obj, "elm,state,inactive", "elm");
1067      }
1068
1069    return ret;
1070 }
1071
1072 static void
1073 _access_obj_process(Evas_Object *obj, Eina_Bool is_access)
1074 {
1075    Eina_List *l;
1076    Elm_Index_Item *it;
1077
1078    ELM_INDEX_DATA_GET(obj, sd);
1079
1080    EINA_LIST_FOREACH(sd->items, l, it)
1081      {
1082         if (it->level != 0) continue;
1083         if (is_access) _access_widget_item_register(it);
1084         else _elm_access_widget_item_unregister((Elm_Widget_Item *)it);
1085      }
1086
1087    if (is_access)
1088      {
1089         elm_index_autohide_disabled_set(obj, EINA_TRUE);
1090         elm_layout_signal_emit(obj, "elm,access,state,active", "elm");
1091         _access_index_register(obj);
1092      }
1093    else
1094      {
1095         // opposition of  _access_index_register();
1096         if (!sd->autohide_disabled)
1097           elm_index_autohide_disabled_set(obj, EINA_FALSE);
1098         elm_layout_signal_emit(obj, "elm,access,state,inactive", "elm");
1099         elm_widget_can_focus_set(obj, EINA_FALSE);
1100         _elm_access_edje_object_part_object_unregister
1101              (obj, elm_layout_edje_get(obj), "access");
1102      }
1103 }
1104
1105 static void
1106 _access_hook(Evas_Object *obj, Eina_Bool is_access)
1107 {
1108    ELM_INDEX_CHECK(obj);
1109    ELM_INDEX_DATA_GET(obj, sd);
1110
1111    if (is_access)
1112      ELM_WIDGET_CLASS(ELM_WIDGET_DATA(sd)->api)->focus_next =
1113      _elm_index_smart_focus_next;
1114    else
1115      ELM_WIDGET_CLASS(ELM_WIDGET_DATA(sd)->api)->focus_next = NULL;
1116    _access_obj_process(obj, is_access);
1117 }
1118
1119 static void
1120 _elm_index_smart_set_user(Elm_Index_Smart_Class *sc)
1121 {
1122    ELM_WIDGET_CLASS(sc)->base.add = _elm_index_smart_add;
1123    ELM_WIDGET_CLASS(sc)->base.del = _elm_index_smart_del;
1124
1125    ELM_WIDGET_CLASS(sc)->theme = _elm_index_smart_theme;
1126    ELM_WIDGET_CLASS(sc)->translate = _elm_index_smart_translate;
1127
1128    /* not a 'focus chain manager' */
1129    ELM_WIDGET_CLASS(sc)->focus_next = NULL;
1130    ELM_WIDGET_CLASS(sc)->focus_direction = NULL;
1131
1132    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_index_smart_sizing_eval;
1133
1134    if (_elm_config->access_mode)
1135      ELM_WIDGET_CLASS(sc)->focus_next = _elm_index_smart_focus_next;
1136
1137    ELM_WIDGET_CLASS(sc)->access = _access_hook;
1138 }
1139
1140 EAPI const Elm_Index_Smart_Class *
1141 elm_index_smart_class_get(void)
1142 {
1143    static Elm_Index_Smart_Class _sc =
1144      ELM_INDEX_SMART_CLASS_INIT_NAME_VERSION(ELM_INDEX_SMART_NAME);
1145    static const Elm_Index_Smart_Class *class = NULL;
1146    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
1147
1148    if (class)
1149      return class;
1150
1151    _elm_index_smart_set(&_sc);
1152    esc->callbacks = _smart_callbacks;
1153    class = &_sc;
1154
1155    return class;
1156 }
1157
1158 EAPI Evas_Object *
1159 elm_index_add(Evas_Object *parent)
1160 {
1161    Evas_Object *obj;
1162
1163    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1164
1165    obj = elm_widget_add(_elm_index_smart_class_new(), parent);
1166    if (!obj) return NULL;
1167
1168    if (!elm_widget_sub_object_add(parent, obj))
1169      ERR("could not add %p as sub object of %p", obj, parent);
1170
1171    return obj;
1172 }
1173
1174 EAPI void
1175 elm_index_autohide_disabled_set(Evas_Object *obj,
1176                                 Eina_Bool disabled)
1177 {
1178    ELM_INDEX_CHECK(obj);
1179    ELM_INDEX_DATA_GET(obj, sd);
1180
1181    disabled = !!disabled;
1182    if (sd->autohide_disabled == disabled) return;
1183    sd->autohide_disabled = disabled;
1184    sd->level = 0;
1185    if (sd->autohide_disabled)
1186      {
1187         _index_box_clear(obj, sd->bx[1], 1);
1188         elm_layout_signal_emit(obj, "elm,state,active", "elm");
1189      }
1190    else
1191      elm_layout_signal_emit(obj, "elm,state,inactive", "elm");
1192
1193    //FIXME: Should be update indicator based on the indicator visiblility
1194 }
1195
1196 EAPI Eina_Bool
1197 elm_index_autohide_disabled_get(const Evas_Object *obj)
1198 {
1199    ELM_INDEX_CHECK(obj) EINA_FALSE;
1200    ELM_INDEX_DATA_GET(obj, sd);
1201
1202    return sd->autohide_disabled;
1203 }
1204
1205 EAPI void
1206 elm_index_item_level_set(Evas_Object *obj,
1207                          int level)
1208 {
1209    ELM_INDEX_CHECK(obj);
1210    ELM_INDEX_DATA_GET(obj, sd);
1211
1212    if (sd->level == level) return;
1213    sd->level = level;
1214 }
1215
1216 EAPI int
1217 elm_index_item_level_get(const Evas_Object *obj)
1218 {
1219    ELM_INDEX_CHECK(obj) 0;
1220    ELM_INDEX_DATA_GET(obj, sd);
1221
1222    return sd->level;
1223 }
1224
1225 //FIXME: Should update indicator based on the autohidden status & indicator visiblility
1226 EAPI void
1227 elm_index_item_selected_set(Elm_Object_Item *it,
1228                             Eina_Bool selected)
1229 {
1230    Elm_Index_Item *it_sel, *it_last;
1231    Evas_Object *obj = WIDGET(it);
1232
1233    ELM_INDEX_ITEM_CHECK_OR_RETURN(it);
1234    ELM_INDEX_DATA_GET(obj, sd);
1235
1236    selected = !!selected;
1237    it_sel = (Elm_Index_Item *)it;
1238    if (it_sel->selected == selected) return;
1239
1240    if (selected)
1241      {
1242         it_last = (Elm_Index_Item *)elm_index_selected_item_get(obj, sd->level);
1243
1244         if (it_last)
1245           {
1246              it_last->selected = 0;
1247              if (it_last->head)
1248                edje_object_signal_emit(VIEW(it_last->head), "elm,state,inactive", "elm");
1249              else
1250                edje_object_signal_emit(VIEW(it_last), "elm,state,inactive", "elm");
1251           }
1252         it_sel->selected = 1;
1253         if (it_sel->head)
1254           edje_object_signal_emit(VIEW(it_sel->head), "elm,state,active", "elm");
1255         else
1256           edje_object_signal_emit(VIEW(it_sel), "elm,state,active", "elm");
1257
1258         evas_object_smart_callback_call
1259            (obj, SIG_CHANGED, it);
1260         evas_object_smart_callback_call
1261            (obj, SIG_SELECTED, it);
1262         if (sd->delay) ecore_timer_del(sd->delay);
1263         sd->delay = ecore_timer_add(sd->delay_change_time,
1264                                     _delay_change_cb, obj);
1265      }
1266    else
1267      {
1268         it_sel->selected = 0;
1269         if (it_sel->head)
1270           edje_object_signal_emit(VIEW(it_sel->head), "elm,state,inactive", "elm");
1271         else
1272           edje_object_signal_emit(VIEW(it_sel), "elm,state,inactive", "elm");
1273      }
1274 }
1275
1276 EAPI Elm_Object_Item *
1277 elm_index_selected_item_get(const Evas_Object *obj,
1278                             int level)
1279 {
1280    Eina_List *l;
1281    Elm_Index_Item *it;
1282
1283    ELM_INDEX_CHECK(obj) NULL;
1284    ELM_INDEX_DATA_GET(obj, sd);
1285
1286    EINA_LIST_FOREACH(sd->items, l, it)
1287      {
1288         if ((it->selected) && (it->level == level))
1289           return (Elm_Object_Item *)it;
1290      }
1291
1292    return NULL;
1293 }
1294
1295 EAPI Elm_Object_Item *
1296 elm_index_item_append(Evas_Object *obj,
1297                       const char *letter,
1298                       Evas_Smart_Cb func,
1299                       const void *data)
1300 {
1301    Elm_Index_Item *it;
1302
1303    ELM_INDEX_CHECK(obj) NULL;
1304    ELM_INDEX_DATA_GET(obj, sd);
1305
1306    it = _item_new(obj, letter, func, data);
1307    if (!it) return NULL;
1308
1309    sd->items = eina_list_append(sd->items, it);
1310    _index_box_clear(obj, sd->bx[sd->level], sd->level);
1311
1312    return (Elm_Object_Item *)it;
1313 }
1314
1315 EAPI Elm_Object_Item *
1316 elm_index_item_prepend(Evas_Object *obj,
1317                        const char *letter,
1318                        Evas_Smart_Cb func,
1319                        const void *data)
1320 {
1321    Elm_Index_Item *it;
1322
1323    ELM_INDEX_CHECK(obj) NULL;
1324    ELM_INDEX_DATA_GET(obj, sd);
1325
1326    it = _item_new(obj, letter, func, data);
1327    if (!it) return NULL;
1328
1329    sd->items = eina_list_prepend(sd->items, it);
1330    _index_box_clear(obj, sd->bx[sd->level], sd->level);
1331
1332    return (Elm_Object_Item *)it;
1333 }
1334
1335 EINA_DEPRECATED EAPI Elm_Object_Item *
1336 elm_index_item_prepend_relative(Evas_Object *obj,
1337                                 const char *letter,
1338                                 const void *item,
1339                                 const Elm_Object_Item *relative)
1340 {
1341    return elm_index_item_insert_before
1342             (obj, (Elm_Object_Item *)relative, letter, NULL, item);
1343 }
1344
1345 EAPI Elm_Object_Item *
1346 elm_index_item_insert_after(Evas_Object *obj,
1347                             Elm_Object_Item *after,
1348                             const char *letter,
1349                             Evas_Smart_Cb func,
1350                             const void *data)
1351 {
1352    Elm_Index_Item *it;
1353
1354    ELM_INDEX_CHECK(obj) NULL;
1355    ELM_INDEX_DATA_GET(obj, sd);
1356
1357    if (!after) return elm_index_item_append(obj, letter, func, data);
1358
1359    it = _item_new(obj, letter, func, data);
1360    if (!it) return NULL;
1361
1362    sd->items = eina_list_append_relative(sd->items, it, after);
1363    _index_box_clear(obj, sd->bx[sd->level], sd->level);
1364
1365    return (Elm_Object_Item *)it;
1366 }
1367
1368 EAPI Elm_Object_Item *
1369 elm_index_item_insert_before(Evas_Object *obj,
1370                              Elm_Object_Item *before,
1371                              const char *letter,
1372                              Evas_Smart_Cb func,
1373                              const void *data)
1374 {
1375    Elm_Index_Item *it;
1376
1377    ELM_INDEX_CHECK(obj) NULL;
1378    ELM_INDEX_DATA_GET(obj, sd);
1379
1380    if (!before) return elm_index_item_prepend(obj, letter, func, data);
1381
1382    it = _item_new(obj, letter, func, data);
1383    if (!it) return NULL;
1384
1385    sd->items = eina_list_prepend_relative(sd->items, it, before);
1386    _index_box_clear(obj, sd->bx[sd->level], sd->level);
1387
1388    return (Elm_Object_Item *)it;
1389 }
1390
1391 EAPI Elm_Object_Item *
1392 elm_index_item_sorted_insert(Evas_Object *obj,
1393                              const char *letter,
1394                              Evas_Smart_Cb func,
1395                              const void *data,
1396                              Eina_Compare_Cb cmp_func,
1397                              Eina_Compare_Cb cmp_data_func)
1398 {
1399    Elm_Index_Item *it;
1400    Eina_List *lnear;
1401    int cmp;
1402
1403    ELM_INDEX_CHECK(obj) NULL;
1404    ELM_INDEX_DATA_GET(obj, sd);
1405
1406    if (!(sd->items)) return elm_index_item_append(obj, letter, func, data);
1407
1408    it = _item_new(obj, letter, func, data);
1409    if (!it) return NULL;
1410
1411    lnear = eina_list_search_sorted_near_list(sd->items, cmp_func, it, &cmp);
1412    if (cmp < 0)
1413      sd->items = eina_list_append_relative_list(sd->items, it, lnear);
1414    else if (cmp > 0)
1415      sd->items = eina_list_prepend_relative_list(sd->items, it, lnear);
1416    else
1417      {
1418         /* If cmp_data_func is not provided, append a duplicated item */
1419         if (!cmp_data_func)
1420           sd->items = eina_list_append_relative_list(sd->items, it, lnear);
1421         else
1422           {
1423              Elm_Index_Item *p_it = eina_list_data_get(lnear);
1424              if (cmp_data_func(p_it->base.data, it->base.data) >= 0)
1425                p_it->base.data = it->base.data;
1426              elm_widget_item_del(it);
1427              it = NULL;
1428           }
1429      }
1430    _index_box_clear(obj, sd->bx[sd->level], sd->level);
1431
1432    if (!it) return NULL;
1433    return (Elm_Object_Item *)it;
1434 }
1435
1436 EAPI Elm_Object_Item *
1437 elm_index_item_find(Evas_Object *obj,
1438                     const void *data)
1439 {
1440    ELM_INDEX_CHECK(obj) NULL;
1441
1442    return (Elm_Object_Item *)_item_find(obj, data);
1443 }
1444
1445 EAPI void
1446 elm_index_item_clear(Evas_Object *obj)
1447 {
1448    Elm_Index_Item *it;
1449    Eina_List *l, *clear = NULL;
1450
1451    ELM_INDEX_CHECK(obj);
1452    ELM_INDEX_DATA_GET(obj, sd);
1453
1454    _index_box_clear(obj, sd->bx[sd->level], sd->level);
1455    EINA_LIST_FOREACH(sd->items, l, it)
1456      {
1457         if (it->level != sd->level) continue;
1458         clear = eina_list_append(clear, it);
1459      }
1460    EINA_LIST_FREE (clear, it)
1461      elm_widget_item_del(it);
1462 }
1463
1464 int
1465 _sort_cb(const void *d1, const void *d2)
1466 {
1467    Elm_Index_Item *it1 = d1, *it2 = d2;
1468    if (it1->priority <= it2->priority) return -1;
1469    else return 1;
1470 }
1471
1472 EAPI void
1473 elm_index_level_go(Evas_Object *obj,
1474                    int level __UNUSED__)
1475 {
1476    ELM_INDEX_CHECK(obj);
1477    ELM_INDEX_DATA_GET(obj, sd);
1478
1479    Elm_Index_Item *it;
1480    Eina_List *l;
1481    int prev;
1482
1483    sd->items = eina_list_sort(sd->items, 0, EINA_COMPARE_CB(_sort_cb));
1484
1485    sd->default_num = 0;
1486    sd->group_num = 0;
1487    sd->show_group = -1;
1488    prev = -1;
1489    EINA_LIST_FOREACH(sd->items, l, it)
1490      {
1491         if (it->priority == -1) sd->default_num++;
1492         if (it->priority != prev)
1493           {
1494              if (prev == -1) sd->show_group = it->priority;
1495              sd->group_num++;
1496              prev = it->priority;
1497           }
1498      }
1499
1500    _index_box_clear(obj, sd->bx[0], 0);
1501    _index_box_auto_fill(obj, sd->bx[0], 0);
1502    if (sd->level == 1)
1503      {
1504         _index_box_clear(obj, sd->bx[1], 1);
1505         _index_box_auto_fill(obj, sd->bx[1], 1);
1506      }
1507 }
1508
1509 EAPI void
1510 elm_index_indicator_disabled_set(Evas_Object *obj,
1511                                  Eina_Bool disabled)
1512 {
1513    ELM_INDEX_CHECK(obj);
1514    ELM_INDEX_DATA_GET(obj, sd);
1515
1516    disabled = !!disabled;
1517    if (sd->indicator_disabled == disabled) return;
1518    sd->indicator_disabled = disabled;
1519    if (!sd->items) return;
1520    if (disabled)
1521      elm_layout_signal_emit(obj, "elm,indicator,state,inactive", "elm");
1522    else
1523      elm_layout_signal_emit(obj, "elm,indicator,state,active", "elm");
1524 }
1525
1526 EAPI Eina_Bool
1527 elm_index_indicator_disabled_get(const Evas_Object *obj)
1528 {
1529    ELM_INDEX_CHECK(obj) EINA_FALSE;
1530    ELM_INDEX_DATA_GET(obj, sd);
1531
1532    return sd->indicator_disabled;
1533 }
1534
1535 EAPI const char *
1536 elm_index_item_letter_get(const Elm_Object_Item *it)
1537 {
1538    ELM_INDEX_ITEM_CHECK_OR_RETURN(it, NULL);
1539
1540    return ((Elm_Index_Item *)it)->letter;
1541 }
1542
1543 EAPI void
1544 elm_index_horizontal_set(Evas_Object *obj,
1545                          Eina_Bool horizontal)
1546 {
1547    ELM_INDEX_CHECK(obj);
1548    ELM_INDEX_DATA_GET(obj, sd);
1549
1550    horizontal = !!horizontal;
1551    if (horizontal == sd->horizontal) return;
1552
1553    sd->horizontal = horizontal;
1554    if (horizontal)
1555      sd->omit_enabled = EINA_FALSE;
1556    _elm_index_smart_theme(obj);
1557 }
1558
1559 EAPI Eina_Bool
1560 elm_index_horizontal_get(const Evas_Object *obj)
1561 {
1562    ELM_INDEX_CHECK(obj) EINA_FALSE;
1563    ELM_INDEX_DATA_GET(obj, sd);
1564
1565    return sd->horizontal;
1566 }
1567
1568 EAPI void
1569 elm_index_delay_change_time_set(Evas_Object *obj, double delay_change_time)
1570 {
1571    ELM_INDEX_CHECK(obj);
1572    ELM_INDEX_DATA_GET(obj, sd);
1573
1574    sd->delay_change_time = delay_change_time;
1575 }
1576
1577 EAPI double
1578 elm_index_delay_change_time_get(const Evas_Object *obj)
1579 {
1580    ELM_INDEX_CHECK(obj) 0.0;
1581    ELM_INDEX_DATA_GET(obj, sd);
1582
1583    return sd->delay_change_time;
1584 }
1585
1586 EAPI void
1587 elm_index_omit_enabled_set(Evas_Object *obj,
1588                            Eina_Bool enabled)
1589 {
1590    ELM_INDEX_CHECK(obj);
1591    ELM_INDEX_DATA_GET(obj, sd);
1592
1593    if (sd->horizontal) return;
1594
1595    enabled = !!enabled;
1596    if (sd->omit_enabled == enabled) return;
1597    sd->omit_enabled = enabled;
1598
1599    _index_box_clear(obj, sd->bx[0], 0);
1600    _index_box_auto_fill(obj, sd->bx[0], 0);
1601    if (sd->level == 1)
1602      {
1603         _index_box_clear(obj, sd->bx[1], 1);
1604         _index_box_auto_fill(obj, sd->bx[1], 1);
1605      }
1606 }
1607
1608 EAPI Eina_Bool
1609 elm_index_omit_enabled_get(const Evas_Object *obj)
1610 {
1611    ELM_INDEX_CHECK(obj) EINA_FALSE;
1612    ELM_INDEX_DATA_GET(obj, sd);
1613
1614    return sd->omit_enabled;
1615 }
1616
1617 EAPI void
1618 elm_index_item_priority_set(Elm_Object_Item *it, int priority)
1619 {
1620    ELM_INDEX_ITEM_CHECK(it);
1621    if (priority < -1)
1622      {
1623         WRN("priority value should be greater than or equal to -1.");
1624         return;
1625      }
1626    ((Elm_Index_Item *)it)->priority = priority;
1627 }