1 #include <Elementary.h>
3 #include "elm_widget_segment_control.h"
5 EAPI const char ELM_SEGMENT_CONTROL_SMART_NAME[] = "elm_segment_control";
7 static const char SIG_CHANGED[] = "changed";
8 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
13 EVAS_SMART_SUBCLASS_NEW
14 (ELM_SEGMENT_CONTROL_SMART_NAME, _elm_segment_control,
15 Elm_Segment_Control_Smart_Class, Elm_Layout_Smart_Class,
16 elm_layout_smart_class_get, _smart_callbacks);
19 _elm_segment_control_smart_sizing_eval(Evas_Object *obj)
21 Evas_Coord minw = -1, minh = -1;
25 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
27 item_count = eina_list_count(sd->items);
29 elm_coords_finger_size_adjust(item_count, &minw, 1, &minh);
30 edje_object_size_min_restricted_calc
31 (ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh, minw, minh);
32 elm_coords_finger_size_adjust(item_count, &minw, 1, &minh);
34 evas_object_size_hint_min_get(obj, &w, &h);
36 if (w > minw) minw = w;
37 if (h > minh) minh = h;
39 evas_object_size_hint_min_set(obj, minw, minh);
43 _item_free(Elm_Segment_Item *it)
45 ELM_SEGMENT_CONTROL_DATA_GET(WIDGET(it), sd);
47 if (sd->selected_item == it) sd->selected_item = NULL;
48 if (sd->items) sd->items = eina_list_remove(sd->items, it);
50 if (it->icon) evas_object_del(it->icon);
51 if (it->label) eina_stringshare_del(it->label);
55 _position_items(Elm_Segment_Control_Smart_Data *sd)
61 int bx, by, bw, bh, pos;
63 item_count = eina_list_count(sd->items);
64 if (item_count <= 0) return;
66 evas_object_geometry_get
67 (ELM_WIDGET_DATA(sd)->resize_obj, &bx, &by, &bw, &bh);
68 sd->item_width = bw / item_count;
69 rtl = elm_widget_mirrored_get(ELM_WIDGET_DATA(sd)->obj);
71 if (rtl) pos = bx + bw - sd->item_width;
74 EINA_LIST_FOREACH(sd->items, l, it)
76 evas_object_move(VIEW(it), pos, by);
77 evas_object_resize(VIEW(it), sd->item_width, bh);
78 if (rtl) pos -= sd->item_width;
79 else pos += sd->item_width;
82 elm_layout_sizing_eval(ELM_WIDGET_DATA(sd)->obj);
86 _swallow_item_objects(Elm_Segment_Item *it)
92 edje_object_part_swallow(VIEW(it), "elm.swallow.icon", it->icon);
93 edje_object_signal_emit(VIEW(it), "elm,state,icon,visible", "elm");
95 else edje_object_signal_emit(VIEW(it), "elm,state,icon,hidden", "elm");
99 edje_object_part_text_escaped_set(VIEW(it), "elm.text", it->label);
100 edje_object_signal_emit(VIEW(it), "elm,state,text,visible", "elm");
103 edje_object_signal_emit(VIEW(it), "elm,state,text,hidden", "elm");
105 edje_object_message_signal_process(VIEW(it));
109 _update_list(Elm_Segment_Control_Smart_Data *sd)
115 Elm_Segment_Item *it;
119 item_count = eina_list_count(sd->items);
123 it = eina_list_nth(sd->items, 0);
126 //Set the segment type
127 edje_object_signal_emit(VIEW(it), "elm,type,segment,single", "elm");
129 //Set the segment state
130 if (sd->selected_item == it)
131 edje_object_signal_emit
132 (VIEW(it), "elm,state,segment,selected", "elm");
134 edje_object_signal_emit(VIEW(it), "elm,state,segment,normal", "elm");
136 if (elm_widget_disabled_get(ELM_WIDGET_DATA(sd)->obj))
137 edje_object_signal_emit(VIEW(it), "elm,state,disabled", "elm");
139 edje_object_signal_emit(VIEW(it), "elm,state,enabled", "elm");
141 _swallow_item_objects(it);
145 rtl = elm_widget_mirrored_get(ELM_WIDGET_DATA(sd)->obj);
146 EINA_LIST_FOREACH(sd->items, l, it)
150 //Set the segment type
154 edje_object_signal_emit
155 (VIEW(it), "elm,type,segment,right", "elm");
157 edje_object_signal_emit
158 (VIEW(it), "elm,type,segment,left", "elm");
160 else if (idx == (item_count - 1))
163 edje_object_signal_emit
164 (VIEW(it), "elm,type,segment,left", "elm");
166 edje_object_signal_emit
167 (VIEW(it), "elm,type,segment,right", "elm");
170 edje_object_signal_emit(VIEW(it), "elm,type,segment,middle", "elm");
172 //Set the segment state
173 if (sd->selected_item == it)
174 edje_object_signal_emit
175 (VIEW(it), "elm,state,segment,selected", "elm");
177 edje_object_signal_emit(VIEW(it), "elm,state,segment,normal", "elm");
179 if (elm_widget_disabled_get(ELM_WIDGET_DATA(sd)->obj))
180 edje_object_signal_emit(VIEW(it), "elm,state,disabled", "elm");
182 edje_object_signal_emit(VIEW(it), "elm,state,enabled", "elm");
184 _swallow_item_objects(it);
190 _elm_segment_control_smart_theme(Evas_Object *obj)
194 Elm_Segment_Item *it;
196 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
198 if (!ELM_WIDGET_CLASS(_elm_segment_control_parent_sc)->theme(obj))
201 rtl = elm_widget_mirrored_get(obj);
203 EINA_LIST_FOREACH(sd->items, l, it)
205 elm_widget_theme_object_set
206 (obj, VIEW(it), "segment_control", "item",
207 elm_widget_style_get(obj));
208 edje_object_scale_set(VIEW(it), elm_widget_scale_get(VIEW(it)) *
209 elm_config_scale_get());
210 edje_object_mirrored_set(VIEW(it), rtl);
219 _elm_segment_control_smart_disable(Evas_Object *obj)
221 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
223 if (!ELM_WIDGET_CLASS(_elm_segment_control_parent_sc)->disable(obj))
231 // TODO: elm_widget_focus_list_next_get supports only Elm_widget list,
232 // not the Elm_Widget_item. Focus switching within widget not
233 // supported until it is supported in elm_widget
236 _elm_list_data_get(const Eina_List *list)
238 Elm_Segment_Item *it = eina_list_data_get(list);
242 edje_object_signal_emit(VIEW(it), "elm,state,segment,selected", "elm");
248 _elm_segment_control_smart_focus_next(const Evas_Object *obj,
249 Elm_Focus_Direction dir,
252 static int count = 0;
253 const Eina_List *items;
254 void *(*list_data_get)(const Eina_List *list);
256 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
259 if ((items = elm_widget_focus_custom_chain_get(obj)))
260 list_data_get = eina_list_data_get;
264 list_data_get = _elm_list_data_get;
265 if (!items) return EINA_FALSE;
268 return elm_widget_focus_list_next_get(obj, items, list_data_get, dir, next);
274 _segment_off(Elm_Segment_Item *it)
276 ELM_SEGMENT_CONTROL_DATA_GET(WIDGET(it), sd);
278 edje_object_signal_emit(VIEW(it), "elm,state,segment,normal", "elm");
280 if (sd->selected_item == it) sd->selected_item = NULL;
284 _segment_on(Elm_Segment_Item *it)
286 ELM_SEGMENT_CONTROL_DATA_GET(WIDGET(it), sd);
288 if (it == sd->selected_item) return;
290 if (sd->selected_item) _segment_off(sd->selected_item);
292 edje_object_signal_emit(VIEW(it), "elm,state,segment,selected", "elm");
294 sd->selected_item = it;
295 evas_object_smart_callback_call(ELM_WIDGET_DATA(sd)->obj, SIG_CHANGED, it);
299 _on_move_resize(void *data, Evas *e __UNUSED__,
300 Evas_Object *obj __UNUSED__,
301 void *event_info __UNUSED__)
303 ELM_SEGMENT_CONTROL_DATA_GET(data, sd);
309 _on_mouse_up(void *data,
311 Evas_Object *obj __UNUSED__,
314 Elm_Segment_Item *it;
315 Evas_Event_Mouse_Up *ev;
316 Evas_Coord x, y, w, h;
319 ELM_SEGMENT_CONTROL_DATA_GET(WIDGET(it), sd);
321 if (elm_widget_disabled_get(ELM_WIDGET_DATA(sd)->obj)) return;
323 if (it == sd->selected_item) return;
326 evas_object_geometry_get(VIEW(it), &x, &y, &w, &h);
328 if ((ev->canvas.x >= x) && (ev->output.x <= (x + w)) && (ev->canvas.y >= y)
329 && (ev->canvas.y <= (y + h)))
332 edje_object_signal_emit(VIEW(it), "elm,state,segment,normal", "elm");
336 _on_mouse_down(void *data,
338 Evas_Object *obj __UNUSED__,
339 void *event_info __UNUSED__)
341 Elm_Segment_Item *it;
344 ELM_SEGMENT_CONTROL_DATA_GET(WIDGET(it), sd);
346 if (elm_widget_disabled_get(ELM_WIDGET_DATA(sd)->obj)) return;
348 if (it == sd->selected_item) return;
350 edje_object_signal_emit(VIEW(it), "elm,state,segment,pressed", "elm");
353 static Elm_Segment_Item *
354 _item_find(const Evas_Object *obj,
357 Elm_Segment_Item *it;
359 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
361 it = eina_list_nth(sd->items, idx);
366 _item_text_set_hook(Elm_Object_Item *it,
370 Elm_Segment_Item *item;
372 item = (Elm_Segment_Item *)it;
374 if ((!part) || (!strcmp(part, "default")) ||
375 (!strcmp(part, "elm.text")))
377 eina_stringshare_replace(&item->label, label);
379 edje_object_signal_emit(VIEW(item), "elm,state,text,visible", "elm");
381 edje_object_signal_emit(VIEW(item), "elm,state,text,hidden", "elm");
387 snprintf(buf, sizeof(buf), "elm,state,%s,visible", part);
388 edje_object_signal_emit(VIEW(item), buf, "elm");
392 snprintf(buf, sizeof(buf), "elm,state,%s,hidden", part);
393 edje_object_signal_emit(VIEW(item), buf, "elm");
397 edje_object_message_signal_process(VIEW(item));
398 //label can be NULL also.
399 edje_object_part_text_escaped_set(VIEW(item), part, label);
403 _item_text_get_hook(const Elm_Object_Item *it,
408 if (!part || !strcmp(part, "default"))
409 snprintf(buf, sizeof(buf), "elm.text");
411 snprintf(buf, sizeof(buf), "%s", part);
413 return edje_object_part_text_get(VIEW(it), buf);
417 _item_content_set_hook(Elm_Object_Item *it,
419 Evas_Object *content)
421 Elm_Segment_Item *item;
423 item = (Elm_Segment_Item *)it;
425 if (!part || !strcmp("icon", part))
427 if (content == item->icon) return;
429 if (item->icon) evas_object_del(item->icon);
430 item->icon = content;
433 elm_widget_sub_object_add(VIEW(item), item->icon);
434 edje_object_part_swallow(VIEW(item), "elm.swallow.icon", item->icon);
435 edje_object_signal_emit(VIEW(item), "elm,state,icon,visible", "elm");
438 edje_object_signal_emit(VIEW(item), "elm,state,icon,hidden", "elm");
444 edje_object_part_swallow(VIEW(it), part, content);
445 snprintf(buf, sizeof(buf), "elm,state,%s,visible", part);
446 edje_object_signal_emit(VIEW(item), buf, "elm");
450 snprintf(buf, sizeof(buf), "elm,state,%s,hidden", part);
451 edje_object_signal_emit(VIEW(item), buf, "elm");
457 _item_content_get_hook(const Elm_Object_Item *it,
460 Elm_Segment_Item *item;
461 item = (Elm_Segment_Item *)it;
463 if (part && !strcmp(part, "icon"))
466 return edje_object_part_swallow_get(VIEW(item), part);
470 _item_del_pre_hook(Elm_Object_Item *it)
472 Elm_Segment_Item *item = (Elm_Segment_Item *)it;
473 ELM_SEGMENT_CONTROL_DATA_GET(WIDGET(it), sd);
482 _access_info_cb(void *data, Evas_Object *obj __UNUSED__)
484 const char *txt = NULL;
485 Elm_Segment_Item *it = (Elm_Segment_Item *)data;
486 ELM_SEGMENT_CONTROL_ITEM_CHECK_OR_RETURN(it, NULL);
488 if (!txt) txt = it->label;
489 if (txt) return strdup(txt);
495 _access_state_cb(void *data, Evas_Object *obj __UNUSED__)
497 Elm_Segment_Item *it = (Elm_Segment_Item *)data;
498 ELM_SEGMENT_CONTROL_ITEM_CHECK_OR_RETURN(it, NULL);
499 ELM_SEGMENT_CONTROL_DATA_GET(WIDGET(it), sd);
501 if (ELM_WIDGET_DATA(sd)->disabled)
502 return strdup(E_("State: Disabled"));
504 if (it == sd->selected_item)
505 return strdup(E_("State: Selected"));
507 return strdup(E_("State: Unselected"));
511 _access_widget_item_register(Elm_Segment_Item *it)
515 _elm_access_widget_item_register((Elm_Widget_Item *)it);
517 ai = _elm_access_object_get(it->base.access_obj);
519 _elm_access_text_set(ai, ELM_ACCESS_TYPE, E_("Segment Control Item"));
520 _elm_access_callback_set(ai, ELM_ACCESS_INFO, _access_info_cb, it);
521 _elm_access_callback_set(ai, ELM_ACCESS_STATE, _access_state_cb, it);
524 static Elm_Segment_Item *
525 _item_new(Evas_Object *obj,
529 Elm_Segment_Item *it;
531 it = elm_widget_item_new(obj, Elm_Segment_Item);
532 if (!it) return NULL;
534 elm_widget_item_del_pre_hook_set(it, _item_del_pre_hook);
535 elm_widget_item_text_set_hook_set(it, _item_text_set_hook);
536 elm_widget_item_text_get_hook_set(it, _item_text_get_hook);
537 elm_widget_item_content_set_hook_set(it, _item_content_set_hook);
538 elm_widget_item_content_get_hook_set(it, _item_content_get_hook);
540 VIEW(it) = edje_object_add(evas_object_evas_get(obj));
541 edje_object_scale_set
542 (VIEW(it), elm_widget_scale_get(VIEW(it)) * elm_config_scale_get());
543 evas_object_smart_member_add(VIEW(it), obj);
545 elm_widget_sub_object_add(obj, VIEW(it));
546 elm_widget_theme_object_set
547 (obj, VIEW(it), "segment_control", "item", elm_object_style_get(obj));
548 edje_object_mirrored_set(VIEW(it), elm_widget_mirrored_get(WIDGET(it)));
550 if (label) eina_stringshare_replace(&it->label, label);
552 edje_object_signal_emit(VIEW(it), "elm,state,text,visible", "elm");
554 edje_object_signal_emit(VIEW(it), "elm,state,text,hidden", "elm");
555 edje_object_message_signal_process(VIEW(it));
556 edje_object_part_text_escaped_set(VIEW(it), "elm.text", label);
559 if (it->icon) elm_widget_sub_object_add(VIEW(it), it->icon);
560 evas_object_event_callback_add
561 (VIEW(it), EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down, it);
562 evas_object_event_callback_add
563 (VIEW(it), EVAS_CALLBACK_MOUSE_UP, _on_mouse_up, it);
564 evas_object_show(VIEW(it));
567 if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
568 _access_widget_item_register(it);
574 _elm_segment_control_smart_add(Evas_Object *obj)
576 EVAS_SMART_DATA_ALLOC(obj, Elm_Segment_Control_Smart_Data);
578 ELM_WIDGET_CLASS(_elm_segment_control_parent_sc)->base.add(obj);
581 (obj, "segment_control", "base", elm_widget_style_get(obj));
583 evas_object_event_callback_add
584 (obj, EVAS_CALLBACK_RESIZE, _on_move_resize, obj);
585 evas_object_event_callback_add
586 (obj, EVAS_CALLBACK_MOVE, _on_move_resize, obj);
588 elm_layout_sizing_eval(obj);
592 _elm_segment_control_smart_del(Evas_Object *obj)
594 Elm_Segment_Item *it;
596 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
598 EINA_LIST_FREE (sd->items, it)
601 elm_widget_item_free(it);
604 ELM_WIDGET_CLASS(_elm_segment_control_parent_sc)->base.del(obj);
608 _elm_segment_control_smart_focus_next(const Evas_Object *obj,
609 Elm_Focus_Direction dir,
612 Eina_List *items = NULL;
614 Elm_Segment_Item *it;
616 ELM_SEGMENT_CONTROL_CHECK(obj) EINA_FALSE;
617 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
619 EINA_LIST_FOREACH(sd->items, l, it)
620 items = eina_list_append(items, it->base.access_obj);
622 return elm_widget_focus_list_next_get
623 (obj, items, eina_list_data_get, dir, next);
627 _access_obj_process(Elm_Segment_Control_Smart_Data * sd, Eina_Bool is_access)
630 Elm_Segment_Item *it;
632 EINA_LIST_FOREACH(sd->items, l, it)
634 if (is_access) _access_widget_item_register(it);
636 _elm_access_widget_item_unregister((Elm_Widget_Item *)it);
641 _access_hook(Evas_Object *obj, Eina_Bool is_access)
643 ELM_SEGMENT_CONTROL_CHECK(obj);
644 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
647 ELM_WIDGET_CLASS(ELM_WIDGET_DATA(sd)->api)->focus_next =
648 _elm_segment_control_smart_focus_next;
650 ELM_WIDGET_CLASS(ELM_WIDGET_DATA(sd)->api)->focus_next = NULL;
651 _access_obj_process(sd, is_access);
655 _elm_segment_control_smart_set_user(Elm_Segment_Control_Smart_Class *sc)
657 ELM_WIDGET_CLASS(sc)->base.add = _elm_segment_control_smart_add;
658 ELM_WIDGET_CLASS(sc)->base.del = _elm_segment_control_smart_del;
660 ELM_WIDGET_CLASS(sc)->theme = _elm_segment_control_smart_theme;
661 ELM_WIDGET_CLASS(sc)->disable = _elm_segment_control_smart_disable;
664 ELM_WIDGET_CLASS(sc)->focus_next = _elm_segment_control_smart_focus_next;
666 ELM_WIDGET_CLASS(sc)->focus_next = NULL; /* not 'focus chain manager' */
669 ELM_WIDGET_CLASS(sc)->focus_direction = NULL;
671 ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_segment_control_smart_sizing_eval;
674 if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
675 ELM_WIDGET_CLASS(sc)->focus_next = _elm_segment_control_smart_focus_next;
677 ELM_WIDGET_CLASS(sc)->access = _access_hook;
680 EAPI const Elm_Segment_Control_Smart_Class *
681 elm_segment_control_smart_class_get(void)
683 static Elm_Segment_Control_Smart_Class _sc =
684 ELM_SEGMENT_CONTROL_SMART_CLASS_INIT_NAME_VERSION
685 (ELM_SEGMENT_CONTROL_SMART_NAME);
686 static const Elm_Segment_Control_Smart_Class *class = NULL;
687 Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
692 _elm_segment_control_smart_set(&_sc);
693 esc->callbacks = _smart_callbacks;
700 elm_segment_control_add(Evas_Object *parent)
704 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
706 obj = elm_widget_add(_elm_segment_control_smart_class_new(), parent);
707 if (!obj) return NULL;
709 if (!elm_widget_sub_object_add(parent, obj))
710 ERR("could not add %p as sub object of %p", obj, parent);
715 EAPI Elm_Object_Item *
716 elm_segment_control_item_add(Evas_Object *obj,
720 Elm_Segment_Item *it;
722 ELM_SEGMENT_CONTROL_CHECK(obj) NULL;
723 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
725 it = _item_new(obj, icon, label);
726 if (!it) return NULL;
728 sd->items = eina_list_append(sd->items, it);
731 return (Elm_Object_Item *)it;
734 EAPI Elm_Object_Item *
735 elm_segment_control_item_insert_at(Evas_Object *obj,
740 Elm_Segment_Item *it, *it_rel;
742 ELM_SEGMENT_CONTROL_CHECK(obj) NULL;
743 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
745 if (idx < 0) idx = 0;
747 it = _item_new(obj, icon, label);
748 if (!it) return NULL;
750 it_rel = _item_find(obj, idx);
751 if (it_rel) sd->items = eina_list_prepend_relative(sd->items, it, it_rel);
752 else sd->items = eina_list_append(sd->items, it);
756 return (Elm_Object_Item *)it;
760 elm_segment_control_item_del_at(Evas_Object *obj,
763 Elm_Segment_Item *it;
765 ELM_SEGMENT_CONTROL_CHECK(obj);
767 it = _item_find(obj, idx);
770 elm_object_item_del((Elm_Object_Item *)it);
774 elm_segment_control_item_label_get(const Evas_Object *obj,
777 Elm_Segment_Item *it;
779 ELM_SEGMENT_CONTROL_CHECK(obj) NULL;
781 it = _item_find(obj, idx);
782 if (it) return it->label;
788 elm_segment_control_item_icon_get(const Evas_Object *obj,
791 ELM_SEGMENT_CONTROL_CHECK(obj) NULL;
793 Elm_Segment_Item *it = _item_find(obj, idx);
794 if (it) return it->icon;
800 elm_segment_control_item_count_get(const Evas_Object *obj)
802 ELM_SEGMENT_CONTROL_CHECK(obj) 0;
803 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
805 return eina_list_count(sd->items);
809 elm_segment_control_item_object_get(const Elm_Object_Item *it)
811 ELM_SEGMENT_CONTROL_ITEM_CHECK_OR_RETURN(it, NULL);
816 EAPI Elm_Object_Item *
817 elm_segment_control_item_selected_get(const Evas_Object *obj)
819 ELM_SEGMENT_CONTROL_CHECK(obj) NULL;
820 ELM_SEGMENT_CONTROL_DATA_GET(obj, sd);
822 return (Elm_Object_Item *)sd->selected_item;
826 elm_segment_control_item_selected_set(Elm_Object_Item *it,
829 Elm_Segment_Item *item = (Elm_Segment_Item *)it;
831 ELM_SEGMENT_CONTROL_ITEM_CHECK_OR_RETURN(it);
832 ELM_SEGMENT_CONTROL_DATA_GET(WIDGET(it), sd);
834 if (item == sd->selected_item)
836 //already in selected state.
837 if (selected) return;
846 EAPI Elm_Object_Item *
847 elm_segment_control_item_get(const Evas_Object *obj,
850 ELM_SEGMENT_CONTROL_CHECK(obj) NULL;
852 return (Elm_Object_Item *)_item_find(obj, idx);
856 elm_segment_control_item_index_get(const Elm_Object_Item *it)
858 ELM_SEGMENT_CONTROL_ITEM_CHECK_OR_RETURN(it, -1);
860 return ((Elm_Segment_Item *)it)->seg_index;