1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #include <Elementary.h>
6 #include "elm_priv.h"
7 
8 #define MY_CLASS EFL_UI_RADIO_GROUP_IMPL_CLASS
9 
10 static Eina_Hash *radio_group_map;
11 
12 typedef struct {
13    Efl_Ui_Radio *selected;
14    Efl_Ui_Radio *fallback_object;
15    Eina_List *registered_set;
16    Eina_Bool in_value_change;
17 } Efl_Ui_Radio_Group_Impl_Data;
18 
19 EOLIAN static void
_efl_ui_radio_group_impl_efl_ui_single_selectable_allow_manual_deselection_set(Eo * obj EINA_UNUSED,Efl_Ui_Radio_Group_Impl_Data * pd EINA_UNUSED,Eina_Bool allow_manual_deselection EINA_UNUSED)20 _efl_ui_radio_group_impl_efl_ui_single_selectable_allow_manual_deselection_set(Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd EINA_UNUSED, Eina_Bool allow_manual_deselection EINA_UNUSED)
21 {
22    if (allow_manual_deselection == EINA_FALSE)
23      ERR("This is right now not supported.");
24 }
25 
26 EOLIAN static Eina_Bool
_efl_ui_radio_group_impl_efl_ui_single_selectable_allow_manual_deselection_get(const Eo * obj EINA_UNUSED,Efl_Ui_Radio_Group_Impl_Data * pd EINA_UNUSED)27 _efl_ui_radio_group_impl_efl_ui_single_selectable_allow_manual_deselection_get(const Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd EINA_UNUSED)
28 {
29    return EINA_FALSE;
30 }
31 
32 EOLIAN static void
_efl_ui_radio_group_impl_efl_ui_single_selectable_fallback_selection_set(Eo * obj EINA_UNUSED,Efl_Ui_Radio_Group_Impl_Data * pd,Efl_Ui_Selectable * fallback)33 _efl_ui_radio_group_impl_efl_ui_single_selectable_fallback_selection_set(Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd, Efl_Ui_Selectable *fallback)
34 {
35    pd->fallback_object = fallback;
36 
37    if (!pd->selected)
38      efl_ui_selectable_selected_set(pd->fallback_object, EINA_TRUE);
39 }
40 
41 EOLIAN static Efl_Ui_Selectable*
_efl_ui_radio_group_impl_efl_ui_single_selectable_fallback_selection_get(const Eo * obj EINA_UNUSED,Efl_Ui_Radio_Group_Impl_Data * pd)42 _efl_ui_radio_group_impl_efl_ui_single_selectable_fallback_selection_get(const Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd)
43 {
44    return pd->fallback_object;
45 }
46 
47 EOLIAN static Efl_Ui_Radio*
_efl_ui_radio_group_impl_efl_ui_single_selectable_last_selected_get(const Eo * obj EINA_UNUSED,Efl_Ui_Radio_Group_Impl_Data * pd)48 _efl_ui_radio_group_impl_efl_ui_single_selectable_last_selected_get(const Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd)
49 {
50    return pd->selected;
51 }
52 
53 EOLIAN static void
_efl_ui_radio_group_impl_efl_ui_radio_group_selected_value_set(Eo * obj EINA_UNUSED,Efl_Ui_Radio_Group_Impl_Data * pd,int selected_value)54 _efl_ui_radio_group_impl_efl_ui_radio_group_selected_value_set(Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd, int selected_value)
55 {
56    Efl_Ui_Radio *reged;
57    Eina_List *n;
58 
59    EINA_LIST_FOREACH(pd->registered_set, n, reged)
60      {
61         if (efl_ui_radio_state_value_get(reged) == selected_value)
62           {
63              efl_ui_selectable_selected_set(reged, EINA_TRUE);
64              return;
65           }
66      }
67    ERR("Value %d not assosiated with any radio button", selected_value);
68 }
69 
70 EOLIAN static int
_efl_ui_radio_group_impl_efl_ui_radio_group_selected_value_get(const Eo * obj EINA_UNUSED,Efl_Ui_Radio_Group_Impl_Data * pd)71 _efl_ui_radio_group_impl_efl_ui_radio_group_selected_value_get(const Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd)
72 {
73    return pd->selected ? efl_ui_radio_state_value_get(pd->selected) : -1;
74 }
75 
76 static void
_selected_cb(void * data,const Efl_Event * ev)77 _selected_cb(void *data, const Efl_Event *ev)
78 {
79    Efl_Ui_Radio_Group_Impl_Data *pd = efl_data_scope_safe_get(data, EFL_UI_RADIO_GROUP_IMPL_CLASS);
80    EINA_SAFETY_ON_NULL_RETURN(pd);
81 
82    if (efl_ui_selectable_selected_get(ev->object))
83      {
84         if (pd->selected)
85           {
86              pd->in_value_change = EINA_TRUE;
87              efl_ui_selectable_selected_set(pd->selected, EINA_FALSE);
88           }
89         pd->in_value_change = EINA_FALSE;
90         EINA_SAFETY_ON_FALSE_RETURN(!pd->selected);
91         pd->selected = ev->object;
92      }
93    else
94      {
95         //if something was unselected, we need to make sure that we are unsetting the internal pointer to NULL
96         if (pd->selected == ev->object)
97           {
98              pd->selected = NULL;
99           }
100         //checkout if we want to do fallback handling
101         if (!pd->in_value_change)
102           {
103              if (!pd->selected && pd->fallback_object)
104                efl_ui_selectable_selected_set(pd->fallback_object, EINA_TRUE);
105           }
106      }
107 
108    if (!pd->in_value_change)
109      {
110         int value;
111         if (pd->selected)
112           value = efl_ui_radio_state_value_get(pd->selected);
113         else
114           value = -1;
115         efl_event_callback_call(data, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, &value);
116         efl_event_callback_call(data, EFL_UI_SELECTABLE_EVENT_SELECTION_CHANGED, NULL);
117      }
118 }
119 
120 static void
_invalidate_cb(void * data,const Efl_Event * ev)121 _invalidate_cb(void *data, const Efl_Event *ev)
122 {
123    efl_ui_radio_group_unregister(data, ev->object);
124 }
125 
126 EFL_CALLBACKS_ARRAY_DEFINE(radio_btn_cb,
127   {EFL_UI_EVENT_SELECTED_CHANGED, _selected_cb},
128   {EFL_EVENT_INVALIDATE, _invalidate_cb},
129 )
130 
131 EOLIAN static void
_efl_ui_radio_group_impl_efl_ui_radio_group_register(Eo * obj,Efl_Ui_Radio_Group_Impl_Data * pd,Efl_Ui_Radio * radio)132 _efl_ui_radio_group_impl_efl_ui_radio_group_register(Eo *obj, Efl_Ui_Radio_Group_Impl_Data *pd, Efl_Ui_Radio *radio)
133 {
134    Efl_Ui_Radio *reged;
135    Eina_List *n;
136 
137    if (eina_hash_find(radio_group_map, &radio))
138      {
139         ERR("Radio button %p is already part of another group", radio);
140         return;
141      }
142 
143    EINA_LIST_FOREACH(pd->registered_set, n, reged)
144      {
145         EINA_SAFETY_ON_TRUE_RETURN(radio == reged);
146         EINA_SAFETY_ON_TRUE_RETURN(efl_ui_radio_state_value_get(radio) == efl_ui_radio_state_value_get(reged));
147      }
148    EINA_SAFETY_ON_TRUE_RETURN(efl_ui_radio_state_value_get(radio) == -1);
149 
150    pd->registered_set = eina_list_append(pd->registered_set, radio);
151    eina_hash_add(radio_group_map, &radio, obj);
152    efl_event_callback_array_add(radio, radio_btn_cb(), obj);
153 }
154 
155 EOLIAN static void
_efl_ui_radio_group_impl_efl_ui_radio_group_unregister(Eo * obj,Efl_Ui_Radio_Group_Impl_Data * pd,Efl_Ui_Radio * radio)156 _efl_ui_radio_group_impl_efl_ui_radio_group_unregister(Eo *obj, Efl_Ui_Radio_Group_Impl_Data *pd, Efl_Ui_Radio *radio)
157 {
158    if (pd->selected == radio)
159      efl_ui_selectable_selected_set(pd->selected, EINA_FALSE);
160 
161    efl_event_callback_array_del(radio, radio_btn_cb(), obj);
162    pd->registered_set = eina_list_remove(pd->registered_set, radio);
163    eina_hash_del(radio_group_map, &radio, obj);
164 }
165 
166 EOLIAN static void
_efl_ui_radio_group_impl_efl_object_destructor(Eo * obj,Efl_Ui_Radio_Group_Impl_Data * pd)167 _efl_ui_radio_group_impl_efl_object_destructor(Eo *obj, Efl_Ui_Radio_Group_Impl_Data *pd)
168 {
169    Eo *radio;
170 
171    EINA_LIST_FREE(pd->registered_set, radio)
172      {
173         efl_event_callback_array_del(radio, radio_btn_cb(), obj);
174         eina_hash_del(radio_group_map, &radio, obj);
175      }
176    efl_destructor(efl_super(obj, MY_CLASS));
177 }
178 
179 void
_efl_ui_radio_group_impl_class_constructor(Efl_Class * klass EINA_UNUSED)180 _efl_ui_radio_group_impl_class_constructor(Efl_Class *klass EINA_UNUSED)
181 {
182    radio_group_map = eina_hash_pointer_new(NULL);
183 }
184 
185 #include "efl_ui_radio_group_impl.eo.c"
186