elementary: Improve include file modularity
[framework/uifw/elementary.git] / src / lib / elm_index.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4 #include <Elementary.h>
5 #include "elm_priv.h"
6 #include "els_box.h"
7
8 /**
9  * @defgroup Index Index
10  * @ingroup Elementary
11  *
12  * An index object is a type of list that categorizes items in it
13  * by letter.
14  *
15  * Signals that you can add callbacks for are:
16  *
17  * "changed" - when the selected index item changes
18  * "delay,changed" - when the selected index item changes, but after some small i
19  *                   dle period
20  * "selected" - when the user releases a finger and selects an item
21  * "level,up" - when the user moves a finger from the first level to the second
22  *              level
23  * "level,down" - when the user moves a finger from the second level to the first
24  *                level
25  */
26
27 #define MIN_GRP_SIZE 2 //for symmetry it is 2, otherwise it can be 1 and zero have no meaning.
28 #define MIN_PIXEL_VALUE 1 //Min pixel value is highly dependent on touch sensitivity support.
29 #define MIN_OBJ_HEIGHT 24 //should be taken from .edc file.
30 /*
31  *  use for find view toplevel
32  */
33 #define SET_VIEW_LEVEL(wd, view_level)\
34    view_level = wd->level;\
35    while ((!wd->tot_items_count[view_level]) && view_level)\
36      {\
37         view_level--; \
38      }
39
40 typedef struct _Widget_Data Widget_Data;
41
42 typedef struct _PlacementPart PlacementPart;
43
44 struct _Widget_Data
45 {
46    Evas_Object *base;
47    Evas_Object *event[2];
48    Evas_Object *bx[2]; // 2 - for now all that's supported
49    Eina_List *items; // 1 list. yes N levels, but only 2 for now and # of items will be small
50    char *popup_str[2];
51    int level;
52    int max_supp_items_count;
53    int tot_items_count[2];
54    int min_obj_height, max_grp_size;
55    int min_1st_level_obj_height;
56    int items_count;
57    Evas_Coord dx, dy;
58    Evas_Coord pwidth, pheight;
59    Ecore_Timer *delay;
60    const char *special_char;
61    Eina_Bool level_active[2];
62    Eina_Bool horizontal : 1;
63    Eina_Bool active : 1;
64    Eina_Bool down : 1;
65    Eina_Bool hide_button : 1;
66    double scale_factor;
67 };
68
69 struct _Elm_Index_Item
70 {
71    Elm_Widget_Item base;
72    const char *letter, *vis_letter;
73    int level, size;
74    Eina_Bool selected : 1;
75 };
76
77 struct _PlacementPart
78 {
79    int start;
80    int count;
81 };
82
83 static const char *widtype = NULL;
84
85 static void _del_hook(Evas_Object *obj);
86 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
87 static void _theme_hook(Evas_Object *obj);
88 static void _sizing_eval(Evas_Object *obj);
89 static void _index_box_auto_fill(Evas_Object *obj, Evas_Object *box, int level);
90 static void _index_box_clear(Evas_Object *obj, Evas_Object *box, int level);
91 static void _item_free(Elm_Index_Item *it);
92 static void _index_process(Evas_Object *obj);
93
94 static const char SIG_CHANGED[] = "changed";
95 static const char SIG_DELAY_CHANGED[] = "delay,changed";
96 static const char SIG_SELECTED[] = "selected";
97 static const char SIG_LEVEL_UP[] = "level,up";
98 static const char SIG_LEVEL_DOWN[] = "level,down";
99
100 static const Evas_Smart_Cb_Description _signals[] = {
101    {SIG_CHANGED, ""},
102    {SIG_DELAY_CHANGED, ""},
103    {SIG_SELECTED, ""},
104    {SIG_LEVEL_UP, ""},
105    {SIG_LEVEL_DOWN, ""},
106    {NULL, NULL}
107 };
108 /* Free a block allocated by `malloc', `realloc' or `calloc' one by one*/
109 static void
110 _del_pre_hook(Evas_Object *obj)
111 {
112    Widget_Data *wd = elm_widget_data_get(obj);
113    if (!wd) return;
114    _index_box_clear(obj, wd->bx[wd->level], wd->level);
115    _index_box_clear(obj, wd->bx[0], 0);
116    while (wd->items) _item_free(wd->items->data);
117    if (wd->delay) ecore_timer_del(wd->delay);
118
119    if(wd->popup_str[0]) free(wd->popup_str[0]);
120    if(wd->popup_str[1]) free(wd->popup_str[1]);
121 }
122
123 static void
124 _del_hook(Evas_Object *obj)
125 {
126    Widget_Data *wd = elm_widget_data_get(obj);
127    free(wd);
128 }
129
130 static void
131 _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data)
132 {
133    Widget_Data *wd = data;
134    if (!wd) return;
135    _els_box_layout(o, priv, wd->horizontal, 0, 0);
136 }
137
138 static void
139 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
140 {
141    Widget_Data *wd = elm_widget_data_get(obj);
142    if (!wd) return;
143    edje_object_signal_emit(wd->base, emission, source);
144 }
145
146 static void
147 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
148 {
149    Widget_Data *wd = elm_widget_data_get(obj);
150    if (!wd) return;
151    edje_object_signal_callback_add(wd->base, emission, source, func_cb, data);
152 }
153
154 static void
155 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
156 {
157    Widget_Data *wd = elm_widget_data_get(obj);
158    edje_object_signal_callback_del_full(wd->base, emission, source, func_cb,
159                                         data);
160 }
161
162 static void
163 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
164 {
165    Widget_Data *wd = elm_widget_data_get(obj);
166    if (!wd) return;
167    if (!wd->horizontal)
168      edje_object_mirrored_set(wd->base, rtl);
169 }
170
171 static void
172 _theme_hook(Evas_Object *obj)
173 {
174    Evas_Coord minw = 0, minh = 0;
175    Widget_Data *wd = elm_widget_data_get(obj);
176    if (!wd) return;
177    _elm_widget_mirrored_reload(obj);
178
179    _index_box_clear(obj, wd->bx[0], 0);
180    _index_box_clear(obj, wd->bx[1], 1);
181    if (wd->horizontal)
182      _elm_theme_object_set(obj, wd->base, "index", "base/horizontal", elm_widget_style_get(obj));
183    else
184      {
185         _elm_theme_object_set(obj, wd->base, "index", "base/vertical", elm_widget_style_get(obj));
186         _mirrored_set(obj, elm_widget_mirrored_get(obj));
187      }
188    edje_object_part_swallow(wd->base, "elm.swallow.event.0", wd->event[0]);
189    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
190    evas_object_size_hint_min_set(wd->event[0], minw, minh);
191
192    edje_object_part_swallow(wd->base, "elm.swallow.index.0", wd->bx[0]);
193    if (edje_object_part_exists(wd->base, "elm.swallow.index.1"))
194      {
195         if (!wd->bx[1])
196           {
197              wd->bx[1] = evas_object_box_add(evas_object_evas_get(wd->base));
198              evas_object_box_layout_set(wd->bx[1], _layout, wd, NULL);
199              elm_widget_sub_object_add(obj, wd->bx[1]);
200           }
201         edje_object_part_swallow(wd->base, "elm.swallow.index.1", wd->bx[1]);
202         evas_object_show(wd->bx[1]);
203      }
204    else if (wd->bx[1])
205      {
206         evas_object_del(wd->bx[1]);
207         wd->bx[1] = NULL;
208      }
209    if (edje_object_part_exists(wd->base, "elm.swallow.event.1"))
210      {
211         if (!wd->event[1])
212           {
213              wd->event[1] = evas_object_rectangle_add(evas_object_evas_get(wd->base));
214              evas_object_color_set(wd->event[1], 0, 0, 0, 0);
215              elm_widget_sub_object_add(obj, wd->event[1]);
216           }
217         edje_object_part_swallow(wd->base, "elm.swallow.event.1", wd->event[1]);
218         evas_object_size_hint_min_set(wd->event[1], minw, minh);
219      }
220    else if (wd->event[1])
221      {
222         evas_object_del(wd->event[1]);
223         wd->event[1] = NULL;
224      }
225    edje_object_message_signal_process(wd->base);
226    edje_object_scale_set(wd->base, elm_widget_scale_get(obj) * _elm_config->scale);
227    _sizing_eval(obj);
228    _index_box_auto_fill(obj, wd->bx[0], 0);
229    if (wd->active)
230      if (wd->level == 1)
231        _index_box_auto_fill(obj, wd->bx[1], 1);
232 }
233
234 static void
235 _sizing_eval(Evas_Object *obj)
236 {
237    Widget_Data *wd = elm_widget_data_get(obj);
238    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
239    if (!wd) return;
240    edje_object_size_min_calc(wd->base, &minw, &minh);
241    evas_object_size_hint_min_set(obj, minw, minh);
242    evas_object_size_hint_max_set(obj, maxw, maxh);
243 }
244
245 static Elm_Index_Item *
246 _item_new(Evas_Object *obj, const char *letter, const void *item)
247 {
248    Widget_Data *wd = elm_widget_data_get(obj);
249    Elm_Index_Item *it;
250    if (!wd) return NULL;
251    it = elm_widget_item_new(obj, Elm_Index_Item);
252    if (!it) return NULL;
253    it->base.data = item;
254    it->level = wd->level;
255    if(wd->level == 0)
256      it->size =  wd->min_obj_height;
257    else
258      it->size =  wd->min_1st_level_obj_height;
259    if(letter)
260      {
261         it->letter = eina_stringshare_add(letter);
262         it->vis_letter = eina_stringshare_add(letter);
263      }
264    else
265      {
266         _item_free(it);
267         return NULL;
268      }
269    return it;
270 }
271
272 static Elm_Index_Item *
273 _item_find(Evas_Object *obj, const void *item)
274 {
275    Widget_Data *wd = elm_widget_data_get(obj);
276    Eina_List *l;
277    Elm_Index_Item *it;
278    if (!wd) return NULL;
279    EINA_LIST_FOREACH(wd->items, l, it)
280       if (it->base.data == item) return it;
281    return NULL;
282 }
283
284 static void
285 _item_free(Elm_Index_Item *it)
286 {
287 /* Automatically filling the box with index item*/
288    Widget_Data *wd = elm_widget_data_get(it->base.widget);
289    if (!wd) return;
290
291    wd->items = eina_list_remove(wd->items, it);
292    elm_widget_item_pre_notify_del(it);
293    eina_stringshare_del(it->letter);
294    eina_stringshare_del(it->vis_letter);
295    elm_widget_item_del(it);
296 }
297
298 // FIXME: always have index filled
299 static void
300 _index_box_auto_fill(Evas_Object *obj, Evas_Object *box, int level)
301 {
302    Widget_Data *wd = elm_widget_data_get(obj);
303    Eina_Bool rtl;
304    Eina_List *l;
305    Elm_Index_Item *it;
306    Evas_Coord mw, mh, w, h;
307    int i = 0;
308    if (!wd) return;
309    if (wd->level_active[level]) return;
310    rtl = elm_widget_mirrored_get(obj);
311    evas_object_geometry_get(box, NULL, NULL, &w, &h);
312    EINA_LIST_FOREACH(wd->items, l, it)
313      {
314         Evas_Object *o;
315         const char *stacking;
316
317         if (it->level != level) continue;
318         if(i > wd->max_supp_items_count) break;
319
320         o = edje_object_add(evas_object_evas_get(obj));
321         it->base.view = o;
322         edje_object_mirrored_set(it->base.view, rtl);
323         if (i & 0x1)
324           _elm_theme_object_set(obj, o, "index", "item_odd/vertical", elm_widget_style_get(obj));
325         else
326           _elm_theme_object_set(obj, o, "index", "item/vertical", elm_widget_style_get(obj));
327         edje_object_part_text_set(o, "elm.text", it->letter);
328         edje_object_size_min_restricted_calc(o, &mw, &mh, 0, 0);
329         evas_object_size_hint_min_set(o, mw, mh);
330         evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
331         evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
332         edje_object_part_text_set(o, "elm.text", it->vis_letter);
333         evas_object_size_hint_min_set(o, mw, it->size);
334         evas_object_size_hint_max_set(o, mw, it->size);
335         evas_object_resize(o, mw, it->size);
336
337         elm_widget_sub_object_add(obj, o);
338         evas_object_box_append(box, o);
339         stacking = edje_object_data_get(o, "stacking");
340         if (stacking)
341           {
342              if (!strcmp(stacking, "below")) evas_object_lower(o);
343              else if (!strcmp(stacking, "above")) evas_object_raise(o);
344           }
345         evas_object_show(o);
346         i++;
347         if(level == 1)
348           wd->tot_items_count[1] = i;
349         evas_object_smart_calculate(box); // force a calc so we know the size
350         evas_object_size_hint_min_get(box, &mw, &mh);
351         if (mh > h)
352           {
353              _index_box_clear(obj, box, level);
354              if (i > 0)
355                {
356                   // FIXME: only i objects fit! try again. overflows right now
357                }
358           }
359      }
360    evas_object_smart_calculate(box);
361    wd->level_active[level] = 1;
362 }
363
364 static void
365 _index_box_clear(Evas_Object *obj, Evas_Object *box __UNUSED__, int level)
366 {
367    Widget_Data *wd = elm_widget_data_get(obj);
368    Eina_List *l;
369    Elm_Index_Item *it;
370    if (!wd) return;
371    if (!wd->level_active[level]) return;
372    EINA_LIST_FOREACH(wd->items, l, it)
373      {
374         if (!it->base.view) continue;
375         if (it->level != level) continue;
376         evas_object_del(it->base.view);
377         it->base.view = NULL;
378      }
379    wd->level_active[level] = 0;
380 }
381
382 static Eina_Bool
383 _delay_change(void *data)
384 {
385    Widget_Data *wd = elm_widget_data_get(data);
386    void *d;
387    int view_level;
388    if (!wd) return ECORE_CALLBACK_CANCEL;
389    wd->delay = NULL;
390    SET_VIEW_LEVEL(wd, view_level);
391    d = (void *)elm_index_item_selected_get(data, view_level);
392    if (d) evas_object_smart_callback_call(data, "delay,changed", d);
393    return ECORE_CALLBACK_CANCEL;
394 }
395
396 static void
397 _sel_eval(Evas_Object *obj, Evas_Coord evx, Evas_Coord evy)
398 {
399    Widget_Data *wd = elm_widget_data_get(obj);
400    Elm_Index_Item *it, *it_closest, *it_last;
401    Eina_List *l;
402    Evas_Coord x, y, w, h, bx, by, bw, bh, xx, yy;
403    double cdv = 0.5;
404    double cdvv = 0.0;
405    double dmax = 0.0;
406    double dmin = 0.0;
407    Evas_Coord dist;
408    Eina_Bool change = EINA_FALSE;
409    char *label = NULL, *last = NULL;
410    int i;
411    int view_level;
412    if (!wd) return;
413
414    SET_VIEW_LEVEL(wd, view_level);
415    for (i = 0; i <= view_level; i++)
416      {
417         it_last = NULL;
418         it_closest  = NULL;
419         dist = 0x7fffffff;
420         evas_object_geometry_get(wd->bx[i], &bx, &by, &bw, &bh);
421         dmin = (double)(wd->min_1st_level_obj_height*wd->tot_items_count[1])/(2*(double)bh);
422         dmax = 1.0-dmin-0.08;
423         EINA_LIST_FOREACH(wd->items, l, it)
424           {
425              if (!((it->level == i) && (it->base.view))) continue;
426              if (it->selected)
427                {
428                   it_last = it;
429                   it->selected = 0;
430                }
431              evas_object_geometry_get(it->base.view, &x, &y, &w, &h);
432              xx = x + (w / 2);
433              yy = y + (h / 2);
434              x = evx - xx;
435              y = evy - yy;
436              x = (x * x) + (y * y);
437              if ((x < dist) || (!it_closest))
438                {
439                   if (wd->horizontal)
440                     cdv = (double)(xx - bx) / (double)bw;
441                   else
442                     cdv = (double)(yy - by) / (double)bh;
443                   it_closest = it;
444                   dist = x;
445                }
446           }
447           if ((i == 0) && (view_level == 0))
448             {
449                if(cdv > dmax || cdv < dmin)
450                  {
451                     if(cdv > dmax)
452                       {
453                          cdvv = dmax;
454                       }
455                     else
456                       {
457                          cdvv = dmin;
458                       }
459                     edje_object_part_drag_value_set(wd->base, "elm.dragable.index.1", cdv, cdvv);
460                  }
461                else
462                  {
463                     edje_object_part_drag_value_set(wd->base, "elm.dragable.index.1", cdv, cdv);
464                  }
465             }
466         if (it_closest) it_closest->selected = 1;
467         if (it_closest != it_last)
468           {
469              change = 1;
470              if (it_last)
471                {
472                   const char *stacking, *selectraise;
473
474                   it = it_last;
475                   if(view_level == it->level)
476                   edje_object_signal_emit(it->base.view, "elm,state,inactive", "elm");
477                   stacking = edje_object_data_get(it->base.view, "stacking");
478                   selectraise = edje_object_data_get(it->base.view, "selectraise");
479                   if ((selectraise) && (!strcmp(selectraise, "on")))
480                     {
481                        if ((stacking) && (!strcmp(stacking, "below")))
482                          evas_object_lower(it->base.view);
483                     }
484                }
485              if (it_closest)
486                {
487                   const char *selectraise;
488
489                   it = it_closest;
490                   if(view_level == it->level)
491                   edje_object_signal_emit(it->base.view, "elm,state,active", "elm");
492                   selectraise = edje_object_data_get(it->base.view, "selectraise");
493                   if ((selectraise) && (!strcmp(selectraise, "on")))
494                     evas_object_raise(it->base.view);
495                   evas_object_smart_callback_call((void *)obj, SIG_CHANGED, (void *)it->base.data);
496                   if (wd->delay) ecore_timer_del(wd->delay);
497                   wd->delay = ecore_timer_add(0.2, _delay_change, obj);
498                }
499           }
500         if (it_closest)
501           {
502              it = it_closest;
503              if (!last)
504                last = strdup(it->letter);
505              else
506                {
507                   if (!label) label = strdup(last);
508                   else
509                     {
510                        /* FIXME: realloc return NULL if the request fails */
511                        label = realloc(label, strlen(label) + strlen(last) + 1);
512                        strcat(label, last);
513                     }
514                   free(last);
515                   last = strdup(it->letter);
516                }
517           }
518      }
519    if (!label) label = strdup("");
520    if (!last) last = strdup("");
521    if(!wd->hide_button)
522      {
523         char *popup_text;
524
525         if(view_level == 0)
526           {
527              if(wd->tot_items_count[0])
528                {
529                   if (wd->popup_str[1]) wd->popup_str[1][0] = '\0';
530                   wd->popup_str[0] = (char *)realloc(wd->popup_str[0], (sizeof(char) * strlen(last) + 1));
531
532                   strcpy(wd->popup_str[0], last);
533                   edje_object_signal_emit(wd->base, "hide_2nd_level", "");
534                }
535              else
536                {
537                   edje_object_signal_emit(wd->base, "button.image.hidden", "");
538                   if(label)free(label);
539                   if(last) free(last);
540                   return;
541                }
542           }
543         if (view_level == 1 && wd->level_active[1])
544           {
545              if(wd->tot_items_count[1])
546                {
547                   wd->popup_str[1] = (char *)realloc(wd->popup_str[1], (sizeof(char) * strlen(last) + 1));
548
549                   strcpy(wd->popup_str[1], last);
550                   edje_object_signal_emit(wd->base, "hide_first_level", "");
551                }
552              else
553                {
554                   edje_object_signal_emit(wd->base, "button.image.hidden", "");
555                   if(label)free(label);
556                   if(last) free(last);
557                   return;
558                }
559           }
560         popup_text = (char *)malloc(sizeof(char) * (strlen(wd->popup_str[0]) + strlen(wd->popup_str[1]) + 1));
561         sprintf(popup_text, "%s%s", wd->popup_str[0], wd->popup_str[1]);
562         edje_object_part_text_set(wd->base, "elm.text", popup_text);
563
564         free(popup_text);
565      }
566
567    if(label)
568      free(label);
569    if(last)
570      free(last);
571 }
572
573 static void
574 _wheel(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
575 {
576    Widget_Data *wd = elm_widget_data_get(data);
577    //   Evas_Event_Mouse_Wheel *ev = event_info;
578    //   Evas_Object *obj = o;
579    if (!wd) return;
580 }
581
582 static void
583 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
584 {
585    Widget_Data *wd = elm_widget_data_get(data);
586    Evas_Event_Mouse_Down *ev = event_info;
587    Evas_Coord x, y, w;
588    if (!wd) return;
589    if (ev->button != 1) return;
590    wd->down = 1;
591    evas_object_geometry_get(wd->base, &x, &y, &w, NULL);
592    wd->dx = ev->canvas.x - x;
593    wd->dy = ev->canvas.y - y;
594    elm_index_active_set(data, 1);
595    _sel_eval(data, ev->canvas.x, ev->canvas.y);
596    edje_object_part_drag_value_set(wd->base, "elm.dragable.pointer",
597                                    (!edje_object_mirrored_get(wd->base)) ? wd->dx : (wd->dx - w), wd->dy);
598 }
599
600 static void
601 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
602 {
603    Widget_Data *wd = elm_widget_data_get(data);
604    Evas_Event_Mouse_Up *ev = event_info;
605    void *d;
606    Elm_Index_Item *it;
607    Eina_List *l;
608    int view_level;
609
610    if (!wd) return;
611    if (ev->button != 1) return;
612    if (wd->level == 1 && wd->delay) ecore_timer_del(wd->delay);
613    wd->delay = NULL;
614    wd->down = 0;
615    SET_VIEW_LEVEL(wd, view_level);
616    d = (void *)elm_index_item_selected_get(data, view_level);
617    EINA_LIST_FOREACH(wd->items, l, it)
618      {
619         edje_object_signal_emit(it->base.view, "elm,state,inactive", "elm");
620      }
621    if (d) evas_object_smart_callback_call(data, SIG_SELECTED, d);
622    elm_index_active_set(data, 0);
623    edje_object_signal_emit(wd->base, "elm,state,level,0", "elm");
624 }
625
626 static void
627 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
628 {
629    Widget_Data *wd = elm_widget_data_get(data);
630    Evas_Event_Mouse_Move *ev = event_info;
631    Evas_Coord minw = 0, minh = 0, x, y, dx, adx, w;
632    void *d;
633    char buf[1024];
634    if (!wd) return;
635    if (!wd->down) return;
636    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
637    evas_object_geometry_get(wd->base, &x, &y, &w, NULL);
638    x = ev->cur.canvas.x - x;
639    y = ev->cur.canvas.y - y;
640    dx = x - wd->dx;
641    adx = dx;
642    if (adx < 0) adx = -dx;
643    edje_object_part_drag_value_set(wd->base, "elm.dragable.pointer"
644                                    , (!edje_object_mirrored_get(wd->base)) ? x : (x - w), y);
645    if (!wd->horizontal)
646      {
647         if (adx > minw)
648           {
649              if (!wd->level)
650                {
651                   wd->level = 1;
652                   snprintf(buf, sizeof(buf), "elm,state,level,%i", wd->level);
653                   edje_object_signal_emit(wd->base, buf, "elm");
654                   evas_object_smart_callback_call(data, SIG_LEVEL_UP, NULL);
655                }
656           }
657         else
658           {
659              if (wd->level == 1)
660                {
661                   wd->level = 0;
662                   snprintf(buf, sizeof(buf), "elm,state,level,%i", wd->level);
663                   edje_object_signal_emit(wd->base, buf, "elm");
664                   d = (void *)elm_index_item_selected_get(data, wd->level);
665                   evas_object_smart_callback_call(data, "changed", d);
666                   if (wd->delay) ecore_timer_del(wd->delay);
667                   wd->delay = ecore_timer_add(0.2, _delay_change, data);
668                   evas_object_smart_callback_call(data, SIG_LEVEL_DOWN, NULL);
669                }
670           }
671      }
672    _sel_eval(data, ev->cur.canvas.x, ev->cur.canvas.y);
673 }
674
675 static void
676 _index_box_refill_job(void *data)
677 {
678    Widget_Data *wd = elm_widget_data_get((Evas_Object *)data);
679    if (!wd) return;
680
681    const char *string;
682    Evas_Coord pw, ph;
683
684    evas_object_geometry_get(wd->base, NULL, NULL, &pw, &ph);
685    wd->scale_factor = elm_scale_get();
686    if ( wd->scale_factor == 0.0 ) {
687      wd->scale_factor = 1.0;
688    }
689    string = edje_object_data_get(wd->base, "min_obj_height");
690    if(string)
691      wd->min_obj_height = (int) (atoi(string))*wd->scale_factor;
692    else
693      wd->min_obj_height = MIN_OBJ_HEIGHT*wd->scale_factor;
694    if(!wd->min_obj_height) return;
695
696    wd->max_grp_size = wd->min_obj_height - 2*MIN_GRP_SIZE;
697    wd->items_count = ph/wd->min_obj_height;
698    wd->max_supp_items_count = wd->max_grp_size*(int)((wd->items_count-1)*0.5)+wd->items_count;
699
700    if(pw != wd->pwidth && ph != wd->pheight)
701      {
702         if(wd->down == 1)
703           {
704              wd->active = 0;
705              elm_index_active_set(data, 1);
706           }
707         _index_box_clear((Evas_Object *)data, wd->bx[0], 0);
708         evas_object_smart_calculate( wd->bx[0]);
709         elm_index_item_go((Evas_Object *)data, wd->level);
710         wd->pwidth = pw;
711         wd->pheight = ph;
712      }
713 }
714
715 static void _index_object_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
716 {
717    Widget_Data *wd;
718    if(!data) return;
719    wd = elm_widget_data_get((Evas_Object *)data);
720    if(!wd) return;
721    ecore_job_add(_index_box_refill_job, (Evas_Object *)data);
722 }
723
724 /**
725  * Add a new index to the parent
726  *
727  * @param parent The parent object
728  * @return The new object or NULL if it cannot be created
729  *
730  * @ingroup Index
731  */
732 EAPI Evas_Object *
733 elm_index_add(Evas_Object *parent)
734 {
735    Evas_Object *obj;
736    Evas_Object *o;
737    Evas *e;
738    Widget_Data *wd;
739    Evas_Coord minw, minh;
740    const char *string;
741
742    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
743
744    ELM_SET_WIDTYPE(widtype, "index");
745    elm_widget_type_set(obj, "index");
746    elm_widget_sub_object_add(parent, obj);
747    elm_widget_data_set(obj, wd);
748    elm_widget_del_hook_set(obj, _del_hook);
749    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
750    elm_widget_theme_hook_set(obj, _theme_hook);
751    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
752    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
753    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
754    elm_widget_can_focus_set(obj, EINA_FALSE);
755
756    wd->horizontal = EINA_FALSE;
757    wd->min_obj_height = 0;
758    wd->max_grp_size = 0;
759    wd->items_count = 0;
760    wd->max_supp_items_count = 0;
761    wd->tot_items_count[0] = 0;
762    wd->tot_items_count[1] = 0;
763    wd->hide_button = 0;
764    wd->special_char = edje_object_data_get(wd->base, "special_char");
765    if(wd->special_char == NULL)  wd->special_char = eina_stringshare_add("*");
766
767    wd->base = edje_object_add(e);
768    _elm_theme_object_set(obj, wd->base, "index", "base/vertical", "default");
769    elm_widget_resize_object_set(obj, wd->base);
770
771    o = evas_object_rectangle_add(e);
772    wd->event[0] = o;
773    evas_object_color_set(o, 0, 0, 0, 0);
774    minw = minh = 0;
775    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
776    evas_object_size_hint_min_set(o, minw, minh);
777    edje_object_part_swallow(wd->base, "elm.swallow.event.0", o);
778    elm_widget_sub_object_add(obj, o);
779    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _index_object_resize, obj);
780    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL, _wheel, obj);
781    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, obj);
782    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _mouse_up, obj);
783    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, obj);
784    evas_object_show(o);
785    if (edje_object_part_exists(wd->base, "elm.swallow.event.1"))
786      {
787         o = evas_object_rectangle_add(e);
788         wd->event[1] = o;
789         evas_object_color_set(o, 0, 0, 0, 0);
790         evas_object_size_hint_min_set(o, minw, minh);
791         edje_object_part_swallow(wd->base, "elm.swallow.event.1", o);
792         elm_widget_sub_object_add(obj, o);
793      }
794
795    wd->bx[0] = evas_object_box_add(e);
796    evas_object_box_layout_set(wd->bx[0], _layout, wd, NULL);
797    elm_widget_sub_object_add(obj, wd->bx[0]);
798    edje_object_part_swallow(wd->base, "elm.swallow.index.0", wd->bx[0]);
799    evas_object_show(wd->bx[0]);
800
801    if (edje_object_part_exists(wd->base, "elm.swallow.index.1"))
802      {
803         wd->bx[1] = evas_object_box_add(e);
804         evas_object_box_layout_set(wd->bx[1], _layout, wd, NULL);
805         elm_widget_sub_object_add(obj, wd->bx[1]);
806         edje_object_part_swallow(wd->base, "elm.swallow.index.1", wd->bx[1]);
807         evas_object_show(wd->bx[1]);
808      }
809
810    evas_object_smart_callbacks_descriptions_set(obj, _signals);
811    wd->scale_factor = elm_scale_get();
812    if ( wd->scale_factor == 0.0 )
813                 wd->scale_factor = 1.0;
814    string = edje_object_data_get(wd->base, "min_1st_level_obj_height");
815    if(string)
816      wd->min_1st_level_obj_height = (int) (atoi(string))*wd->scale_factor;
817    else
818      wd->min_1st_level_obj_height = MIN_OBJ_HEIGHT*wd->scale_factor;
819    wd->popup_str[0] = calloc(1, sizeof(char) * 1);
820    wd->popup_str[1] = calloc(1, sizeof(char) * 1);
821
822    _mirrored_set(obj, elm_widget_mirrored_get(obj));
823    _sizing_eval(obj);
824    return obj;
825 }
826
827 static int
828 _group_count(Evas_Object *obj, int extraIndex, int adj_pos, int vis_pos)
829 {
830    Widget_Data *wd = elm_widget_data_get(obj);
831    if (!wd) return 0;
832    int group_count = MIN_GRP_SIZE;
833    while(group_count <= wd->max_grp_size)
834      {
835         if(extraIndex <= wd->max_grp_size*adj_pos)
836           {
837              if(group_count*adj_pos>=extraIndex) return group_count;
838           }
839         else
840           return wd->max_grp_size;
841
842         group_count += MIN_GRP_SIZE;
843      }
844    return group_count;
845 }
846
847 static void
848 _index_process(Evas_Object *obj)
849 {
850    int extraIndex;
851    int j,i, group_count;
852    Eina_List *l;
853    Elm_Index_Item *it;
854    int count;
855    int n;
856
857    Widget_Data *wd = elm_widget_data_get(obj);
858    if (!wd) return;
859
860    if (wd->items_count == 0) return;
861
862    const int adj_pos = (wd->items_count-1)*0.5;
863    if(wd->tot_items_count[wd->level] <= wd->max_supp_items_count)
864       n = wd->tot_items_count[wd->level];
865    else
866       n = wd->max_supp_items_count;
867    group_count = MIN_GRP_SIZE;
868
869    int *indx = (int*)calloc(n, sizeof(int));
870    if (!indx) return;
871
872    const int minh = wd->min_obj_height;
873    EINA_LIST_FOREACH(wd->items, l, it)
874      {
875         it->vis_letter = eina_stringshare_add(it->letter);
876         it->size =  minh;
877      }
878    int remainder;
879    int numberofparts;
880    int N = wd->items_count;
881
882    for (i=0;i<n;i++)
883      {
884         indx[i] = minh;
885      }
886    extraIndex=n-N;
887    if (extraIndex < 0) return;
888
889    group_count = _group_count(obj, extraIndex, adj_pos, N);
890    if (group_count <= 0)
891      {
892         if (indx)
893           free(indx);
894         indx = NULL;
895         return;
896      }
897
898    PlacementPart place[adj_pos];
899    remainder = extraIndex%group_count;
900    numberofparts=(extraIndex/group_count)+(remainder == 0? 0: 1);
901
902    for (i=0;i<numberofparts; i++)
903      {
904         place[i].count=group_count+1;
905         count = (int)(((float)(i+1)/(float)(numberofparts+1))*N);
906         place[i].start= count +i*group_count-1;
907      }
908    if (remainder)
909      place[numberofparts-1].count=remainder+1;
910
911    for (i=0;i<numberofparts;i++)
912      {
913         for (j=0;j<place[i].count; j++)
914           {
915              indx[((place[i].start)+j)]= MIN_PIXEL_VALUE;
916           }
917         indx[(place[i].start+(place[i].count)/2)] = minh-place[i].count+1;
918      }
919    count = 0;
920    EINA_LIST_FOREACH(wd->items, l, it)
921      {
922         int size = indx[count];
923         count++;
924         if (size == minh)
925           {
926              it->vis_letter = eina_stringshare_add(it->letter);
927              continue;
928           }
929         else if (size == 1)
930           {
931              eina_stringshare_del(it->vis_letter);
932              it->vis_letter = eina_stringshare_add("");
933           }
934         else
935           {
936              eina_stringshare_del(it->vis_letter);
937              it->vis_letter = eina_stringshare_add(wd->special_char);
938           }
939         it->size = size*wd->scale_factor;
940      }
941    if (indx)
942      {
943         free(indx);
944         indx = NULL;
945      }
946 }
947
948 /**
949  * Set the active state of the index programatically
950  *
951  * @param obj The index object
952  * @param active The active state
953  *
954  * @ingroup Index
955  */
956 EAPI void
957 elm_index_active_set(Evas_Object *obj, Eina_Bool active)
958 {
959    ELM_CHECK_WIDTYPE(obj, widtype);
960    Widget_Data *wd = elm_widget_data_get(obj);
961    if (!wd) return;
962    if (wd->active == active) return;
963    wd->active = active;
964    wd->level = 0;
965    if (wd->active)
966      {
967         _index_box_clear(obj, wd->bx[1], 1);
968         _index_process(obj);
969         _index_box_auto_fill(obj, wd->bx[0], 0);
970         if(wd->tot_items_count[wd->level])
971           edje_object_signal_emit(wd->base, "elm,state,active", "elm");
972         else
973           edje_object_signal_emit(wd->base, "button.image.hidden", "");
974      }
975    else
976      edje_object_signal_emit(wd->base, "elm,state,inactive", "elm");
977 }
978
979 /**
980  * Get the active state of the index programatically
981  *
982  * @param obj The index object
983  * @return The active state
984  *
985  * @ingroup Index
986  */
987 EAPI Eina_Bool
988 elm_index_active_get(const Evas_Object *obj)
989 {
990    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
991    Widget_Data *wd = elm_widget_data_get(obj);
992    if (!wd) return EINA_FALSE;
993    return wd->active;
994 }
995
996 /**
997  * Sets the level of the item.
998  *
999  * @param obj The index object.
1000  * @param level To be documented.
1001  *
1002  * @ingroup Index
1003  */
1004 EAPI void
1005 elm_index_item_level_set(Evas_Object *obj, int level)
1006 {
1007    ELM_CHECK_WIDTYPE(obj, widtype);
1008    Widget_Data *wd = elm_widget_data_get(obj);
1009    if (!wd) return;
1010    if (wd->level == level) return;
1011    wd->level = level;
1012 }
1013
1014 /**
1015  * Gets the level of the item.
1016  *
1017  * @param obj The index object
1018  *
1019  * @ingroup Index
1020  */
1021 EAPI int
1022 elm_index_item_level_get(const Evas_Object *obj)
1023 {
1024    ELM_CHECK_WIDTYPE(obj, widtype) 0;
1025    Widget_Data *wd = elm_widget_data_get(obj);
1026    if (!wd) return 0;
1027    return wd->level;
1028 }
1029
1030 /**
1031  * Returns the selected item.
1032  *
1033  * @param obj The index object.
1034  * @param level to be documented.
1035  *
1036  * @ingroup Index
1037  */
1038 EAPI void *
1039 elm_index_item_selected_get(const Evas_Object *obj, int level)
1040 {
1041    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1042    Widget_Data *wd = elm_widget_data_get(obj);
1043    Eina_List *l;
1044    Elm_Index_Item *it;
1045    if (!wd) return NULL;
1046    EINA_LIST_FOREACH(wd->items, l, it)
1047      if ((it->selected) && (it->level == level))
1048        return elm_widget_item_data_get(it);
1049    return NULL;
1050 }
1051
1052 /**
1053  * Appends a new item.
1054  *
1055  * @param obj The index object.
1056  * @param letter Letter under which the item should be indexed
1057  * @param item The item to put in the index
1058  *
1059  * @ingroup Index
1060  */
1061 EAPI void
1062 elm_index_item_append(Evas_Object *obj, const char *letter, const void *item)
1063 {
1064    ELM_CHECK_WIDTYPE(obj, widtype);
1065    Widget_Data *wd = elm_widget_data_get(obj);
1066    Elm_Index_Item *it;
1067    if (!wd) return;
1068    it = _item_new(obj, letter, item);
1069    if (!it) return;
1070    wd->items = eina_list_append(wd->items, it);
1071    wd->tot_items_count[wd->level]++;
1072    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1073 }
1074
1075 /**
1076  * Prepends a new item.
1077  *
1078  * @param obj The index object.
1079  * @param letter Letter under which the item should be indexed
1080  * @param item The item to put in the index
1081  *
1082  * @ingroup Index
1083  */
1084 EAPI void
1085 elm_index_item_prepend(Evas_Object *obj, const char *letter, const void *item)
1086 {
1087    ELM_CHECK_WIDTYPE(obj, widtype);
1088    Widget_Data *wd = elm_widget_data_get(obj);
1089    Elm_Index_Item *it;
1090
1091    if (!wd) return;
1092    it = _item_new(obj, letter, item);
1093    if (!it) return;
1094    wd->items = eina_list_prepend(wd->items, it);
1095    wd->tot_items_count[wd->level]++;
1096    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1097 }
1098
1099 /**
1100  * Append an item after @p relative in letter @p letter.
1101  *
1102  * @param obj The index object
1103  * @param letter Letter under which the item should be indexed
1104  * @param item The item to put in the index
1105  * @param relative The item to put @p item after
1106  *
1107  * @ingroup Index
1108  */
1109 EAPI void
1110 elm_index_item_append_relative(Evas_Object *obj, const char *letter, const void *item, const void *relative)
1111 {
1112    ELM_CHECK_WIDTYPE(obj, widtype);
1113    Widget_Data *wd = elm_widget_data_get(obj);
1114    Elm_Index_Item *it, *it_rel;
1115    if (!wd) return;
1116    if (!relative)
1117      {
1118         elm_index_item_append(obj, letter, item);
1119         wd->tot_items_count[wd->level]++;
1120         return;
1121      }
1122    it = _item_new(obj, letter, item);
1123    if (!it) return;
1124
1125    it_rel = _item_find(obj, relative);
1126    if (!it_rel)
1127      {
1128         elm_index_item_append(obj, letter, item);
1129         wd->tot_items_count[wd->level]++;
1130         return;
1131      }
1132
1133    wd->items = eina_list_append_relative(wd->items, it, it_rel);
1134    wd->tot_items_count[wd->level]++;
1135    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1136 }
1137
1138 /**
1139  * Prepend an item before @p relative in letter @p letter.
1140  *
1141  * @param obj The index object
1142  * @param letter Letter under which the item should be indexed
1143  * @param item The item to put in the index
1144  * @param relative The item to put @p item before
1145  *
1146  * @ingroup Index
1147  */
1148 EAPI void
1149 elm_index_item_prepend_relative(Evas_Object *obj, const char *letter, const void *item, const void *relative)
1150 {
1151    ELM_CHECK_WIDTYPE(obj, widtype);
1152    Widget_Data *wd = elm_widget_data_get(obj);
1153    Elm_Index_Item *it, *it_rel;
1154    if (!wd) return;
1155    if (!relative)
1156      {
1157         elm_index_item_prepend(obj, letter, item);
1158         wd->tot_items_count[wd->level]++;
1159         return;
1160      }
1161    it = _item_new(obj, letter, item);
1162    if (!it) return;
1163
1164    it_rel = _item_find(obj, relative);
1165    if (!it_rel)
1166      {
1167         elm_index_item_append(obj, letter, item);
1168         wd->tot_items_count[wd->level]++;
1169         return;
1170      }
1171
1172    wd->items = eina_list_prepend_relative(wd->items, it, it_rel);
1173    wd->tot_items_count[wd->level]++;
1174    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1175 }
1176
1177 /**
1178  * Insert a new @p item into the sorted index @p obj in @p letter.
1179  *
1180  * @param obj The index object
1181  * @param letter Letter under which the item should be indexed
1182  * @param item The item to put in the index
1183  * @param cmp_func The function called for the sort of index items.
1184  * @param cmp_data_func The function called for the sort of the data. It will
1185  * be used when cmp_func return 0. It means the index item already exists.
1186  * So, to decide which data item should be pointed by the index item, a function
1187  * to compare them is needed. If this function is not provided, index items
1188  * will be duplicated. If cmp_data_func returns a non-negative value, the
1189  * previous index item data will be replaced by the inserted @p item. So
1190  * if the previous data need to be free, it should be done in this function,
1191  * because the reference will be lost.
1192  *
1193  * @ingroup Index
1194  */
1195 EAPI void
1196 elm_index_item_sorted_insert(Evas_Object *obj, const char *letter, const void *item, Eina_Compare_Cb cmp_func, Eina_Compare_Cb cmp_data_func)
1197 {
1198    ELM_CHECK_WIDTYPE(obj, widtype);
1199    Widget_Data *wd = elm_widget_data_get(obj);
1200    Eina_List *lnear;
1201    Elm_Index_Item *it;
1202    int cmp;
1203
1204    if (!wd) return;
1205    if (!(wd->items))
1206      {
1207         elm_index_item_append(obj, letter, item);
1208         return;
1209      }
1210
1211    it = _item_new(obj, letter, item);
1212    if (!it) return;
1213
1214    lnear = eina_list_search_sorted_near_list(wd->items, cmp_func, it, &cmp);
1215    if (cmp < 0)
1216      wd->items =  eina_list_append_relative_list(wd->items, it, lnear);
1217    else if (cmp > 0)
1218      wd->items = eina_list_prepend_relative_list(wd->items, it, lnear);
1219    else
1220      {
1221         /* If cmp_data_func is not provided, append a duplicated item */
1222         if (!cmp_data_func)
1223           wd->items =  eina_list_append_relative_list(wd->items, it, lnear);
1224         else
1225           {
1226              Elm_Index_Item *p_it = eina_list_data_get(lnear);
1227              if (cmp_data_func(p_it->base.data, it->base.data) >= 0)
1228                p_it->base.data = it->base.data;
1229              _item_free(it);
1230           }
1231      }
1232
1233    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1234 }
1235
1236 /**
1237  * Remove an item from the index.
1238  *
1239  * @param obj The index object
1240  * @param item The item to remove from the index
1241  *
1242  * @ingroup Index
1243  */
1244 EAPI void
1245 elm_index_item_del(Evas_Object *obj, const void *item)
1246 {
1247    ELM_CHECK_WIDTYPE(obj, widtype);
1248    Widget_Data *wd = elm_widget_data_get(obj);
1249    Elm_Index_Item *it;
1250    if (!wd) return;
1251    it = _item_find(obj, item);
1252    if (!it) return;
1253    _item_free(it);
1254    wd->tot_items_count[wd->level]--;
1255    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1256 }
1257
1258 /**
1259  * Find an index item using item data.
1260  *
1261  * @param obj The index object
1262  * @param item The item pointed by index item
1263  * @return The index item pointing to @p item
1264  *
1265  * @ingroup Index
1266  */
1267 EAPI Elm_Index_Item *
1268 elm_index_item_find(Evas_Object *obj, const void *item)
1269 {
1270    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1271    Widget_Data *wd = elm_widget_data_get(obj);
1272    if (!wd) return NULL;
1273    return _item_find(obj, item);
1274 }
1275
1276 /**
1277  * Clears an index of its items.
1278  *
1279  * @param obj The index object.
1280  *
1281  * @ingroup Index
1282  */
1283 EAPI void
1284 elm_index_item_clear(Evas_Object *obj)
1285 {
1286    ELM_CHECK_WIDTYPE(obj, widtype);
1287    Widget_Data *wd = elm_widget_data_get(obj);
1288    Elm_Index_Item *it;
1289    Eina_List *l, *clear = NULL;
1290    if (!wd) return;
1291    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1292    EINA_LIST_FOREACH(wd->items, l, it)
1293      {
1294         if (it->level != wd->level) continue;
1295         clear = eina_list_append(clear, it);
1296      }
1297    EINA_LIST_FREE(clear, it)
1298      {
1299         _item_free(it);
1300         wd->tot_items_count[wd->level]--;
1301      }
1302 }
1303
1304 /**
1305  * Go to item at @p level
1306  *
1307  * @param obj The index object
1308  * @param level The index level
1309  *
1310  * @ingroup Index
1311  */
1312 EAPI void
1313 elm_index_item_go(Evas_Object *obj, int level)
1314 {
1315    ELM_CHECK_WIDTYPE(obj, widtype);
1316    Widget_Data *wd = elm_widget_data_get(obj);
1317    if (!wd) return;
1318    if(level == 0)
1319      _index_process(obj);
1320    _index_box_auto_fill(obj, wd->bx[0], 0);
1321    if (wd->level == 1) _index_box_auto_fill(obj, wd->bx[1], 1);
1322 }
1323
1324 /**
1325  * Returns the data associated with the item.
1326  *
1327  * @param it The list item
1328  * @return The data associated with @p it
1329  *
1330  * @ingroup Index
1331  */
1332 EAPI void *
1333 elm_index_item_data_get(const Elm_Index_Item *it)
1334 {
1335    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
1336    return elm_widget_item_data_get(it);
1337 }
1338
1339 /**
1340  * Set the data item from the index item
1341  *
1342  * This set a new data value.
1343  *
1344  * @param it The item
1345  * @param data The new data pointer to set
1346  *
1347  * @ingroup Index
1348  */
1349 EAPI void
1350 elm_index_item_data_set(Elm_Index_Item *it, const void *data)
1351 {
1352    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
1353    elm_widget_item_data_set(it, data);
1354 }
1355
1356 /**
1357  * Make the Central Button Image invisible.
1358  *
1359  * @param obj The Index.
1360  * @param invisible Whether button visible or not.
1361  * @return void.
1362  *
1363  * @ingroup Index
1364  */
1365 EAPI void
1366 elm_index_button_image_invisible_set(Evas_Object *obj, Eina_Bool invisible)
1367 {
1368    ELM_CHECK_WIDTYPE(obj, widtype);
1369    Widget_Data *wd = elm_widget_data_get(obj);
1370    wd->hide_button = invisible;
1371
1372    edje_object_signal_emit(wd->base, "elm,state,button,image,hide", "elm");
1373    return;
1374 }
1375
1376 /**
1377  * Set the function called when a index item is freed.
1378  *
1379  * @param it The item to set the callback on
1380  * @param func The function called
1381  *
1382  * @ingroup Index
1383  */
1384 EAPI void
1385 elm_index_item_del_cb_set(Elm_Index_Item *it, Evas_Smart_Cb func)
1386 {
1387    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it);
1388    elm_widget_item_del_cb_set(it, func);
1389 }
1390
1391 /**
1392  * Gets the letter of the item.
1393  *
1394  * @param it The list item
1395  * @return The letter of @p it
1396  *
1397  * @ingroup Index
1398  */
1399 EAPI const char *
1400 elm_index_item_letter_get(const Elm_Index_Item *it)
1401 {
1402    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, NULL);
1403    return it->letter;
1404 }
1405