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