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