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