Merge branch 'master' into svn_merge
[framework/uifw/elementary.git] / src / lib / elm_diskselector.c
1 /**
2  * @defgroup Diskselector
3  *
4  * A diskselector is a kind of list widget. It scrolls horizontally,
5  * and can contain label and icon objects. Three items are displayed
6  * with the selected on the middle.
7  *
8  * It can act like a circular list with round mode and labels can be
9  * reduced for a defined length for side items.
10  *
11  * Signals that you can add callbacks for are:
12  *
13  * "selected" - when item is selected (scroller stops)
14  */
15
16 #include <Elementary.h>
17 #include "elm_priv.h"
18
19 #ifndef MAX
20 # define MAX(a, b) (((a) > (b)) ? (a) : (b))
21 #endif
22
23 #ifndef CEIL
24 #define CEIL(a) (((a) % 2 != 0) ? ((a) / 2 + 1) : ((a) / 2))
25 #endif
26
27 #define DISPLAY_ITEM_NUM_MIN 3
28
29 typedef struct _Widget_Data Widget_Data;
30
31 struct _Widget_Data
32 {
33    Evas_Object *self;
34    Evas_Object *scroller;
35    Evas_Object *main_box;
36    Evas_Object *left_blank;
37    Evas_Object *right_blank;
38    Elm_Diskselector_Item *selected_item;
39    Elm_Diskselector_Item *first;
40    Elm_Diskselector_Item *second;
41    Elm_Diskselector_Item *s_last;
42    Elm_Diskselector_Item *last;
43    Eina_List *items;
44    Eina_List *r_items;
45    Eina_List *over_items;
46    Eina_List *under_items;
47    int item_count, len_threshold, len_side, display_item_num;
48    Ecore_Idler *idler;
49    Ecore_Idler *check_idler;
50    Evas_Coord minw, minh;
51    Eina_Bool init:1;
52    Eina_Bool round:1;
53    Eina_Bool display_item_num_by_api:1;
54 };
55
56 struct _Elm_Diskselector_Item
57 {
58    Elm_Widget_Item base;
59    Eina_List *node;
60    Evas_Object *icon;
61    const char *label;
62    Evas_Smart_Cb func;
63 };
64
65 static const char *widtype = NULL;
66
67 #define ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it, ...)                  \
68    ELM_WIDGET_ITEM_CHECK_OR_RETURN((Elm_Widget_Item *)it, __VA_ARGS__); \
69    ELM_CHECK_WIDTYPE(it->base.widget, widtype) __VA_ARGS__;
70
71 static Eina_Bool _move_scroller(void *data);
72 static void _del_hook(Evas_Object * obj);
73 static void _del_pre_hook(Evas_Object * obj);
74 static void _sizing_eval(Evas_Object * obj);
75 static void _theme_hook(Evas_Object * obj);
76 static void _on_focus_hook(void *data, Evas_Object *obj);
77 static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src, Evas_Callback_Type type, void *event_info);
78 static void _sub_del(void *data, Evas_Object * obj, void *event_info);
79 static void _round_items_del(Widget_Data *wd);
80 static void _scroller_move_cb(void *data, Evas_Object *obj, void *event_info);
81 static void _item_click_cb(void *data, Evas_Object *obj __UNUSED__,
82                            const char *emission __UNUSED__,
83                            const char *source __UNUSED__);
84 static void _selected_item_indicate(Elm_Diskselector_Item *it);
85
86 static const char SIG_SELECTED[] = "selected";
87 static const Evas_Smart_Cb_Description _signals[] = {
88        {SIG_SELECTED, ""},
89        {NULL, NULL}
90 };
91
92 static void
93 _diskselector_object_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
94 {
95    Widget_Data *wd;
96    Evas_Coord w, h;
97
98    wd = elm_widget_data_get(data);
99    if (!wd) return;
100
101    if (wd->minw == -1 && wd->minh == -1) elm_coords_finger_size_adjust(6, &wd->minw, 1, &wd->minh);
102    edje_object_size_min_restricted_calc(elm_smart_scroller_edje_object_get(
103          wd->scroller), &wd->minw, &wd->minh, wd->minw, wd->minh);
104    evas_object_size_hint_min_set(obj, wd->minw, wd->minh);
105    evas_object_size_hint_max_set(obj, -1, -1);
106
107    evas_object_geometry_get(wd->scroller, NULL, NULL, &w, &h);
108    if (wd->round)
109      evas_object_resize(wd->main_box, (w / wd->display_item_num) * (wd->item_count + (CEIL(wd->display_item_num) * 2)), h);
110    else
111      evas_object_resize(wd->main_box, (w / wd->display_item_num) * (wd->item_count + CEIL(wd->display_item_num)), h);
112
113    elm_smart_scroller_paging_set(wd->scroller, 0, 0,
114                                  (int)(w / wd->display_item_num), 0);
115
116    if (!wd->idler)
117      wd->idler = ecore_idler_add(_move_scroller, data);
118 }
119
120 static Elm_Diskselector_Item *
121 _item_new(Evas_Object *obj, Evas_Object *icon, const char *label, Evas_Smart_Cb func, const void *data)
122 {
123    Elm_Diskselector_Item *it;
124    const char *style = elm_widget_style_get(obj);
125
126    it = elm_widget_item_new(obj, Elm_Diskselector_Item);
127    if (!it) return NULL;
128
129    it->label = eina_stringshare_add(label);
130    it->icon = icon;
131    it->func = func;
132    it->base.data = data;
133    it->base.view = edje_object_add(evas_object_evas_get(obj));
134    _elm_theme_object_set(obj, it->base.view, "diskselector", "item", style);
135    evas_object_size_hint_weight_set(it->base.view, EVAS_HINT_EXPAND,
136                                     EVAS_HINT_EXPAND);
137    evas_object_size_hint_align_set(it->base.view, EVAS_HINT_FILL,
138                                    EVAS_HINT_FILL);
139    evas_object_show(it->base.view);
140
141    if (it->label)
142      {
143         edje_object_part_text_set(it->base.view, "elm.text", it->label);
144         edje_object_signal_callback_add(it->base.view, "elm,action,click", "", _item_click_cb, it);
145      }
146    if (it->icon)
147      {
148         evas_object_size_hint_min_set(it->icon, 24, 24);
149         evas_object_size_hint_max_set(it->icon, 40, 40);
150         edje_object_part_swallow(it->base.view, "elm.swallow.icon", it->icon);
151         evas_object_show(it->icon);
152         elm_widget_sub_object_add(obj, it->icon);
153      }
154    return it;
155 }
156
157 static void
158 _item_del(Elm_Diskselector_Item *item)
159 {
160    if (!item) return;
161    eina_stringshare_del(item->label);
162    if (item->icon)
163      evas_object_del(item->icon);
164    elm_widget_item_del(item);
165 }
166
167 static void
168 _theme_data_get(Widget_Data *wd)
169 {
170    const char* str;
171    Evas_Object *parent;
172    str = edje_object_data_get(wd->right_blank, "len_threshold");
173    if (str) wd->len_threshold = MAX(0, atoi(str));
174    else wd->len_threshold = 0;
175
176    if (!wd->display_item_num_by_api)
177      {
178         str = edje_object_data_get(wd->right_blank, "display_item_num");
179         if (str) wd->display_item_num = MAX(DISPLAY_ITEM_NUM_MIN, atoi(str));
180         else wd->display_item_num = DISPLAY_ITEM_NUM_MIN;
181      }
182
183    str = edje_object_data_get(wd->right_blank, "min_width");
184    if (str) wd->minw = MAX(-1, atoi(str));
185    else
186      {
187         parent = elm_widget_parent_widget_get(wd->self);
188         if (!parent) wd->minw = -1;
189         else evas_object_geometry_get(parent, NULL, NULL, &wd->minw, NULL);
190      }
191
192    str = edje_object_data_get(wd->right_blank, "min_height");
193    if (str) wd->minh = MAX(-1, atoi(str));
194    else wd->minh = -1;
195 }
196
197 static void
198 _default_display_item_num_set(Widget_Data *wd)
199 {
200    const char* str;
201    str = edje_object_data_get(wd->right_blank, "display_item_num");
202    if (str) wd->display_item_num = MAX(DISPLAY_ITEM_NUM_MIN, atoi(str));
203    else wd->display_item_num = DISPLAY_ITEM_NUM_MIN;
204 }
205
206 static void
207 _del_hook(Evas_Object * obj)
208 {
209    Widget_Data *wd = elm_widget_data_get(obj);
210    if (!wd) return;
211    free(wd);
212 }
213
214 static void
215 _del_pre_hook(Evas_Object * obj)
216 {
217    Elm_Diskselector_Item *it;
218    Eina_List *l;
219
220    Widget_Data *wd = elm_widget_data_get(obj);
221    if (!wd) return;
222
223    if (wd->left_blank)
224      evas_object_del(wd->left_blank);
225    if (wd->right_blank)
226      evas_object_del(wd->right_blank);
227    if (wd->last)
228      {
229         eina_stringshare_del(wd->last->label);
230         evas_object_del(wd->last->base.view);
231         free(wd->last);
232      }
233    if (wd->s_last)
234      {
235         eina_stringshare_del(wd->s_last->label);
236         evas_object_del(wd->s_last->base.view);
237         free(wd->s_last);
238      }
239    if (wd->second)
240      {
241         eina_stringshare_del(wd->second->label);
242         evas_object_del(wd->second->base.view);
243         free(wd->second);
244      }
245    if (wd->first)
246      {
247         eina_stringshare_del(wd->first->label);
248         evas_object_del(wd->first->base.view);
249         free(wd->first);
250      }
251
252    EINA_LIST_FOREACH(wd->under_items, l, it)
253      {
254         if (it)
255           {
256              eina_stringshare_del(it->label);
257              evas_object_del(wd->first->base.view);
258              free(it);
259           }
260      }
261
262    EINA_LIST_FOREACH(wd->over_items, l, it)
263    {
264      if (it)
265         {
266            eina_stringshare_del(it->label);
267            evas_object_del(wd->first->base.view);
268            free(it);
269         }
270    }
271
272    EINA_LIST_FREE(wd->items, it) _item_del(it);
273    eina_list_free(wd->r_items);
274 }
275
276 static void
277 _sizing_eval(Evas_Object * obj)
278 {
279    Widget_Data *wd = elm_widget_data_get(obj);
280    if (!wd) return;
281    _diskselector_object_resize(obj, NULL, obj, NULL);
282 }
283
284 static void
285 _theme_hook(Evas_Object * obj)
286 {
287    Eina_List *l;
288    Elm_Diskselector_Item *it;
289    Widget_Data *wd = elm_widget_data_get(obj);
290    if (!wd) return;
291
292    if (wd->scroller)
293      elm_smart_scroller_object_theme_set(obj, wd->scroller, "diskselector",
294                                          "base", elm_widget_style_get(obj));
295    if (wd->round)
296      {
297         EINA_LIST_FOREACH(wd->r_items, l, it)
298           {
299              _elm_theme_object_set(obj, it->base.view, "diskselector", "item",
300                                    elm_widget_style_get(obj));
301           }
302      }
303    else
304      {
305         EINA_LIST_FOREACH(wd->items, l, it)
306           {
307              _elm_theme_object_set(obj, it->base.view, "diskselector", "item",
308                                    elm_widget_style_get(obj));
309           }
310      }
311    _elm_theme_object_set(obj, wd->right_blank, "diskselector", "item",
312                                    elm_widget_style_get(obj));
313    _theme_data_get(wd);
314    _sizing_eval(obj);
315 }
316
317 static void
318 _sub_del(void *data __UNUSED__, Evas_Object * obj, void *event_info)
319 {
320    Widget_Data *wd = elm_widget_data_get(obj);
321    Evas_Object *sub = event_info;
322    Elm_Diskselector_Item *it;
323    const Eina_List *l;
324
325    if (!wd) return;
326    if (!sub) abort();
327    if (sub == wd->scroller)
328      wd->scroller = NULL;
329    else
330      {
331         EINA_LIST_FOREACH(wd->items, l, it)
332           {
333              if (sub == it->icon)
334                {
335                   it->icon = NULL;
336                   _sizing_eval(obj);
337                   break;
338                }
339           }
340      }
341 }
342
343 static void
344 _select_item(Elm_Diskselector_Item *it)
345 {
346    if (!it) return;
347    Widget_Data *wd = elm_widget_data_get(it->base.widget);
348    wd->selected_item = it;
349    _selected_item_indicate(wd->selected_item);
350    if (it->func) it->func((void *)it->base.data, it->base.widget, it);
351    evas_object_smart_callback_call(it->base.widget, SIG_SELECTED, it);
352 }
353
354 static void
355 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
356 {
357    Widget_Data *wd = elm_widget_data_get(obj);
358    if (!wd)
359      return;
360
361    if (elm_widget_focus_get(obj))
362      {
363         edje_object_signal_emit(wd->self, "elm,action,focus", "elm");
364         evas_object_focus_set(wd->self, EINA_TRUE);
365      }
366    else
367      {
368         edje_object_signal_emit(wd->self, "elm,action,unfocus", "elm");
369         evas_object_focus_set(wd->self, EINA_FALSE);
370      }
371 }
372
373 static Eina_Bool
374 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
375 {
376    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
377    Evas_Event_Key_Down *ev = event_info;
378    Widget_Data *wd = elm_widget_data_get(obj);
379    if (!wd) return EINA_FALSE;
380    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
381    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
382
383    Elm_Diskselector_Item *it = NULL;
384    Eina_List *l;
385
386    if (!wd->selected_item) {
387         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
388         return EINA_TRUE;
389    }
390
391    if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")) ||
392        (!strcmp(ev->keyname, "Up"))  || (!strcmp(ev->keyname, "KP_Up")))
393      {
394         l = wd->selected_item->node->prev;
395         if ((!l) && (wd->round))
396           l = eina_list_last(wd->items);
397      }
398    else if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right")) ||
399             (!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
400      {
401         l = wd->selected_item->node->next;
402         if ((!l) && (wd->round))
403           l = wd->items;
404      }
405    else if ((!strcmp(ev->keyname, "Home")) || (!strcmp(ev->keyname, "KP_Home")))
406      l = wd->items;
407    else if ((!strcmp(ev->keyname, "End")) || (!strcmp(ev->keyname, "KP_End")))
408      l = eina_list_last(wd->items);
409    else return EINA_FALSE;
410
411    if (l)
412      it = eina_list_data_get(l);
413
414    if (it)
415      {
416         wd->selected_item = it;
417         if (!wd->idler)
418           wd->idler = ecore_idler_add(_move_scroller, obj);
419      }
420
421    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
422    return EINA_TRUE;
423 }
424
425 static int
426 _count_letter(const char *str)
427 {
428    int pos = 0;
429    int code = 0, chnum;
430
431    for (chnum = 0; ; chnum++)
432      {
433         pos = evas_string_char_next_get(str, pos, &code);
434         if (code == 0) break;
435      }
436    return chnum;
437 }
438
439 static int
440 _check_letter(const char *str, int length)
441 {
442    int pos = 0;
443    int code = 0, chnum;
444
445    for (chnum = 0; ; chnum++)
446      {
447         if (chnum == length) break;
448         pos = evas_string_char_next_get(str, pos, &code);
449         if (code == 0) break;
450      }
451    return pos;
452 }
453
454 static Eina_Bool
455 _check_string(void *data)
456 {
457    int mid, steps, length, diff;
458    Elm_Diskselector_Item *it;
459    Eina_List *list, *l;
460    Evas_Coord ox, ow;
461    char buf[1024];
462    Widget_Data *wd = data;
463
464    evas_object_geometry_get(wd->scroller, &ox, NULL, &ow, NULL);
465    if (ow <= 0)
466      return EINA_FALSE;
467    if (!wd->init)
468      return EINA_FALSE;
469    if (!wd->round)
470      list = wd->items;
471    else
472      list = wd->r_items;
473
474    EINA_LIST_FOREACH(list, l, it)
475      {
476         Evas_Coord x, w;
477         int len;
478         evas_object_geometry_get(it->base.view, &x, NULL, &w, NULL);
479         /* item not visible */
480         if ((x + w <= ox) || (x >= ox + ow))
481           continue;
482
483         len = _count_letter(it->label);
484 //        // FIXME: len should be # of ut8f letters. ie count using utf8 string walk, not stringshare len
485 //        len = eina_stringshare_strlen(it->label);
486
487         if (x <= ox + 5)
488           edje_object_signal_emit(it->base.view, "elm,state,left_side",
489                                   "elm");
490         else if (x + w >= ox + ow - 5)
491           edje_object_signal_emit(it->base.view, "elm,state,right_side",
492                                   "elm");
493         else
494           {
495              if ((wd->len_threshold) && (len > wd->len_threshold))
496                edje_object_signal_emit(it->base.view, "elm,state,center_small",
497                                        "elm");
498              else
499                edje_object_signal_emit(it->base.view, "elm,state,center",
500                                        "elm");
501           }
502
503         // if len is les that the limit len, skip anyway
504         if (len <= wd->len_side)
505           continue;
506
507         steps = len - wd->len_side + 1;
508         mid = x + w / 2;
509         if (mid <= ox + ow / 2)
510           diff = (ox + ow / 2) - mid;
511         else
512           diff = mid - (ox + ow / 2);
513
514         length = len - (int)(diff * steps / (ow / 3));
515         length = MAX(length, wd->len_side);
516         // limit string len to "length" ut8f chars
517         length = _check_letter(it->label, length);
518         // cut it off at byte mark returned form _check_letter
519         strncpy(buf, it->label, length);
520         buf[length] = '\0';
521         edje_object_part_text_set(it->base.view, "elm.text", buf);
522      }
523
524    if (wd->check_idler)
525      ecore_idler_del(wd->check_idler);
526    wd->check_idler = NULL;
527    return EINA_FALSE;
528 }
529
530 static void
531 _selected_item_indicate(Elm_Diskselector_Item *it)
532 {
533    Elm_Diskselector_Item *item;
534    Eina_List *l;
535    Widget_Data *wd;
536    wd = elm_widget_data_get(it->base.widget);
537
538    if (!wd) return;
539
540    EINA_LIST_FOREACH(wd->r_items, l, item)
541      {
542         if (!strcmp(item->label, it->label)) edje_object_signal_emit(item->base.view, "elm,state,selected", "elm");
543         else
544            edje_object_signal_emit(item->base.view, "elm,state,default", "elm");
545      }
546 }
547
548 static void
549 _item_click_cb(void *data, Evas_Object *obj __UNUSED__,
550                const char *emission __UNUSED__, const char *source __UNUSED__)
551 {
552    Elm_Diskselector_Item *it = data;
553
554    if (!it) return;
555
556    Widget_Data *wd;
557    wd = elm_widget_data_get(it->base.widget);
558
559    if (!wd) return;
560
561    if (wd->selected_item != it)
562      {
563         wd->selected_item = it;
564         _selected_item_indicate(wd->selected_item);
565      }
566
567    if (it->func) it->func((void *)it->base.data, it->base.widget, it);
568 }
569
570 static void
571 _scroller_move_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
572 {
573    Evas_Coord x, y, w, h, bw;
574    Widget_Data *wd = data;
575
576    _check_string(wd);
577    elm_smart_scroller_child_pos_get(obj, &x, &y);
578    elm_smart_scroller_child_viewport_size_get(obj, &w, &h);
579    if (wd->round)
580      {
581         evas_object_geometry_get(wd->main_box, NULL, NULL, &bw, NULL);
582         if (x > ((w / wd->display_item_num) * (wd->item_count + (wd->display_item_num % 2))))
583            elm_smart_scroller_child_region_show(wd->scroller,
584                                                x - ((w / wd->display_item_num) * wd->item_count),
585                                                y, w, h);
586         else if (x < 0)
587            elm_smart_scroller_child_region_show(wd->scroller,
588                                                x + ((w / wd->display_item_num) * wd->item_count),
589                                                y, w, h);
590      }
591 }
592
593 static void
594 _scroller_stop_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
595 {
596    Elm_Diskselector_Item *it;
597    Widget_Data *wd = data;
598    Evas_Coord x, w, ow;
599    Eina_List *l, *list;
600
601    if (wd->idler)
602      return;
603
604    if (!wd->round)
605      list = wd->items;
606    else
607      list = wd->r_items;
608
609    evas_object_geometry_get(wd->scroller, NULL, NULL, &ow, NULL);
610    EINA_LIST_FOREACH(list, l, it)
611      {
612         evas_object_geometry_get(it->base.view, &x, NULL, &w, NULL);
613         if (abs((int)(ow / 2 - (int)(x + w / 2))) < 10)
614           break;
615      }
616
617    if (!it)
618      return;
619
620    _select_item(it);
621 }
622
623 static Eina_Bool
624 _move_scroller(void *data)
625 {
626    Evas_Object *obj = data;
627    Widget_Data *wd;
628    Eina_List *l;
629    Elm_Diskselector_Item *dit;
630    Evas_Coord y, w, h;
631    int i;
632
633    wd = elm_widget_data_get(obj);
634    if (!wd) return EINA_FALSE;
635
636    if (wd->round)
637      i = 1;
638    else
639      i = 0;
640
641    EINA_LIST_FOREACH(wd->items, l, dit)
642      {
643         if (wd->selected_item == dit)
644           break;
645         i++;
646      }
647    if (!dit)
648      {
649         wd->selected_item =
650            (Elm_Diskselector_Item *) eina_list_nth(wd->items, 0);
651         return EINA_FALSE;
652      }
653
654    evas_object_geometry_get(wd->scroller, NULL, &y, &w, &h);
655    elm_smart_scroller_child_region_show(wd->scroller, w / wd->display_item_num * i, y, w, h);
656    _select_item(dit);
657    if (wd->idler)
658      {
659         ecore_idler_del(wd->idler);
660         wd->idler = NULL;
661      }
662    wd->init = EINA_TRUE;
663    _check_string(wd);
664
665    return EINA_TRUE;
666 }
667
668 static void
669 _round_item_del(Widget_Data *wd, Elm_Diskselector_Item *it)
670 {
671    if (!it) return;
672    elm_box_unpack(wd->main_box, it->base.view);
673    wd->r_items = eina_list_remove(wd->r_items, it);
674    eina_stringshare_del(it->label);
675    evas_object_del(it->base.view);
676    free(it);
677 }
678
679 static void
680 _round_items_del(Widget_Data *wd)
681 {
682    Eina_List *l;
683    Elm_Diskselector_Item * it;
684
685    _round_item_del(wd, wd->last);
686    wd->last = NULL;
687    _round_item_del(wd, wd->s_last);
688    wd->s_last = NULL;
689    _round_item_del(wd, wd->second);
690    wd->second = NULL;
691    _round_item_del(wd, wd->first);
692    wd->first = NULL;
693
694    EINA_LIST_FOREACH(wd->under_items, l, it)
695      {
696         _round_item_del(wd, it);
697         it = NULL;
698      }
699
700    EINA_LIST_FOREACH(wd->over_items, l, it)
701      {
702         _round_item_del(wd, it);
703         it = NULL;
704      }
705 }
706
707 static void
708 _round_items_add(Widget_Data *wd)
709 {
710    Elm_Diskselector_Item *dit;
711    Elm_Diskselector_Item *it;
712    Elm_Diskselector_Item *temp_it;
713    int i = 0;
714    dit = it = eina_list_nth(wd->items, 0);
715    if (!dit) return;
716
717    if (!wd->first)
718      {
719         wd->first = _item_new(it->base.widget, it->icon, it->label, it->func,
720                               it->base.data);
721         wd->first->node = it->node;
722         wd->r_items = eina_list_append(wd->r_items, wd->first);
723      }
724
725    it = eina_list_nth(wd->items, 1);
726    if (!it)
727      it = dit;
728    if (!wd->second)
729      {
730         wd->second = _item_new(it->base.widget, it->icon, it->label, it->func,
731                                it->base.data);
732         wd->second->node = it->node;
733         wd->r_items = eina_list_append(wd->r_items, wd->second);
734      }
735
736    // if more than 3 itmes should be displayed
737    for (i = 2; i < CEIL(wd->display_item_num); i++)
738      {
739         it = eina_list_nth(wd->items, i);
740         if (!it) it = dit;
741         temp_it = _item_new(it->base.widget, it->icon, it->label, it->func, it->base.data);
742         wd->over_items = eina_list_append(wd->over_items, temp_it);
743         wd->r_items = eina_list_append(wd->r_items, temp_it);
744      }
745
746    it = eina_list_nth(wd->items, wd->item_count - 1);
747    if (!it)
748      it = dit;
749    if (!wd->last)
750      {
751         wd->last = _item_new(it->base.widget, it->icon, it->label, it->func,
752                              it->base.data);
753         wd->last->node = it->node;
754         wd->r_items = eina_list_prepend(wd->r_items, wd->last);
755      }
756
757    it = eina_list_nth(wd->items, wd->item_count - 2);
758    if (!it)
759      it = dit;
760    if (!wd->s_last)
761      {
762         wd->s_last = _item_new(it->base.widget, it->icon, it->label, it->func,
763                                it->base.data);
764         wd->s_last->node = it->node;
765         wd->r_items = eina_list_prepend(wd->r_items, wd->s_last);
766      }
767
768    // if more than 3 itmes should be displayed
769    for (i = 3; i <= CEIL(wd->display_item_num); i++)
770      {
771         it = eina_list_nth(wd->items, wd->item_count - i);
772         if (!it) it = dit;
773         temp_it = _item_new(it->base.widget, it->icon, it->label, it->func, it->base.data);
774         wd->under_items = eina_list_append(wd->under_items, temp_it);
775         wd->r_items = eina_list_prepend(wd->r_items, temp_it);
776      }
777 }
778
779 /**
780  * Add a new diskselector object
781  *
782  * @param parent The parent object
783  * @return The new object or NULL if it cannot be created
784  *
785  * @ingroup Diskselector
786  */
787 EAPI Evas_Object *
788 elm_diskselector_add(Evas_Object *parent)
789 {
790    Evas *e;
791    Evas_Object *obj;
792    Widget_Data *wd;
793
794    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
795
796    ELM_SET_WIDTYPE(widtype, "diskselector");
797    elm_widget_type_set(obj, "diskselector");
798    elm_widget_sub_object_add(parent, obj);
799    elm_widget_data_set(obj, wd);
800    elm_widget_del_hook_set(obj, _del_hook);
801    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
802    elm_widget_theme_hook_set(obj, _theme_hook);
803    elm_widget_can_focus_set(obj, EINA_TRUE);
804    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
805    elm_widget_event_hook_set(obj, _event_hook);
806
807    wd->self = obj;
808    wd->item_count = 0;
809    wd->round = EINA_FALSE;
810    wd->init = EINA_FALSE;
811    wd->len_side = 3;
812    wd->display_item_num_by_api = EINA_FALSE;
813
814    wd->scroller = elm_smart_scroller_add(e);
815    elm_smart_scroller_widget_set(wd->scroller, obj);
816    _theme_hook(obj);
817    elm_widget_resize_object_set(obj, wd->scroller);
818    elm_smart_scroller_policy_set(wd->scroller, ELM_SMART_SCROLLER_POLICY_OFF,
819                                  ELM_SMART_SCROLLER_POLICY_OFF);
820    elm_smart_scroller_bounce_allow_set(wd->scroller, EINA_TRUE, EINA_FALSE);
821    evas_object_smart_callback_add(wd->scroller, "scroll", _scroller_move_cb,
822                                   wd);
823    evas_object_smart_callback_add(wd->scroller, "animate,stop",
824                                   _scroller_stop_cb, wd);
825    _elm_theme_object_set(obj, wd->scroller, "diskselector", "base",
826                          "default");
827    evas_object_event_callback_add(wd->scroller, EVAS_CALLBACK_RESIZE,
828                                   _diskselector_object_resize, obj);
829
830    wd->main_box = elm_box_add(parent);
831    elm_box_horizontal_set(wd->main_box, EINA_TRUE);
832    elm_box_homogeneous_set(wd->main_box, EINA_TRUE);
833    evas_object_size_hint_weight_set(wd->main_box, EVAS_HINT_EXPAND,
834                                     EVAS_HINT_EXPAND);
835    evas_object_size_hint_align_set(wd->main_box, EVAS_HINT_FILL,
836                                    EVAS_HINT_FILL);
837    _elm_theme_object_set(obj, wd->main_box, "diskselector", "base",
838                          "default");
839    elm_widget_sub_object_add(obj, wd->main_box);
840
841    elm_smart_scroller_child_set(wd->scroller, wd->main_box);
842
843    wd->left_blank = edje_object_add(evas_object_evas_get(obj));
844    _elm_theme_object_set(obj, wd->left_blank, "diskselector", "item",
845                          "default");
846    evas_object_size_hint_weight_set(wd->left_blank, EVAS_HINT_EXPAND,
847                                     EVAS_HINT_EXPAND);
848    evas_object_size_hint_align_set(wd->left_blank, EVAS_HINT_FILL,
849                                    EVAS_HINT_FILL);
850    elm_box_pack_end(wd->main_box, wd->left_blank);
851    evas_object_show(wd->left_blank);
852
853    wd->right_blank = edje_object_add(evas_object_evas_get(obj));
854    _elm_theme_object_set(obj, wd->right_blank, "diskselector", "item",
855                          "default");
856    evas_object_size_hint_weight_set(wd->right_blank, EVAS_HINT_EXPAND,
857                                     EVAS_HINT_EXPAND);
858    evas_object_size_hint_align_set(wd->right_blank, EVAS_HINT_FILL,
859                                    EVAS_HINT_FILL);
860    elm_box_pack_end(wd->main_box, wd->right_blank);
861    evas_object_show(wd->right_blank);
862
863    _theme_data_get(wd);
864
865    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
866    evas_object_smart_callbacks_descriptions_set(obj, _signals);
867    _sizing_eval(obj);
868    return obj;
869 }
870
871 /**
872  * Get round mode
873  *
874  * If round mode is activated the items list will work like a circle list,
875  * so when the user reaches the last item, the first one will popup.
876  *
877  * @param obj The diskselector object
878  * @return if or not set round mode or false if not a valid diskselector
879  *
880  * @ingroup Diskselector
881  */
882 EAPI Eina_Bool
883 elm_diskselector_round_get(const Evas_Object *obj)
884 {
885    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
886    Widget_Data *wd = elm_widget_data_get(obj);
887    if (!wd) return EINA_FALSE;
888    return wd->round;
889 }
890
891 /**
892  * Set round mode
893  *
894  * If round mode is activated the items list will work like a circle list,
895  * so when the user reaches the last item, the first one will popup.
896  *
897  * @param it The item of diskselector
898  * @param if or not set round mode
899  *
900  * @ingroup Diskselector
901  */
902 EAPI void
903 elm_diskselector_round_set(Evas_Object * obj, Eina_Bool round)
904 {
905    Eina_List *elist;
906    Elm_Diskselector_Item *it;
907
908    ELM_CHECK_WIDTYPE(obj, widtype);
909    Widget_Data *wd = elm_widget_data_get(obj);
910    if (!wd) return;
911
912    if (wd->round == round)
913      return;
914
915    wd->round = round;
916    if (round)
917      {
918         wd->r_items = eina_list_clone(wd->items);
919         elm_box_unpack(wd->main_box, wd->left_blank);
920         evas_object_hide(wd->left_blank);
921         elm_box_unpack(wd->main_box, wd->right_blank);
922         evas_object_hide(wd->right_blank);
923         if (!wd->items)
924           return;
925
926         _round_items_add(wd);
927
928         if (wd->last)
929           elm_box_pack_start(wd->main_box, wd->last->base.view);
930         if (wd->s_last)
931           elm_box_pack_start(wd->main_box, wd->s_last->base.view);
932
933         // if more than 3 items should be displayed
934         EINA_LIST_FOREACH(wd->under_items, elist, it)
935            elm_box_pack_start(wd->main_box, it->base.view);
936
937         if (wd->first)
938           elm_box_pack_end(wd->main_box, wd->first->base.view);
939         if (wd->second)
940           elm_box_pack_end(wd->main_box, wd->second->base.view);
941
942         // if more than 3 items should be displayed
943         EINA_LIST_FOREACH(wd->over_items, elist, it)
944            elm_box_pack_end(wd->main_box, it->base.view);
945      }
946    else
947      {
948         _round_items_del(wd);
949         elm_box_pack_start(wd->main_box, wd->left_blank);
950         elm_box_pack_end(wd->main_box, wd->right_blank);
951         eina_list_free(wd->r_items);
952         wd->r_items = NULL;
953      }
954
955    _selected_item_indicate(wd->selected_item);
956    _sizing_eval(obj);
957 }
958
959 /**
960  * Get the side labels max length
961  *
962  * @param obj The diskselector object
963  * @return The max length defined for side labels, or 0 if not a valid
964  * diskselector
965  *
966  * @ingroup Diskselector
967  */
968 EAPI int
969 elm_diskselector_side_label_length_get(const Evas_Object *obj)
970 {
971    ELM_CHECK_WIDTYPE(obj, widtype) 0;
972    Widget_Data *wd = elm_widget_data_get(obj);
973    if (!wd) return 0;
974    return wd->len_side;
975 }
976
977 /**
978  * Set the side labels max length
979  *
980  * @param obj The diskselector object
981  * @param len The max length defined for side labels
982  *
983  * @ingroup Diskselector
984  */
985 EAPI void
986 elm_diskselector_side_label_length_set(Evas_Object *obj, int len)
987 {
988    ELM_CHECK_WIDTYPE(obj, widtype);
989    Widget_Data *wd = elm_widget_data_get(obj);
990    if (!wd) return;
991    wd->len_side = len;
992 }
993
994 EAPI void
995 elm_diskselector_side_label_lenght_set(Evas_Object *obj, int len)
996 {
997    return elm_diskselector_side_label_length_set(obj, len);
998 }
999
1000 EAPI int
1001 elm_diskselector_side_label_lenght_get(const Evas_Object *obj)
1002 {
1003    return elm_diskselector_side_label_length_get(obj);
1004 }
1005
1006 /**
1007  * Set bounce mode
1008  *
1009  * This will enable or disable the scroller bounce mode for the diskselector.
1010  * See elm_scroller_bounce_set() for details. Horizontal bounce is enabled by
1011  * default.
1012  *
1013  * @param obj The diskselector object
1014  * @param h_bounce Allow bounce horizontally
1015  * @param v_bounce Allow bounce vertically
1016  *
1017  * @ingroup Diskselector
1018  */
1019 EAPI void
1020 elm_diskselector_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
1021 {
1022    ELM_CHECK_WIDTYPE(obj, widtype);
1023    Widget_Data *wd = elm_widget_data_get(obj);
1024    if (!wd) return;
1025    if (wd->scroller)
1026      elm_smart_scroller_bounce_allow_set(wd->scroller, h_bounce, v_bounce);
1027 }
1028
1029 /**
1030  * Get the bounce mode
1031  *
1032  * @param obj The Diskselector object
1033  * @param h_bounce Allow bounce horizontally
1034  * @param v_bounce Allow bounce vertically
1035  *
1036  * @ingroup Diskselector
1037  */
1038 EAPI void
1039 elm_diskselector_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce)
1040 {
1041    ELM_CHECK_WIDTYPE(obj, widtype);
1042    Widget_Data *wd = elm_widget_data_get(obj);
1043    if (!wd) return;
1044    elm_smart_scroller_bounce_allow_get(wd->scroller, h_bounce, v_bounce);
1045 }
1046
1047 /**
1048  * Get the scrollbar policy
1049  *
1050  * This sets the scrollbar visibility policy for the given scroller.
1051  * ELM_SMART_SCROLLER_POLICY_AUTO means the scrollber is made visible if it
1052  * is needed, and otherwise kept hidden. ELM_SMART_SCROLLER_POLICY_ON turns
1053  * it on all the time, and ELM_SMART_SCROLLER_POLICY_OFF always keeps it off.
1054  * This applies respectively for the horizontal and vertical scrollbars.
1055  * The both are disabled by default.
1056  *
1057  * @param obj The diskselector object
1058  * @param policy_h Horizontal scrollbar policy
1059  * @param policy_v Vertical scrollbar policy
1060  *
1061  * @ingroup Diskselector
1062  */
1063
1064 EAPI void
1065 elm_diskselector_scroller_policy_get(const Evas_Object *obj, Elm_Scroller_Policy *policy_h, Elm_Scroller_Policy *policy_v)
1066 {
1067    ELM_CHECK_WIDTYPE(obj, widtype);
1068    Elm_Smart_Scroller_Policy s_policy_h, s_policy_v;
1069    Widget_Data *wd = elm_widget_data_get(obj);
1070    if ((!wd) || (!wd->scroller)) return;
1071    elm_smart_scroller_policy_get(wd->scroller, &s_policy_h, &s_policy_v);
1072    *policy_h = (Elm_Scroller_Policy) s_policy_h;
1073    *policy_v = (Elm_Scroller_Policy) s_policy_v;
1074 }
1075
1076
1077 /**
1078  * Set the scrollbar policy
1079  *
1080  * This sets the scrollbar visibility policy for the given scroller.
1081  * ELM_SMART_SCROLLER_POLICY_AUTO means the scrollber is made visible if it
1082  * is needed, and otherwise kept hidden. ELM_SMART_SCROLLER_POLICY_ON turns
1083  * it on all the time, and ELM_SMART_SCROLLER_POLICY_OFF always keeps it off.
1084  * This applies respectively for the horizontal and vertical scrollbars.
1085  * The both are disabled by default.
1086  *
1087  * @param obj The diskselector object
1088  * @param policy_h Horizontal scrollbar policy
1089  * @param policy_v Vertical scrollbar policy
1090  *
1091  * @ingroup Diskselector
1092  */
1093 EAPI void
1094 elm_diskselector_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
1095 {
1096    ELM_CHECK_WIDTYPE(obj, widtype);
1097    Widget_Data *wd = elm_widget_data_get(obj);
1098    if (!wd) return;
1099    if ((policy_h >= 3) || (policy_v >= 3)) return;
1100    if (wd->scroller)
1101      elm_smart_scroller_policy_set(wd->scroller, policy_h, policy_v);
1102 }
1103
1104 /**
1105  * Clears a diskselector of all items.
1106  *
1107  * @param obj The diskselector object
1108  *
1109  * @ingroup Diskselector
1110  */
1111 EAPI void
1112 elm_diskselector_clear(Evas_Object *obj)
1113 {
1114    ELM_CHECK_WIDTYPE(obj, widtype);
1115    Widget_Data *wd = elm_widget_data_get(obj);
1116    Elm_Diskselector_Item *it;
1117
1118    if (!wd) return;
1119    if (!wd->items) return;
1120
1121    wd->selected_item = NULL;
1122    EINA_LIST_FREE(wd->items, it) _item_del(it);
1123    _round_items_del(wd);
1124    _sizing_eval(obj);
1125 }
1126
1127 /**
1128  * Returns a list of all the diskselector items.
1129  *
1130  * @param obj The diskselector object
1131  * @return An Eina_List* of the diskselector items, or NULL on failure
1132  *
1133  * @ingroup Diskselector
1134  */
1135 EAPI const Eina_List *
1136 elm_diskselector_items_get(const Evas_Object *obj)
1137 {
1138    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1139    Widget_Data *wd = elm_widget_data_get(obj);
1140    if (!wd) return NULL;
1141    return wd->items;
1142 }
1143
1144 /**
1145  * Appends an item to the diskselector object.
1146  *
1147  * @param obj The diskselector object
1148  * @param label The label of the diskselector item
1149  * @param icon The icon object to use for the left side of the item
1150  * @param func The function to call when the item is selected
1151  * @param data The data to associate with the item for related callbacks
1152  *
1153  * @return The created item or NULL upon failure
1154  *
1155  * @ingroup Diskselector
1156  */
1157 EAPI Elm_Diskselector_Item *
1158 elm_diskselector_item_append(Evas_Object *obj, const char *label, Evas_Object *icon, Evas_Smart_Cb func, const void *data)
1159 {
1160    Elm_Diskselector_Item *it;
1161    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1162    Widget_Data *wd = elm_widget_data_get(obj);
1163    if (!wd) return NULL;
1164
1165    it = _item_new(obj, icon, label, func, data);
1166    wd->items = eina_list_append(wd->items, it);
1167    it->node = eina_list_last(wd->items);
1168    wd->item_count++;
1169    if (wd->round)
1170      {
1171         _round_items_del(wd);
1172         wd->r_items = eina_list_append(wd->r_items, it);
1173         _round_items_add(wd);
1174         if (wd->last)
1175           elm_box_pack_start(wd->main_box, wd->last->base.view);
1176         if (wd->s_last)
1177           elm_box_pack_start(wd->main_box, wd->s_last->base.view);
1178         elm_box_pack_end(wd->main_box, it->base.view);
1179         if (wd->first)
1180           elm_box_pack_end(wd->main_box, wd->first->base.view);
1181         if (wd->second)
1182           elm_box_pack_end(wd->main_box, wd->second->base.view);
1183      }
1184    else
1185      {
1186         elm_box_unpack(wd->main_box, wd->right_blank);
1187         elm_box_pack_end(wd->main_box, it->base.view);
1188         elm_box_pack_end(wd->main_box, wd->right_blank);
1189      }
1190    if (!wd->selected_item)
1191      wd->selected_item = it;
1192    if (!wd->idler)
1193      wd->idler = ecore_idler_add(_move_scroller, obj);
1194    _sizing_eval(obj);
1195    return it;
1196 }
1197
1198 /**
1199  * Delete the item
1200  *
1201  * @param it The item of diskselector
1202  *
1203  * @ingroup Diskselector
1204  */
1205 EAPI void
1206 elm_diskselector_item_del(Elm_Diskselector_Item * it)
1207 {
1208    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it);
1209    Elm_Diskselector_Item *dit;
1210    Elm_Diskselector_Item *item;
1211    Eina_List *l;
1212    int i = 0;
1213    Widget_Data *wd = elm_widget_data_get(it->base.widget);
1214    if (!wd) return;
1215
1216    elm_box_unpack(wd->main_box, it->base.view);
1217
1218    if (wd->round)
1219      wd->r_items = eina_list_remove(wd->r_items, it);
1220
1221    wd->items = eina_list_remove(wd->items, it);
1222
1223    if (wd->selected_item == it)
1224      {
1225         dit = (Elm_Diskselector_Item *) eina_list_nth(wd->items, 0);
1226         if (dit != it)
1227           wd->selected_item = dit;
1228         else
1229           wd->selected_item = eina_list_nth(wd->items, 1);
1230
1231         _selected_item_indicate(wd->selected_item);
1232      }
1233
1234    _item_del(it);
1235    wd->item_count -= 1;
1236
1237    if (wd->round)
1238      {
1239         if (!wd->item_count)
1240           {
1241              evas_object_hide(wd->first->base.view);
1242              evas_object_hide(wd->second->base.view);
1243              evas_object_hide(wd->last->base.view);
1244              evas_object_hide(wd->s_last->base.view);
1245
1246              EINA_LIST_FOREACH(wd->under_items, l, item)
1247                 evas_object_hide(item->base.view);
1248
1249              EINA_LIST_FOREACH(wd->over_items, l, item)
1250                 evas_object_hide(item->base.view);
1251           }
1252         else
1253           {
1254              dit = eina_list_nth(wd->items, 0);
1255              if (dit)
1256                {
1257                   eina_stringshare_replace(&wd->first->label, dit->label);
1258                   edje_object_part_text_set(wd->first->base.view, "elm.text",
1259                                             wd->first->label);
1260                }
1261              dit = eina_list_nth(wd->items, 1);
1262              if (dit)
1263                {
1264                   eina_stringshare_replace(&wd->second->label, dit->label);
1265                   edje_object_part_text_set(wd->second->base.view, "elm.text",
1266                                             wd->second->label);
1267                }
1268              // if more than 3 itmes should be displayed
1269              for (i = 2; i < CEIL(wd->display_item_num); i++)
1270                {
1271                   dit = eina_list_nth(wd->items, i);
1272                   item = eina_list_nth(wd->over_items, i - 2);
1273                   eina_stringshare_replace(&item->label, dit->label);
1274                   edje_object_part_text_set(item->base.view, "elm.text", item->label);
1275                }
1276
1277              dit = eina_list_nth(wd->items, eina_list_count(wd->items) - 1);
1278              if (dit)
1279                {
1280                   eina_stringshare_replace(&wd->last->label, dit->label);
1281                   edje_object_part_text_set(wd->last->base.view, "elm.text",
1282                                             wd->last->label);
1283                }
1284              dit = eina_list_nth(wd->items, eina_list_count(wd->items) - 2);
1285              if (dit)
1286                {
1287                   eina_stringshare_replace(&wd->s_last->label, dit->label);
1288                   edje_object_part_text_set(wd->s_last->base.view, "elm.text",
1289                                             wd->s_last->label);
1290                }
1291              // if more than 3 itmes should be displayed
1292              for (i = 3; i <= CEIL(wd->display_item_num); i++)
1293                {
1294                   dit = eina_list_nth(wd->items, wd->item_count - i);
1295                   item = eina_list_nth(wd->under_items, i - 3);
1296                   eina_stringshare_replace(&item->label, dit->label);
1297                   edje_object_part_text_set(item->base.view, "elm.text", item->label);
1298                }
1299           }
1300      }
1301    wd->check_idler = ecore_idler_add(_check_string, wd);
1302    _sizing_eval(wd->self);
1303 }
1304
1305 /**
1306  * Get the label of item
1307  *
1308  * @param it The item of diskselector
1309  * @return The label of item
1310  *
1311  * @ingroup Diskselector
1312  */
1313 EAPI const char *
1314 elm_diskselector_item_label_get(const Elm_Diskselector_Item * it)
1315 {
1316    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it, NULL);
1317    return it->label;
1318 }
1319
1320 /**
1321  * Set the label of item
1322  *
1323  * @param it The item of diskselector
1324  * @param label The label of item
1325  *
1326  * @ingroup Diskselector
1327  */
1328 EAPI void
1329 elm_diskselector_item_label_set(Elm_Diskselector_Item * it, const char *label)
1330 {
1331    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it);
1332    eina_stringshare_replace(&it->label, label);
1333    edje_object_part_text_set(it->base.view, "elm.text", it->label);
1334 }
1335
1336 /**
1337  * Get the selected item
1338  *
1339  * @param obj The diskselector object
1340  * @return The selected diskselector item
1341  *
1342  * @ingroup Diskselector
1343  */
1344 EAPI Elm_Diskselector_Item *
1345 elm_diskselector_selected_item_get(const Evas_Object *obj)
1346 {
1347    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1348    Widget_Data *wd = elm_widget_data_get(obj);
1349    if (!wd) return NULL;
1350    return wd->selected_item;
1351 }
1352
1353 /**
1354  * Set the selected state of an item
1355  *
1356  * This sets the selected state (EINA_TRUE selected, EINA_FALSE not selected)
1357  * of the given item @p it.
1358  * If a new item is selected the previosly selected will be unselected.
1359  * If the item @p it is unselected, the first item will be selected.
1360  *
1361  * @param it The diskselector item
1362  * @param selected The selected state
1363  *
1364  * @ingroup Diskselector
1365  */
1366 EAPI void
1367 elm_diskselector_item_selected_set(Elm_Diskselector_Item *it, Eina_Bool selected)
1368 {
1369    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it);
1370    Widget_Data *wd;
1371    wd = elm_widget_data_get(it->base.widget);
1372    if (!wd) return;
1373
1374    if ((wd->selected_item == it) && (selected))
1375      return;
1376
1377    if ((wd->selected_item == it) && (!selected))
1378      wd->selected_item = eina_list_data_get(wd->items);
1379    else
1380      {
1381         wd->selected_item = it;
1382         _selected_item_indicate(wd->selected_item);
1383      }
1384
1385    if (!wd->idler)
1386      ecore_idler_add(_move_scroller, it->base.widget);
1387 }
1388
1389 /*
1390  * Get the selected state of @p item.
1391  *
1392  * @param it The diskselector item
1393  * @return If true, the item is selected
1394  *
1395  * @ingroup Diskselector
1396  */
1397 EAPI Eina_Bool
1398 elm_diskselector_item_selected_get(const Elm_Diskselector_Item *it)
1399 {
1400    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it, EINA_FALSE);
1401    Widget_Data *wd;
1402
1403    wd = elm_widget_data_get(it->base.widget);
1404    if (!wd) return EINA_FALSE;
1405    return (wd->selected_item == it);
1406 }
1407
1408 /**
1409  * Set the function called when a diskselector item is freed.
1410  *
1411  * @param it The item to set the callback on
1412  * @param func The function called
1413  *
1414  * @ingroup Diskselector
1415  */
1416 EAPI void
1417 elm_diskselector_item_del_cb_set(Elm_Diskselector_Item *it, Evas_Smart_Cb func)
1418 {
1419    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it);
1420    elm_widget_item_del_cb_set(it, func);
1421 }
1422
1423 /**
1424  * Returns the data associated with the item.
1425  *
1426  * @param it The diskselector item
1427  * @return The data associated with @p it
1428  *
1429  * @ingroup Diskselector
1430  */
1431 EAPI void *
1432 elm_diskselector_item_data_get(const Elm_Diskselector_Item *it)
1433 {
1434    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it, NULL);
1435    return elm_widget_item_data_get(it);
1436 }
1437
1438 /**
1439  * Returns the icon associated with the item.
1440  *
1441  * @param it The diskselector item
1442  * @return The icon associated with @p it
1443  *
1444  * @ingroup Diskselector
1445  */
1446 EAPI Evas_Object *
1447 elm_diskselector_item_icon_get(const Elm_Diskselector_Item *it)
1448 {
1449    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it, NULL);
1450    return it->icon;
1451 }
1452
1453 /**
1454  * Sets the icon associated with the item.
1455  *
1456  * Once the icon object is set, a previously set one will be deleted.
1457  * You probably don't want, then, to have the <b>same</b> icon object set
1458  * for more than one item of the diskselector.
1459  *
1460  * @param it The diskselector item
1461  * @param icon The icon object to associate with @p it
1462  *
1463  * @ingroup Diskselector
1464  */
1465 EAPI void
1466 elm_diskselector_item_icon_set(Elm_Diskselector_Item *it, Evas_Object *icon)
1467 {
1468    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it);
1469    if (it->icon == icon) return;
1470    if (it->icon)
1471      evas_object_del(it->icon);
1472    it->icon = icon;
1473    if (it->base.view)
1474      edje_object_part_swallow(it->base.view, "elm.swallow.icon", icon);
1475 }
1476
1477 /**
1478  * Gets the item before @p it in the list.
1479  *
1480  * @param it The diskselector item
1481  * @return The item before @p it, or NULL on failure
1482  *
1483  * @ingroup Diskselector
1484  */
1485 EAPI Elm_Diskselector_Item *
1486 elm_diskselector_item_prev_get(const Elm_Diskselector_Item *it)
1487 {
1488    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it, NULL);
1489    if (it->node->prev) return it->node->prev->data;
1490    else return NULL;
1491 }
1492
1493 /**
1494  * Gets the item after @p it in the list.
1495  *
1496  * @param it The diskselector item
1497  * @return The item after @p it, or NULL on failure
1498  *
1499  * @ingroup Diskselector
1500  */
1501 EAPI Elm_Diskselector_Item *
1502 elm_diskselector_item_next_get(const Elm_Diskselector_Item *it)
1503 {
1504    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(it, NULL);
1505    if (it->node->next) return it->node->next->data;
1506    else return NULL;
1507 }
1508
1509 /**
1510  * Get the first item in the diskselector
1511  *
1512  * @param obj The diskselector object
1513  * @return The first item, or NULL if none
1514  *
1515  * @ingroup Diskselector
1516  */
1517 EAPI Elm_Diskselector_Item *
1518 elm_diskselector_first_item_get(const Evas_Object *obj)
1519 {
1520    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1521    Widget_Data *wd;
1522
1523    wd = elm_widget_data_get(obj);
1524    if (!wd || !wd->items)
1525      return NULL;
1526
1527    return eina_list_data_get(wd->items);
1528 }
1529
1530 /**
1531  * Get the last item in the diskselector
1532  *
1533  * @param obj The diskselector object
1534  * @return The last item, or NULL if none
1535  *
1536  * @ingroup Diskselector
1537  */
1538 EAPI Elm_Diskselector_Item *
1539 elm_diskselector_last_item_get(const Evas_Object *obj)
1540 {
1541    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1542
1543    Widget_Data *wd;
1544    wd = elm_widget_data_get(obj);
1545    if (!wd || !wd->items)
1546      return NULL;
1547
1548    return eina_list_data_get(eina_list_last(wd->items));
1549 }
1550
1551 /**
1552  * Set the text to be shown in the diskselector item.
1553  *
1554  * @param item Target item
1555  * @param text The text to set in the content
1556  *
1557  * Setup the text as tooltip to object. The item can have only one tooltip,
1558  * so any previous tooltip data is removed.
1559  *
1560  * @ingroup Diskselector
1561  */
1562 EAPI void
1563 elm_diskselector_item_tooltip_text_set(Elm_Diskselector_Item *item, const char *text)
1564 {
1565    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item);
1566    elm_widget_item_tooltip_text_set(item, text);
1567 }
1568
1569 /**
1570  * Set the content to be shown in the tooltip item
1571  *
1572  * Setup the tooltip to item. The item can have only one tooltip,
1573  * so any previous tooltip data is removed. @p func(with @p data) will
1574  * be called every time that need show the tooltip and it should
1575  * return a valid Evas_Object. This object is then managed fully by
1576  * tooltip system and is deleted when the tooltip is gone.
1577  *
1578  * @param item the diskselector item being attached a tooltip.
1579  * @param func the function used to create the tooltip contents.
1580  * @param data what to provide to @a func as callback data/context.
1581  * @param del_cb called when data is not needed anymore, either when
1582  *        another callback replaces @func, the tooltip is unset with
1583  *        elm_diskselector_item_tooltip_unset() or the owner @a item
1584  *        dies. This callback receives as the first parameter the
1585  *        given @a data, and @c event_info is the item.
1586  *
1587  * @ingroup Diskselector
1588  */
1589 EAPI void
1590 elm_diskselector_item_tooltip_content_cb_set(Elm_Diskselector_Item *item, Elm_Tooltip_Item_Content_Cb func, const void *data, Evas_Smart_Cb del_cb)
1591 {
1592    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item);
1593    elm_widget_item_tooltip_content_cb_set(item, func, data, del_cb);
1594 }
1595
1596 /**
1597  * Unset tooltip from item
1598  *
1599  * @param item diskselector item to remove previously set tooltip.
1600  *
1601  * Remove tooltip from item. The callback provided as del_cb to
1602  * elm_diskselector_item_tooltip_content_cb_set() will be called to notify
1603  * it is not used anymore.
1604  *
1605  * @see elm_diskselector_item_tooltip_content_cb_set()
1606  *
1607  * @ingroup Diskselector
1608  */
1609 EAPI void
1610 elm_diskselector_item_tooltip_unset(Elm_Diskselector_Item *item)
1611 {
1612    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item);
1613    elm_widget_item_tooltip_unset(item);
1614 }
1615
1616 /**
1617  * Sets a different style for this item tooltip.
1618  *
1619  * @note before you set a style you should define a tooltip with
1620  *       elm_diskselector_item_tooltip_content_cb_set() or
1621  *       elm_diskselector_item_tooltip_text_set()
1622  *
1623  * @param item diskselector item with tooltip already set.
1624  * @param style the theme style to use (default, transparent, ...)
1625  *
1626  * @ingroup Diskselector
1627  */
1628 EAPI void
1629 elm_diskselector_item_tooltip_style_set(Elm_Diskselector_Item *item, const char *style)
1630 {
1631    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item);
1632    elm_widget_item_tooltip_style_set(item, style);
1633 }
1634
1635 /**
1636  * Get the style for this item tooltip.
1637  *
1638  * @param item diskselector item with tooltip already set.
1639  * @return style the theme style in use, defaults to "default". If the
1640  *         object does not have a tooltip set, then NULL is returned.
1641  *
1642  * @ingroup Diskselector
1643  */
1644 EAPI const char *
1645 elm_diskselector_item_tooltip_style_get(const Elm_Diskselector_Item *item)
1646 {
1647    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item, NULL);
1648    return elm_widget_item_tooltip_style_get(item);
1649 }
1650
1651 /**
1652  * Set the cursor to be shown when mouse is over the diskselector item
1653  *
1654  * @param item Target item
1655  * @param cursor the cursor name to be used.
1656  *
1657  * @see elm_object_cursor_set()
1658  * @ingroup Diskselector
1659  */
1660 EAPI void
1661 elm_diskselector_item_cursor_set(Elm_Diskselector_Item *item, const char *cursor)
1662 {
1663    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item);
1664    elm_widget_item_cursor_set(item, cursor);
1665 }
1666
1667 /**
1668  * Get the cursor to be shown when mouse is over the diskselector item
1669  *
1670  * @param item diskselector item with cursor already set.
1671  * @return the cursor name.
1672  *
1673  * @ingroup Diskselector
1674  */
1675 EAPI const char *
1676 elm_diskselector_item_cursor_get(const Elm_Diskselector_Item *item)
1677 {
1678    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item, NULL);
1679    return elm_widget_item_cursor_get(item);
1680 }
1681
1682 /**
1683  * Unset the cursor to be shown when mouse is over the diskselector item
1684  *
1685  * @param item Target item
1686  *
1687  * @see elm_object_cursor_unset()
1688  * @ingroup Diskselector
1689  */
1690 EAPI void
1691 elm_diskselector_item_cursor_unset(Elm_Diskselector_Item *item)
1692 {
1693    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item);
1694    elm_widget_item_cursor_unset(item);
1695 }
1696
1697 /**
1698  * Sets a different style for this item cursor.
1699  *
1700  * @note before you set a style you should define a cursor with
1701  *       elm_diskselector_item_cursor_set()
1702  *
1703  * @param item diskselector item with cursor already set.
1704  * @param style the theme style to use (default, transparent, ...)
1705  *
1706  * @ingroup Diskselector
1707  */
1708 EAPI void
1709 elm_diskselector_item_cursor_style_set(Elm_Diskselector_Item *item, const char *style)
1710 {
1711    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item);
1712    elm_widget_item_cursor_style_set(item, style);
1713 }
1714
1715 /**
1716  * Get the style for this item cursor.
1717  *
1718  * @param item diskselector item with cursor already set.
1719  * @return style the theme style in use, defaults to "default". If the
1720  *         object does not have a cursor set, then NULL is returned.
1721  *
1722  * @ingroup Diskselector
1723  */
1724 EAPI const char *
1725 elm_diskselector_item_cursor_style_get(const Elm_Diskselector_Item *item)
1726 {
1727    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item, NULL);
1728    return elm_widget_item_cursor_style_get(item);
1729 }
1730
1731 /**
1732  * Set if the cursor set should be searched on the theme or should use
1733  * the provided by the engine, only.
1734  *
1735  * @note before you set if should look on theme you should define a cursor
1736  * with elm_object_cursor_set(). By default it will only look for cursors
1737  * provided by the engine.
1738  *
1739  * @param item widget item with cursor already set.
1740  * @param engine_only boolean to define it cursors should be looked only
1741  * between the provided by the engine or searched on widget's theme as well.
1742  *
1743  * @ingroup Diskselector
1744  */
1745 EAPI void
1746 elm_diskselector_item_cursor_engine_only_set(Elm_Diskselector_Item *item, Eina_Bool engine_only)
1747 {
1748    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item);
1749    elm_widget_item_cursor_engine_only_set(item, engine_only);
1750 }
1751
1752 /**
1753  * Get the cursor engine only usage for this item cursor.
1754  *
1755  * @param item widget item with cursor already set.
1756  * @return engine_only boolean to define it cursors should be looked only
1757  * between the provided by the engine or searched on widget's theme as well. If
1758  *         the object does not have a cursor set, then EINA_FALSE is returned.
1759  *
1760  * @ingroup Diskselector
1761  */
1762 EAPI Eina_Bool
1763 elm_diskselector_item_cursor_engine_only_get(const Elm_Diskselector_Item *item)
1764 {
1765    ELM_DISKSELECTOR_ITEM_CHECK_OR_RETURN(item, EINA_FALSE);
1766    return elm_widget_item_cursor_engine_only_get(item);
1767 }
1768 /**
1769  * Set the number of items to be displayed
1770  *
1771  * @param obj The diskselector object
1772  * @param num The number of itmes that diskselector will display
1773  *
1774  * @ingroup Diskselector
1775  */
1776 EAPI void
1777 elm_diskselector_display_item_num_set(Evas_Object *obj, int num)
1778 {
1779    ELM_CHECK_WIDTYPE(obj, widtype);
1780    Widget_Data *wd = elm_widget_data_get(obj);
1781    if (!wd) return;
1782    if (num < DISPLAY_ITEM_NUM_MIN) num = DISPLAY_ITEM_NUM_MIN;
1783    wd->display_item_num = num;
1784    wd->display_item_num_by_api = EINA_TRUE;
1785 }