elementary/index - merged with opensource for page control
[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 #define MIN_GRP_SIZE 2 //for symmetry it is 2, otherwise it can be 1 and zero have no meaning.
6 #define MIN_PIXEL_VALUE 1 //Min pixel value is highly dependent on touch sensitivity support.
7 #define MIN_OBJ_HEIGHT 24 //should be taken from .edc file.
8
9 typedef struct _Widget_Data Widget_Data;
10
11 typedef struct _PlacementPart PlacementPart;
12 typedef struct _Elm_Index_Item Elm_Index_Item;
13
14 struct _Widget_Data
15 {
16    Evas_Object *base;
17    Evas_Object *event[2];
18    Evas_Object *bx[2]; // 2 - for now all that's supported
19    Eina_List *items; // 1 list. yes N levels, but only 2 for now and # of items will be small
20    int level;
21    int max_supp_items_count;
22    int tot_items_count[2];
23    int min_obj_height, max_grp_size;
24    int min_1st_level_obj_height;
25    int items_count;
26    Evas_Coord dx, dy;
27    Evas_Coord pwidth, pheight;
28    Ecore_Timer *delay;
29    const char *special_char;
30    Eina_Bool level_active[2];
31    Eina_Bool horizontal : 1;
32    Eina_Bool autohide_disabled : 1;
33    Eina_Bool down : 1;
34    Eina_Bool indicator_disabled : 1;
35 };
36
37 struct _Elm_Index_Item
38 {
39    ELM_WIDGET_ITEM;
40    const char *letter, *vis_letter;
41    int level, size;
42    Evas_Smart_Cb func;
43    Eina_Bool selected : 1;
44 };
45
46 struct _PlacementPart
47 {
48    int start;
49    int count;
50 };
51
52 static const char *widtype = NULL;
53
54 static void _del_hook(Evas_Object *obj);
55 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
56 static void _theme_hook(Evas_Object *obj);
57 static void _sizing_eval(Evas_Object *obj);
58 static void _index_box_auto_fill(Evas_Object *obj, Evas_Object *box, int level);
59 static void _index_box_clear(Evas_Object *obj, Evas_Object *box, int level);
60 static void _item_free(Elm_Index_Item *it);
61 static void _index_process(Evas_Object *obj);
62
63 static const char SIG_CHANGED[] = "changed";
64 static const char SIG_DELAY_CHANGED[] = "delay,changed";
65 static const char SIG_SELECTED[] = "selected";
66 static const char SIG_LEVEL_UP[] = "level,up";
67 static const char SIG_LEVEL_DOWN[] = "level,down";
68
69 static const Evas_Smart_Cb_Description _signals[] = {
70    {SIG_CHANGED, ""},
71    {SIG_DELAY_CHANGED, ""},
72    {SIG_SELECTED, ""},
73    {SIG_LEVEL_UP, ""},
74    {SIG_LEVEL_DOWN, ""},
75    {NULL, NULL}
76 };
77
78 static void
79 _del_pre_hook(Evas_Object *obj)
80 {
81    Widget_Data *wd = elm_widget_data_get(obj);
82    Elm_Index_Item *it;
83    if (!wd) return;
84    _index_box_clear(obj, wd->bx[wd->level], wd->level);
85    _index_box_clear(obj, wd->bx[0], 0);
86    while (wd->items)
87      {
88         it = wd->items->data;
89         _item_free(it);
90         elm_widget_item_free(it);
91      }
92    if (wd->delay) ecore_timer_del(wd->delay);
93 }
94
95 static void
96 _del_hook(Evas_Object *obj)
97 {
98    Widget_Data *wd = elm_widget_data_get(obj);
99    free(wd);
100 }
101
102 static void
103 _layout(Evas_Object *o, Evas_Object_Box_Data *priv, void *data)
104 {
105    Widget_Data *wd = data;
106    if (!wd) return;
107    _els_box_layout(o, priv, wd->horizontal, 1, 0);
108 }
109
110 static void
111 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
112 {
113    Widget_Data *wd = elm_widget_data_get(obj);
114    if (!wd) return;
115    edje_object_signal_emit(wd->base, emission, source);
116 }
117
118 static void
119 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
120 {
121    Widget_Data *wd = elm_widget_data_get(obj);
122    if (!wd) return;
123    edje_object_signal_callback_add(wd->base, emission, source, func_cb, data);
124 }
125
126 static void
127 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
128 {
129    Widget_Data *wd = elm_widget_data_get(obj);
130    edje_object_signal_callback_del_full(wd->base, emission, source, func_cb,
131                                         data);
132 }
133
134 static void
135 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
136 {
137    Widget_Data *wd = elm_widget_data_get(obj);
138    if (!wd) return;
139    if (!wd->horizontal)
140      edje_object_mirrored_set(wd->base, rtl);
141 }
142
143 static void
144 _theme_hook(Evas_Object *obj)
145 {
146    Evas_Coord minw = 0, minh = 0;
147    Widget_Data *wd = elm_widget_data_get(obj);
148    if (!wd) return;
149    _elm_widget_mirrored_reload(obj);
150
151    _index_box_clear(obj, wd->bx[0], 0);
152    _index_box_clear(obj, wd->bx[1], 1);
153    if (wd->horizontal)
154      _elm_theme_object_set(obj, wd->base, "index", "base/horizontal", elm_widget_style_get(obj));
155    else
156      {
157         _elm_theme_object_set(obj, wd->base, "index", "base/vertical", elm_widget_style_get(obj));
158         _mirrored_set(obj, elm_widget_mirrored_get(obj));
159      }
160    edje_object_part_swallow(wd->base, "elm.swallow.event.0", wd->event[0]);
161    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
162    evas_object_size_hint_min_set(wd->event[0], minw, minh);
163    edje_object_part_swallow(wd->base, "elm.swallow.index.0", wd->bx[0]);
164    if (edje_object_part_exists(wd->base, "elm.swallow.index.1"))
165      {
166         if (!wd->bx[1])
167           {
168              wd->bx[1] = evas_object_box_add(evas_object_evas_get(wd->base));
169              evas_object_box_layout_set(wd->bx[1], _layout, wd, NULL);
170              elm_widget_sub_object_add(obj, wd->bx[1]);
171           }
172         edje_object_part_swallow(wd->base, "elm.swallow.index.1", wd->bx[1]);
173         evas_object_show(wd->bx[1]);
174      }
175    else if (wd->bx[1])
176      {
177         evas_object_del(wd->bx[1]);
178         wd->bx[1] = NULL;
179      }
180    if (edje_object_part_exists(wd->base, "elm.swallow.event.1"))
181      {
182         if (!wd->event[1])
183           {
184              wd->event[1] = evas_object_rectangle_add(evas_object_evas_get(wd->base));
185              evas_object_color_set(wd->event[1], 0, 0, 0, 0);
186              elm_widget_sub_object_add(obj, wd->event[1]);
187           }
188         edje_object_part_swallow(wd->base, "elm.swallow.event.1", wd->event[1]);
189         evas_object_size_hint_min_set(wd->event[1], minw, minh);
190      }
191    else if (wd->event[1])
192      {
193         evas_object_del(wd->event[1]);
194         wd->event[1] = NULL;
195      }
196    edje_object_message_signal_process(wd->base);
197    edje_object_scale_set(wd->base, elm_widget_scale_get(obj) * _elm_config->scale);
198    _sizing_eval(obj);
199    _index_box_auto_fill(obj, wd->bx[0], 0);
200
201    if (wd->autohide_disabled)
202      {
203         if (wd->level == 1) _index_box_auto_fill(obj, wd->bx[1], 1);
204         edje_object_signal_emit(wd->base, "elm,state,active", "elm");
205      }
206    else
207      edje_object_signal_emit(wd->base, "elm,state,inactive", "elm");
208 }
209
210 static void
211 _sizing_eval(Evas_Object *obj)
212 {
213    Widget_Data *wd = elm_widget_data_get(obj);
214    Evas_Coord minw = -1, minh = -1, maxw = -1, maxh = -1;
215    if (!wd) return;
216    edje_object_size_min_calc(wd->base, &minw, &minh);
217    evas_object_size_hint_min_set(obj, minw, minh);
218    evas_object_size_hint_max_set(obj, maxw, maxh);
219 }
220
221 static Eina_Bool
222 _item_del_pre_hook(Elm_Object_Item *it)
223 {
224    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
225    if (!wd) return EINA_FALSE;
226    _item_free((Elm_Index_Item *)it);
227    _index_box_clear(WIDGET(it), wd->bx[wd->level], wd->level);
228    return EINA_TRUE;
229 }
230
231 static Elm_Index_Item *
232 _item_new(Evas_Object *obj, const char *letter, Evas_Smart_Cb func, const void *data)
233 {
234    Widget_Data *wd = elm_widget_data_get(obj);
235    Elm_Index_Item *it;
236    if (!wd) return NULL;
237    it = elm_widget_item_new(obj, Elm_Index_Item);
238    if (!it) return NULL;
239    elm_widget_item_del_pre_hook_set(it, _item_del_pre_hook);
240    it->func = func;
241    it->base.data = data;
242    it->level = wd->level;
243    if(wd->level == 0)
244      it->size =  wd->min_obj_height;
245    else
246      it->size =  wd->min_1st_level_obj_height;
247    if(letter)
248      {
249         it->letter = eina_stringshare_add(letter);
250         it->vis_letter = eina_stringshare_add(letter);
251      }
252    return it;
253 }
254
255 static Elm_Index_Item *
256 _item_find(Evas_Object *obj, const void *data)
257 {
258    Widget_Data *wd = elm_widget_data_get(obj);
259    Eina_List *l;
260    Elm_Index_Item *it;
261    if (!wd) return NULL;
262    EINA_LIST_FOREACH(wd->items, l, it)
263      if (it->base.data == data) return it;
264    return NULL;
265 }
266
267 static void
268 _item_free(Elm_Index_Item *it)
269 {
270    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
271    if (!wd) return;
272    wd->items = eina_list_remove(wd->items, it);
273    if (it->letter) eina_stringshare_del(it->letter);
274    if (it->vis_letter) eina_stringshare_del(it->vis_letter);
275 }
276
277 // FIXME: always have index filled
278 static void
279 _index_box_auto_fill(Evas_Object *obj, Evas_Object *box, int level)
280 {
281    Widget_Data *wd = elm_widget_data_get(obj);
282    Eina_Bool rtl;
283    Eina_List *l;
284    Elm_Index_Item *it;
285    Evas_Coord mw, mh, w, h;
286    int i = 0;
287    if (!wd) return;
288    if (wd->level_active[level]) return;
289    rtl = elm_widget_mirrored_get(obj);
290    evas_object_geometry_get(box, NULL, NULL, &w, &h);
291    EINA_LIST_FOREACH(wd->items, l, it)
292      {
293         Evas_Object *o;
294         const char *stacking;
295
296         if (it->level != level) continue;
297
298 //FIXME: Need to check. This cause one less items show up.
299 //        if(i > wd->max_supp_items_count) break;
300
301         o = edje_object_add(evas_object_evas_get(obj));
302         VIEW(it) = o;
303         edje_object_mirrored_set(VIEW(it), rtl);
304
305         if (wd->horizontal)
306           {
307              if (i & 0x1)
308                _elm_theme_object_set(obj, o, "index", "item_odd/horizontal",
309                                      elm_widget_style_get(obj));
310              else
311                _elm_theme_object_set(obj, o, "index", "item/horizontal",
312                                      elm_widget_style_get(obj));
313           }
314         else
315           {
316              if (i & 0x1)
317                _elm_theme_object_set(obj, o, "index", "item_odd/vertical",
318                                      elm_widget_style_get(obj));
319              else
320                _elm_theme_object_set(obj, o, "index", "item/vertical",
321                                      elm_widget_style_get(obj));
322           }
323
324         edje_object_part_text_set(o, "elm.text", it->letter);
325         edje_object_size_min_restricted_calc(o, &mw, &mh, 0, 0);
326         evas_object_size_hint_min_set(o, mw, mh);
327         evas_object_size_hint_weight_set(o, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
328         evas_object_size_hint_align_set(o, EVAS_HINT_FILL, EVAS_HINT_FILL);
329
330         edje_object_part_text_set(o, "elm.text", it->vis_letter);
331
332         //FIXME: Need to check. This cause the page index size incorrect.
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 (!VIEW(it)) continue;
375         if (it->level != level) continue;
376         evas_object_del(VIEW(it));
377         VIEW(it) = 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    Elm_Object_Item *item;
387    if (!wd) return ECORE_CALLBACK_CANCEL;
388    wd->delay = NULL;
389    item = elm_index_selected_item_get(data, wd->level);
390    if (item) evas_object_smart_callback_call(data, SIG_DELAY_CHANGED, item);
391    return ECORE_CALLBACK_CANCEL;
392 }
393
394 static void
395 _sel_eval(Evas_Object *obj, Evas_Coord evx, Evas_Coord evy)
396 {
397    Widget_Data *wd = elm_widget_data_get(obj);
398    Elm_Index_Item *it, *it_closest, *it_last;
399    Eina_List *l;
400    Evas_Coord x, y, w, h, bx, by, bw, bh, xx, yy;
401    double cdv = 0.5;
402    Evas_Coord dist;
403    char *label = NULL, *last = NULL;
404    int i;
405    if (!wd) return;
406    for (i = 0; i <= wd->level; i++)
407      {
408         it_last = NULL;
409         it_closest  = NULL;
410         dist = 0x7fffffff;
411         evas_object_geometry_get(wd->bx[i], &bx, &by, &bw, &bh);
412         EINA_LIST_FOREACH(wd->items, l, it)
413           {
414              if (it->level != i) continue;
415              if (it->level != wd->level)
416                {
417                   if (it->selected)
418                     {
419                        it_closest = it;
420                        break;
421                     }
422                   continue;
423                }
424              if (it->selected)
425                {
426                   it_last = it;
427                   it->selected = 0;
428                }
429              evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
430              xx = x + (w / 2);
431              yy = y + (h / 2);
432              x = evx - xx;
433              y = evy - yy;
434              x = (x * x) + (y * y);
435              if ((x < dist) || (!it_closest))
436                {
437                   if (wd->horizontal)
438                     cdv = (double)(xx - bx) / (double)bw;
439                   else
440                     cdv = (double)(yy - by) / (double)bh;
441                   it_closest = it;
442                   dist = x;
443                }
444           }
445         if ((i == 0) && (wd->level == 0))
446           edje_object_part_drag_value_set(wd->base, "elm.dragable.index.1",
447                                           cdv, cdv);
448         if (it_closest) it_closest->selected = 1;
449         if (it_closest != it_last)
450           {
451              if (it_last)
452                {
453                   const char *stacking, *selectraise;
454
455                   it = it_last;
456                   edje_object_signal_emit(VIEW(it), "elm,state,inactive", "elm");
457                   stacking = edje_object_data_get(VIEW(it), "stacking");
458                   selectraise = edje_object_data_get(VIEW(it), "selectraise");
459                   if ((selectraise) && (!strcmp(selectraise, "on")))
460                     {
461                        if ((stacking) && (!strcmp(stacking, "below")))
462                          evas_object_lower(VIEW(it));
463                     }
464                }
465              if (it_closest)
466                {
467                   const char *selectraise;
468
469                   it = it_closest;
470                   edje_object_signal_emit(VIEW(it), "elm,state,active", "elm");
471                   selectraise = edje_object_data_get(VIEW(it), "selectraise");
472                   if ((selectraise) && (!strcmp(selectraise, "on")))
473                     evas_object_raise(VIEW(it));
474                   evas_object_smart_callback_call((void *)obj, SIG_CHANGED, (void *)it);
475                   if (wd->delay) ecore_timer_del(wd->delay);
476                   wd->delay = ecore_timer_add(0.2, _delay_change, obj);
477                }
478           }
479         if (it_closest)
480           {
481              it = it_closest;
482              if (!last)
483                last = strdup(it->letter);
484              else
485                {
486                   if (!label) label = strdup(last);
487                   else
488                     {
489                        label = realloc(label, strlen(label) + strlen(last) + 1);
490                        if (!label) return;
491                        strcat(label, last);
492                     }
493                   free(last);
494                   last = strdup(it->letter);
495                }
496           }
497      }
498    if (!label) label = strdup("");
499    if (!last) last = strdup("");
500    edje_object_part_text_set(wd->base, "elm.text.body", label);
501    edje_object_part_text_set(wd->base, "elm.text", last);
502    free(label);
503    free(last);
504 }
505
506 static void
507 _wheel(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
508 {
509    Widget_Data *wd = elm_widget_data_get(data);
510    //   Evas_Event_Mouse_Wheel *ev = event_info;
511    //   Evas_Object *obj = o;
512    if (!wd) return;
513 }
514
515 static void
516 _mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
517 {
518    Widget_Data *wd = elm_widget_data_get(data);
519    Evas_Event_Mouse_Down *ev = event_info;
520    Evas_Coord x, y, w;
521    if (!wd) return;
522    if (ev->button != 1) return;
523    wd->down = 1;
524    evas_object_geometry_get(wd->base, &x, &y, &w, NULL);
525    wd->dx = ev->canvas.x - x;
526    wd->dy = ev->canvas.y - y;
527    if (!wd->autohide_disabled)
528      {
529         _index_box_clear(data, wd->bx[1], 1);
530         _index_box_auto_fill(data, wd->bx[0], 0);
531         edje_object_signal_emit(wd->base, "elm,state,active", "elm");
532      }
533    _sel_eval(data, ev->canvas.x, ev->canvas.y);
534    edje_object_part_drag_value_set(wd->base, "elm.dragable.pointer",
535                                    (!edje_object_mirrored_get(wd->base)) ? wd->dx : (wd->dx - w), wd->dy);
536    if (wd->items && !wd->indicator_disabled)
537      edje_object_signal_emit(wd->base, "elm,indicator,state,active", "elm");
538 }
539
540 static void
541 _mouse_up(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
542 {
543    Widget_Data *wd = elm_widget_data_get(data);
544    Evas_Event_Mouse_Up *ev = event_info;
545    Elm_Object_Item *item;
546    Elm_Index_Item *id_item;
547    if (!wd) return;
548    if (ev->button != 1) return;
549    if (wd->level == 1 && wd->delay) ecore_timer_del(wd->delay);
550    wd->delay = NULL;
551    wd->down = 0;
552    item = elm_index_selected_item_get(data, wd->level);
553    if (item)
554      {
555         evas_object_smart_callback_call(data, SIG_SELECTED, item);
556         id_item = (Elm_Index_Item *)item;
557         if (id_item->func)
558           id_item->func((void *)id_item->base.data, WIDGET(id_item), id_item);
559      }
560    if (!wd->autohide_disabled)
561      edje_object_signal_emit(wd->base, "elm,state,inactive", "elm");
562    edje_object_signal_emit(wd->base, "elm,state,level,0", "elm");
563    if (wd->items && !wd->indicator_disabled)
564      edje_object_signal_emit(wd->base, "elm,indicator,state,inactive", "elm");
565 }
566
567 static void
568 _mouse_move(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
569 {
570    Widget_Data *wd = elm_widget_data_get(data);
571    Evas_Event_Mouse_Move *ev = event_info;
572    Evas_Coord minw = 0, minh = 0, x, y, dx, adx, w;
573    Elm_Object_Item *item;
574    char buf[1024];
575    if (!wd) return;
576    if (!wd->down) return;
577    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
578    evas_object_geometry_get(wd->base, &x, &y, &w, NULL);
579    x = ev->cur.canvas.x - x;
580    y = ev->cur.canvas.y - y;
581    dx = x - wd->dx;
582    adx = dx;
583    if (adx < 0) adx = -dx;
584    edje_object_part_drag_value_set(wd->base, "elm.dragable.pointer"
585                                    , (!edje_object_mirrored_get(wd->base)) ? x : (x - w), y);
586    if (!wd->horizontal)
587      {
588         if (adx > minw)
589           {
590              if (!wd->level)
591                {
592                   wd->level = 1;
593                   snprintf(buf, sizeof(buf), "elm,state,level,%i", wd->level);
594                   edje_object_signal_emit(wd->base, buf, "elm");
595                   evas_object_smart_callback_call(data, SIG_LEVEL_UP, NULL);
596                }
597           }
598         else
599           {
600              if (wd->level == 1)
601                {
602                   wd->level = 0;
603                   snprintf(buf, sizeof(buf), "elm,state,level,%i", wd->level);
604                   edje_object_signal_emit(wd->base, buf, "elm");
605                   item = elm_index_item_selected_get(data, wd->level);
606                   evas_object_smart_callback_call(data, SIG_CHANGED, NULL);
607                   if (wd->delay) ecore_timer_del(wd->delay);
608                   wd->delay = ecore_timer_add(0.2, _delay_change, data);
609                   evas_object_smart_callback_call(data, SIG_LEVEL_DOWN, NULL);
610                }
611           }
612      }
613    _sel_eval(data, ev->cur.canvas.x, ev->cur.canvas.y);
614 }
615
616 static void
617 _index_box_refill_job(void *data)
618 {
619    Widget_Data *wd = elm_widget_data_get((Evas_Object *)data);
620    if (!wd) return;
621
622    const char *string;
623    Evas_Coord pw, ph;
624
625    evas_object_geometry_get(wd->base, NULL, NULL, &pw, &ph);
626    string = edje_object_data_get(wd->base, "min_obj_height");
627    wd->min_obj_height = MIN_OBJ_HEIGHT;
628
629    wd->max_grp_size = wd->min_obj_height - 2*MIN_GRP_SIZE;
630    wd->items_count = ph/wd->min_obj_height;
631    wd->max_supp_items_count = wd->max_grp_size*(int)((wd->items_count-1)*0.5)+wd->items_count;
632
633    if(pw != wd->pwidth && ph != wd->pheight)
634      {
635         if(wd->down == 1)
636           edje_object_signal_emit(wd->base, "elm,state,active", "elm");
637         _index_box_clear((Evas_Object *)data, wd->bx[0], 0);
638         evas_object_smart_calculate( wd->bx[0]);
639         elm_index_item_go((Evas_Object *)data, wd->level);
640         wd->pwidth = pw;
641         wd->pheight = ph;
642      }
643 }
644
645 static void _index_object_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
646 {
647    Widget_Data *wd;
648    if(!data) return;
649    wd = elm_widget_data_get((Evas_Object *)data);
650    if(!wd) return;
651    ecore_job_add(_index_box_refill_job, (Evas_Object *)data);
652 }
653
654 EAPI Evas_Object *
655 elm_index_add(Evas_Object *parent)
656 {
657    Evas_Object *obj;
658    Evas_Object *o;
659    Evas *e;
660    Widget_Data *wd;
661    Evas_Coord minw, minh;
662
663    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
664
665    ELM_SET_WIDTYPE(widtype, "index");
666    elm_widget_type_set(obj, "index");
667    elm_widget_sub_object_add(parent, obj);
668    elm_widget_data_set(obj, wd);
669    elm_widget_del_hook_set(obj, _del_hook);
670    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
671    elm_widget_theme_hook_set(obj, _theme_hook);
672    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
673    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
674    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
675    elm_widget_can_focus_set(obj, EINA_FALSE);
676
677    wd->indicator_disabled = EINA_FALSE;
678    wd->horizontal = EINA_FALSE;
679    wd->autohide_disabled = EINA_FALSE;
680    wd->min_obj_height = 0;
681    wd->max_grp_size = 0;
682    wd->items_count = 0;
683    wd->tot_items_count[0] = 0;
684    wd->tot_items_count[1] = 0;
685    wd->special_char = edje_object_data_get(wd->base, "special_char");
686    if(!wd->special_char)  wd->special_char = eina_stringshare_add("*");
687
688    wd->base = edje_object_add(e);
689    _elm_theme_object_set(obj, wd->base, "index", "base/vertical", "default");
690    elm_widget_resize_object_set(obj, wd->base);
691
692    o = evas_object_rectangle_add(e);
693    wd->event[0] = o;
694    evas_object_color_set(o, 0, 0, 0, 0);
695    minw = minh = 0;
696    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
697    evas_object_size_hint_min_set(o, minw, minh);
698    edje_object_part_swallow(wd->base, "elm.swallow.event.0", o);
699    elm_widget_sub_object_add(obj, o);
700    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _index_object_resize, obj);
701    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_WHEEL, _wheel, obj);
702    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, obj);
703    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP, _mouse_up, obj);
704    evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, obj);
705    evas_object_show(o);
706    if (edje_object_part_exists(wd->base, "elm.swallow.event.1"))
707      {
708         o = evas_object_rectangle_add(e);
709         wd->event[1] = o;
710         evas_object_color_set(o, 0, 0, 0, 0);
711         evas_object_size_hint_min_set(o, minw, minh);
712         edje_object_part_swallow(wd->base, "elm.swallow.event.1", o);
713         elm_widget_sub_object_add(obj, o);
714      }
715
716    wd->bx[0] = evas_object_box_add(e);
717    evas_object_box_layout_set(wd->bx[0], _layout, wd, NULL);
718    elm_widget_sub_object_add(obj, wd->bx[0]);
719    edje_object_part_swallow(wd->base, "elm.swallow.index.0", wd->bx[0]);
720    evas_object_show(wd->bx[0]);
721
722    if (edje_object_part_exists(wd->base, "elm.swallow.index.1"))
723      {
724         wd->bx[1] = evas_object_box_add(e);
725         evas_object_box_layout_set(wd->bx[1], _layout, wd, NULL);
726         elm_widget_sub_object_add(obj, wd->bx[1]);
727         edje_object_part_swallow(wd->base, "elm.swallow.index.1", wd->bx[1]);
728         evas_object_show(wd->bx[1]);
729      }
730
731    evas_object_smart_callbacks_descriptions_set(obj, _signals);
732    wd->min_1st_level_obj_height = MIN_OBJ_HEIGHT;
733
734    _mirrored_set(obj, elm_widget_mirrored_get(obj));
735    _sizing_eval(obj);
736    return obj;
737 }
738
739 static int
740 _group_count(Evas_Object *obj, int extraIndex, int adj_pos)
741 {
742    Widget_Data *wd = elm_widget_data_get(obj);
743    if (!wd) return 0;
744    int group_count = MIN_GRP_SIZE;
745    while(group_count <= wd->max_grp_size)
746      {
747         if(extraIndex <= wd->max_grp_size*adj_pos)
748           {
749              if(group_count*adj_pos>=extraIndex) return group_count;
750           }
751         else
752           return wd->max_grp_size;
753
754         group_count += MIN_GRP_SIZE;
755      }
756    return group_count;
757 }
758
759 static void
760 _index_process(Evas_Object *obj)
761 {
762 //FIXME: It seems max_supp_items_count has incorrect value.
763    return;
764    int extraIndex;
765    int j,i, group_count;
766    Eina_List *l;
767    Elm_Index_Item *it;
768    int count;
769    int n;
770
771    Widget_Data *wd = elm_widget_data_get(obj);
772    if (!wd) return;
773
774    if (wd->items_count == 0) return;
775
776    const int adj_pos = (wd->items_count-1)*0.5;
777    if(wd->tot_items_count[wd->level] <= wd->max_supp_items_count)
778       n = wd->tot_items_count[wd->level];
779    else
780       n = wd->max_supp_items_count;
781    group_count = MIN_GRP_SIZE;
782
783    int *indx = (int*)calloc(n, sizeof(int));
784    if (!indx) return;
785
786    const int minh = wd->min_obj_height;
787    EINA_LIST_FOREACH(wd->items, l, it)
788      {
789         it->vis_letter = eina_stringshare_add(it->letter);
790         it->size =  minh;
791      }
792    int remainder;
793    int numberofparts;
794    int N = wd->items_count;
795
796    for (i=0;i<n;i++)
797      {
798         indx[i] = minh;
799      }
800    extraIndex=n-N;
801    if (extraIndex < 0)
802      {
803         free(indx);
804         indx = NULL;
805         return;
806      }
807
808    group_count = _group_count(obj, extraIndex, adj_pos);
809    if (group_count <= 0)
810      {
811         if (indx)
812           free(indx);
813         indx = NULL;
814         return;
815      }
816
817    PlacementPart place[adj_pos];
818    remainder = extraIndex%group_count;
819    numberofparts=(extraIndex/group_count)+(remainder == 0? 0: 1);
820
821    for (i=0;i<numberofparts; i++)
822      {
823         place[i].count=group_count+1;
824         count = (int)(((float)(i+1)/(float)(numberofparts+1))*N);
825         place[i].start= count +i*group_count-1;
826      }
827    if (remainder)
828      place[numberofparts-1].count=remainder+1;
829
830    for (i=0;i<numberofparts;i++)
831      {
832         for (j=0;j<place[i].count; j++)
833           {
834              indx[((place[i].start)+j)]= MIN_PIXEL_VALUE;
835           }
836         indx[(place[i].start+(place[i].count)/2)] = minh-place[i].count+1;
837      }
838    count = 0;
839    EINA_LIST_FOREACH(wd->items, l, it)
840      {
841         int size = indx[count];
842         count++;
843         if (size == minh)
844           {
845              it->vis_letter = eina_stringshare_add(it->letter);
846              continue;
847           }
848         else if (size == 1)
849           {
850              eina_stringshare_del(it->vis_letter);
851              it->vis_letter = eina_stringshare_add("");
852           }
853         else
854           {
855              eina_stringshare_del(it->vis_letter);
856              it->vis_letter = eina_stringshare_add(wd->special_char);
857           }
858         it->size = size;
859      }
860    if (indx)
861      {
862         free(indx);
863         indx = NULL;
864      }
865 }
866
867 EINA_DEPRECATED EAPI void
868 elm_index_active_set(Evas_Object *obj, Eina_Bool active)
869 {
870    elm_index_autohide_disabled_set(obj, !active);
871 }
872
873 EINA_DEPRECATED EAPI Eina_Bool
874 elm_index_active_get(const Evas_Object *obj)
875 {
876    return !elm_index_autohide_disabled_get(obj);
877 }
878
879 EAPI void
880 elm_index_autohide_disabled_set(Evas_Object *obj, Eina_Bool disabled)
881 {
882    ELM_CHECK_WIDTYPE(obj, widtype);
883    Widget_Data *wd = elm_widget_data_get(obj);
884    if (!wd) return;
885    disabled = !!disabled;
886    if (wd->autohide_disabled == disabled) return;
887    wd->autohide_disabled = disabled;
888    wd->level = 0;
889    if (wd->autohide_disabled)
890      {
891         _index_box_clear(obj, wd->bx[1], 1);
892         _index_process(obj);
893         _index_box_auto_fill(obj, wd->bx[0], 0);
894         edje_object_signal_emit(wd->base, "elm,state,active", "elm");
895      }
896    else
897      edje_object_signal_emit(wd->base, "elm,state,inactive", "elm");
898
899    //FIXME: Should be update indicator based on the indicator visiblility
900 }
901
902 EAPI Eina_Bool
903 elm_index_autohide_disabled_get(const Evas_Object *obj)
904 {
905    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
906    Widget_Data *wd = elm_widget_data_get(obj);
907    if (!wd) return EINA_FALSE;
908    return wd->autohide_disabled;
909 }
910
911 EAPI void
912 elm_index_item_level_set(Evas_Object *obj, int level)
913 {
914    ELM_CHECK_WIDTYPE(obj, widtype);
915    Widget_Data *wd = elm_widget_data_get(obj);
916    if (!wd) return;
917    if (wd->level == level) return;
918    wd->level = level;
919 }
920
921 EAPI int
922 elm_index_item_level_get(const Evas_Object *obj)
923 {
924    ELM_CHECK_WIDTYPE(obj, widtype) 0;
925    Widget_Data *wd = elm_widget_data_get(obj);
926    if (!wd) return 0;
927    return wd->level;
928 }
929
930 EAPI void
931 elm_index_item_selected_set(Elm_Object_Item *it, Eina_Bool selected)
932 {
933    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
934    Evas_Coord x, y, w, h;
935    Widget_Data *wd = elm_widget_data_get(WIDGET(it));
936    if (!wd) return;
937
938    //FIXME: Should be update indicator based on the autohidden status & indicator visiblility
939
940    if (selected)
941      {
942         evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
943         _sel_eval(WIDGET(it), x + (w/2), y + (h/2));
944      }
945    else
946      _sel_eval(WIDGET(it), -99999, -9999);
947
948 }
949
950 EINA_DEPRECATED EAPI Elm_Object_Item *
951 elm_index_item_selected_get(const Evas_Object *obj, int level)
952 {
953    return elm_index_selected_item_get(obj, level);
954 }
955
956 EAPI Elm_Object_Item *
957 elm_index_selected_item_get(const Evas_Object *obj, int level)
958 {
959    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
960    Widget_Data *wd = elm_widget_data_get(obj);
961    Eina_List *l;
962    Elm_Index_Item *it;
963    if (!wd) return NULL;
964    EINA_LIST_FOREACH(wd->items, l, it)
965      {
966         if ((it->selected) && (it->level == level))
967           return (Elm_Object_Item *)it;
968      }
969    return NULL;
970 }
971
972 EAPI Elm_Object_Item *
973 elm_index_item_append(Evas_Object *obj, const char *letter, const void *data)
974 {
975    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
976    Widget_Data *wd = elm_widget_data_get(obj);
977    Elm_Index_Item *it;
978    if (!wd) return NULL;
979    it = _item_new(obj, letter, NULL, data);
980    if (!it) return NULL;
981    wd->items = eina_list_append(wd->items, it);
982    wd->tot_items_count[wd->level]++;
983    _index_box_clear(obj, wd->bx[wd->level], wd->level);
984    return (Elm_Object_Item *)it;
985 }
986
987 EAPI Elm_Object_Item *
988 elm_index_item_prepend(Evas_Object *obj, const char *letter, const void *data)
989 {
990    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
991    Widget_Data *wd = elm_widget_data_get(obj);
992    Elm_Index_Item *it;
993
994    if (!wd) return NULL;
995    it = _item_new(obj, letter, NULL, data);
996    if (!it) return NULL;
997    wd->items = eina_list_prepend(wd->items, it);
998    wd->tot_items_count[wd->level]++;
999    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1000    return (Elm_Object_Item *)it;
1001 }
1002
1003 EINA_DEPRECATED EAPI Elm_Object_Item *
1004 elm_index_item_append_relative(Evas_Object *obj, const char *letter, const void *item, const Elm_Object_Item *relative)
1005 {
1006    return elm_index_item_insert_after(obj, (Elm_Object_Item *) relative, letter, NULL, item);
1007 }
1008
1009 EINA_DEPRECATED EAPI Elm_Object_Item *
1010 elm_index_item_prepend_relative(Evas_Object *obj, const char *letter, const void *item, const Elm_Object_Item *relative)
1011 {
1012    return elm_index_item_insert_before(obj, (Elm_Object_Item *) relative, letter, NULL, item);
1013 }
1014
1015 EAPI Elm_Object_Item *
1016 elm_index_item_insert_after(Evas_Object *obj, Elm_Object_Item *after, const char *letter, Evas_Smart_Cb func, const void *data)
1017 {
1018    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1019    Widget_Data *wd = elm_widget_data_get(obj);
1020    Elm_Index_Item *it;
1021    if (!wd) return NULL;
1022    if (!after)
1023      {
1024         it = (Elm_Index_Item *)elm_index_item_append(obj, letter, data);
1025         wd->tot_items_count[wd->level]++;
1026         return (Elm_Object_Item *)it;
1027      }
1028    it = _item_new(obj, letter, func, data);
1029    if (!it) return NULL;
1030    wd->items = eina_list_append_relative(wd->items, it, after);
1031    wd->tot_items_count[wd->level]++;
1032    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1033    return (Elm_Object_Item *)it;
1034 }
1035
1036 EAPI Elm_Object_Item *
1037 elm_index_item_insert_before(Evas_Object *obj, Elm_Object_Item *before, const char *letter, Evas_Smart_Cb func, const void *data)
1038 {
1039    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1040    Widget_Data *wd = elm_widget_data_get(obj);
1041    Elm_Index_Item *it;
1042    if (!wd) return NULL;
1043    if (!before)
1044      {
1045         it = (Elm_Index_Item *)elm_index_item_prepend(obj, letter, data);
1046         wd->tot_items_count[wd->level]++;
1047         return (Elm_Object_Item *)it;
1048      }
1049    it = _item_new(obj, letter, func, data);
1050    if (!it) return NULL;
1051    wd->items = eina_list_prepend_relative(wd->items, it, before);
1052    wd->tot_items_count[wd->level]++;
1053    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1054    return (Elm_Object_Item *)it;
1055 }
1056
1057 EAPI Elm_Object_Item *
1058 elm_index_item_sorted_insert(Evas_Object *obj, const char *letter, const void *data, Eina_Compare_Cb cmp_func, Eina_Compare_Cb cmp_data_func)
1059 {
1060    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1061    Widget_Data *wd = elm_widget_data_get(obj);
1062    Eina_List *lnear;
1063    Elm_Index_Item *it;
1064    int cmp;
1065
1066    if (!wd) return NULL;
1067    if (!(wd->items))
1068      return elm_index_item_append(obj, letter, data);
1069
1070    it = _item_new(obj, letter, NULL, data);
1071    if (!it) return NULL;
1072
1073    lnear = eina_list_search_sorted_near_list(wd->items, cmp_func, it, &cmp);
1074    if (cmp < 0)
1075      wd->items =  eina_list_append_relative_list(wd->items, it, lnear);
1076    else if (cmp > 0)
1077      wd->items = eina_list_prepend_relative_list(wd->items, it, lnear);
1078    else
1079      {
1080         /* If cmp_data_func is not provided, append a duplicated item */
1081         if (!cmp_data_func)
1082           wd->items =  eina_list_append_relative_list(wd->items, it, lnear);
1083         else
1084           {
1085              Elm_Index_Item *p_it = eina_list_data_get(lnear);
1086              if (cmp_data_func(p_it->base.data, it->base.data) >= 0)
1087                p_it->base.data = it->base.data;
1088              _item_free(it);
1089              elm_widget_item_free(it);
1090           }
1091      }
1092    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1093    return (Elm_Object_Item *)it;
1094 }
1095
1096 EAPI void
1097 elm_index_item_del(Evas_Object *obj __UNUSED__, Elm_Object_Item *it)
1098 {
1099    elm_object_item_del(it);
1100 }
1101
1102 EAPI Elm_Object_Item *
1103 elm_index_item_find(Evas_Object *obj, const void *data)
1104 {
1105    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1106    Widget_Data *wd = elm_widget_data_get(obj);
1107    if (!wd) return NULL;
1108    return (Elm_Object_Item *) _item_find(obj, data);
1109 }
1110
1111 EAPI void
1112 elm_index_item_clear(Evas_Object *obj)
1113 {
1114    ELM_CHECK_WIDTYPE(obj, widtype);
1115    Widget_Data *wd = elm_widget_data_get(obj);
1116    Elm_Index_Item *it;
1117    Eina_List *l, *clear = NULL;
1118    if (!wd) return;
1119    _index_box_clear(obj, wd->bx[wd->level], wd->level);
1120    EINA_LIST_FOREACH(wd->items, l, it)
1121      {
1122         if (it->level != wd->level) continue;
1123         clear = eina_list_append(clear, it);
1124      }
1125    EINA_LIST_FREE(clear, it)
1126      {
1127         wd->tot_items_count[wd->level]--;
1128         _item_free(it);
1129         elm_widget_item_free(it);
1130      }
1131 }
1132
1133 EINA_DEPRECATED EAPI void
1134 elm_index_item_go(Evas_Object *obj, int level __UNUSED__)
1135 {
1136    elm_index_level_go(obj, level);
1137 }
1138
1139 EAPI void
1140 elm_index_level_go(Evas_Object *obj, int level __UNUSED__)
1141 {
1142    ELM_CHECK_WIDTYPE(obj, widtype);
1143    Widget_Data *wd = elm_widget_data_get(obj);
1144    if (!wd) return;
1145    //FIXME: Check the crash problem
1146 //   if(level == 0) _index_process(obj);
1147    _index_box_auto_fill(obj, wd->bx[0], 0);
1148    if (wd->level == 1) _index_box_auto_fill(obj, wd->bx[1], 1);
1149 }
1150
1151 EAPI void *
1152 elm_index_item_data_get(const Elm_Object_Item *it)
1153 {
1154    return elm_object_item_data_get(it);
1155 }
1156
1157 EAPI void
1158 elm_index_item_data_set(Elm_Object_Item *it, const void *data)
1159 {
1160    elm_object_item_data_set(it, (void *) data);
1161 }
1162
1163 EAPI void
1164 elm_index_indicator_disabled_set(Evas_Object *obj, Eina_Bool disabled)
1165 {
1166    ELM_CHECK_WIDTYPE(obj, widtype);
1167    Widget_Data *wd = elm_widget_data_get(obj);
1168    if (!wd) return;
1169
1170    disabled = !!disabled;
1171    if (wd->indicator_disabled == disabled) return;
1172    wd->indicator_disabled = disabled;
1173    if (!wd->items) return;
1174    if (disabled)
1175      edje_object_signal_emit(wd->base, "elm,indicator,state,inactive", "elm");
1176    else
1177      edje_object_signal_emit(wd->base, "elm,indicator,state,active", "elm");
1178 }
1179
1180 EAPI Eina_Bool
1181 elm_index_indicator_disabled_get(const Evas_Object *obj)
1182 {
1183    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1184    Widget_Data *wd = elm_widget_data_get(obj);
1185    if (!wd) return EINA_FALSE;
1186
1187    return wd->indicator_disabled;
1188 }
1189
1190 EAPI void
1191 elm_index_item_del_cb_set(Elm_Object_Item *it, Evas_Smart_Cb func)
1192 {
1193    elm_object_item_del_cb_set(it, func);
1194 }
1195
1196 EAPI const char *
1197 elm_index_item_letter_get(const Elm_Object_Item *it)
1198 {
1199    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
1200    return ((Elm_Index_Item *)it)->letter;
1201 }
1202
1203 EAPI void
1204 elm_index_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
1205 {
1206    ELM_CHECK_WIDTYPE(obj, widtype);
1207    Widget_Data *wd = elm_widget_data_get(obj);
1208    if (!wd) return;
1209
1210    horizontal = !!horizontal;
1211    if (horizontal == wd->horizontal) return;
1212    wd->horizontal = horizontal;
1213    _theme_hook(obj);
1214 }
1215
1216 EAPI Eina_Bool
1217 elm_index_horizontal_get(const Evas_Object *obj)
1218 {
1219    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1220    Widget_Data *wd = elm_widget_data_get(obj);
1221    if (!wd) return EINA_FALSE;
1222    return wd->horizontal;
1223 }
1224
1225