[elementary] Documenting/exemplyfing flip selector's API:
[framework/uifw/elementary.git] / src / lib / elm_flipselector.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /* TODO: ideally, the default theme would use map{} blocks on the TEXT
5    parts to implement their fading in/out propertly (as in the clock
6    widget) */
7 /* TODO: if one ever wants to extend it to receiving generic widgets
8    as items, be my guest. in this case, remember to implement the
9    items tooltip infra. */
10 /* TODO: implement disabled mode -- disable_hook() and stuff. */
11 /* TODO: fix default theme image borders for looong strings as item
12    labels. */
13 /* TODO: set text elipsis on labels if one enforces mininum size on
14  * the overall widget less the required for displaying it. */
15 /* TODO: find a way to, in the default theme, to detect we are
16  * bootstrapping (receiving the 1st message) and populate the downmost
17  * TEXT parts with the same text as the upmost, where appropriate. */
18
19 #define FLIP_FIRST_INTERVAL (0.85)
20 #define FLIP_MIN_INTERVAL (0.1)
21 #define MSG_FLIP_DOWN (1)
22 #define MSG_FLIP_UP (2)
23 #define MAX_LEN_DEFAULT (50)
24
25 #define DATA_GET eina_list_data_get
26
27 struct _Elm_Flipselector_Item
28 {
29    Elm_Widget_Item base;
30    const char *label;
31    Evas_Smart_Cb func;
32    void *data;
33    int deleted : 1;
34 };
35
36 typedef struct _Widget_Data Widget_Data;
37
38 struct _Widget_Data
39 {
40    Evas_Object *self;
41    Evas_Object *base;
42    Eina_List *items;
43    Eina_List *current;
44    Eina_List *sentinel; /* item containing the largest label string */
45    int walking;
46    unsigned int max_len;
47    Ecore_Timer *spin;
48    double interval, first_interval;
49 };
50
51 static const char *widtype = NULL;
52 static void _del_hook(Evas_Object *obj);
53 static void _theme_hook(Evas_Object *obj);
54 static void _sizing_eval(Evas_Object *obj);
55 static void _update_view(Evas_Object *obj);
56 static void _callbacks_set(Evas_Object *obj);
57 static void _flip_up(Widget_Data *wd);
58 static void _flip_down(Widget_Data *wd);
59
60 static const char SIG_SELECTED[] = "selected";
61 static const char SIG_UNDERFLOWED[] = "underflowed";
62 static const char SIG_OVERFLOWED[] = "overflowed";
63 static const Evas_Smart_Cb_Description _signals[] = {
64   {SIG_SELECTED, ""},
65   {SIG_UNDERFLOWED, ""},
66   {SIG_OVERFLOWED, ""},
67   {NULL, NULL}
68 };
69
70 #define ELM_FLIPSELECTOR_ITEM_CHECK_DELETED_RETURN(it, ...)             \
71    ELM_WIDGET_ITEM_WIDTYPE_CHECK_OR_RETURN(it, __VA_ARGS__);            \
72   if (it->deleted)                                                      \
73     {                                                                   \
74        ERR(""#it" has been DELETED.\n");                                \
75        return __VA_ARGS__;                                              \
76     }                                                                   \
77
78 static Elm_Flipselector_Item *
79 _item_new(Evas_Object *obj, const char *label, Evas_Smart_Cb func, const void *data)
80 {
81    unsigned int len;
82    Elm_Flipselector_Item *it;
83    Widget_Data *wd = elm_widget_data_get(obj);
84
85    it = elm_widget_item_new(obj, Elm_Flipselector_Item);
86    if (!it)
87      return NULL;
88
89    len = strlen(label);
90    if (len > wd->max_len)
91      len = wd->max_len;
92
93    it->label = eina_stringshare_add_length(label, len);
94    it->func = func;
95    it->base.data = data;
96
97    /* TODO: no view here, but if one desires general contents in the
98     * future... */
99    return it;
100 }
101
102 static inline void
103 _item_free(Elm_Flipselector_Item *it)
104 {
105    eina_stringshare_del(it->label);
106    elm_widget_item_del(it);
107 }
108
109 static void
110 _del_hook(Evas_Object *obj)
111 {
112    Elm_Flipselector_Item *item;
113
114    Widget_Data *wd = elm_widget_data_get(obj);
115    if (!wd)
116      return;
117
118    if (wd->walking)
119      ERR("flipselector deleted while walking.\n");
120
121    EINA_LIST_FREE(wd->items, item)
122       _item_free(item);
123
124    if (wd->spin) ecore_timer_del(wd->spin);
125    free(wd);
126 }
127
128 static void
129 _theme_hook(Evas_Object *obj)
130 {
131    Widget_Data *wd;
132    const char *max_len;
133
134    wd = elm_widget_data_get(obj);
135    if (!wd)
136      return;
137
138    _elm_theme_object_set(obj, wd->base, "flipselector", "base",
139                          elm_widget_style_get(obj));
140    edje_object_scale_set(wd->base,
141                          elm_widget_scale_get(obj) * _elm_config->scale);
142
143    max_len = edje_object_data_get(wd->base, "max_len");
144    if (!max_len)
145      wd->max_len = MAX_LEN_DEFAULT;
146    else
147      {
148         wd->max_len = atoi(max_len);
149         if (!wd->max_len)
150           wd->max_len = MAX_LEN_DEFAULT;
151      }
152
153    _update_view(obj);
154    _sizing_eval(obj);
155 }
156
157 static void
158 _sentinel_eval(Widget_Data *wd)
159 {
160    Elm_Flipselector_Item *it;
161    Eina_List *l;
162
163    if (!wd->items)
164      {
165         wd->sentinel = NULL;
166         return;
167      }
168
169    wd->sentinel = wd->items;
170
171    EINA_LIST_FOREACH(wd->items, l, it)
172      {
173         if (strlen(elm_flipselector_item_label_get(it)) >
174             strlen(elm_flipselector_item_label_get(DATA_GET(wd->sentinel))))
175           wd->sentinel = l;
176      }
177 }
178
179 /* TODO: create a flag to avoid looping here all times */
180 static void
181 _flipselector_process_deletions(Widget_Data *wd)
182 {
183    Elm_Flipselector_Item *it;
184    Eina_List *l;
185    Eina_Bool skip = EINA_TRUE;
186    Eina_Bool sentinel_eval = EINA_FALSE;
187
188    wd->walking++; /* avoid nested deletions */
189
190    EINA_LIST_FOREACH(wd->items, l, it)
191      {
192         if (!it->deleted)
193           continue;
194
195         if (wd->current == l)
196           {
197              if (wd->current == wd->sentinel)
198                sentinel_eval = EINA_TRUE;
199
200              wd->current = eina_list_prev(wd->current);
201           }
202         wd->items = eina_list_remove(wd->items, it);
203
204         if (!wd->current)
205           wd->current = wd->items;
206
207         _item_free(it);
208         skip = EINA_FALSE;
209
210         if (eina_list_count(wd->items) <= 1)
211           edje_object_signal_emit(wd->base, "elm,state,button,hidden", "elm");
212         else
213           edje_object_signal_emit(wd->base, "elm,state,button,visible", "elm");
214      }
215
216    if (!skip)
217      _update_view(wd->self);
218
219    if (sentinel_eval)
220      _sentinel_eval(wd);
221
222    wd->walking--;
223 }
224
225 static inline void
226 _flipselector_walk(Widget_Data *wd)
227 {
228    if (wd->walking < 0)
229      {
230         ERR("walking was negative. fixed!\n");
231         wd->walking = 0;
232      }
233    wd->walking++;
234 }
235
236 static inline void
237 _flipselector_unwalk(Widget_Data *wd)
238 {
239    wd->walking--;
240    if (wd->walking < 0)
241      {
242         ERR("walking became negative. fixed!\n");
243         wd->walking = 0;
244      }
245
246    if (wd->walking)
247      return;
248
249    _flipselector_process_deletions(wd);
250 }
251
252 static Eina_Bool
253 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
254 {
255    Evas_Event_Key_Down *ev;
256    Widget_Data *wd;
257    Eina_Bool is_up = EINA_TRUE;
258
259    if (type != EVAS_CALLBACK_KEY_DOWN)
260      return EINA_FALSE;
261
262    wd = elm_widget_data_get(obj);
263    if (!wd)
264      return EINA_FALSE;
265
266    ev = event_info;
267    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
268      return EINA_FALSE;
269
270    if (elm_widget_disabled_get(obj))
271      return EINA_FALSE;
272
273    if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
274      is_up = EINA_FALSE;
275    else if ((strcmp(ev->keyname, "Up")) && (strcmp(ev->keyname, "KP_Up")))
276      return EINA_FALSE;
277
278    if (wd->spin) ecore_timer_del(wd->spin);
279
280    /* TODO: if direction setting via API is not coming in, replace
281       these calls by flip_{next,prev} */
282    _flipselector_walk(wd);
283    if (is_up)
284      _flip_up(wd);
285    else
286      _flip_down(wd);
287    _flipselector_unwalk(wd);
288
289    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
290    return EINA_TRUE;
291 }
292
293 static void
294 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
295 {
296    Widget_Data *wd = elm_widget_data_get(obj);
297    if (!wd)
298      return;
299
300    /* FIXME: no treatment of this signal so far */
301    if (elm_widget_focus_get(obj))
302      {
303         edje_object_signal_emit(wd->base, "elm,action,focus", "elm");
304         evas_object_focus_set(wd->base, EINA_TRUE);
305      }
306    else
307      {
308         edje_object_signal_emit(wd->base, "elm,action,unfocus", "elm");
309         evas_object_focus_set(wd->base, EINA_FALSE);
310      }
311 }
312
313 static void
314 _sizing_eval(Evas_Object *obj)
315 {
316    Widget_Data *wd;
317    const char *tmp = NULL;
318    Evas_Coord minw = -1, minh = -1, w, h;
319
320    wd = elm_widget_data_get(obj);
321    if (!wd)
322      return;
323
324    elm_coords_finger_size_adjust(1, &minw, 2, &minh);
325
326    if (wd->sentinel)
327      {
328         const char *label = \
329                             elm_flipselector_item_label_get(DATA_GET(wd->sentinel));
330
331         tmp = edje_object_part_text_get(wd->base, "top");
332         edje_object_part_text_set(wd->base, "top", label);
333      }
334
335    edje_object_size_min_restricted_calc(wd->base, &minw, &minh, minw, minh);
336    elm_coords_finger_size_adjust(1, &minw, 2, &minh);
337    evas_object_size_hint_min_get(obj, &w, &h);
338
339    if (wd->sentinel)
340      edje_object_part_text_set(wd->base, "top", tmp);
341
342    if (w > minw) minw = w;
343    if (h > minh) minh = h;
344
345    evas_object_size_hint_min_set(obj, minw, minh);
346 }
347
348 static void
349 _update_view(Evas_Object *obj)
350 {
351    Widget_Data *wd;
352    const char *label;
353    Elm_Flipselector_Item *item;
354
355    wd = elm_widget_data_get(obj);
356    if (!wd)
357      return;
358
359    label = NULL;
360    item = DATA_GET(wd->current);
361    if (item)
362      label = item->label;
363
364    edje_object_part_text_set(wd->base, "top", label ? label : "");
365    edje_object_part_text_set(wd->base, "bottom", label ? label : "");
366
367    edje_object_message_signal_process(wd->base);
368 }
369
370 static void
371 _changed(Widget_Data *wd)
372 {
373    Elm_Flipselector_Item *item;
374
375    item = DATA_GET(wd->current);
376    if (!item)
377      return;
378
379    if (item->func)
380      item->func((void *)item->base.data, item->base.widget, item);
381    if (!item->deleted)
382      evas_object_smart_callback_call(wd->self, SIG_SELECTED, item);
383 }
384
385 static void
386 _send_msg(Widget_Data *wd, int flipside, char *label)
387 {
388    Edje_Message_String msg;
389
390    msg.str = label;
391    edje_object_message_send(wd->base, EDJE_MESSAGE_STRING, flipside, &msg);
392    edje_object_message_signal_process(wd->base);
393
394    _changed(wd);
395 }
396
397 static void
398 _flip_up(Widget_Data *wd)
399 {
400    Elm_Flipselector_Item *item;
401
402    if (!wd->current)
403      return;
404
405    if (wd->current == wd->items)
406      {
407         wd->current = eina_list_last(wd->items);
408         evas_object_smart_callback_call(wd->self, SIG_UNDERFLOWED, NULL);
409      }
410    else
411      wd->current = eina_list_prev(wd->current);
412
413    item = DATA_GET(wd->current);
414    if (!item)
415      return;
416
417    _send_msg(wd, MSG_FLIP_UP, (char *)item->label);
418 }
419
420 static Eina_Bool
421 _signal_val_up(void *data)
422 {
423    Widget_Data *wd = elm_widget_data_get(data);
424
425    if (!wd)
426      goto val_up_exit_on_error;
427
428    _flipselector_walk(wd);
429
430    if (wd->interval > FLIP_MIN_INTERVAL)
431      wd->interval = wd->interval / 1.05;
432
433    ecore_timer_interval_set(wd->spin, wd->interval);
434
435    _flip_up(wd);
436
437    _flipselector_unwalk(wd);
438
439    return ECORE_CALLBACK_RENEW;
440
441 val_up_exit_on_error:
442    return ECORE_CALLBACK_CANCEL;
443 }
444
445 static void
446 _signal_val_up_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
447 {
448    Widget_Data *wd = elm_widget_data_get(data);
449    if (!wd)
450      return;
451
452    wd->interval = wd->first_interval;
453
454    if (wd->spin)
455      ecore_timer_del(wd->spin);
456    wd->spin = ecore_timer_add(wd->interval, _signal_val_up, data);
457
458    _signal_val_up(data);
459 }
460
461 static void
462 _flip_down(Widget_Data *wd)
463 {
464    Elm_Flipselector_Item *item;
465
466    if (!wd->current)
467      return;
468
469    wd->current = eina_list_next(wd->current);
470    if (!wd->current)
471      {
472         wd->current = wd->items;
473         evas_object_smart_callback_call(wd->self, SIG_OVERFLOWED, NULL);
474      }
475
476    item = DATA_GET(wd->current);
477    if (!item)
478      return;
479
480    _send_msg(wd, MSG_FLIP_DOWN, (char *)item->label);
481 }
482
483 static Eina_Bool
484 _signal_val_down(void *data)
485 {
486    Widget_Data *wd = elm_widget_data_get(data);
487
488    if (!wd)
489      goto val_down_exit_on_error;
490
491    _flipselector_walk(wd);
492
493    if (wd->interval > FLIP_MIN_INTERVAL)
494      wd->interval = wd->interval / 1.05;
495    ecore_timer_interval_set(wd->spin, wd->interval);
496
497    _flip_down(wd);
498
499    _flipselector_unwalk(wd);
500
501    return ECORE_CALLBACK_RENEW;
502
503 val_down_exit_on_error:
504    return ECORE_CALLBACK_CANCEL;
505 }
506
507 static void
508 _signal_val_down_start(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
509 {
510    Widget_Data *wd = elm_widget_data_get(data);
511    if (!wd)
512      return;
513
514    wd->interval = wd->first_interval;
515
516    if (wd->spin)
517      ecore_timer_del(wd->spin);
518    wd->spin = ecore_timer_add(wd->interval, _signal_val_down, data);
519
520    _signal_val_down(data);
521 }
522
523 static void
524 _signal_val_change_stop(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
525 {
526    Widget_Data *wd = elm_widget_data_get(data);
527    if (!wd)
528      return;
529
530    if (wd->spin)
531      ecore_timer_del(wd->spin);
532    wd->spin = NULL;
533 }
534
535 static void
536 _callbacks_set(Evas_Object *obj)
537 {
538    Widget_Data *wd = elm_widget_data_get(obj);
539
540    edje_object_signal_callback_add(wd->base, "elm,action,up,start",
541                                    "", _signal_val_up_start, obj);
542    edje_object_signal_callback_add(wd->base, "elm,action,up,stop",
543                                    "", _signal_val_change_stop, obj);
544    edje_object_signal_callback_add(wd->base, "elm,action,down,start",
545                                    "", _signal_val_down_start, obj);
546    edje_object_signal_callback_add(wd->base, "elm,action,down,stop",
547                                    "", _signal_val_change_stop, obj);
548 }
549
550 EAPI Evas_Object *
551 elm_flipselector_add(Evas_Object *parent)
552 {
553    Evas_Object *obj;
554    Evas *e;
555    Widget_Data *wd;
556
557    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
558
559    ELM_SET_WIDTYPE(widtype, "flipselector");
560    elm_widget_type_set(obj, "flipselector");
561    elm_widget_sub_object_add(parent, obj);
562    elm_widget_data_set(obj, wd);
563
564    wd->self = obj;
565    elm_widget_del_hook_set(obj, _del_hook);
566    elm_widget_theme_hook_set(obj, _theme_hook);
567    /* TODO: elm_widget_disable_hook_set(obj, _disable_hook); */
568
569    elm_widget_can_focus_set(obj, EINA_TRUE);
570    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
571    elm_widget_event_hook_set(obj, _event_hook);
572
573    wd->base = edje_object_add(e);
574    elm_widget_resize_object_set(obj, wd->base);
575
576    _callbacks_set(obj);
577
578    wd->first_interval = FLIP_FIRST_INTERVAL;
579
580    _theme_hook(obj);
581
582    evas_object_smart_callbacks_descriptions_set(obj, _signals);
583    return obj;
584 }
585
586 EAPI void
587 elm_flipselector_flip_next(Evas_Object *obj)
588 {
589    ELM_CHECK_WIDTYPE(obj, widtype);
590
591    Widget_Data *wd = elm_widget_data_get(obj);
592    if (!wd)
593      return;
594
595    if (wd->spin) ecore_timer_del(wd->spin);
596
597    _flipselector_walk(wd);
598    _flip_down(wd);
599    _flipselector_unwalk(wd);
600 }
601
602 EAPI void
603 elm_flipselector_flip_prev(Evas_Object *obj)
604 {
605    ELM_CHECK_WIDTYPE(obj, widtype);
606
607    Widget_Data *wd = elm_widget_data_get(obj);
608    if (!wd)
609      return;
610
611    if (wd->spin) ecore_timer_del(wd->spin);
612
613    _flipselector_walk(wd);
614    _flip_up(wd);
615    _flipselector_unwalk(wd);
616 }
617
618 EAPI Elm_Flipselector_Item *
619 elm_flipselector_item_append(Evas_Object *obj, const char *label, void (*func)(void *data, Evas_Object *obj, void *event_info), void *data)
620 {
621    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
622
623    Elm_Flipselector_Item *item;
624    Widget_Data *wd;
625
626    wd = elm_widget_data_get(obj);
627    if (!wd)
628      return NULL;
629
630    item = _item_new(obj, label, func, data);
631    if (!item)
632      return NULL;
633
634    wd->items = eina_list_append(wd->items, item);
635    if (!wd->current) {
636         wd->current = wd->items;
637         _update_view(obj);
638    }
639
640    if (!wd->sentinel ||
641        (strlen(elm_flipselector_item_label_get(item)) >
642         strlen(elm_flipselector_item_label_get(DATA_GET(wd->sentinel)))))
643      {
644         wd->sentinel = eina_list_last(wd->items);
645         _sizing_eval(obj);
646      }
647
648    if (eina_list_count(wd->items) >= 2)
649      edje_object_signal_emit(wd->base, "elm,state,button,visible", "elm");
650
651    return item;
652 }
653
654 EAPI Elm_Flipselector_Item *
655 elm_flipselector_item_prepend(Evas_Object *obj, const char *label, void (*func)(void *data, Evas_Object *obj, void *event_info), void *data)
656 {
657    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
658
659    Elm_Flipselector_Item *item;
660    Widget_Data *wd;
661
662    wd = elm_widget_data_get(obj);
663    if (!wd)
664      return NULL;
665
666    item = _item_new(obj, label, func, data);
667    if (!item)
668      return NULL;
669
670    wd->items = eina_list_prepend(wd->items, item);
671    if (!wd->current) {
672         wd->current = wd->items;
673         _update_view(obj);
674    }
675
676    if (!wd->sentinel ||
677        (strlen(elm_flipselector_item_label_get(item)) >
678         strlen(elm_flipselector_item_label_get(DATA_GET(wd->sentinel)))))
679      {
680         wd->sentinel = wd->items;
681         _sizing_eval(obj);
682      }
683
684    if (eina_list_count(wd->items) >= 2)
685      edje_object_signal_emit(wd->base, "elm,state,button,visible", "elm");
686
687    return item;
688 }
689
690 /* TODO: account for deleted items?  */
691 EAPI const Eina_List *
692 elm_flipselector_items_get(const Evas_Object *obj)
693 {
694    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
695
696    Widget_Data *wd = elm_widget_data_get(obj);
697    if (!wd)
698      return NULL;
699
700    return wd->items;
701 }
702
703 EAPI Elm_Flipselector_Item *
704 elm_flipselector_first_item_get(const Evas_Object *obj)
705 {
706    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
707
708    Elm_Flipselector_Item *it;
709    Widget_Data *wd;
710    Eina_List *l;
711
712    wd = elm_widget_data_get(obj);
713    if (!wd || !wd->items)
714      return NULL;
715
716    EINA_LIST_FOREACH(wd->items, l, it)
717      {
718         if (it->deleted)
719           continue;
720
721         return it;
722      }
723
724    return NULL;
725 }
726
727 EAPI Elm_Flipselector_Item *
728 elm_flipselector_last_item_get(const Evas_Object *obj)
729 {
730    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
731
732    Elm_Flipselector_Item *it;
733    Widget_Data *wd;
734    Eina_List *l;
735
736    wd = elm_widget_data_get(obj);
737    if (!wd || !wd->items)
738      return NULL;
739
740    EINA_LIST_REVERSE_FOREACH(wd->items, l, it)
741      {
742         if (it->deleted)
743           continue;
744
745         return it;
746      }
747
748    return NULL;
749 }
750
751 EAPI Elm_Flipselector_Item *
752 elm_flipselector_selected_item_get(const Evas_Object *obj)
753 {
754    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
755
756    Widget_Data *wd = elm_widget_data_get(obj);
757    if (!wd || !wd->current)
758      return NULL;
759
760    return DATA_GET(wd->current);
761 }
762
763 EAPI void
764 elm_flipselector_item_selected_set(Elm_Flipselector_Item *item, Eina_Bool selected)
765 {
766    ELM_FLIPSELECTOR_ITEM_CHECK_DELETED_RETURN(item);
767
768    Elm_Flipselector_Item *_item, *cur;
769    int flipside = MSG_FLIP_UP;
770    Widget_Data *wd;
771    Eina_List *l;
772
773    wd = elm_widget_data_get(item->base.widget);
774    if (!wd)
775      return;
776
777    cur = DATA_GET(wd->current);
778    if ((selected) && (cur == item))
779      return;
780
781    _flipselector_walk(wd);
782
783    if ((!selected) && (cur == item))
784      {
785         EINA_LIST_FOREACH(wd->items, l, _item)
786           {
787              if (!_item->deleted)
788                {
789                   wd->current = l;
790                   _send_msg(wd, MSG_FLIP_UP, (char *)_item->label);
791                   break;
792                }
793           }
794         _flipselector_unwalk(wd);
795         return;
796      }
797
798    EINA_LIST_FOREACH(wd->items, l, _item)
799      {
800         if (_item == cur)
801           flipside = MSG_FLIP_DOWN;
802
803         if (_item == item)
804           {
805              wd->current = l;
806              _send_msg(wd, flipside, (char *)item->label);
807              break;
808           }
809      }
810
811    _flipselector_unwalk(wd);
812 }
813
814 EAPI Eina_Bool
815 elm_flipselector_item_selected_get(const Elm_Flipselector_Item *item)
816 {
817    ELM_FLIPSELECTOR_ITEM_CHECK_DELETED_RETURN(item, EINA_FALSE);
818    Widget_Data *wd;
819
820    wd = elm_widget_data_get(item->base.widget);
821    if (!wd) return EINA_FALSE;
822    return (eina_list_data_get(wd->current) == item);
823 }
824
825 EAPI void
826 elm_flipselector_item_del(Elm_Flipselector_Item *item)
827 {
828    ELM_FLIPSELECTOR_ITEM_CHECK_DELETED_RETURN(item);
829
830    Widget_Data *wd;
831
832    wd = elm_widget_data_get(item->base.widget);
833    if (!wd)
834      return;
835
836    if (wd->walking > 0)
837      {
838         item->deleted = EINA_TRUE;
839         return;
840      }
841
842    _flipselector_walk(wd);
843
844    wd->items = eina_list_remove(wd->items, item);
845    _item_free(item);
846    _sentinel_eval(wd);
847
848    _flipselector_unwalk(wd);
849 }
850
851 EAPI const char *
852 elm_flipselector_item_label_get(const Elm_Flipselector_Item *item)
853 {
854    ELM_FLIPSELECTOR_ITEM_CHECK_DELETED_RETURN(item, NULL);
855
856    Elm_Flipselector_Item *_item;
857    Widget_Data *wd;
858    Eina_List *l;
859
860    wd = elm_widget_data_get(item->base.widget);
861    if ((!wd) || (!wd->items))
862      return NULL;
863
864    EINA_LIST_FOREACH(wd->items, l, _item)
865       if (_item == item)
866         return item->label;
867
868    return NULL;
869 }
870
871 EAPI void
872 elm_flipselector_item_label_set(Elm_Flipselector_Item *item, const char *label)
873 {
874    ELM_FLIPSELECTOR_ITEM_CHECK_DELETED_RETURN(item);
875
876    Widget_Data *wd;
877    Eina_List *l;
878
879    if ((!item) || (!label))
880      return;
881
882    wd = elm_widget_data_get(item->base.widget);
883    if ((!wd) || (!wd->items))
884      return;
885
886    l = eina_list_data_find_list(wd->items, item);
887    if (!l)
888      return;
889
890    eina_stringshare_del(item->label);
891    item->label = eina_stringshare_add_length(label, wd->max_len);
892
893    if (strlen(label) >
894        strlen(elm_flipselector_item_label_get(DATA_GET(wd->sentinel))))
895      wd->sentinel = l;
896
897    if (wd->current == l)
898      {
899         _update_view(item->base.widget);
900         _sizing_eval(wd->self);
901      }
902
903    return;
904 }
905
906 EAPI Elm_Flipselector_Item *
907 elm_flipselector_item_prev_get(Elm_Flipselector_Item *item)
908 {
909    ELM_FLIPSELECTOR_ITEM_CHECK_DELETED_RETURN(item, NULL);
910
911    Elm_Flipselector_Item *_item;
912    Widget_Data *wd;
913    Eina_List *l;
914
915    wd = elm_widget_data_get(item->base.widget);
916    if ((!wd) || (!wd->items))
917      return NULL;
918
919    EINA_LIST_FOREACH(wd->items, l, _item)
920       if (_item == item)
921         {
922            l = eina_list_prev(l);
923            if (!l)
924              return NULL;
925            return DATA_GET(l);
926         }
927
928    return NULL;
929 }
930
931 EAPI Elm_Flipselector_Item *
932 elm_flipselector_item_next_get(Elm_Flipselector_Item *item)
933 {
934    ELM_FLIPSELECTOR_ITEM_CHECK_DELETED_RETURN(item, NULL);
935
936    Elm_Flipselector_Item *_item;
937    Widget_Data *wd;
938    Eina_List *l;
939
940    wd = elm_widget_data_get(item->base.widget);
941    if ((!wd) || (!wd->items))
942      return NULL;
943
944    EINA_LIST_FOREACH(wd->items, l, _item)
945       if (_item == item)
946         {
947            l = eina_list_next(l);
948            if (!l)
949              return NULL;
950            return DATA_GET(l);
951         }
952
953    return NULL;
954 }
955
956 EAPI void
957 elm_flipselector_interval_set(Evas_Object *obj, double interval)
958 {
959    ELM_CHECK_WIDTYPE(obj, widtype);
960
961    Widget_Data *wd = elm_widget_data_get(obj);
962    if (!wd)
963      return;
964
965    wd->first_interval = interval;
966 }
967
968 EAPI double
969 elm_flipselector_interval_get(const Evas_Object *obj)
970 {
971    ELM_CHECK_WIDTYPE(obj, widtype) 0.0;
972
973    Widget_Data *wd = elm_widget_data_get(obj);
974
975    if (!wd)
976      return 0.0;
977    return wd->first_interval;
978 }