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