diff --git a/src/bin/elementary/meson.build b/src/bin/elementary/meson.build index 65479f79ee..c17a182b86 100644 --- a/src/bin/elementary/meson.build +++ b/src/bin/elementary/meson.build @@ -100,6 +100,7 @@ elementary_test_src = [ 'test_ui_panes.c', 'test_ui_panel.c', 'test_ui_active_view.c', + 'test_ui_radio.c', 'test_part_bg.c', 'test_part_shadow.c', 'test_photo.c', diff --git a/src/bin/elementary/test.c b/src/bin/elementary/test.c index c797426c2c..bcca771d63 100644 --- a/src/bin/elementary/test.c +++ b/src/bin/elementary/test.c @@ -391,6 +391,7 @@ void test_ui_active_view_plain(void *data, Evas_Object *obj, void *event_info); void test_ui_active_view_scroll(void *data, Evas_Object *obj, void *event_info); void test_ui_relative_layout(void *data, Evas_Object *obj, void *event_info); +void test_efl_ui_radio(void *data, Evas_Object *obj, void *event_info); static void _list_udpate(void); @@ -1076,6 +1077,7 @@ add_tests: ADD_TEST(NULL, "Selectors", "DaySelector", test_dayselector); ADD_TEST(NULL, "Selectors", "Main menu", test_main_menu); ADD_TEST(NULL, "Selectors", "Combobox", test_combobox); + ADD_TEST_EO(NULL, "Selectors", "Efl.Ui.Radio_Box", test_efl_ui_radio); //------------------------------// ADD_TEST(NULL, "Cursors", "Cursor", test_cursor); diff --git a/src/bin/elementary/test_ui_radio.c b/src/bin/elementary/test_ui_radio.c new file mode 100644 index 0000000000..259846f96d --- /dev/null +++ b/src/bin/elementary/test_ui_radio.c @@ -0,0 +1,136 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include + +const char *countries[] = +{ + "Germany", + "USA", + "France", + "Korea", + "UK", + "Romania", + "Italy", + NULL, +}; +#define MAX_INDEX 8 + +static void +_check_button_selection_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev) +{ + if (efl_ui_check_selected_get(ev->object)) + printf("Object %p is now selected\n", ev->object); + else + printf("Object %p is now unselected\n", ev->object); +} + +static Eina_Array* +create_radios(Efl_Ui_Win *win) +{ + Eina_Array *arr = eina_array_new(5); + + for (unsigned int i = 0; countries[i]; ++i) + { + Efl_Ui_Radio *rbtn = efl_add(EFL_UI_RADIO_CLASS, win); + efl_ui_radio_state_value_set(rbtn, i); + efl_text_set(rbtn, countries[i]); + efl_event_callback_add(rbtn, EFL_UI_CHECK_EVENT_SELECTED_CHANGED, _check_button_selection_changed_cb, NULL); + eina_array_push(arr, rbtn); + } + + return arr; +} + +static void +_value_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev) +{ + Efl_Ui_Radio_Group *g = ev->object; + int index = efl_ui_radio_group_selected_value_get(g); + if (index == -1) + { + printf("Nothing is selected anymore\n"); + } + else + { + EINA_SAFETY_ON_FALSE_RETURN((index >= 0) && index < MAX_INDEX); + printf("Now selected value %s\n", countries[index]); + } + +} + +static void +_select_btn_clicked(void *data, const Efl_Event *ev EINA_UNUSED) +{ + Efl_Ui_Check *c = data; + + efl_ui_check_selected_set(c, EINA_TRUE); +} + +static void +_set_selected_btn_clicked(void *data, const Efl_Event *ev EINA_UNUSED) +{ + Efl_Ui_Radio_Group *group = data; + + efl_ui_radio_group_selected_value_set(group, 0); +} + +static void +_set_selected_object_btn_clicked(void *data, const Efl_Event *ev) +{ + Efl_Ui_Radio_Group *group = data; + + efl_ui_radio_group_selected_value_set(group, 3); + efl_ui_radio_group_selected_object_set(group, efl_key_data_get(ev->object, "uk")); +} + +void test_efl_ui_radio(void *data EINA_UNUSED, + Evas_Object *obj EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Efl_Ui_Win *win; + Efl_Ui_Table *table; + Efl_Ui_Box *bx; + Eina_Array *arr; + Efl_Ui_Button *o; + Efl_Ui_Radio *uk; + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(), + efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_BASIC), + efl_text_set(efl_added, "Efl.Ui.Radio_Box"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE)); + table = efl_add(EFL_UI_TABLE_CLASS, win); + efl_content_set(win, table); + + bx = efl_add(EFL_UI_RADIO_BOX_CLASS, table); + efl_pack_table(table, bx, 0, 0, 1, 3); + efl_event_callback_add(bx, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, _value_changed_cb, NULL); + + arr = create_radios(win); + for (unsigned int i = 0; i < eina_array_count(arr); ++i) + { + Efl_Ui_Radio *r = eina_array_data_get(arr, i); + efl_pack_end(bx, r); + if (i == 4) + uk = r; + } + + o = efl_add(EFL_UI_BUTTON_CLASS, table); + efl_pack_table(table, o, 1, 0, 1, 1); + efl_text_set(o, "Selected France check"); + efl_event_callback_add(o, EFL_UI_EVENT_CLICKED, _select_btn_clicked, eina_array_data_get(arr, 2)); + + o = efl_add(EFL_UI_BUTTON_CLASS, table); + efl_pack_table(table, o, 1, 1, 1, 1); + efl_text_set(o, "Set value for Germany"); + efl_event_callback_add(o, EFL_UI_EVENT_CLICKED, _set_selected_btn_clicked, bx); + + o = efl_add(EFL_UI_BUTTON_CLASS, table); + efl_pack_table(table, o, 1, 2, 1, 1); + efl_text_set(o, "Set object for UK"); + efl_key_data_set(o, "uk", uk); + efl_event_callback_add(o, EFL_UI_EVENT_CLICKED, _set_selected_object_btn_clicked, bx); + + eina_array_free(arr); +} diff --git a/src/examples/elementary/efl_ui_radio_example_01.c b/src/examples/elementary/efl_ui_radio_example_01.c new file mode 100644 index 0000000000..b6b72e2ae2 --- /dev/null +++ b/src/examples/elementary/efl_ui_radio_example_01.c @@ -0,0 +1,46 @@ +/* + * gcc -o efl_ui_radio_example_01 efl_ui_radio_example_01.c `pkg-config --cflags --libs elementary` + */ +#define EFL_BETA_API_SUPPORT 1 + +#include +#include + +const char *example_strings[] = { + "Seoul", + "Karlsruhe", + "New York", + "Hong Kong", + "Hamburg", + "Berlin", + "Paris", + NULL +}; + +EAPI_MAIN void +efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) +{ + Eo *win, *box; + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + + win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(), + efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_BASIC), + efl_text_set(efl_added, "Efl.Ui.Radio example"), + efl_ui_win_autodel_set(efl_added, EINA_TRUE) + ); + + box = efl_add(EFL_UI_RADIO_BOX_CLASS, win, + efl_content_set(win, efl_added)); + + for (int i = 0; example_strings[i]; ++i) + { + Eo *radio; + + radio = efl_add(EFL_UI_RADIO_CLASS, box); + efl_text_set(radio, example_strings[i]); + efl_ui_radio_state_value_set(radio, i + 1); + efl_pack_end(box, radio); + } +} +EFL_MAIN() diff --git a/src/examples/elementary/meson.build b/src/examples/elementary/meson.build index 35a7eeac03..f29a94f687 100644 --- a/src/examples/elementary/meson.build +++ b/src/examples/elementary/meson.build @@ -117,7 +117,8 @@ examples = [ 'efl_canvas_layout_text', 'efl_ui_theme_example_01', 'efl_ui_theme_example_02', - 'efl_ui_slideshow_example' + 'efl_ui_slideshow_example', + 'efl_ui_radio_example_01', ] foreach example : examples diff --git a/src/lib/elementary/efl_ui_radio.c b/src/lib/elementary/efl_ui_radio.c index a25a9b6007..35e273a06f 100644 --- a/src/lib/elementary/efl_ui_radio.c +++ b/src/lib/elementary/efl_ui_radio.c @@ -373,6 +373,7 @@ ELM_LAYOUT_TEXT_ALIASES_IMPLEMENT(MY_CLASS_PFX) ELM_LAYOUT_TEXT_ALIASES_OPS(MY_CLASS_PFX) #include "efl_ui_radio.eo.c" +#include "efl_ui_radio_group.eo.c" #include "efl_ui_radio_eo.legacy.c" #include "efl_ui_radio_legacy_eo.h" diff --git a/src/lib/elementary/efl_ui_radio.eo b/src/lib/elementary/efl_ui_radio.eo index a833f39e09..e59e548300 100644 --- a/src/lib/elementary/efl_ui_radio.eo +++ b/src/lib/elementary/efl_ui_radio.eo @@ -19,52 +19,6 @@ class @beta Efl.Ui.Radio extends Efl.Ui.Check implements Efl.Access.Widget.Actio value: int; [[The value to use if this radio object is selected.]] } } - @property value_pointer { - set { - [[Set a convenience pointer to an integer, which changes when radio group - value changes. - - This sets a pointer to an integer that in addition to the radio - object state will also be modified directly. To stop setting the - object pointed to, simply use NULL as the valuep argument. If - valuep is not NULL then when called, the radio object - state will also be modified to reflect the value of the integer - valuep points to, just like calling elm_radio_value_set(). - ]] - } - values { - valuep: ptr(int); [[Pointer to the integer to modify]] - } - } - @property selected_object { - get { - [[Get the selected radio object.]] - return: Efl.Canvas.Object; [[The selected radio object]] - } - } - group_add { - [[Add this radio to a group of other radio objects - - Radio objects work in groups. Each member should have a different - integer value assigned. In order to have them work as a group, they - need to know about each other. This adds the given radio object to - the group of which the group object indicated is a member. - ]] - - params { - @in group: Efl.Ui.Radio; [[Any radio object whose group the obj is - to join.]] - } - } - @property group_value { - [[Change the value of the group. - - This will enable the radio button in the group that is assosiated with this value. A value which is not assosiated with any radio button will result in every radio button beeing disabled. - ]] - values { - value : int; [[The value of the radio button in the group which should be enabled.]] - } - } } implements { Efl.Object.constructor; diff --git a/src/lib/elementary/efl_ui_radio_box.c b/src/lib/elementary/efl_ui_radio_box.c new file mode 100644 index 0000000000..b58e76f3fe --- /dev/null +++ b/src/lib/elementary/efl_ui_radio_box.c @@ -0,0 +1,127 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include +#include "elm_priv.h" + +#define MY_CLASS EFL_UI_RADIO_BOX_CLASS + +typedef struct { + Eina_Bool in_pack; + Efl_Ui_Radio_Group *group; +} Efl_Ui_Radio_Box_Data; + +static inline Eina_Bool +register_safe_in_group_begin(Eo *subobj, Efl_Ui_Radio_Box_Data *pd) +{ + EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(subobj, EFL_UI_RADIO_CLASS), EINA_FALSE); + if (!pd->in_pack) + efl_ui_radio_group_register(pd->group, subobj); + pd->in_pack = EINA_TRUE; + + return EINA_TRUE; +} + +static inline Eina_Bool +register_safe_group_end(Eo *subobj, Efl_Ui_Radio_Box_Data *pd, Eina_Bool result) +{ + if (!result) + efl_ui_radio_group_unregister(pd->group, subobj); + pd->in_pack = EINA_FALSE; + + return result; +} + +#define REGISTER_SAFE(f) \ + Eina_Bool result; \ + if (!register_safe_in_group_begin(subobj, pd)) \ + return EINA_FALSE; \ + result = f ; \ + return register_safe_group_end(subobj, pd, result); + +static void +unpack_from_logical(Eo *obj, Efl_Ui_Radio_Box_Data *pd) +{ + int length = efl_content_count(obj); + for (int i = 0; i < length; ++i) + { + efl_ui_radio_group_unregister(pd->group, efl_pack_content_get(obj, i)); + } +} + +EOLIAN static Eina_Bool +_efl_ui_radio_box_efl_pack_pack_clear(Eo *obj, Efl_Ui_Radio_Box_Data *pd) +{ + unpack_from_logical(obj, pd); + return efl_pack_clear(efl_super(obj, MY_CLASS)); +} + +EOLIAN static Eina_Bool +_efl_ui_radio_box_efl_pack_unpack_all(Eo *obj, Efl_Ui_Radio_Box_Data *pd) +{ + unpack_from_logical(obj, pd); + return efl_pack_unpack_all(efl_super(obj, MY_CLASS)); +} + +EOLIAN static Eina_Bool +_efl_ui_radio_box_efl_pack_unpack(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj) +{ + efl_ui_radio_group_unregister(pd->group, subobj); + return efl_pack_unpack(efl_super(obj, MY_CLASS), subobj); +} + +EOLIAN static Efl_Gfx_Entity* +_efl_ui_radio_box_efl_pack_linear_pack_unpack_at(Eo *obj, Efl_Ui_Radio_Box_Data *pd, int index) +{ + efl_ui_radio_group_unregister(pd->group, efl_pack_content_get(obj, index)); + return efl_pack_unpack_at(efl_super(obj, MY_CLASS), index); +} + +EOLIAN static Eina_Bool +_efl_ui_radio_box_efl_pack_pack(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj) +{ + REGISTER_SAFE(efl_pack(efl_super(obj, MY_CLASS), subobj)) +} + +EOLIAN static Eina_Bool +_efl_ui_radio_box_efl_pack_linear_pack_begin(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj) +{ + REGISTER_SAFE(efl_pack_begin(efl_super(obj, MY_CLASS), subobj)) +} + +EOLIAN static Eina_Bool +_efl_ui_radio_box_efl_pack_linear_pack_end(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj) +{ + REGISTER_SAFE(efl_pack_end(efl_super(obj, MY_CLASS), subobj)) +} + +EOLIAN static Eina_Bool +_efl_ui_radio_box_efl_pack_linear_pack_before(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj, const Efl_Gfx_Entity *existing) +{ + REGISTER_SAFE(efl_pack_before(efl_super(obj, MY_CLASS), subobj, existing)); +} + +EOLIAN static Eina_Bool +_efl_ui_radio_box_efl_pack_linear_pack_after(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj, const Efl_Gfx_Entity *existing) +{ + REGISTER_SAFE(efl_pack_after(efl_super(obj, MY_CLASS), subobj, existing)); +} + +EOLIAN static Eina_Bool +_efl_ui_radio_box_efl_pack_linear_pack_at(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj, int index) +{ + REGISTER_SAFE(efl_pack_at(efl_super(obj, MY_CLASS), subobj, index)); +} + +EOLIAN static Efl_Object* +_efl_ui_radio_box_efl_object_constructor(Eo *obj, Efl_Ui_Radio_Box_Data *pd) +{ + pd->group = efl_new(EFL_UI_RADIO_GROUP_IMPL_CLASS, NULL); + efl_composite_attach(obj, pd->group); + efl_event_callback_forwarder_add(pd->group, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, obj); + return efl_constructor(efl_super(obj, MY_CLASS)); +} + + +#include "efl_ui_radio_box.eo.c" diff --git a/src/lib/elementary/efl_ui_radio_box.eo b/src/lib/elementary/efl_ui_radio_box.eo new file mode 100644 index 0000000000..07cfb81bbc --- /dev/null +++ b/src/lib/elementary/efl_ui_radio_box.eo @@ -0,0 +1,21 @@ +class @beta Efl.Ui.Radio_Box extends Efl.Ui.Box implements Efl.Ui.Radio_Group +{ + methods { + } + implements { + Efl.Pack.pack_clear; + Efl.Pack.unpack_all; + Efl.Pack.unpack; + Efl.Pack.pack; + Efl.Pack_Linear.pack_begin; + Efl.Pack_Linear.pack_end; + Efl.Pack_Linear.pack_before; + Efl.Pack_Linear.pack_after; + Efl.Pack_Linear.pack_at; + Efl.Pack_Linear.pack_unpack_at; + Efl.Object.constructor; + } + composite { + Efl.Ui.Radio_Group; + } +} diff --git a/src/lib/elementary/efl_ui_radio_eo.h b/src/lib/elementary/efl_ui_radio_eo.h index c16605e9a3..bd8665d728 100644 --- a/src/lib/elementary/efl_ui_radio_eo.h +++ b/src/lib/elementary/efl_ui_radio_eo.h @@ -1 +1,7 @@ +#define _EFL_UI_RADIO_EO_CLASS_TYPE +typedef Eo Efl_Ui_Radio; + +#include "efl_ui_radio_group.eo.h" +#include "efl_ui_radio_group_impl.eo.h" #include "efl_ui_radio.eo.h" +#include "efl_ui_radio_box.eo.h" diff --git a/src/lib/elementary/efl_ui_radio_group.eo b/src/lib/elementary/efl_ui_radio_group.eo new file mode 100644 index 0000000000..c19636308c --- /dev/null +++ b/src/lib/elementary/efl_ui_radio_group.eo @@ -0,0 +1,50 @@ +interface @beta Efl.Ui.Radio_Group +{ + [[A object for organising a group of radio buttons + + A group of radio buttons is a set of pair-wise different values. (Where values are the assosiated values of each radio button) + At any point of time only 1 or 0 buttons can be selected. If a new button is selected, the previous selected button will be unselected. + ]] + methods { + @property selected_object { + [[Which object is currently selected in the group + + $NULL if no object is selected. + ]] + values { + selected_object : Efl.Ui.Radio; [[The selected radio button in the group, $NULL for no object]] + } + } + @property selected_value { + [[Each group has a selected value, representing which radio group is selected. + + A value of -1 here does represent that no button is selected. + Possible values here are only those that are assisiated with a registered radio button. + ]] + values { + selected_value : int; [[The value of the selection state]] + } + } + register { + [[Register a new radio button to this group. + + The assosiated value of the radio button must not collide with any other assosiated value of registered buttons. + ]] + params { + radio : Efl.Ui.Radio; [[The radio button to regsiter]] + } + } + unregister { + [[Unregsiter a before registered button from this group. + + if the button was selected before, no object will be selected afterwards. + ]] + params { + radio : Efl.Ui.Radio; [[The radio button to unregister]] + } + } + } + events { + value,changed : int; [[Emitted each time the $selected_value has changed.]] + } +} diff --git a/src/lib/elementary/efl_ui_radio_group_impl.c b/src/lib/elementary/efl_ui_radio_group_impl.c new file mode 100644 index 0000000000..4e68299540 --- /dev/null +++ b/src/lib/elementary/efl_ui_radio_group_impl.c @@ -0,0 +1,152 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include +#include "elm_priv.h" + +#define MY_CLASS EFL_UI_RADIO_GROUP_IMPL_CLASS + +static Eina_Hash *radio_group_map; + +typedef struct { + Efl_Ui_Radio *selected; + Eina_List *registered_set; +} Efl_Ui_Radio_Group_Impl_Data; + +EOLIAN static void +_efl_ui_radio_group_impl_efl_ui_radio_group_selected_object_set(Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd, Efl_Ui_Radio *selected_object) +{ + int new_value = -1; + Eo *old_selected; + + if (pd->selected == selected_object) return; + + old_selected = pd->selected; + pd->selected = selected_object; + + //it is essential to *first* set pd->selected to the new state before calling this + //otherwise this here will be called again, and the event will get emitted twice + if (old_selected && efl_alive_get(old_selected)) + efl_ui_check_selected_set(old_selected, EINA_FALSE); + + if (pd->selected) + { + efl_ui_check_selected_set(pd->selected, EINA_TRUE); + new_value = efl_ui_radio_state_value_get(pd->selected); + } + efl_event_callback_call(obj, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, &new_value); +} + +EOLIAN static Efl_Ui_Radio* +_efl_ui_radio_group_impl_efl_ui_radio_group_selected_object_get(const Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd) +{ + return pd->selected; +} + +EOLIAN static void +_efl_ui_radio_group_impl_efl_ui_radio_group_selected_value_set(Eo *obj, Efl_Ui_Radio_Group_Impl_Data *pd, int selected_value) +{ + Efl_Ui_Radio *reged; + Eina_List *n; + + EINA_LIST_FOREACH(pd->registered_set, n, reged) + { + if (efl_ui_radio_state_value_get(reged) == selected_value) + { + efl_ui_radio_group_selected_object_set(obj, reged); + return; + } + } + ERR("Value %d not assosiated with any radio button", selected_value); +} + +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) +{ + return pd->selected ? efl_ui_radio_state_value_get(pd->selected) : -1; +} + +static void +_selected_cb(void *data, const Efl_Event *ev) +{ + if (efl_ui_check_selected_get(ev->object)) + { + efl_ui_radio_group_selected_object_set(data, ev->object); + } + else + { + //if something was unselected, we need to make sure that we are unsetting the internal pointer to NULL + if (efl_ui_radio_group_selected_object_get(data) == ev->object) + { + efl_ui_radio_group_selected_object_set(data, NULL); + } + } +} + +static void +_invalidate_cb(void *data, const Efl_Event *ev) +{ + efl_ui_radio_group_unregister(data, ev->object); +} + +EFL_CALLBACKS_ARRAY_DEFINE(radio_btn_cb, + {EFL_UI_CHECK_EVENT_SELECTED_CHANGED, _selected_cb}, + {EFL_EVENT_INVALIDATE, _invalidate_cb}, +) + +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) +{ + Efl_Ui_Radio *reged; + Eina_List *n; + + if (eina_hash_find(radio_group_map, &radio)) + { + ERR("Radio button %p is already part of another group", radio); + return; + } + + EINA_LIST_FOREACH(pd->registered_set, n, reged) + { + EINA_SAFETY_ON_TRUE_RETURN(radio == reged); + EINA_SAFETY_ON_TRUE_RETURN(efl_ui_radio_state_value_get(radio) == efl_ui_radio_state_value_get(reged)); + } + EINA_SAFETY_ON_TRUE_RETURN(efl_ui_radio_state_value_get(radio) == -1); + + pd->registered_set = eina_list_append(pd->registered_set, radio); + eina_hash_add(radio_group_map, &radio, obj); + efl_event_callback_array_add(radio, radio_btn_cb(), obj); +} + +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) +{ + if (pd->selected == radio) + efl_ui_radio_group_selected_object_set(obj, NULL); + + efl_event_callback_array_del(radio, radio_btn_cb(), obj); + pd->registered_set = eina_list_remove(pd->registered_set, radio); + eina_hash_del(radio_group_map, &radio, obj); +} + +EOLIAN static void +_efl_ui_radio_group_impl_efl_object_destructor(Eo *obj, Efl_Ui_Radio_Group_Impl_Data *pd) +{ + Eo *radio; + + EINA_LIST_FREE(pd->registered_set, radio) + { + efl_event_callback_array_del(radio, radio_btn_cb(), obj); + eina_hash_del(radio_group_map, &radio, obj); + } + efl_destructor(efl_super(obj, MY_CLASS)); +} + +void +_efl_ui_radio_group_impl_class_constructor(Efl_Class *klass EINA_UNUSED) +{ + radio_group_map = eina_hash_pointer_new(NULL); +} + +#include "efl_ui_radio_group_impl.eo.c" diff --git a/src/lib/elementary/efl_ui_radio_group_impl.eo b/src/lib/elementary/efl_ui_radio_group_impl.eo new file mode 100644 index 0000000000..82204cf386 --- /dev/null +++ b/src/lib/elementary/efl_ui_radio_group_impl.eo @@ -0,0 +1,11 @@ +class @beta Efl.Ui.Radio_Group_Impl extends Efl.Object implements Efl.Ui.Radio_Group +{ + implements { + class.constructor; + Efl.Object.destructor; + Efl.Ui.Radio_Group.selected_object {get; set;} + Efl.Ui.Radio_Group.selected_value {get; set;} + Efl.Ui.Radio_Group.register; + Efl.Ui.Radio_Group.unregister; + } +} diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build index d3c418144d..3cd4f68b6b 100644 --- a/src/lib/elementary/meson.build +++ b/src/lib/elementary/meson.build @@ -57,6 +57,9 @@ pub_eo_files = [ 'efl_ui_panes.eo', 'efl_ui_progressbar.eo', 'efl_ui_radio.eo', + 'efl_ui_radio_group.eo', + 'efl_ui_radio_box.eo', + 'efl_ui_radio_group_impl.eo', 'efl_ui_slider.eo', 'efl_ui_slider_interval.eo', 'efl_ui_spin.eo', @@ -813,6 +816,8 @@ elementary_src = [ 'elm_prefs_data.c', 'efl_ui_progressbar.c', 'efl_ui_radio.c', + 'efl_ui_radio_group_impl.c', + 'efl_ui_radio_box.c', 'elm_route.c', 'elm_scroller.c', 'elm_segment_control.c', diff --git a/src/tests/elementary/efl_ui_suite.c b/src/tests/elementary/efl_ui_suite.c index 6fab5d7003..66395696bc 100644 --- a/src/tests/elementary/efl_ui_suite.c +++ b/src/tests/elementary/efl_ui_suite.c @@ -27,6 +27,7 @@ static const Efl_Test_Case etc[] = { { "efl_ui_widget", efl_ui_test_widget }, { "efl_ui_active_view", efl_ui_test_active_view}, { "efl_ui_check", efl_ui_test_check }, + { "efl_ui_radio_group", efl_ui_test_radio_group }, { NULL, NULL } }; diff --git a/src/tests/elementary/efl_ui_suite.h b/src/tests/elementary/efl_ui_suite.h index 472493818a..b5aec1b098 100644 --- a/src/tests/elementary/efl_ui_suite.h +++ b/src/tests/elementary/efl_ui_suite.h @@ -36,6 +36,7 @@ void efl_ui_model(TCase *tc); void efl_ui_test_widget(TCase *tc); void efl_ui_test_active_view(TCase *tc); void efl_ui_test_check(TCase *tc); +void efl_ui_test_radio_group(TCase *tc); void loop_timer_interval_set(Eo *obj, double in); diff --git a/src/tests/elementary/efl_ui_test_radio_group.c b/src/tests/elementary/efl_ui_test_radio_group.c new file mode 100644 index 0000000000..4c515bf140 --- /dev/null +++ b/src/tests/elementary/efl_ui_test_radio_group.c @@ -0,0 +1,266 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include +#include "efl_ui_suite.h" +#include "suite_helpers.h" + +static Eo *win, *radio_group; + +int state_values = 0; + +typedef struct { + int called; + int value; +} Group_Changed_Called; + +Group_Changed_Called changed_evt; + +#define RESET_EVT \ + changed_evt.called = 0; \ + changed_evt.value = 200000000; + +#define EXPECT_EVT(c, v) \ + ck_assert_int_eq(changed_evt.called, c); \ + ck_assert_int_eq(changed_evt.value, v); + +static void +_group_value_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev) +{ + changed_evt.called ++; + changed_evt.value = *((int*)ev->info); +} + +static void +check_setup() +{ + win = win_add(); + radio_group = efl_new(EFL_UI_RADIO_GROUP_IMPL_CLASS, NULL); + efl_event_callback_add(radio_group, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, _group_value_changed_cb, NULL); +} + +static void +check_teardown() +{ + efl_unref(radio_group); + if (win) + { + efl_del(win); + win = NULL; + } +} + +static Eo* +radio(void) +{ + state_values += 1; + return efl_add(EFL_UI_RADIO_CLASS, win, efl_ui_radio_state_value_set(efl_added, state_values)); +} + +EFL_START_TEST(active_selected_value_setting) +{ + Eo *r1 = radio(); + Eo *r2 = radio(); + + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, r1); + efl_ui_radio_group_register(radio_group, r2); + + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL); + + RESET_EVT + efl_ui_radio_group_selected_value_set(radio_group, 1); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r1); + ck_assert_int_eq(efl_ui_check_selected_get(r1), EINA_TRUE); + ck_assert_int_eq(efl_ui_check_selected_get(r2), EINA_FALSE); + EXPECT_EVT(1,1); + + RESET_EVT + efl_ui_radio_group_selected_object_set(radio_group, r2); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 2); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r2); + ck_assert_int_eq(efl_ui_check_selected_get(r1), EINA_FALSE); + ck_assert_int_eq(efl_ui_check_selected_get(r2), EINA_TRUE); + EXPECT_EVT(1,2); +} +EFL_END_TEST + +EFL_START_TEST(active_selection_setting) +{ + Eo *r1 = radio(); + Eo *r2 = radio(); + + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, r1); + efl_ui_radio_group_register(radio_group, r2); + + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL); + + RESET_EVT + efl_ui_radio_group_selected_object_set(radio_group, r1); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r1); + ck_assert_int_eq(efl_ui_check_selected_get(r1), EINA_TRUE); + ck_assert_int_eq(efl_ui_check_selected_get(r2), EINA_FALSE); + EXPECT_EVT(1,1); + + RESET_EVT + efl_ui_radio_group_selected_object_set(radio_group, r2); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 2); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r2); + ck_assert_int_eq(efl_ui_check_selected_get(r1), EINA_FALSE); + ck_assert_int_eq(efl_ui_check_selected_get(r2), EINA_TRUE); + EXPECT_EVT(1,2); +} +EFL_END_TEST + +EFL_START_TEST(active_selection_object_setting) +{ + Eo *r = radio(); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, r); + efl_ui_radio_group_register(radio_group, radio()); + + RESET_EVT + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL); + efl_ui_check_selected_set(r, EINA_TRUE); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r); + EXPECT_EVT(1,1); +} +EFL_END_TEST + +EFL_START_TEST(unregister_setted) +{ + Eo *r = radio(); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, r); + efl_ui_radio_group_register(radio_group, radio()); + + RESET_EVT + efl_ui_radio_group_selected_object_set(radio_group, r); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r); + EXPECT_EVT(1,1); + RESET_EVT + efl_ui_radio_group_unregister(radio_group, r); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL); + EXPECT_EVT(1,-1); +} +EFL_END_TEST + +EFL_START_TEST(delete_setted) +{ + Eo *r = radio(); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, r); + efl_ui_radio_group_register(radio_group, radio()); + RESET_EVT + efl_ui_radio_group_selected_object_set(radio_group, r); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r); + EXPECT_EVT(1,1); + RESET_EVT + efl_del(r); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL); + EXPECT_EVT(1,-1); +} +EFL_END_TEST + +EFL_START_TEST(external_setting) +{ + Eo *r = radio(); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, radio()); + efl_ui_radio_group_register(radio_group, r); + efl_ui_radio_group_register(radio_group, radio()); + RESET_EVT + efl_ui_check_selected_set(r, EINA_TRUE); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r); + EXPECT_EVT(1,1); + RESET_EVT + efl_ui_check_selected_set(r, EINA_FALSE); + ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1); + ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL); + EXPECT_EVT(1,-1); +} +EFL_END_TEST + +EFL_START_TEST(pairwise_different_error) +{ + Eo *r = radio(); + Eo *r1 = radio(); + Eo *r2 = radio(); + efl_ui_radio_state_value_set(r, -1); + efl_ui_radio_state_value_set(r1, 14); + efl_ui_radio_state_value_set(r2, 14); + EXPECT_ERROR_START; + efl_ui_radio_group_register(radio_group, r); + EXPECT_ERROR_END; + efl_ui_radio_group_register(radio_group, r1); + EXPECT_ERROR_START; + efl_ui_radio_group_register(radio_group, r2); + EXPECT_ERROR_END; +} +EFL_END_TEST + +EFL_START_TEST(group_double_registeration) +{ + Eo *r = radio(); + efl_ui_radio_group_register(radio_group, r); + EXPECT_ERROR_START; + efl_ui_radio_group_register(radio_group, r); + EXPECT_ERROR_END; +} +EFL_END_TEST + +EFL_START_TEST(group_registeration_in_two_groups) +{ + Eo *radio_group2 = efl_new(EFL_UI_RADIO_GROUP_IMPL_CLASS, NULL); + Eo *r = radio(); + efl_ui_radio_group_register(radio_group, r); + EXPECT_ERROR_START; + efl_ui_radio_group_register(radio_group2, r); + EXPECT_ERROR_END; +} +EFL_END_TEST + +EFL_START_TEST(group_invalid_value) +{ + Eo *radio_group2 = efl_new(EFL_UI_RADIO_GROUP_IMPL_CLASS, NULL); + Eo *r = radio(); + efl_ui_radio_group_register(radio_group, r); + EXPECT_ERROR_START; + efl_ui_radio_group_selected_value_set(radio_group2, 1000); + EXPECT_ERROR_END; +} +EFL_END_TEST + +void efl_ui_test_radio_group(TCase *tc) +{ + tcase_add_checked_fixture(tc, fail_on_errors_setup, fail_on_errors_teardown); + tcase_add_checked_fixture(tc, check_setup, check_teardown); + tcase_add_test(tc, active_selected_value_setting); + tcase_add_test(tc, active_selection_setting); + tcase_add_test(tc, active_selection_object_setting); + tcase_add_test(tc, pairwise_different_error); + tcase_add_test(tc, group_double_registeration); + tcase_add_test(tc, group_registeration_in_two_groups); + tcase_add_test(tc, unregister_setted); + tcase_add_test(tc, external_setting); + tcase_add_test(tc, delete_setted); + tcase_add_test(tc, group_invalid_value); +} diff --git a/src/tests/elementary/meson.build b/src/tests/elementary/meson.build index 735ba0a829..43b3ca1cfe 100644 --- a/src/tests/elementary/meson.build +++ b/src/tests/elementary/meson.build @@ -140,6 +140,7 @@ efl_ui_suite_src = [ 'efl_ui_test_widget.c', 'efl_ui_test_active_view.c', 'efl_ui_test_check.c', + 'efl_ui_test_radio_group.c', ] efl_ui_suite = executable('efl_ui_suite',