Elementary migration revision 69832
[framework/uifw/elementary.git] / src / lib / elm_index.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "els_box.h"
4
5 typedef struct _Widget_Data Widget_Data;
6 typedef struct _Elm_Index_Item Elm_Index_Item;
7
8 struct _Widget_Data
9 {
10    Evas_Object *base;
11    Evas_Object *event[2];
12    Evas_Object *bx[2]; // 2 - for now all that's supported
13    Eina_List *items; // 1 list. yes N levels, but only 2 for now and # of items will be small
14    int level;
15    Evas_Coord dx, dy;
16    Ecore_Timer *delay;
17    Eina_Bool level_active[2];
18    Eina_Bool horizontal : 1;
19    Eina_Bool autohide_disabled : 1;
20    Eina_Bool down : 1;
21    Eina_Bool indicator_disabled : 1;
22 };
23
24 struct _Elm_Index_Item
25 {
26    ELM_WIDGET_ITEM;
27    const char *letter;
28    int level;
29    Evas_Smart_Cb func;
30    Eina_Bool selected : 1;
31 };
32
33 static const char *widtype = NULL;
34
35 static void _del_hook(Evas_Object *obj);
36 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
37 static void _theme_hook(Evas_Object *obj);
38 static void _sizing_eval(Evas_Object *obj);
39 static void _index_box_auto_fill(Evas_Object *obj, Evas_Object *box, int level);
40 static void _index_box_clear(Evas_Object *obj, Evas_Object *box, int level);
41 static void _item_free(Elm_Index_Item *it);
42
43 static const char SIG_CHANGED[] = "changed";
44 static const char SIG_DELAY_CHANGED[] = "delay,changed";
45 static const char SIG_SELECTED[] = "selected";
46 static const char SIG_LEVEL_UP[] = "level,up";
47 static const char SIG_LEVEL_DOWN[] = "level,down";
48
49 static const Evas_Smart_Cb_Description _signals[] = {
50    {SIG_CHANGED, ""},
51    {SIG_DELAY_CHANGED, ""},
52    {SIG_SELECTED, ""},
53    {SIG_LEVEL_UP, ""},
54    {SIG_LEVEL_DOWN, ""},
55    {NULL, NULL}
56 };
57
58 static void
59 _del_pre_hook(Evas_Object *obj)
60 {
61    Widget_Data *wd = elm_widget_data_get(obj);
62    Elm_Index_Item *it;
63    if (!wd) return;
64    _index_box_clear(obj, wd->bx[wd->level], wd->level);
65    _index_box_clear(obj, wd->bx[0], 0);
66    while (wd->items)
67      {
68         it = wd->items->data;
69         _item_free(it);
70         elm_widget_item_free(it);
71      }
72    if (wd->delay) ecore_timer_del(wd->delay);
73    wd->delay = NULL;
74 }
75
76 static void
77 _del_hook(Evas_Object *obj)
78 {
79    Widget_Data *wd = elm_widget_data_get(obj);
80    free(wd);
81 }
82
83 static void
84 _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data)
85 {
86    Widget_Data *wd = data;
87    if (!wd) return;
88    _els_box_layout(o, priv, wd->horizontal, 1, 0);
89 }
90
91 static void
92 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
93 {
94    Widget_Data *wd = elm_widget_data_get(obj);
95    if (!wd) return;
96    edje_object_signal_emit(wd->base, emission, source);
97 }
98
99 static void
100 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
101 {
102    Widget_Data *wd = elm_widget_data_get(obj);
103    if (!wd) return;
104    edje_object_signal_callback_add(wd->base, emission, source, func_cb, data);
105 }
106
107 static void
108 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
109 {
110    Widget_Data *wd = elm_widget_data_get(obj);
111    edje_object_signal_callback_del_full(wd->base, emission, source, func_cb,
112                                         data);
113 }
114
115 static void
116 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
117 {
118    Widget_Data *wd = elm_widget_data_get(obj);
119    if (!wd) return;
120    if (!wd->horizontal)
121      edje_object_mirrored_set(wd->base, rtl);
122 }
123
124 static void
125 _theme_hook(Evas_Object *obj)
126 {
127    Evas_Coord minw = 0, minh = 0;
128    Widget_Data *wd = elm_widget_data_get(obj);
129    if (!wd) return;
130    _elm_widget_mirrored_reload(obj);
131
132    _index_box_clear(obj, wd->bx[0], 0);
133    _index_box_clear(obj, wd->bx[1], 1);
134    if (wd->horizontal)
135      _elm_theme_object_set(obj, wd->base, "index", "base/horizontal", elm_widget_style_get(obj));
136    else
137      {
138         _elm_theme_object_set(obj, wd->base, "index", "base/vertical", elm_widget_style_get(obj));
139         _mirrored_set(obj, elm_widget_mirrored_get(obj));
140      }
141    edje_object_part_swallow(wd->base, "elm.swallow.event.0", wd->event[0]);
142    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
143    evas_object_size_hint_min_set(wd->event[0], minw, minh);
144    edje_object_part_swallow(wd->base, "elm.swallow.index.0", wd->bx[0]);
145    if (edje_object_part_exists(wd->base, "elm.swallow.index.1"))
146      {
147         if (!wd->bx[1])
148           {
149              wd->bx[1] = evas_object_box_add(evas_object_evas_get(wd->base));
150              evas_object_box_layout_set(wd->bx[1], _layout, wd, NULL);
151              elm_widget_sub_object_add(obj, wd->bx[1]);
152           }
153         edje_object_part_swallow(wd->base, "elm.swallow.index.1", wd->bx[1]);
154         evas_object_show(wd->bx[1]);
155      }
156    else if (wd->bx[1])
157      {
158         evas_object_del(wd->bx[1]);
159         wd->bx[1] = NULL;
160      }
161    if (edje_object_part_exists(wd->base, "elm.swallow.event.1"))
162      {
163         if (!wd->event[1])
164           {
165              wd->event[1] = evas_object_rectangle_add(evas_object_evas_get(wd->base));
166              evas_object_color_set(wd->event[1], 0, 0, 0, 0);
167              elm_widget_sub_object_add(obj, wd->event[1]);
168           }
169         edje_object_part_swallow(wd->base, "elm.swallow.event.1", wd->event[1]);
170         evas_object_size_hint_min_set(wd->event[1], minw, minh);
171      }
172    else if (wd->event[1])
173      {
174         evas_object_del(wd->event[1]);
175         wd->event[1] = NULL;
176      }
177    edje_object_message_signal_process(wd->base);
178    edje_object_scale_set(wd->base, elm_widget_scale_get(obj) * _elm_config->scale);
179    _sizing_eval(obj);
180    _index_box_auto_fill(obj, wd->bx[0], 0);
181
182    if (wd->autohide_disabled)
183      {
184         if (wd->level == 1) _index_box_auto_fill(obj, wd->bx[1], 1);
185         edje_object_signal_emit(wd->base, "elm,state,active", "elm");
186      }
187    else
188      edje_object_signal_emit(wd->base, "elm,state,inactive", "elm");
189 }
190
191 static void
192 _sizing_eval(Evas_Object *obj)
193 {
194    Widget_Data *wd = elm_widget_data_get(obj);
195    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
196    if (!wd) return;
197    edje_object_size_min_calc(wd->base, &minw, &minh);
198    evas_object_size_hint_min_set(obj, minw, minh);
199    evas_object_size_hint_max_set(obj, maxw, maxh);
200 }
201
202 static Eina_Bool
203 _item_del_pre_hook(Elm_Object_Item *it)
204 {
205    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
206    if (!wd) return EINA_FALSE;
207    _item_free((Elm_Index_Item *)it);
208    _index_box_clear(WIDGET(it), wd->bx[wd->level], wd->level);
209    return EINA_TRUE;
210 }
211
212 static Elm_Index_Item *
213 _item_new(Evas_Object *obj, const char *letter, Evas_Smart_Cb func, const void *data)
214 {
215    Widget_Data *wd = elm_widget_data_get(obj);
216    Elm_Index_Item *it;
217    if (!wd) return NULL;
218    it = elm_widget_item_new(obj, Elm_Index_Item);
219    if (!it) return NULL;
220    elm_widget_item_del_pre_hook_set(it, _item_del_pre_hook);
221    if (letter) it->letter = eina_stringshare_add(letter);
222    it->func = func;
223    it->base.data = data;
224    it->level = wd->level;
225    return it;
226 }
227
228 static Elm_Index_Item *
229 _item_find(Evas_Object *obj, const void *data)
230 {
231    Widget_Data *wd = elm_widget_data_get(obj);
232    Eina_List *l;
233    Elm_Index_Item *it;
234    if (!wd) return NULL;
235    EINA_LIST_FOREACH(wd->items, l, it)
236      if (it->base.data == data) return it;
237    return NULL;
238 }
239
240 static void
241 _item_free(Elm_Index_Item *it)
242 {
243    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
244    if (!wd) return;
245    wd->items = eina_list_remove(wd->items, it);
246    if (it->letter) eina_stringshare_del(it->letter);
247 }
248
249 // FIXME: always have index filled
250 static void
251 _index_box_auto_fill(Evas_Object *obj, Evas_Object *box, int level)
252 {
253    Widget_Data *wd = elm_widget_data_get(obj);
254    Eina_Bool rtl;
255    Eina_List *l;
256    Elm_Index_Item *it;
257    Evas_Coord mw, mh, w, h;
258    int i = 0;
259    if (!wd) return;
260    if (wd->level_active[level]) return;
261    rtl = elm_widget_mirrored_get(obj);
262    evas_object_geometry_get(box, NULL, NULL, &w, &h);
263    EINA_LIST_FOREACH(wd->items, l, it)
264      {
265         Evas_Object *o;
266         const char *stacking;
267
268         if (it->level != level) continue;
269
270 //FIXME: Need to check. This cause one less items show up.
271 //        if(i > wd->max_supp_items_count) break;
272
273         o = edje_object_add(evas_object_evas_get(obj));
274         VIEW(it) = o;
275         edje_object_mirrored_set(VIEW(it), rtl);
276
277         if (wd->horizontal)
278           {
279              if (i & 0x1)
280                _elm_theme_object_set(obj, o, "index", "item_odd/horizontal",
281                                      elm_widget_style_get(obj));
282              else
283                _elm_theme_object_set(obj, o, "index", "item/horizontal",
284                                      elm_widget_style_get(obj));
285           }
286         else
287           {
288              if (i & 0x1)
289                _elm_theme_object_set(obj, o, "index", "item_odd/vertical",
290                                      elm_widget_style_get(obj));
291              else
292                _elm_theme_object_set(obj, o, "index", "item/vertical",
293                                      elm_widget_style_get(obj));
294           }
295
296         edje_object_part_text_set(o, "elm.text", it->letter);
297         edje_object_size_min_restricted_calc(o, &mw, &mh, 0, 0);
298         evas_object_size_hint_min_set(o, mw, mh);
299         evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
300         evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
301         elm_widget_sub_object_add(obj, o);
302         evas_object_box_append(box, o);
303         stacking = edje_object_data_get(o, "stacking");
304         if (stacking)
305           {
306              if (!strcmp(stacking, "below")) evas_object_lower(o);
307              else if (!strcmp(stacking, "above")) evas_object_raise(o);
308           }
309         evas_object_show(o);
310         i++;
311         evas_object_smart_calculate(box); // force a calc so we know the size
312         evas_object_size_hint_min_get(box, &mw, &mh);
313         if (mh > h)
314           {
315              _index_box_clear(obj, box, level);
316              if (i > 0)
317                {
318                   // FIXME: only i objects fit! try again. overflows right now
319                }
320           }
321      }
322    evas_object_smart_calculate(box);
323    wd->level_active[level] = 1;
324 }
325
326 static void
327 _index_box_clear(Evas_Object *obj, Evas_Object *box __UNUSED__, int level)
328 {
329    Widget_Data *wd = elm_widget_data_get(obj);
330    Eina_List *l;
331    Elm_Index_Item *it;
332    if (!wd) return;
333    if (!wd->level_active[level]) return;
334    EINA_LIST_FOREACH(wd->items, l, it)
335      {
336         if (!VIEW(it)) continue;
337         if (it->level != level) continue;
338         evas_object_del(VIEW(it));
339         VIEW(it) = NULL;
340      }
341    wd->level_active[level] = 0;
342 }
343
344 static Eina_Bool
345 _delay_change(void *data)
346 {
347    Widget_Data *wd = elm_widget_data_get(data);
348    Elm_Object_Item *item;
349    if (!wd) return ECORE_CALLBACK_CANCEL;
350    wd->delay = NULL;
351    item = elm_index_selected_item_get(data, wd->level);
352    if (item) evas_object_smart_callback_call(data, SIG_DELAY_CHANGED, item);
353    return ECORE_CALLBACK_CANCEL;
354 }
355
356 static void
357 _sel_eval(Evas_Object *obj, Evas_Coord evx, Evas_Coord evy)
358 {
359    Widget_Data *wd = elm_widget_data_get(obj);
360    Elm_Index_Item *it, *it_closest, *it_last;
361    Eina_List *l;
362    Evas_Coord x, y, w, h, bx, by, bw, bh, xx, yy;
363    double cdv = 0.5;
364    Evas_Coord dist;
365    char *label = NULL, *last = NULL;
366    int i;
367    if (!wd) return;
368    for (i = 0; i <= wd->level; i++)
369      {
370         it_last = NULL;
371         it_closest  = NULL;
372         dist = 0x7fffffff;
373         evas_object_geometry_get(wd->bx[i], &bx, &by, &bw, &bh);
374         EINA_LIST_FOREACH(wd->items, l, it)
375           {
376              if (it->level != i) continue;
377              if (it->level != wd->level)
378                {
379                   if (it->selected)
380                     {
381                        it_closest = it;
382                        break;
383                     }
384                   continue;
385                }
386              if (it->selected)
387                {
388                   it_last = it;
389                   it->selected = 0;
390                }
391              evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
392              xx = x + (w / 2);
393              yy = y + (h / 2);
394              x = evx - xx;
395              y = evy - yy;
396              x = (x * x) + (y * y);
397              if ((x < dist) || (!it_closest))
398                {
399                   if (wd->horizontal)
400                     cdv = (double)(xx - bx) / (double)bw;
401                   else
402                     cdv = (double)(yy - by) / (double)bh;
403                   it_closest = it;
404                   dist = x;
405                }
406           }
407         if ((i == 0) && (wd->level == 0))
408           edje_object_part_drag_value_set(wd->base, "elm.dragable.index.1",
409                                           cdv, cdv);
410         if (it_closest) it_closest->selected = 1;
411         if (it_closest != it_last)
412           {
413              if (it_last)
414                {
415                   const char *stacking, *selectraise;
416
417                   it = it_last;
418                   edje_object_signal_emit(VIEW(it), "elm,state,inactive", "elm");
419                   stacking = edje_object_data_get(VIEW(it), "stacking");
420                   selectraise = edje_object_data_get(VIEW(it), "selectraise");
421                   if ((selectraise) && (!strcmp(selectraise, "on")))
422                     {
423                        if ((stacking) && (!strcmp(stacking, "below")))
424                          evas_object_lower(VIEW(it));
425                     }
426                }
427              if (it_closest)
428                {
429                   const char *selectraise;
430
431                   it = it_closest;
432                   edje_object_signal_emit(VIEW(it), "elm,state,active", "elm");
433                   selectraise = edje_object_data_get(VIEW(it), "selectraise");
434                   if ((selectraise) && (!strcmp(selectraise, "on")))
435                     evas_object_raise(VIEW(it));
436                   evas_object_smart_callback_call((void *)obj, SIG_CHANGED, (void *)it);
437                   if (wd->delay) ecore_timer_del(wd->delay);
438                   wd->delay = ecore_timer_add(0.2, _delay_change, obj);
439                }
440           }
441         if (it_closest)
442           {
443              it = it_closest;
444              if (!last && it->letter)
445                last = strdup(it->letter);
446              else
447                {
448                   if (!label && last) label = strdup(last);
449                   else
450                     {
451                        if (label && last)
452                          {
453                             label = realloc(label, strlen(label) +
454                                             strlen(last) + 1);
455                             if (!label) return;
456                             strcat(label, last);
457                          }
458                     }
459                   free(last);
460                   if (it->letter) last = strdup(it->letter);
461                }
462           }
463      }
464    if (!label) label = strdup("");
465    if (!last) last = strdup("");
466    edje_object_part_text_set(wd->base, "elm.text.body", label);
467    edje_object_part_text_set(wd->base, "elm.text", last);
468    free(label);
469    free(last);
470 }
471
472 static void
473 _wheel(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
474 {
475    Widget_Data *wd = elm_widget_data_get(data);
476    //   Evas_Event_Mouse_Wheel *ev = event_info;
477    //   Evas_Object *obj = o;
478    if (!wd) return;
479 }
480
481 static void
482 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
483 {
484    Widget_Data *wd = elm_widget_data_get(data);
485    Evas_Event_Mouse_Down *ev = event_info;
486    Evas_Coord x, y, w;
487    if (!wd) return;
488    if (ev->button != 1) return;
489    wd->down = 1;
490    evas_object_geometry_get(wd->base, &x, &y, &w, NULL);
491    wd->dx = ev->canvas.x - x;
492    wd->dy = ev->canvas.y - y;
493    if (!wd->autohide_disabled)
494      {
495         _index_box_clear(data, wd->bx[1], 1);
496         _index_box_auto_fill(data, wd->bx[0], 0);
497         edje_object_signal_emit(wd->base, "elm,state,active", "elm");
498      }
499    _sel_eval(data, ev->canvas.x, ev->canvas.y);
500    edje_object_part_drag_value_set(wd->base, "elm.dragable.pointer",
501                                    (!edje_object_mirrored_get(wd->base)) ? wd->dx : (wd->dx - w), wd->dy);
502    if (wd->items && !wd->indicator_disabled)
503      edje_object_signal_emit(wd->base, "elm,indicator,state,active", "elm");
504 }
505
506 static void
507 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
508 {
509    Widget_Data *wd = elm_widget_data_get(data);
510    Evas_Event_Mouse_Up *ev = event_info;
511    Elm_Object_Item *item;
512    Elm_Index_Item *id_item;
513    if (!wd) return;
514    if (ev->button != 1) return;
515    wd->down = 0;
516    item = elm_index_selected_item_get(data, wd->level);
517    if (item)
518      {
519         evas_object_smart_callback_call(data, SIG_SELECTED, item);
520         id_item = (Elm_Index_Item *)item;
521         if (id_item->func)
522           id_item->func((void *)id_item->base.data, WIDGET(id_item), id_item);
523      }
524    if (!wd->autohide_disabled)
525      edje_object_signal_emit(wd->base, "elm,state,inactive", "elm");
526    edje_object_signal_emit(wd->base, "elm,state,level,0", "elm");
527    if (wd->items && !wd->indicator_disabled)
528      edje_object_signal_emit(wd->base, "elm,indicator,state,inactive", "elm");
529 }
530
531 static void
532 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
533 {
534    Widget_Data *wd = elm_widget_data_get(data);
535    Evas_Event_Mouse_Move *ev = event_info;
536    Evas_Coord minw = 0, minh = 0, x, y, dx, adx, w;
537    char buf[1024];
538    if (!wd) return;
539    if (!wd->down) return;
540    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
541    evas_object_geometry_get(wd->base, &x, &y, &w, NULL);
542    x = ev->cur.canvas.x - x;
543    y = ev->cur.canvas.y - y;
544    dx = x - wd->dx;
545    adx = dx;
546    if (adx < 0) adx = -dx;
547    edje_object_part_drag_value_set(wd->base, "elm.dragable.pointer"
548                                    , (!edje_object_mirrored_get(wd->base)) ? x : (x - w), y);
549    if (!wd->horizontal)
550      {
551         if (adx > minw)
552           {
553              if (!wd->level)
554                {
555                   wd->level = 1;
556                   snprintf(buf, sizeof(buf), "elm,state,level,%i", wd->level);
557                   edje_object_signal_emit(wd->base, buf, "elm");
558                   evas_object_smart_callback_call(data, SIG_LEVEL_UP, NULL);
559                }
560           }
561         else
562           {
563              if (wd->level == 1)
564                {
565                   wd->level = 0;
566                   snprintf(buf, sizeof(buf), "elm,state,level,%i", wd->level);
567                   edje_object_signal_emit(wd->base, buf, "elm");
568                   evas_object_smart_callback_call(data, SIG_LEVEL_DOWN, NULL);
569                }
570           }
571      }
572    _sel_eval(data, ev->cur.canvas.x, ev->cur.canvas.y);
573 }
574
575 EAPI Evas_Object *
576 elm_index_add(Evas_Object *parent)
577 {
578    Evas_Object *obj;
579    Evas_Object *o;
580    Evas *e;
581    Widget_Data *wd;
582    Evas_Coord minw, minh;
583
584    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
585
586    ELM_SET_WIDTYPE(widtype, "index");
587    elm_widget_type_set(obj, "index");
588    elm_widget_sub_object_add(parent, obj);
589    elm_widget_data_set(obj, wd);
590    elm_widget_del_hook_set(obj, _del_hook);
591    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
592    elm_widget_theme_hook_set(obj, _theme_hook);
593    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
594    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
595    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
596    elm_widget_can_focus_set(obj, EINA_FALSE);
597
598    wd->indicator_disabled = EINA_FALSE;
599    wd->horizontal = EINA_FALSE;
600    wd->autohide_disabled = EINA_FALSE;
601
602    wd->base = edje_object_add(e);
603    _elm_theme_object_set(obj, wd->base, "index", "base/vertical", "default");
604    elm_widget_resize_object_set(obj, wd->base);
605
606    o = evas_object_rectangle_add(e);
607    wd->event[0] = o;
608    evas_object_color_set(o, 0, 0, 0, 0);
609    minw = minh = 0;
610    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
611    evas_object_size_hint_min_set(o, minw, minh);
612    edje_object_part_swallow(wd->base, "elm.swallow.event.0", o);
613    elm_widget_sub_object_add(obj, o);
614    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL, _wheel, obj);
615    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, obj);
616    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _mouse_up, obj);
617    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, obj);
618    evas_object_show(o);
619    if (edje_object_part_exists(wd->base, "elm.swallow.event.1"))
620      {
621         o = evas_object_rectangle_add(e);
622         wd->event[1] = o;
623         evas_object_color_set(o, 0, 0, 0, 0);
624         evas_object_size_hint_min_set(o, minw, minh);
625         edje_object_part_swallow(wd->base, "elm.swallow.event.1", o);
626         elm_widget_sub_object_add(obj, o);
627      }
628
629    wd->bx[0] = evas_object_box_add(e);
630    evas_object_box_layout_set(wd->bx[0], _layout, wd, NULL);
631    elm_widget_sub_object_add(obj, wd->bx[0]);
632    edje_object_part_swallow(wd->base, "elm.swallow.index.0", wd->bx[0]);
633    evas_object_show(wd->bx[0]);
634
635    if (edje_object_part_exists(wd->base, "elm.swallow.index.1"))
636      {
637         wd->bx[1] = evas_object_box_add(e);
638         evas_object_box_layout_set(wd->bx[1], _layout, wd, NULL);
639         elm_widget_sub_object_add(obj, wd->bx[1]);
640         edje_object_part_swallow(wd->base, "elm.swallow.index.1", wd->bx[1]);
641         evas_object_show(wd->bx[1]);
642      }
643
644    evas_object_smart_callbacks_descriptions_set(obj, _signals);
645
646    _mirrored_set(obj, elm_widget_mirrored_get(obj));
647    _sizing_eval(obj);
648    return obj;
649 }
650
651 EAPI void
652 elm_index_autohide_disabled_set(Evas_Object *obj, Eina_Bool disabled)
653 {
654    ELM_CHECK_WIDTYPE(obj, widtype);
655    Widget_Data *wd = elm_widget_data_get(obj);
656    if (!wd) return;
657    disabled = !!disabled;
658    if (wd->autohide_disabled == disabled) return;
659    wd->autohide_disabled = disabled;
660    wd->level = 0;
661    if (wd->autohide_disabled)
662      {
663         _index_box_clear(obj, wd->bx[1], 1);
664         _index_box_auto_fill(obj, wd->bx[0], 0);
665         edje_object_signal_emit(wd->base, "elm,state,active", "elm");
666      }
667    else
668      edje_object_signal_emit(wd->base, "elm,state,inactive", "elm");
669
670    //FIXME: Should be update indicator based on the indicator visiblility
671 }
672
673 EAPI Eina_Bool
674 elm_index_autohide_disabled_get(const Evas_Object *obj)
675 {
676    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
677    Widget_Data *wd = elm_widget_data_get(obj);
678    if (!wd) return EINA_FALSE;
679    return wd->autohide_disabled;
680 }
681
682 EAPI void
683 elm_index_item_level_set(Evas_Object *obj, int level)
684 {
685    ELM_CHECK_WIDTYPE(obj, widtype);
686    Widget_Data *wd = elm_widget_data_get(obj);
687    if (!wd) return;
688    if (wd->level == level) return;
689    wd->level = level;
690 }
691
692 EAPI int
693 elm_index_item_level_get(const Evas_Object *obj)
694 {
695    ELM_CHECK_WIDTYPE(obj, widtype) 0;
696    Widget_Data *wd = elm_widget_data_get(obj);
697    if (!wd) return 0;
698    return wd->level;
699 }
700
701 EAPI void
702 elm_index_item_selected_set(Elm_Object_Item *it, Eina_Bool selected)
703 {
704    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
705    Evas_Coord x, y, w, h;
706    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
707    if (!wd) return;
708
709    //FIXME: Should be update indicator based on the autohidden status & indicator visiblility
710
711    if (selected)
712      {
713         evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
714         _sel_eval(WIDGET(it), x + (w/2), y + (h/2));
715      }
716    else
717      _sel_eval(WIDGET(it), -99999, -9999);
718
719 }
720
721 EAPI Elm_Object_Item *
722 elm_index_selected_item_get(const Evas_Object *obj, int level)
723 {
724    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
725    Widget_Data *wd = elm_widget_data_get(obj);
726    Eina_List *l;
727    Elm_Index_Item *it;
728    if (!wd) return NULL;
729    EINA_LIST_FOREACH(wd->items, l, it)
730      {
731         if ((it->selected) && (it->level == level))
732           return (Elm_Object_Item *)it;
733      }
734    return NULL;
735 }
736
737 EAPI Elm_Object_Item *
738 elm_index_item_append(Evas_Object *obj, const char *letter, Evas_Smart_Cb func, const void *data)
739 {
740    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
741    Widget_Data *wd = elm_widget_data_get(obj);
742    Elm_Index_Item *it;
743    if (!wd) return NULL;
744    it = _item_new(obj, letter, func, data);
745    if (!it) return NULL;
746    wd->items = eina_list_append(wd->items, it);
747    _index_box_clear(obj, wd->bx[wd->level], wd->level);
748    return (Elm_Object_Item *)it;
749 }
750
751 EAPI Elm_Object_Item *
752 elm_index_item_prepend(Evas_Object *obj, const char *letter, Evas_Smart_Cb func, const void *data)
753 {
754    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
755    Widget_Data *wd = elm_widget_data_get(obj);
756    Elm_Index_Item *it;
757
758    if (!wd) return NULL;
759    it = _item_new(obj, letter, func, data);
760    if (!it) return NULL;
761    wd->items = eina_list_prepend(wd->items, it);
762    _index_box_clear(obj, wd->bx[wd->level], wd->level);
763    return (Elm_Object_Item *)it;
764 }
765
766 EINA_DEPRECATED EAPI Elm_Object_Item *
767 elm_index_item_prepend_relative(Evas_Object *obj, const char *letter, const void *item, const Elm_Object_Item *relative)
768 {
769    return elm_index_item_insert_before(obj, (Elm_Object_Item *) relative, letter, NULL, item);
770 }
771
772 EAPI Elm_Object_Item *
773 elm_index_item_insert_after(Evas_Object *obj, Elm_Object_Item *after, const char *letter, Evas_Smart_Cb func, const void *data)
774 {
775    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
776    Widget_Data *wd = elm_widget_data_get(obj);
777    Elm_Index_Item *it;
778    if (!wd) return NULL;
779    if (!after) return elm_index_item_append(obj, letter, func, data);
780    it = _item_new(obj, letter, func, data);
781    if (!it) return NULL;
782    wd->items = eina_list_append_relative(wd->items, it, after);
783    _index_box_clear(obj, wd->bx[wd->level], wd->level);
784    return (Elm_Object_Item *)it;
785 }
786
787 EAPI Elm_Object_Item *
788 elm_index_item_insert_before(Evas_Object *obj, Elm_Object_Item *before, const char *letter, Evas_Smart_Cb func, const void *data)
789 {
790    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
791    Widget_Data *wd = elm_widget_data_get(obj);
792    Elm_Index_Item *it;
793    if (!wd) return NULL;
794    if (!before) return elm_index_item_prepend(obj, letter, func, data);
795    it = _item_new(obj, letter, func, data);
796    if (!it) return NULL;
797    wd->items = eina_list_prepend_relative(wd->items, it, before);
798    _index_box_clear(obj, wd->bx[wd->level], wd->level);
799    return (Elm_Object_Item *)it;
800 }
801
802 EAPI Elm_Object_Item *
803 elm_index_item_sorted_insert(Evas_Object *obj, const char *letter, Evas_Smart_Cb func, const void *data, Eina_Compare_Cb cmp_func, Eina_Compare_Cb cmp_data_func)
804 {
805    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
806    Widget_Data *wd = elm_widget_data_get(obj);
807    Eina_List *lnear;
808    Elm_Index_Item *it;
809    int cmp;
810
811    if (!wd) return NULL;
812    if (!(wd->items))
813      return elm_index_item_append(obj, letter, func, data);
814
815    it = _item_new(obj, letter, func, data);
816    if (!it) return NULL;
817
818    lnear = eina_list_search_sorted_near_list(wd->items, cmp_func, it, &cmp);
819    if (cmp < 0)
820      wd->items =  eina_list_append_relative_list(wd->items, it, lnear);
821    else if (cmp > 0)
822      wd->items = eina_list_prepend_relative_list(wd->items, it, lnear);
823    else
824      {
825         /* If cmp_data_func is not provided, append a duplicated item */
826         if (!cmp_data_func)
827           wd->items =  eina_list_append_relative_list(wd->items, it, lnear);
828         else
829           {
830              Elm_Index_Item *p_it = eina_list_data_get(lnear);
831              if (cmp_data_func(p_it->base.data, it->base.data) >= 0)
832                p_it->base.data = it->base.data;
833              _item_free(it);
834              elm_widget_item_free(it);
835           }
836      }
837    _index_box_clear(obj, wd->bx[wd->level], wd->level);
838    return (Elm_Object_Item *)it;
839 }
840
841 EAPI Elm_Object_Item *
842 elm_index_item_find(Evas_Object *obj, const void *data)
843 {
844    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
845    Widget_Data *wd = elm_widget_data_get(obj);
846    if (!wd) return NULL;
847    return (Elm_Object_Item *) _item_find(obj, data);
848 }
849
850 EAPI void
851 elm_index_item_clear(Evas_Object *obj)
852 {
853    ELM_CHECK_WIDTYPE(obj, widtype);
854    Widget_Data *wd = elm_widget_data_get(obj);
855    Elm_Index_Item *it;
856    Eina_List *l, *clear = NULL;
857    if (!wd) return;
858    _index_box_clear(obj, wd->bx[wd->level], wd->level);
859    EINA_LIST_FOREACH(wd->items, l, it)
860      {
861         if (it->level != wd->level) continue;
862         clear = eina_list_append(clear, it);
863      }
864    EINA_LIST_FREE(clear, it)
865      {
866         _item_free(it);
867         elm_widget_item_free(it);
868      }
869 }
870
871 EAPI void
872 elm_index_level_go(Evas_Object *obj, int level __UNUSED__)
873 {
874    ELM_CHECK_WIDTYPE(obj, widtype);
875    Widget_Data *wd = elm_widget_data_get(obj);
876    if (!wd) return;
877    _index_box_auto_fill(obj, wd->bx[0], 0);
878    if (wd->level == 1) _index_box_auto_fill(obj, wd->bx[1], 1);
879 }
880
881 EAPI void
882 elm_index_indicator_disabled_set(Evas_Object *obj, Eina_Bool disabled)
883 {
884    ELM_CHECK_WIDTYPE(obj, widtype);
885    Widget_Data *wd = elm_widget_data_get(obj);
886    if (!wd) return;
887
888    disabled = !!disabled;
889    if (wd->indicator_disabled == disabled) return;
890    wd->indicator_disabled = disabled;
891    if (!wd->items) return;
892    if (disabled)
893      edje_object_signal_emit(wd->base, "elm,indicator,state,inactive", "elm");
894    else
895      edje_object_signal_emit(wd->base, "elm,indicator,state,active", "elm");
896 }
897
898 EAPI Eina_Bool
899 elm_index_indicator_disabled_get(const Evas_Object *obj)
900 {
901    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
902    Widget_Data *wd = elm_widget_data_get(obj);
903    if (!wd) return EINA_FALSE;
904
905    return wd->indicator_disabled;
906 }
907
908 EAPI const char *
909 elm_index_item_letter_get(const Elm_Object_Item *it)
910 {
911    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
912    return ((Elm_Index_Item *)it)->letter;
913 }
914
915 EAPI void
916 elm_index_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
917 {
918    ELM_CHECK_WIDTYPE(obj, widtype);
919    Widget_Data *wd = elm_widget_data_get(obj);
920    if (!wd) return;
921
922    horizontal = !!horizontal;
923    if (horizontal == wd->horizontal) return;
924    wd->horizontal = horizontal;
925    _theme_hook(obj);
926 }
927
928 EAPI Eina_Bool
929 elm_index_horizontal_get(const Evas_Object *obj)
930 {
931    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
932    Widget_Data *wd = elm_widget_data_get(obj);
933    if (!wd) return EINA_FALSE;
934    return wd->horizontal;
935 }