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