elm: Set timer/animator to NULL after they're deleted.
[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         o = edje_object_add(evas_object_evas_get(obj));
270         VIEW(it) = o;
271         edje_object_mirrored_set(VIEW(it), rtl);
272
273         if (wd->horizontal)
274           {
275              if (i & 0x1)
276                _elm_theme_object_set(obj, o, "index", "item_odd/horizontal",
277                                      elm_widget_style_get(obj));
278              else
279                _elm_theme_object_set(obj, o, "index", "item/horizontal",
280                                      elm_widget_style_get(obj));
281           }
282         else
283           {
284              if (i & 0x1)
285                _elm_theme_object_set(obj, o, "index", "item_odd/vertical",
286                                      elm_widget_style_get(obj));
287              else
288                _elm_theme_object_set(obj, o, "index", "item/vertical",
289                                      elm_widget_style_get(obj));
290           }
291
292         edje_object_part_text_set(o, "elm.text", it->letter);
293         edje_object_size_min_restricted_calc(o, &mw, &mh, 0, 0);
294         evas_object_size_hint_min_set(o, mw, mh);
295         evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
296         evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
297         elm_widget_sub_object_add(obj, o);
298         evas_object_box_append(box, o);
299         stacking = edje_object_data_get(o, "stacking");
300         if (stacking)
301           {
302              if (!strcmp(stacking, "below")) evas_object_lower(o);
303              else if (!strcmp(stacking, "above")) evas_object_raise(o);
304           }
305         evas_object_show(o);
306         i++;
307         evas_object_smart_calculate(box); // force a calc so we know the size
308         evas_object_size_hint_min_get(box, &mw, &mh);
309         if (mh > h)
310           {
311              _index_box_clear(obj, box, level);
312              if (i > 0)
313                {
314                   // FIXME: only i objects fit! try again. overflows right now
315                }
316           }
317      }
318    evas_object_smart_calculate(box);
319    wd->level_active[level] = 1;
320 }
321
322 static void
323 _index_box_clear(Evas_Object *obj, Evas_Object *box __UNUSED__, int level)
324 {
325    Widget_Data *wd = elm_widget_data_get(obj);
326    Eina_List *l;
327    Elm_Index_Item *it;
328    if (!wd) return;
329    if (!wd->level_active[level]) return;
330    EINA_LIST_FOREACH(wd->items, l, it)
331      {
332         if (!VIEW(it)) continue;
333         if (it->level != level) continue;
334         evas_object_del(VIEW(it));
335         VIEW(it) = NULL;
336      }
337    wd->level_active[level] = 0;
338 }
339
340 static Eina_Bool
341 _delay_change(void *data)
342 {
343    Widget_Data *wd = elm_widget_data_get(data);
344    Elm_Object_Item *item;
345    if (!wd) return ECORE_CALLBACK_CANCEL;
346    wd->delay = NULL;
347    item = elm_index_selected_item_get(data, wd->level);
348    if (item) evas_object_smart_callback_call(data, SIG_DELAY_CHANGED, item);
349    return ECORE_CALLBACK_CANCEL;
350 }
351
352 static void
353 _sel_eval(Evas_Object *obj, Evas_Coord evx, Evas_Coord evy)
354 {
355    Widget_Data *wd = elm_widget_data_get(obj);
356    Elm_Index_Item *it, *it_closest, *it_last;
357    Eina_List *l;
358    Evas_Coord x, y, w, h, bx, by, bw, bh, xx, yy;
359    double cdv = 0.5;
360    Evas_Coord dist;
361    char *label = NULL, *last = NULL;
362    int i;
363    if (!wd) return;
364    for (i = 0; i <= wd->level; i++)
365      {
366         it_last = NULL;
367         it_closest  = NULL;
368         dist = 0x7fffffff;
369         evas_object_geometry_get(wd->bx[i], &bx, &by, &bw, &bh);
370         EINA_LIST_FOREACH(wd->items, l, it)
371           {
372              if (it->level != i) continue;
373              if (it->level != wd->level)
374                {
375                   if (it->selected)
376                     {
377                        it_closest = it;
378                        break;
379                     }
380                   continue;
381                }
382              if (it->selected)
383                {
384                   it_last = it;
385                   it->selected = 0;
386                }
387              evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
388              xx = x + (w / 2);
389              yy = y + (h / 2);
390              x = evx - xx;
391              y = evy - yy;
392              x = (x * x) + (y * y);
393              if ((x < dist) || (!it_closest))
394                {
395                   if (wd->horizontal)
396                     cdv = (double)(xx - bx) / (double)bw;
397                   else
398                     cdv = (double)(yy - by) / (double)bh;
399                   it_closest = it;
400                   dist = x;
401                }
402           }
403         if ((i == 0) && (wd->level == 0))
404           edje_object_part_drag_value_set(wd->base, "elm.dragable.index.1",
405                                           cdv, cdv);
406         if (it_closest) it_closest->selected = 1;
407         if (it_closest != it_last)
408           {
409              if (it_last)
410                {
411                   const char *stacking, *selectraise;
412
413                   it = it_last;
414                   edje_object_signal_emit(VIEW(it), "elm,state,inactive", "elm");
415                   stacking = edje_object_data_get(VIEW(it), "stacking");
416                   selectraise = edje_object_data_get(VIEW(it), "selectraise");
417                   if ((selectraise) && (!strcmp(selectraise, "on")))
418                     {
419                        if ((stacking) && (!strcmp(stacking, "below")))
420                          evas_object_lower(VIEW(it));
421                     }
422                }
423              if (it_closest)
424                {
425                   const char *selectraise;
426
427                   it = it_closest;
428                   edje_object_signal_emit(VIEW(it), "elm,state,active", "elm");
429                   selectraise = edje_object_data_get(VIEW(it), "selectraise");
430                   if ((selectraise) && (!strcmp(selectraise, "on")))
431                     evas_object_raise(VIEW(it));
432                   evas_object_smart_callback_call((void *)obj, SIG_CHANGED, (void *)it);
433                   if (wd->delay) ecore_timer_del(wd->delay);
434                   wd->delay = ecore_timer_add(0.2, _delay_change, obj);
435                }
436           }
437         if (it_closest)
438           {
439              it = it_closest;
440              if (!last && it->letter)
441                last = strdup(it->letter);
442              else
443                {
444                   if (!label && last) label = strdup(last);
445                   else
446                     {
447                        if (label && last)
448                          {
449                             label = realloc(label, strlen(label) +
450                                             strlen(last) + 1);
451                             if (!label) return;
452                             strcat(label, last);
453                          }
454                     }
455                   free(last);
456                   if (it->letter) last = strdup(it->letter);
457                }
458           }
459      }
460    if (!label) label = strdup("");
461    if (!last) last = strdup("");
462    edje_object_part_text_set(wd->base, "elm.text.body", label);
463    edje_object_part_text_set(wd->base, "elm.text", last);
464    free(label);
465    free(last);
466 }
467
468 static void
469 _wheel(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
470 {
471    Widget_Data *wd = elm_widget_data_get(data);
472    //   Evas_Event_Mouse_Wheel *ev = event_info;
473    //   Evas_Object *obj = o;
474    if (!wd) return;
475 }
476
477 static void
478 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
479 {
480    Widget_Data *wd = elm_widget_data_get(data);
481    Evas_Event_Mouse_Down *ev = event_info;
482    Evas_Coord x, y, w;
483    if (!wd) return;
484    if (ev->button != 1) return;
485    wd->down = 1;
486    evas_object_geometry_get(wd->base, &x, &y, &w, NULL);
487    wd->dx = ev->canvas.x - x;
488    wd->dy = ev->canvas.y - y;
489    if (!wd->autohide_disabled)
490      {
491         _index_box_clear(data, wd->bx[1], 1);
492         _index_box_auto_fill(data, wd->bx[0], 0);
493         edje_object_signal_emit(wd->base, "elm,state,active", "elm");
494      }
495    _sel_eval(data, ev->canvas.x, ev->canvas.y);
496    edje_object_part_drag_value_set(wd->base, "elm.dragable.pointer",
497                                    (!edje_object_mirrored_get(wd->base)) ? wd->dx : (wd->dx - w), wd->dy);
498    if (wd->items && !wd->indicator_disabled)
499      edje_object_signal_emit(wd->base, "elm,indicator,state,active", "elm");
500 }
501
502 static void
503 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
504 {
505    Widget_Data *wd = elm_widget_data_get(data);
506    Evas_Event_Mouse_Up *ev = event_info;
507    Elm_Object_Item *item;
508    Elm_Index_Item *id_item;
509    if (!wd) return;
510    if (ev->button != 1) return;
511    wd->down = 0;
512    item = elm_index_selected_item_get(data, wd->level);
513    if (item)
514      {
515         evas_object_smart_callback_call(data, SIG_SELECTED, item);
516         id_item = (Elm_Index_Item *)item;
517         if (id_item->func)
518           id_item->func((void *)id_item->base.data, WIDGET(id_item), id_item);
519      }
520    if (!wd->autohide_disabled)
521      edje_object_signal_emit(wd->base, "elm,state,inactive", "elm");
522    edje_object_signal_emit(wd->base, "elm,state,level,0", "elm");
523    if (wd->items && !wd->indicator_disabled)
524      edje_object_signal_emit(wd->base, "elm,indicator,state,inactive", "elm");
525 }
526
527 static void
528 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
529 {
530    Widget_Data *wd = elm_widget_data_get(data);
531    Evas_Event_Mouse_Move *ev = event_info;
532    Evas_Coord minw = 0, minh = 0, x, y, dx, adx, w;
533    char buf[1024];
534    if (!wd) return;
535    if (!wd->down) return;
536    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
537    evas_object_geometry_get(wd->base, &x, &y, &w, NULL);
538    x = ev->cur.canvas.x - x;
539    y = ev->cur.canvas.y - y;
540    dx = x - wd->dx;
541    adx = dx;
542    if (adx < 0) adx = -dx;
543    edje_object_part_drag_value_set(wd->base, "elm.dragable.pointer"
544                                    , (!edje_object_mirrored_get(wd->base)) ? x : (x - w), y);
545    if (!wd->horizontal)
546      {
547         if (adx > minw)
548           {
549              if (!wd->level)
550                {
551                   wd->level = 1;
552                   snprintf(buf, sizeof(buf), "elm,state,level,%i", wd->level);
553                   edje_object_signal_emit(wd->base, buf, "elm");
554                   evas_object_smart_callback_call(data, SIG_LEVEL_UP, NULL);
555                }
556           }
557         else
558           {
559              if (wd->level == 1)
560                {
561                   wd->level = 0;
562                   snprintf(buf, sizeof(buf), "elm,state,level,%i", wd->level);
563                   edje_object_signal_emit(wd->base, buf, "elm");
564                   evas_object_smart_callback_call(data, SIG_LEVEL_DOWN, NULL);
565                }
566           }
567      }
568    _sel_eval(data, ev->cur.canvas.x, ev->cur.canvas.y);
569 }
570
571 EAPI Evas_Object *
572 elm_index_add(Evas_Object *parent)
573 {
574    Evas_Object *obj;
575    Evas_Object *o;
576    Evas *e;
577    Widget_Data *wd;
578    Evas_Coord minw, minh;
579
580    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
581
582    ELM_SET_WIDTYPE(widtype, "index");
583    elm_widget_type_set(obj, "index");
584    elm_widget_sub_object_add(parent, obj);
585    elm_widget_data_set(obj, wd);
586    elm_widget_del_hook_set(obj, _del_hook);
587    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
588    elm_widget_theme_hook_set(obj, _theme_hook);
589    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
590    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
591    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
592    elm_widget_can_focus_set(obj, EINA_FALSE);
593
594    wd->indicator_disabled = EINA_FALSE;
595    wd->horizontal = EINA_FALSE;
596    wd->autohide_disabled = EINA_FALSE;
597
598    wd->base = edje_object_add(e);
599    _elm_theme_object_set(obj, wd->base, "index", "base/vertical", "default");
600    elm_widget_resize_object_set(obj, wd->base);
601
602    o = evas_object_rectangle_add(e);
603    wd->event[0] = o;
604    evas_object_color_set(o, 0, 0, 0, 0);
605    minw = minh = 0;
606    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
607    evas_object_size_hint_min_set(o, minw, minh);
608    edje_object_part_swallow(wd->base, "elm.swallow.event.0", o);
609    elm_widget_sub_object_add(obj, o);
610    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL, _wheel, obj);
611    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, obj);
612    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _mouse_up, obj);
613    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, obj);
614    evas_object_show(o);
615    if (edje_object_part_exists(wd->base, "elm.swallow.event.1"))
616      {
617         o = evas_object_rectangle_add(e);
618         wd->event[1] = o;
619         evas_object_color_set(o, 0, 0, 0, 0);
620         evas_object_size_hint_min_set(o, minw, minh);
621         edje_object_part_swallow(wd->base, "elm.swallow.event.1", o);
622         elm_widget_sub_object_add(obj, o);
623      }
624
625    wd->bx[0] = evas_object_box_add(e);
626    evas_object_box_layout_set(wd->bx[0], _layout, wd, NULL);
627    elm_widget_sub_object_add(obj, wd->bx[0]);
628    edje_object_part_swallow(wd->base, "elm.swallow.index.0", wd->bx[0]);
629    evas_object_show(wd->bx[0]);
630
631    if (edje_object_part_exists(wd->base, "elm.swallow.index.1"))
632      {
633         wd->bx[1] = evas_object_box_add(e);
634         evas_object_box_layout_set(wd->bx[1], _layout, wd, NULL);
635         elm_widget_sub_object_add(obj, wd->bx[1]);
636         edje_object_part_swallow(wd->base, "elm.swallow.index.1", wd->bx[1]);
637         evas_object_show(wd->bx[1]);
638      }
639
640    evas_object_smart_callbacks_descriptions_set(obj, _signals);
641
642    _mirrored_set(obj, elm_widget_mirrored_get(obj));
643    _sizing_eval(obj);
644    return obj;
645 }
646
647 EAPI void
648 elm_index_autohide_disabled_set(Evas_Object *obj, Eina_Bool disabled)
649 {
650    ELM_CHECK_WIDTYPE(obj, widtype);
651    Widget_Data *wd = elm_widget_data_get(obj);
652    if (!wd) return;
653    disabled = !!disabled;
654    if (wd->autohide_disabled == disabled) return;
655    wd->autohide_disabled = disabled;
656    wd->level = 0;
657    if (wd->autohide_disabled)
658      {
659         _index_box_clear(obj, wd->bx[1], 1);
660         _index_box_auto_fill(obj, wd->bx[0], 0);
661         edje_object_signal_emit(wd->base, "elm,state,active", "elm");
662      }
663    else
664      edje_object_signal_emit(wd->base, "elm,state,inactive", "elm");
665
666    //FIXME: Should be update indicator based on the indicator visiblility
667 }
668
669 EAPI Eina_Bool
670 elm_index_autohide_disabled_get(const Evas_Object *obj)
671 {
672    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
673    Widget_Data *wd = elm_widget_data_get(obj);
674    if (!wd) return EINA_FALSE;
675    return wd->autohide_disabled;
676 }
677
678 EAPI void
679 elm_index_item_level_set(Evas_Object *obj, int level)
680 {
681    ELM_CHECK_WIDTYPE(obj, widtype);
682    Widget_Data *wd = elm_widget_data_get(obj);
683    if (!wd) return;
684    if (wd->level == level) return;
685    wd->level = level;
686 }
687
688 EAPI int
689 elm_index_item_level_get(const Evas_Object *obj)
690 {
691    ELM_CHECK_WIDTYPE(obj, widtype) 0;
692    Widget_Data *wd = elm_widget_data_get(obj);
693    if (!wd) return 0;
694    return wd->level;
695 }
696
697 EAPI void
698 elm_index_item_selected_set(Elm_Object_Item *it, Eina_Bool selected)
699 {
700    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
701    Evas_Coord x, y, w, h;
702    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
703    if (!wd) return;
704
705    //FIXME: Should be update indicator based on the autohidden status & indicator visiblility
706
707    if (selected)
708      {
709         evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
710         _sel_eval(WIDGET(it), x + (w/2), y + (h/2));
711      }
712    else
713      _sel_eval(WIDGET(it), -99999, -9999);
714
715 }
716
717 EAPI Elm_Object_Item *
718 elm_index_selected_item_get(const Evas_Object *obj, int level)
719 {
720    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
721    Widget_Data *wd = elm_widget_data_get(obj);
722    Eina_List *l;
723    Elm_Index_Item *it;
724    if (!wd) return NULL;
725    EINA_LIST_FOREACH(wd->items, l, it)
726      {
727         if ((it->selected) && (it->level == level))
728           return (Elm_Object_Item *)it;
729      }
730    return NULL;
731 }
732
733 EAPI Elm_Object_Item *
734 elm_index_item_append(Evas_Object *obj, const char *letter, Evas_Smart_Cb func, const void *data)
735 {
736    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
737    Widget_Data *wd = elm_widget_data_get(obj);
738    Elm_Index_Item *it;
739    if (!wd) return NULL;
740    it = _item_new(obj, letter, func, data);
741    if (!it) return NULL;
742    wd->items = eina_list_append(wd->items, it);
743    _index_box_clear(obj, wd->bx[wd->level], wd->level);
744    return (Elm_Object_Item *)it;
745 }
746
747 EAPI Elm_Object_Item *
748 elm_index_item_prepend(Evas_Object *obj, const char *letter, Evas_Smart_Cb func, const void *data)
749 {
750    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
751    Widget_Data *wd = elm_widget_data_get(obj);
752    Elm_Index_Item *it;
753
754    if (!wd) return NULL;
755    it = _item_new(obj, letter, func, data);
756    if (!it) return NULL;
757    wd->items = eina_list_prepend(wd->items, it);
758    _index_box_clear(obj, wd->bx[wd->level], wd->level);
759    return (Elm_Object_Item *)it;
760 }
761
762 EINA_DEPRECATED EAPI Elm_Object_Item *
763 elm_index_item_prepend_relative(Evas_Object *obj, const char *letter, const void *item, const Elm_Object_Item *relative)
764 {
765    return elm_index_item_insert_before(obj, (Elm_Object_Item *) relative, letter, NULL, item);
766 }
767
768 EAPI Elm_Object_Item *
769 elm_index_item_insert_after(Evas_Object *obj, Elm_Object_Item *after, const char *letter, Evas_Smart_Cb func, const void *data)
770 {
771    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
772    Widget_Data *wd = elm_widget_data_get(obj);
773    Elm_Index_Item *it;
774    if (!wd) return NULL;
775    if (!after) return elm_index_item_append(obj, letter, func, data);
776    it = _item_new(obj, letter, func, data);
777    if (!it) return NULL;
778    wd->items = eina_list_append_relative(wd->items, it, after);
779    _index_box_clear(obj, wd->bx[wd->level], wd->level);
780    return (Elm_Object_Item *)it;
781 }
782
783 EAPI Elm_Object_Item *
784 elm_index_item_insert_before(Evas_Object *obj, Elm_Object_Item *before, const char *letter, Evas_Smart_Cb func, const void *data)
785 {
786    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
787    Widget_Data *wd = elm_widget_data_get(obj);
788    Elm_Index_Item *it;
789    if (!wd) return NULL;
790    if (!before) return elm_index_item_prepend(obj, letter, func, data);
791    it = _item_new(obj, letter, func, data);
792    if (!it) return NULL;
793    wd->items = eina_list_prepend_relative(wd->items, it, before);
794    _index_box_clear(obj, wd->bx[wd->level], wd->level);
795    return (Elm_Object_Item *)it;
796 }
797
798 EAPI Elm_Object_Item *
799 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)
800 {
801    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
802    Widget_Data *wd = elm_widget_data_get(obj);
803    Eina_List *lnear;
804    Elm_Index_Item *it;
805    int cmp;
806
807    if (!wd) return NULL;
808    if (!(wd->items))
809      return elm_index_item_append(obj, letter, func, data);
810
811    it = _item_new(obj, letter, func, data);
812    if (!it) return NULL;
813
814    lnear = eina_list_search_sorted_near_list(wd->items, cmp_func, it, &cmp);
815    if (cmp < 0)
816      wd->items =  eina_list_append_relative_list(wd->items, it, lnear);
817    else if (cmp > 0)
818      wd->items = eina_list_prepend_relative_list(wd->items, it, lnear);
819    else
820      {
821         /* If cmp_data_func is not provided, append a duplicated item */
822         if (!cmp_data_func)
823           wd->items =  eina_list_append_relative_list(wd->items, it, lnear);
824         else
825           {
826              Elm_Index_Item *p_it = eina_list_data_get(lnear);
827              if (cmp_data_func(p_it->base.data, it->base.data) >= 0)
828                p_it->base.data = it->base.data;
829              _item_free(it);
830              elm_widget_item_free(it);
831           }
832      }
833    _index_box_clear(obj, wd->bx[wd->level], wd->level);
834    return (Elm_Object_Item *)it;
835 }
836
837 EAPI Elm_Object_Item *
838 elm_index_item_find(Evas_Object *obj, const void *data)
839 {
840    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
841    Widget_Data *wd = elm_widget_data_get(obj);
842    if (!wd) return NULL;
843    return (Elm_Object_Item *) _item_find(obj, data);
844 }
845
846 EAPI void
847 elm_index_item_clear(Evas_Object *obj)
848 {
849    ELM_CHECK_WIDTYPE(obj, widtype);
850    Widget_Data *wd = elm_widget_data_get(obj);
851    Elm_Index_Item *it;
852    Eina_List *l, *clear = NULL;
853    if (!wd) return;
854    _index_box_clear(obj, wd->bx[wd->level], wd->level);
855    EINA_LIST_FOREACH(wd->items, l, it)
856      {
857         if (it->level != wd->level) continue;
858         clear = eina_list_append(clear, it);
859      }
860    EINA_LIST_FREE(clear, it)
861      {
862         _item_free(it);
863         elm_widget_item_free(it);
864      }
865 }
866
867 EAPI void
868 elm_index_level_go(Evas_Object *obj, int level __UNUSED__)
869 {
870    ELM_CHECK_WIDTYPE(obj, widtype);
871    Widget_Data *wd = elm_widget_data_get(obj);
872    if (!wd) return;
873    _index_box_auto_fill(obj, wd->bx[0], 0);
874    if (wd->level == 1) _index_box_auto_fill(obj, wd->bx[1], 1);
875 }
876
877 EAPI void
878 elm_index_indicator_disabled_set(Evas_Object *obj, Eina_Bool disabled)
879 {
880    ELM_CHECK_WIDTYPE(obj, widtype);
881    Widget_Data *wd = elm_widget_data_get(obj);
882    if (!wd) return;
883
884    disabled = !!disabled;
885    if (wd->indicator_disabled == disabled) return;
886    wd->indicator_disabled = disabled;
887    if (!wd->items) return;
888    if (disabled)
889      edje_object_signal_emit(wd->base, "elm,indicator,state,inactive", "elm");
890    else
891      edje_object_signal_emit(wd->base, "elm,indicator,state,active", "elm");
892 }
893
894 EAPI Eina_Bool
895 elm_index_indicator_disabled_get(const Evas_Object *obj)
896 {
897    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
898    Widget_Data *wd = elm_widget_data_get(obj);
899    if (!wd) return EINA_FALSE;
900
901    return wd->indicator_disabled;
902 }
903
904 EAPI const char *
905 elm_index_item_letter_get(const Elm_Object_Item *it)
906 {
907    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
908    return ((Elm_Index_Item *)it)->letter;
909 }
910
911 EAPI void
912 elm_index_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
913 {
914    ELM_CHECK_WIDTYPE(obj, widtype);
915    Widget_Data *wd = elm_widget_data_get(obj);
916    if (!wd) return;
917
918    horizontal = !!horizontal;
919    if (horizontal == wd->horizontal) return;
920    wd->horizontal = horizontal;
921    _theme_hook(obj);
922 }
923
924 EAPI Eina_Bool
925 elm_index_horizontal_get(const Evas_Object *obj)
926 {
927    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
928    Widget_Data *wd = elm_widget_data_get(obj);
929    if (!wd) return EINA_FALSE;
930    return wd->horizontal;
931 }
932
933