1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_OBJECT_PROTECTED
6 #define EFL_ACCESS_WIDGET_ACTION_PROTECTED
7 
8 #define ELM_WIDGET_ITEM_PROTECTED
9 #include <Elementary.h>
10 #include "elm_priv.h"
11 #include "elm_widget_flipselector.h"
12 
13 #include "elm_flipselector_eo.h"
14 #include "elm_flipselector_item_eo.h"
15 
16 #define MY_CLASS ELM_FLIPSELECTOR_CLASS
17 
18 #define MY_CLASS_NAME "Elm_Flipselector"
19 #define MY_CLASS_NAME_LEGACY "elm_flipselector"
20 
21 /* TODO: ideally, the default theme would use map{} blocks on the TEXT
22    parts to implement their fading in/out properly (as in the clock
23    widget) */
24 /* TODO: if one ever wants to extend it to receiving generic widgets
25    as items, be my guest. in this case, remember to implement the
26    items tooltip infra. */
27 /* TODO: fix default theme image borders for looong strings as item
28    labels. */
29 /* TODO: set text elipsis on labels if one enforces mininum size on
30  * the overall widget less the required for displaying it. */
31 /* TODO: find a way to, in the default theme, to detect we are
32  * bootstrapping (receiving the 1st message) and populate the downmost
33  * TEXT parts with the same text as the upmost, where appropriate. */
34 
35 #define FLIP_FIRST_INTERVAL (0.85)
36 #define FLIP_MIN_INTERVAL   (0.1)
37 #define MSG_FLIP_DOWN       (1)
38 #define MSG_FLIP_UP         (2)
39 #define MAX_LEN_DEFAULT     (50)
40 
41 #define DATA_GET            eina_list_data_get
42 
43 static const char SIG_SELECTED[] = "selected";
44 static const char SIG_UNDERFLOWED[] = "underflowed";
45 static const char SIG_OVERFLOWED[] = "overflowed";
46 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
47    {SIG_SELECTED, ""},
48    {SIG_UNDERFLOWED, ""},
49    {SIG_OVERFLOWED, ""},
50    {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
51    {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
52    {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
53    {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
54    {NULL, NULL}
55 };
56 
57 static Eina_Bool _key_action_flip(Evas_Object *obj, const char *params);
58 
59 static const Elm_Action key_actions[] = {
60    {"flip", _key_action_flip},
61    {NULL, NULL}
62 };
63 
64 EOLIAN static void
_elm_flipselector_efl_canvas_group_group_calculate(Eo * obj,Elm_Flipselector_Data * sd)65 _elm_flipselector_efl_canvas_group_group_calculate(Eo *obj, Elm_Flipselector_Data *sd)
66 {
67    char *tmp = NULL;
68    Evas_Coord minw = -1, minh = -1, w, h;
69 
70    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
71 
72    if (sd->evaluating) return;
73 
74    elm_coords_finger_size_adjust(1, &minw, 2, &minh);
75 
76    sd->evaluating = EINA_TRUE;
77 
78    if (sd->sentinel)
79      {
80         const char *label = elm_object_item_text_get(DATA_GET(sd->sentinel));
81         const char *src = elm_layout_text_get(obj, "elm.top");
82 
83         if (src)
84             tmp = strdup(src);
85         elm_layout_text_set(obj, "elm.top", label);
86      }
87 
88    edje_object_size_min_restricted_calc
89      (wd->resize_obj, &minw, &minh, minw, minh);
90    elm_coords_finger_size_adjust(1, &minw, 2, &minh);
91    evas_object_size_hint_combined_min_get(obj, &w, &h);
92 
93    if (sd->sentinel)
94      {
95         elm_layout_text_set(obj, "elm.top", tmp);
96         efl_canvas_group_need_recalculate_set(obj, EINA_FALSE);
97         free(tmp);
98      }
99 
100    if (w > minw) minw = w;
101    if (h > minh) minh = h;
102 
103    sd->evaluating = EINA_FALSE;
104 
105    evas_object_size_hint_min_set(obj, minw, minh);
106 }
107 
108 static void
_update_view(Evas_Object * obj)109 _update_view(Evas_Object *obj)
110 {
111    const char *label;
112    Elm_Object_Item *eo_item;
113 
114    ELM_FLIPSELECTOR_DATA_GET(obj, sd);
115    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
116 
117    label = NULL;
118    eo_item = DATA_GET(sd->current);
119    ELM_FLIPSELECTOR_ITEM_DATA_GET(eo_item, item);
120    if (item) label = item->label;
121 
122    elm_layout_text_set(obj, "elm.top", label ? label : "");
123    elm_layout_text_set(obj, "elm.bottom", label ? label : "");
124 
125    edje_object_message_signal_process(wd->resize_obj);
126 }
127 
128 EOLIAN static void
_elm_flipselector_item_elm_widget_item_part_text_set(Eo * eo_item,Elm_Flipselector_Item_Data * item,const char * part,const char * label)129 _elm_flipselector_item_elm_widget_item_part_text_set(Eo *eo_item,
130                                                      Elm_Flipselector_Item_Data *item,
131                                                      const char *part,
132                                                      const char *label)
133 {
134    Eina_List *l;
135 
136    if (!label) return;
137 
138    if (part && strcmp(part, "default")) return;
139 
140    ELM_FLIPSELECTOR_DATA_GET(WIDGET(item), sd);
141 
142    if (!sd->items) return;
143 
144    l = eina_list_data_find_list(sd->items, eo_item);
145    if (!l) return;
146 
147    eina_stringshare_del(item->label);
148    item->label = eina_stringshare_add_length(label, sd->max_len);
149 
150    if (strlen(label) > strlen(elm_object_item_text_get(DATA_GET(sd->sentinel))))
151      sd->sentinel = l;
152 
153    if (sd->current == l)
154      {
155         _update_view(WIDGET(item));
156         elm_layout_sizing_eval(WIDGET(item));
157      }
158 }
159 
160 EOLIAN static const char *
_elm_flipselector_item_elm_widget_item_part_text_get(const Eo * eo_it EINA_UNUSED,Elm_Flipselector_Item_Data * it,const char * part)161 _elm_flipselector_item_elm_widget_item_part_text_get(const Eo *eo_it EINA_UNUSED,
162                                                      Elm_Flipselector_Item_Data *it,
163                                                      const char *part)
164 {
165    if (part && strcmp(part, "default")) return NULL;
166 
167    return it->label;
168 }
169 
170 EOLIAN static void
_elm_flipselector_item_elm_widget_item_signal_emit(Eo * eo_it EINA_UNUSED,Elm_Flipselector_Item_Data * it,const char * emission,const char * source)171 _elm_flipselector_item_elm_widget_item_signal_emit(Eo *eo_it EINA_UNUSED,
172                                                    Elm_Flipselector_Item_Data *it,
173                                                    const char *emission,
174                                                    const char *source)
175 {
176    edje_object_signal_emit(VIEW(it), emission, source);
177 }
178 
179 static inline void
_flipselector_walk(Elm_Flipselector_Data * sd)180 _flipselector_walk(Elm_Flipselector_Data *sd)
181 {
182    if (sd->walking < 0)
183      {
184         ERR("walking was negative. fixed!\n");
185         sd->walking = 0;
186      }
187    sd->walking++;
188 }
189 
190 static void
_sentinel_eval(Elm_Flipselector_Data * sd)191 _sentinel_eval(Elm_Flipselector_Data *sd)
192 {
193    Elm_Object_Item *it;
194    Eina_List *l;
195 
196    if (!sd->items)
197      {
198         sd->sentinel = NULL;
199         return;
200      }
201 
202    sd->sentinel = sd->items;
203 
204    EINA_LIST_FOREACH(sd->items, l, it)
205      {
206         if (strlen(elm_object_item_text_get(it)) >
207             strlen(elm_object_item_text_get(DATA_GET(sd->sentinel))))
208           sd->sentinel = l;
209      }
210 }
211 
212 static inline void
_flipselector_unwalk(Elm_Flipselector_Data * sd)213 _flipselector_unwalk(Elm_Flipselector_Data *sd)
214 {
215    sd->walking--;
216 
217    if (sd->walking < 0)
218      {
219         ERR("walking became negative. fixed!\n");
220         sd->walking = 0;
221      }
222    if (sd->walking) return;
223 }
224 
225 static void
_on_item_changed(Elm_Flipselector_Data * sd)226 _on_item_changed(Elm_Flipselector_Data *sd)
227 {
228    Elm_Object_Item *eo_item;
229 
230    eo_item = DATA_GET(sd->current);
231    ELM_FLIPSELECTOR_ITEM_DATA_GET(eo_item, item);
232    if (!item) return;
233    if (sd->deleting) return;
234 
235    if (item->func)
236      item->func((void *)WIDGET_ITEM_DATA_GET(eo_item), WIDGET(item), eo_item);
237    evas_object_smart_callback_call(sd->obj, "selected", eo_item);
238 }
239 
240 static void
_send_msg(Elm_Flipselector_Data * sd,int flipside,char * label)241 _send_msg(Elm_Flipselector_Data *sd,
242           int flipside,
243           char *label)
244 {
245    Edje_Message_String msg;
246    ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd);
247 
248    msg.str = label;
249    edje_object_message_send
250      (wd->resize_obj, EDJE_MESSAGE_STRING, flipside, &msg);
251    edje_object_message_signal_process(wd->resize_obj);
252 
253    _on_item_changed(sd);
254 }
255 
256 static void
_view_update(void * data)257 _view_update(void *data)
258 {
259    Evas_Object *obj = data;
260    ELM_FLIPSELECTOR_DATA_GET(obj, sd);
261    Elm_Object_Item *eo_item;
262 
263    sd->view_update = NULL;
264    sd->need_update = EINA_FALSE;
265 
266    if (sd->current)
267      {
268         eo_item = sd->current->data;
269         ELM_FLIPSELECTOR_ITEM_DATA_GET(eo_item, item);
270         _send_msg(sd, MSG_FLIP_DOWN, (char *)item->label);
271      }
272    else
273      {
274         _send_msg(sd, MSG_FLIP_DOWN, "");
275         elm_layout_signal_emit(obj, "elm,state,button,hidden", "elm");
276      }
277 }
278 
279 EOLIAN static void
_elm_flipselector_item_efl_object_destructor(Eo * eo_item,Elm_Flipselector_Item_Data * item)280 _elm_flipselector_item_efl_object_destructor(Eo *eo_item, Elm_Flipselector_Item_Data *item)
281 {
282    Eina_List *l;
283    ELM_FLIPSELECTOR_DATA_GET(WIDGET(item), sd);
284 
285    if (sd->deleting)
286      {
287         eina_stringshare_del(item->label);
288         sd->items = eina_list_remove(sd->items, eo_item);
289         efl_destructor(efl_super(eo_item, ELM_FLIPSELECTOR_ITEM_CLASS));
290         return;
291      }
292 
293    if ((sd->current) && (sd->current->data == eo_item))
294      {
295         sd->need_update = EINA_TRUE;
296         l = sd->current->prev;
297         if (!l) l = sd->current->next;
298         if (!l) sd->current = NULL;
299         else sd->current = l;
300      }
301 
302    eina_stringshare_del(item->label);
303    sd->items = eina_list_remove(sd->items, eo_item);
304 
305    _sentinel_eval(sd);
306 
307    if (sd->need_update)
308      {
309         if (sd->view_update) ecore_job_del(sd->view_update);
310         sd->view_update = ecore_job_add(_view_update, WIDGET(item));
311      }
312 
313    efl_destructor(efl_super(eo_item, ELM_FLIPSELECTOR_ITEM_CLASS));
314 }
315 
316 EOLIAN static Eo *
_elm_flipselector_item_efl_object_constructor(Eo * obj,Elm_Flipselector_Item_Data * it)317 _elm_flipselector_item_efl_object_constructor(Eo *obj, Elm_Flipselector_Item_Data *it)
318 {
319    obj = efl_constructor(efl_super(obj, ELM_FLIPSELECTOR_ITEM_CLASS));
320    it->base = efl_data_scope_get(obj, ELM_WIDGET_ITEM_CLASS);
321 
322    return obj;
323 }
324 
325 static Elm_Object_Item *
_item_new(Evas_Object * obj,const char * label,Evas_Smart_Cb func,const void * data)326 _item_new(Evas_Object *obj,
327           const char *label,
328           Evas_Smart_Cb func,
329           const void *data)
330 {
331    unsigned int len;
332    Eo *eo_item;
333 
334    ELM_FLIPSELECTOR_DATA_GET(obj, sd);
335 
336    eo_item = efl_add(ELM_FLIPSELECTOR_ITEM_CLASS, obj);
337    if (!eo_item) return NULL;
338 
339    ELM_FLIPSELECTOR_ITEM_DATA_GET(eo_item, it);
340 
341    len = strlen(label);
342    if (len > sd->max_len) len = sd->max_len;
343 
344    it->label = eina_stringshare_add_length(label, len);
345    it->func = func;
346    WIDGET_ITEM_DATA_SET(eo_item, data);
347 
348    /* TODO: no view here, but if one desires general contents in the
349     * future... */
350    return eo_item;
351 }
352 
353 EOLIAN static Eina_Error
_elm_flipselector_efl_ui_widget_theme_apply(Eo * obj,Elm_Flipselector_Data * sd)354 _elm_flipselector_efl_ui_widget_theme_apply(Eo *obj, Elm_Flipselector_Data *sd)
355 {
356    const char *max_len;
357 
358    Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
359    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EFL_UI_THEME_APPLY_ERROR_GENERIC);
360 
361    int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
362    if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
363 
364    max_len = edje_object_data_get(wd->resize_obj, "max_len");
365    if (!max_len) sd->max_len = MAX_LEN_DEFAULT;
366    else
367      {
368         sd->max_len = atoi(max_len);
369 
370         if (!sd->max_len) sd->max_len = MAX_LEN_DEFAULT;
371      }
372 
373    _update_view(obj);
374    elm_layout_sizing_eval(obj);
375 
376    return int_ret;
377 }
378 
379 static void
_flip_up(Elm_Flipselector_Data * sd)380 _flip_up(Elm_Flipselector_Data *sd)
381 {
382    Elm_Object_Item *eo_item;
383 
384    if (!sd->current) return;
385 
386    if (sd->deleting) return;
387    if (sd->current == sd->items)
388      {
389         sd->current = eina_list_last(sd->items);
390         efl_event_callback_legacy_call
391           (sd->obj, ELM_FLIPSELECTOR_EVENT_UNDERFLOWED, NULL);
392      }
393    else
394      sd->current = eina_list_prev(sd->current);
395 
396    eo_item = DATA_GET(sd->current);
397    ELM_FLIPSELECTOR_ITEM_DATA_GET(eo_item, item);
398    if (!item) return;
399 
400    _send_msg(sd, MSG_FLIP_UP, (char *)item->label);
401 }
402 
403 static void
_flip_down(Elm_Flipselector_Data * sd)404 _flip_down(Elm_Flipselector_Data *sd)
405 {
406    Elm_Object_Item *eo_item;
407 
408    if (!sd->current) return;
409 
410    if (sd->deleting) return;
411    sd->current = eina_list_next(sd->current);
412    if (!sd->current)
413      {
414         sd->current = sd->items;
415         efl_event_callback_legacy_call
416           (sd->obj, ELM_FLIPSELECTOR_EVENT_OVERFLOWED, NULL);
417      }
418 
419    eo_item = DATA_GET(sd->current);
420    ELM_FLIPSELECTOR_ITEM_DATA_GET(eo_item, item);
421    if (!item) return;
422 
423    _send_msg(sd, MSG_FLIP_DOWN, (char *)item->label);
424 }
425 
426 static Eina_Bool
_key_action_flip(Evas_Object * obj,const char * params)427 _key_action_flip(Evas_Object *obj, const char *params)
428 {
429    ELM_FLIPSELECTOR_DATA_GET(obj, sd);
430    const char *dir = params;
431 
432    ELM_SAFE_FREE(sd->spin, ecore_timer_del);
433 
434    /* TODO: if direction setting via API is not coming in, replace
435       these calls by flip_{next,prev} */
436    _flipselector_walk(sd);
437 
438    if (!strcmp(dir, "up")) _flip_up(sd);
439    else if (!strcmp(dir, "down")) _flip_down(sd);
440    else return EINA_FALSE;
441 
442    _flipselector_unwalk(sd);
443    return EINA_TRUE;
444 }
445 
446 static void
_clear_items(Evas_Object * obj)447 _clear_items(Evas_Object *obj)
448 {
449    ELM_FLIPSELECTOR_DATA_GET(obj, sd);
450    sd->current = NULL;
451    while(sd->items)
452      elm_object_item_del(DATA_GET(sd->items));
453 }
454 
455 static void
_items_add(Evas_Object * obj)456 _items_add(Evas_Object *obj)
457 {
458    double d;
459    Eina_Bool reverse;
460    char buf[16];
461 
462    ELM_FLIPSELECTOR_DATA_GET(obj, sd);
463    reverse = (sd->val_min > sd->val_max);
464    _clear_items(obj);
465    for (d = sd->val_min; d < sd->val_max;)
466      {
467         snprintf(buf, sizeof(buf), "%.2f", d);
468         elm_flipselector_item_append(obj, buf, NULL, NULL);
469         if (reverse) d = d - sd->step;
470         else d = d + sd->step;
471      }
472    snprintf(buf, sizeof(buf), "%.2f", sd->val_max);
473    elm_flipselector_item_append(obj, buf, NULL, NULL);
474 }
475 
476 EOLIAN static void
_elm_flipselector_efl_ui_range_display_range_limits_set(Eo * obj,Elm_Flipselector_Data * sd,double min,double max)477 _elm_flipselector_efl_ui_range_display_range_limits_set(Eo *obj, Elm_Flipselector_Data *sd, double min, double max)
478 {
479    if (EINA_DBL_EQ(sd->val_min, min) && EINA_DBL_EQ(sd->val_max, max)) return;
480 
481    sd->val_min = min;
482    sd->val_max = max;
483 
484    _items_add(obj);
485 }
486 
487 EOLIAN static void
_elm_flipselector_efl_ui_range_display_range_limits_get(const Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd,double * min,double * max)488 _elm_flipselector_efl_ui_range_display_range_limits_get(const Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double *min, double *max)
489 {
490    if (min) *min = sd->val_min;
491    if (max) *max = sd->val_max;
492 }
493 
494 EOLIAN static void
_elm_flipselector_efl_ui_range_interactive_range_step_set(Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd,double step)495 _elm_flipselector_efl_ui_range_interactive_range_step_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double step)
496 {
497    if (EINA_DBL_EQ(sd->step, step)) return;
498 
499    if (EINA_DBL_EQ(step, 0.0)) step = 1.0;
500    else if (step < 0.0) step *= -1;
501 
502    sd->step = step;
503    _items_add(obj);
504 }
505 
506 EOLIAN static double
_elm_flipselector_efl_ui_range_interactive_range_step_get(const Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd)507 _elm_flipselector_efl_ui_range_interactive_range_step_get(const Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd)
508 {
509    return sd->step;
510 }
511 
512 EOLIAN static double
_elm_flipselector_efl_ui_range_display_range_value_get(const Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd)513 _elm_flipselector_efl_ui_range_display_range_value_get(const Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd)
514 {
515    if (EINA_DBL_EQ(sd->val_min, 0) && EINA_DBL_EQ(sd->val_max, 0))
516      {
517         WRN("This API can be used only if you set min and max and flipselector values are numericals");
518         return 0;
519      }
520    ELM_FLIPSELECTOR_ITEM_DATA_GET(sd->current->data, item);
521    return atof(item->label);
522 }
523 
524 EOLIAN static void
_elm_flipselector_efl_ui_range_display_range_value_set(Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd,double val)525 _elm_flipselector_efl_ui_range_display_range_value_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double val)
526 {
527    Eina_List *l;
528    Elm_Object_Item *it;
529 
530    EINA_LIST_FOREACH(sd->items, l, it)
531      {
532         if (atof(elm_object_item_text_get(it)) >= val)
533           break;
534      }
535    elm_flipselector_item_selected_set(it, EINA_TRUE);
536 }
537 
538 static Eina_Bool
_signal_val_up(void * data)539 _signal_val_up(void *data)
540 {
541    ELM_FLIPSELECTOR_DATA_GET(data, sd);
542 
543    _flipselector_walk(sd);
544 
545    if (sd->interval > FLIP_MIN_INTERVAL) sd->interval = sd->interval / 1.05;
546 
547    ecore_timer_interval_set(sd->spin, sd->interval);
548 
549    _flip_up(sd);
550 
551    _flipselector_unwalk(sd);
552 
553    return ECORE_CALLBACK_RENEW;
554 }
555 
556 static void
_signal_val_up_start(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)557 _signal_val_up_start(void *data,
558                      Evas_Object *obj EINA_UNUSED,
559                      const char *emission EINA_UNUSED,
560                      const char *source EINA_UNUSED)
561 {
562    ELM_FLIPSELECTOR_DATA_GET(data, sd);
563 
564    sd->interval = sd->first_interval;
565 
566    ecore_timer_del(sd->spin);
567    sd->spin = ecore_timer_add(sd->interval, _signal_val_up, data);
568 
569    _signal_val_up(data);
570 }
571 
572 static Eina_Bool
_signal_val_down(void * data)573 _signal_val_down(void *data)
574 {
575    ELM_FLIPSELECTOR_DATA_GET(data, sd);
576 
577    _flipselector_walk(sd);
578 
579    if (sd->interval > FLIP_MIN_INTERVAL) sd->interval = sd->interval / 1.05;
580    ecore_timer_interval_set(sd->spin, sd->interval);
581 
582    _flip_down(sd);
583 
584    _flipselector_unwalk(sd);
585 
586    return ECORE_CALLBACK_RENEW;
587 }
588 
589 static void
_signal_val_down_start(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)590 _signal_val_down_start(void *data,
591                        Evas_Object *obj EINA_UNUSED,
592                        const char *emission EINA_UNUSED,
593                        const char *source EINA_UNUSED)
594 {
595    ELM_FLIPSELECTOR_DATA_GET(data, sd);
596 
597    sd->interval = sd->first_interval;
598 
599    ecore_timer_del(sd->spin);
600    sd->spin = ecore_timer_add(sd->interval, _signal_val_down, data);
601 
602    _signal_val_down(data);
603 }
604 
605 static void
_signal_val_change_stop(void * data,Evas_Object * obj EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)606 _signal_val_change_stop(void *data,
607                         Evas_Object *obj EINA_UNUSED,
608                         const char *emission EINA_UNUSED,
609                         const char *source EINA_UNUSED)
610 {
611    ELM_FLIPSELECTOR_DATA_GET(data, sd);
612 
613    ELM_SAFE_FREE(sd->spin, ecore_timer_del);
614 }
615 
616 EOLIAN static void
_elm_flipselector_efl_canvas_group_group_add(Eo * obj,Elm_Flipselector_Data * priv)617 _elm_flipselector_efl_canvas_group_group_add(Eo *obj, Elm_Flipselector_Data *priv)
618 {
619    efl_canvas_group_add(efl_super(obj, MY_CLASS));
620 
621    if (!elm_layout_theme_set
622        (obj, "flipselector", "base", elm_widget_style_get(obj)))
623      CRI("Failed to set layout!");
624 
625    elm_layout_signal_callback_add
626      (obj, "elm,action,up,start", "*", _signal_val_up_start, obj);
627    elm_layout_signal_callback_add
628      (obj, "elm,action,up,stop", "*", _signal_val_change_stop, obj);
629    elm_layout_signal_callback_add
630      (obj, "elm,action,down,start", "*", _signal_val_down_start, obj);
631    elm_layout_signal_callback_add
632      (obj, "elm,action,down,stop", "*", _signal_val_change_stop, obj);
633 
634    priv->first_interval = FLIP_FIRST_INTERVAL;
635    priv->step = 1.0;
636 
637    elm_widget_can_focus_set(obj, EINA_TRUE);
638 
639    efl_ui_widget_theme_apply(obj);
640 }
641 
642 EOLIAN static void
_elm_flipselector_efl_canvas_group_group_del(Eo * obj,Elm_Flipselector_Data * sd)643 _elm_flipselector_efl_canvas_group_group_del(Eo *obj, Elm_Flipselector_Data *sd)
644 {
645    sd->deleting = EINA_TRUE;
646 
647    if (sd->walking) ERR("flipselector deleted while walking.\n");
648 
649    while (sd->items)
650      efl_del(DATA_GET(sd->items));
651 
652    ecore_timer_del(sd->spin);
653    ecore_job_del(sd->view_update);
654 
655    efl_canvas_group_del(efl_super(obj, MY_CLASS));
656 }
657 
658 EAPI Evas_Object *
elm_flipselector_add(Evas_Object * parent)659 elm_flipselector_add(Evas_Object *parent)
660 {
661    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
662    return elm_legacy_add(MY_CLASS, parent);
663 }
664 
665 EOLIAN static Eo *
_elm_flipselector_efl_object_constructor(Eo * obj,Elm_Flipselector_Data * sd)666 _elm_flipselector_efl_object_constructor(Eo *obj, Elm_Flipselector_Data *sd)
667 {
668    obj = efl_constructor(efl_super(obj, MY_CLASS));
669    sd->obj = obj;
670    efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
671    evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
672    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_LIST);
673    legacy_object_focus_handle(obj);
674 
675    return obj;
676 }
677 
678 EOLIAN static void
_elm_flipselector_flip_next(Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd)679 _elm_flipselector_flip_next(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd)
680 {
681    ELM_SAFE_FREE(sd->spin, ecore_timer_del);
682 
683    _flipselector_walk(sd);
684    _flip_down(sd);
685    _flipselector_unwalk(sd);
686 }
687 
688 EOLIAN static void
_elm_flipselector_flip_prev(Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd)689 _elm_flipselector_flip_prev(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd)
690 {
691    ELM_SAFE_FREE(sd->spin, ecore_timer_del);
692 
693    _flipselector_walk(sd);
694    _flip_up(sd);
695    _flipselector_unwalk(sd);
696 }
697 
698 EOLIAN static Elm_Object_Item *
_elm_flipselector_item_append(Eo * obj,Elm_Flipselector_Data * sd,const char * label,Evas_Smart_Cb func,const void * data)699 _elm_flipselector_item_append(Eo *obj, Elm_Flipselector_Data *sd, const char *label, Evas_Smart_Cb func, const void *data)
700 {
701    Elm_Object_Item *item;
702 
703    item = _item_new(obj, label, func, data);
704    if (!item) return NULL;
705 
706    sd->items = eina_list_append(sd->items, item);
707    if (!sd->current)
708      {
709         sd->current = sd->items;
710         _update_view(obj);
711      }
712 
713    if (!sd->sentinel ||
714        (strlen(elm_object_item_text_get(item)) >
715         strlen(elm_object_item_text_get(DATA_GET(sd->sentinel)))))
716      {
717         sd->sentinel = eina_list_last(sd->items);
718         elm_layout_sizing_eval(obj);
719      }
720 
721    if (eina_list_count(sd->items) > 1)
722      elm_layout_signal_emit(obj, "elm,state,button,visible", "elm");
723 
724    return item;
725 }
726 
727 EOLIAN static Elm_Object_Item *
_elm_flipselector_item_prepend(Eo * obj,Elm_Flipselector_Data * sd,const char * label,Evas_Smart_Cb func,void * data)728 _elm_flipselector_item_prepend(Eo *obj, Elm_Flipselector_Data *sd, const char *label, Evas_Smart_Cb func, void *data)
729 {
730    Elm_Object_Item *item;
731 
732    item = _item_new(obj, label, func, data);
733    if (!item) return NULL;
734 
735    sd->items = eina_list_prepend(sd->items, item);
736    if (!sd->current)
737      {
738         sd->current = sd->items;
739         _update_view(obj);
740      }
741 
742    if (!sd->sentinel ||
743        (strlen(elm_object_item_text_get(item)) >
744         strlen(elm_object_item_text_get(DATA_GET(sd->sentinel)))))
745      {
746         sd->sentinel = sd->items;
747         elm_layout_sizing_eval(obj);
748      }
749 
750    if (eina_list_count(sd->items) >= 2)
751      elm_layout_signal_emit(obj, "elm,state,button,visible", "elm");
752 
753    return item;
754 }
755 
756 EOLIAN static const Eina_List*
_elm_flipselector_items_get(const Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd)757 _elm_flipselector_items_get(const Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd)
758 {
759    return sd->items;
760 }
761 
762 EOLIAN static Elm_Object_Item*
_elm_flipselector_first_item_get(const Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd)763 _elm_flipselector_first_item_get(const Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd)
764 {
765    return eina_list_data_get(sd->items);
766 }
767 
768 EOLIAN static Elm_Object_Item*
_elm_flipselector_last_item_get(const Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd)769 _elm_flipselector_last_item_get(const Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd)
770 {
771    return eina_list_last_data_get(sd->items);
772 }
773 
774 EOLIAN static Elm_Object_Item*
_elm_flipselector_selected_item_get(const Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd)775 _elm_flipselector_selected_item_get(const Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd)
776 {
777    return DATA_GET(sd->current);
778 }
779 
780 EOLIAN static void
_elm_flipselector_item_selected_set(Eo * eo_item,Elm_Flipselector_Item_Data * item,Eina_Bool selected)781 _elm_flipselector_item_selected_set(Eo *eo_item,
782                                     Elm_Flipselector_Item_Data *item,
783                                     Eina_Bool selected)
784 {
785    Elm_Object_Item *_eo_item, *eo_cur;
786    int flipside = MSG_FLIP_UP;
787    Eina_List *l;
788 
789    ELM_FLIPSELECTOR_DATA_GET(WIDGET(item), sd);
790 
791    eo_cur = DATA_GET(sd->current);
792    if ((selected) && (eo_cur == eo_item)) return;
793 
794    _flipselector_walk(sd);
795 
796    if ((!selected) && (eo_cur == eo_item))
797      {
798         EINA_LIST_FOREACH(sd->items, l, _eo_item)
799           {
800              ELM_FLIPSELECTOR_ITEM_DATA_GET(_eo_item, _item);
801              sd->current = l;
802              _send_msg(sd, MSG_FLIP_UP, (char *)_item->label);
803              break;
804           }
805         _flipselector_unwalk(sd);
806         return;
807      }
808 
809    EINA_LIST_FOREACH(sd->items, l, _eo_item)
810      {
811         if (_eo_item == eo_cur) flipside = MSG_FLIP_DOWN;
812 
813         if (_eo_item == eo_item)
814           {
815              ELM_FLIPSELECTOR_ITEM_DATA_GET(_eo_item, _item);
816              sd->current = l;
817              _send_msg(sd, flipside, (char *)_item->label);
818              break;
819           }
820      }
821 
822    _flipselector_unwalk(sd);
823 }
824 
825 EOLIAN static Eina_Bool
_elm_flipselector_item_selected_get(const Eo * eo_item,Elm_Flipselector_Item_Data * item)826 _elm_flipselector_item_selected_get(const Eo *eo_item,
827                                     Elm_Flipselector_Item_Data *item)
828 {
829    ELM_FLIPSELECTOR_DATA_GET(WIDGET(item), sd);
830 
831    return eina_list_data_get(sd->current) == eo_item;
832 }
833 
834 EOLIAN static Elm_Object_Item *
_elm_flipselector_item_prev_get(const Eo * eo_item,Elm_Flipselector_Item_Data * item)835 _elm_flipselector_item_prev_get(const Eo *eo_item,
836                                 Elm_Flipselector_Item_Data *item)
837 {
838    Eina_List *l;
839 
840    ELM_FLIPSELECTOR_DATA_GET(WIDGET(item), sd);
841 
842    if ((!sd->items)) return NULL;
843 
844    l = eina_list_data_find_list(sd->items, eo_item);
845    if (l && l->prev) return DATA_GET(l->prev);
846 
847    return NULL;
848 }
849 
850 EOLIAN static Elm_Object_Item *
_elm_flipselector_item_next_get(const Eo * eo_item,Elm_Flipselector_Item_Data * item)851 _elm_flipselector_item_next_get(const Eo *eo_item,
852                                 Elm_Flipselector_Item_Data *item)
853 {
854    Eina_List *l;
855 
856    ELM_FLIPSELECTOR_DATA_GET(WIDGET(item), sd);
857 
858    if ((!sd->items)) return NULL;
859 
860    l = eina_list_data_find_list(sd->items, eo_item);
861    if (l && l->next) return DATA_GET(l->next);
862 
863    return NULL;
864 }
865 
866 EOLIAN void
_elm_flipselector_first_interval_set(Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd,double interval)867 _elm_flipselector_first_interval_set(Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd, double interval)
868 {
869    sd->first_interval = interval;
870 }
871 
872 EOLIAN double
_elm_flipselector_first_interval_get(const Eo * obj EINA_UNUSED,Elm_Flipselector_Data * sd)873 _elm_flipselector_first_interval_get(const Eo *obj EINA_UNUSED, Elm_Flipselector_Data *sd)
874 {
875    return sd->first_interval;
876 }
877 
878 EOLIAN static void
_elm_flipselector_class_constructor(Efl_Class * klass)879 _elm_flipselector_class_constructor(Efl_Class *klass)
880 {
881    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
882 }
883 
884 EOLIAN const Efl_Access_Action_Data *
_elm_flipselector_efl_access_widget_action_elm_actions_get(const Eo * obj EINA_UNUSED,Elm_Flipselector_Data * pd EINA_UNUSED)885 _elm_flipselector_efl_access_widget_action_elm_actions_get(const Eo *obj EINA_UNUSED, Elm_Flipselector_Data *pd EINA_UNUSED)
886 {
887    static Efl_Access_Action_Data atspi_actions[] = {
888           { "flip,up", "flip", "up", _key_action_flip},
889           { "flip,down", "flip", "down", _key_action_flip},
890           { NULL, NULL, NULL, NULL}
891    };
892    return &atspi_actions[0];
893 }
894 
895 /* Standard widget overrides */
896 
897 ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(elm_flipselector, Elm_Flipselector_Data)
898 
899 /* Internal EO APIs and hidden overrides */
900 
901 #define ELM_FLIPSELECTOR_EXTRA_OPS \
902    EFL_CANVAS_GROUP_CALC_OPS(elm_flipselector), \
903    EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_flipselector)
904 
905 #include "elm_flipselector_item_eo.c"
906 #include "elm_flipselector_eo.c"
907