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