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