summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <mail@marcel-hollerbach.de>2019-05-29 13:03:37 +0200
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2019-06-20 16:02:00 +0200
commitc9177a9f8d75fc7bd2634a0adb63106492f3e94c (patch)
treec116e4c39d0f3f7d36233fdfc9b57dedc6b91441
parent42b293ae1f89aa3737fe7a4d81ebc3596fd2c631 (diff)
Introduce Efl.Ui.Radio_Group & Efl.Ui.Radio_Box
Radio_Group is a interface that manages that radio groups can be grouped inside a external object, the current API of radio was considered confusing in that regard. It is implemented in the Radio_Group_Internal class which is private to EFL, a instance of it can be found with get due to the class function in efl_ui_radio.eo. This architecture was taken like this, in order to have implementation and interface seperated. With those two seperated we can inherit from regular widgets, implement the interface, and composite attach the internal object to the regular widget. This makes a lot of things easier. Radio_Box is a class which is extending Efl.Ui.Box, which has an internal Radio_Group. This is extremly usefull for cases where you just want to have a list of radio buttons in your UI. The radio group is also exposed using composition to the internal object. Simular things can be done for the table. For now i did not add API to find the group of a radio button. However, this can be quickly added if requested. ref T7867 Reviewed-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com> Reviewed-by: Xavi Artigas <xavierartigas@yahoo.es> Differential Revision: https://phab.enlightenment.org/D9058
-rw-r--r--src/bin/elementary/meson.build1
-rw-r--r--src/bin/elementary/test.c2
-rw-r--r--src/bin/elementary/test_ui_radio.c136
-rw-r--r--src/examples/elementary/efl_ui_radio_example_01.c46
-rw-r--r--src/examples/elementary/meson.build3
-rw-r--r--src/lib/elementary/efl_ui_radio.c1
-rw-r--r--src/lib/elementary/efl_ui_radio.eo46
-rw-r--r--src/lib/elementary/efl_ui_radio_box.c127
-rw-r--r--src/lib/elementary/efl_ui_radio_box.eo21
-rw-r--r--src/lib/elementary/efl_ui_radio_eo.h6
-rw-r--r--src/lib/elementary/efl_ui_radio_group.eo50
-rw-r--r--src/lib/elementary/efl_ui_radio_group_impl.c152
-rw-r--r--src/lib/elementary/efl_ui_radio_group_impl.eo11
-rw-r--r--src/lib/elementary/meson.build5
-rw-r--r--src/tests/elementary/efl_ui_suite.c1
-rw-r--r--src/tests/elementary/efl_ui_suite.h1
-rw-r--r--src/tests/elementary/efl_ui_test_radio_group.c266
-rw-r--r--src/tests/elementary/meson.build1
18 files changed, 829 insertions, 47 deletions
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 = [
100 'test_ui_panes.c', 100 'test_ui_panes.c',
101 'test_ui_panel.c', 101 'test_ui_panel.c',
102 'test_ui_active_view.c', 102 'test_ui_active_view.c',
103 'test_ui_radio.c',
103 'test_part_bg.c', 104 'test_part_bg.c',
104 'test_part_shadow.c', 105 'test_part_shadow.c',
105 'test_photo.c', 106 '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);
391void test_ui_active_view_scroll(void *data, Evas_Object *obj, void *event_info); 391void test_ui_active_view_scroll(void *data, Evas_Object *obj, void *event_info);
392 392
393void test_ui_relative_layout(void *data, Evas_Object *obj, void *event_info); 393void test_ui_relative_layout(void *data, Evas_Object *obj, void *event_info);
394void test_efl_ui_radio(void *data, Evas_Object *obj, void *event_info);
394 395
395static void _list_udpate(void); 396static void _list_udpate(void);
396 397
@@ -1076,6 +1077,7 @@ add_tests:
1076 ADD_TEST(NULL, "Selectors", "DaySelector", test_dayselector); 1077 ADD_TEST(NULL, "Selectors", "DaySelector", test_dayselector);
1077 ADD_TEST(NULL, "Selectors", "Main menu", test_main_menu); 1078 ADD_TEST(NULL, "Selectors", "Main menu", test_main_menu);
1078 ADD_TEST(NULL, "Selectors", "Combobox", test_combobox); 1079 ADD_TEST(NULL, "Selectors", "Combobox", test_combobox);
1080 ADD_TEST_EO(NULL, "Selectors", "Efl.Ui.Radio_Box", test_efl_ui_radio);
1079 1081
1080 //------------------------------// 1082 //------------------------------//
1081 ADD_TEST(NULL, "Cursors", "Cursor", test_cursor); 1083 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 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#include <Efl_Ui.h>
6
7const char *countries[] =
8{
9 "Germany",
10 "USA",
11 "France",
12 "Korea",
13 "UK",
14 "Romania",
15 "Italy",
16 NULL,
17};
18#define MAX_INDEX 8
19
20static void
21_check_button_selection_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev)
22{
23 if (efl_ui_check_selected_get(ev->object))
24 printf("Object %p is now selected\n", ev->object);
25 else
26 printf("Object %p is now unselected\n", ev->object);
27}
28
29static Eina_Array*
30create_radios(Efl_Ui_Win *win)
31{
32 Eina_Array *arr = eina_array_new(5);
33
34 for (unsigned int i = 0; countries[i]; ++i)
35 {
36 Efl_Ui_Radio *rbtn = efl_add(EFL_UI_RADIO_CLASS, win);
37 efl_ui_radio_state_value_set(rbtn, i);
38 efl_text_set(rbtn, countries[i]);
39 efl_event_callback_add(rbtn, EFL_UI_CHECK_EVENT_SELECTED_CHANGED, _check_button_selection_changed_cb, NULL);
40 eina_array_push(arr, rbtn);
41 }
42
43 return arr;
44}
45
46static void
47_value_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev)
48{
49 Efl_Ui_Radio_Group *g = ev->object;
50 int index = efl_ui_radio_group_selected_value_get(g);
51 if (index == -1)
52 {
53 printf("Nothing is selected anymore\n");
54 }
55 else
56 {
57 EINA_SAFETY_ON_FALSE_RETURN((index >= 0) && index < MAX_INDEX);
58 printf("Now selected value %s\n", countries[index]);
59 }
60
61}
62
63static void
64_select_btn_clicked(void *data, const Efl_Event *ev EINA_UNUSED)
65{
66 Efl_Ui_Check *c = data;
67
68 efl_ui_check_selected_set(c, EINA_TRUE);
69}
70
71static void
72_set_selected_btn_clicked(void *data, const Efl_Event *ev EINA_UNUSED)
73{
74 Efl_Ui_Radio_Group *group = data;
75
76 efl_ui_radio_group_selected_value_set(group, 0);
77}
78
79static void
80_set_selected_object_btn_clicked(void *data, const Efl_Event *ev)
81{
82 Efl_Ui_Radio_Group *group = data;
83
84 efl_ui_radio_group_selected_value_set(group, 3);
85 efl_ui_radio_group_selected_object_set(group, efl_key_data_get(ev->object, "uk"));
86}
87
88void test_efl_ui_radio(void *data EINA_UNUSED,
89 Evas_Object *obj EINA_UNUSED,
90 void *event_info EINA_UNUSED)
91{
92 Efl_Ui_Win *win;
93 Efl_Ui_Table *table;
94 Efl_Ui_Box *bx;
95 Eina_Array *arr;
96 Efl_Ui_Button *o;
97 Efl_Ui_Radio *uk;
98
99 win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(),
100 efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_BASIC),
101 efl_text_set(efl_added, "Efl.Ui.Radio_Box"),
102 efl_ui_win_autodel_set(efl_added, EINA_TRUE));
103 table = efl_add(EFL_UI_TABLE_CLASS, win);
104 efl_content_set(win, table);
105
106 bx = efl_add(EFL_UI_RADIO_BOX_CLASS, table);
107 efl_pack_table(table, bx, 0, 0, 1, 3);
108 efl_event_callback_add(bx, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, _value_changed_cb, NULL);
109
110 arr = create_radios(win);
111 for (unsigned int i = 0; i < eina_array_count(arr); ++i)
112 {
113 Efl_Ui_Radio *r = eina_array_data_get(arr, i);
114 efl_pack_end(bx, r);
115 if (i == 4)
116 uk = r;
117 }
118
119 o = efl_add(EFL_UI_BUTTON_CLASS, table);
120 efl_pack_table(table, o, 1, 0, 1, 1);
121 efl_text_set(o, "Selected France check");
122 efl_event_callback_add(o, EFL_UI_EVENT_CLICKED, _select_btn_clicked, eina_array_data_get(arr, 2));
123
124 o = efl_add(EFL_UI_BUTTON_CLASS, table);
125 efl_pack_table(table, o, 1, 1, 1, 1);
126 efl_text_set(o, "Set value for Germany");
127 efl_event_callback_add(o, EFL_UI_EVENT_CLICKED, _set_selected_btn_clicked, bx);
128
129 o = efl_add(EFL_UI_BUTTON_CLASS, table);
130 efl_pack_table(table, o, 1, 2, 1, 1);
131 efl_text_set(o, "Set object for UK");
132 efl_key_data_set(o, "uk", uk);
133 efl_event_callback_add(o, EFL_UI_EVENT_CLICKED, _set_selected_object_btn_clicked, bx);
134
135 eina_array_free(arr);
136}
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 @@
1/*
2 * gcc -o efl_ui_radio_example_01 efl_ui_radio_example_01.c `pkg-config --cflags --libs elementary`
3 */
4#define EFL_BETA_API_SUPPORT 1
5
6#include <Efl_Ui.h>
7#include <Elementary.h>
8
9const char *example_strings[] = {
10 "Seoul",
11 "Karlsruhe",
12 "New York",
13 "Hong Kong",
14 "Hamburg",
15 "Berlin",
16 "Paris",
17 NULL
18};
19
20EAPI_MAIN void
21efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED)
22{
23 Eo *win, *box;
24
25 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
26
27 win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(),
28 efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_BASIC),
29 efl_text_set(efl_added, "Efl.Ui.Radio example"),
30 efl_ui_win_autodel_set(efl_added, EINA_TRUE)
31 );
32
33 box = efl_add(EFL_UI_RADIO_BOX_CLASS, win,
34 efl_content_set(win, efl_added));
35
36 for (int i = 0; example_strings[i]; ++i)
37 {
38 Eo *radio;
39
40 radio = efl_add(EFL_UI_RADIO_CLASS, box);
41 efl_text_set(radio, example_strings[i]);
42 efl_ui_radio_state_value_set(radio, i + 1);
43 efl_pack_end(box, radio);
44 }
45}
46EFL_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 = [
117 'efl_canvas_layout_text', 117 'efl_canvas_layout_text',
118 'efl_ui_theme_example_01', 118 'efl_ui_theme_example_01',
119 'efl_ui_theme_example_02', 119 'efl_ui_theme_example_02',
120 'efl_ui_slideshow_example' 120 'efl_ui_slideshow_example',
121 'efl_ui_radio_example_01',
121] 122]
122 123
123foreach example : examples 124foreach 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)
373 ELM_LAYOUT_TEXT_ALIASES_OPS(MY_CLASS_PFX) 373 ELM_LAYOUT_TEXT_ALIASES_OPS(MY_CLASS_PFX)
374 374
375#include "efl_ui_radio.eo.c" 375#include "efl_ui_radio.eo.c"
376#include "efl_ui_radio_group.eo.c"
376#include "efl_ui_radio_eo.legacy.c" 377#include "efl_ui_radio_eo.legacy.c"
377 378
378#include "efl_ui_radio_legacy_eo.h" 379#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
19 value: int; [[The value to use if this radio object is selected.]] 19 value: int; [[The value to use if this radio object is selected.]]
20 } 20 }
21 } 21 }
22 @property value_pointer {
23 set {
24 [[Set a convenience pointer to an integer, which changes when radio group
25 value changes.
26
27 This sets a pointer to an integer that in addition to the radio
28 object state will also be modified directly. To stop setting the
29 object pointed to, simply use NULL as the valuep argument. If
30 valuep is not NULL then when called, the radio object
31 state will also be modified to reflect the value of the integer
32 valuep points to, just like calling elm_radio_value_set().
33 ]]
34 }
35 values {
36 valuep: ptr(int); [[Pointer to the integer to modify]]
37 }
38 }
39 @property selected_object {
40 get {
41 [[Get the selected radio object.]]
42 return: Efl.Canvas.Object; [[The selected radio object]]
43 }
44 }
45 group_add {
46 [[Add this radio to a group of other radio objects
47
48 Radio objects work in groups. Each member should have a different
49 integer value assigned. In order to have them work as a group, they
50 need to know about each other. This adds the given radio object to
51 the group of which the group object indicated is a member.
52 ]]
53
54 params {
55 @in group: Efl.Ui.Radio; [[Any radio object whose group the obj is
56 to join.]]
57 }
58 }
59 @property group_value {
60 [[Change the value of the group.
61
62 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.
63 ]]
64 values {
65 value : int; [[The value of the radio button in the group which should be enabled.]]
66 }
67 }
68 } 22 }
69 implements { 23 implements {
70 Efl.Object.constructor; 24 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 @@
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_BOX_CLASS
9
10typedef struct {
11 Eina_Bool in_pack;
12 Efl_Ui_Radio_Group *group;
13} Efl_Ui_Radio_Box_Data;
14
15static inline Eina_Bool
16register_safe_in_group_begin(Eo *subobj, Efl_Ui_Radio_Box_Data *pd)
17{
18 EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(subobj, EFL_UI_RADIO_CLASS), EINA_FALSE);
19 if (!pd->in_pack)
20 efl_ui_radio_group_register(pd->group, subobj);
21 pd->in_pack = EINA_TRUE;
22
23 return EINA_TRUE;
24}
25
26static inline Eina_Bool
27register_safe_group_end(Eo *subobj, Efl_Ui_Radio_Box_Data *pd, Eina_Bool result)
28{
29 if (!result)
30 efl_ui_radio_group_unregister(pd->group, subobj);
31 pd->in_pack = EINA_FALSE;
32
33 return result;
34}
35
36#define REGISTER_SAFE(f) \
37 Eina_Bool result; \
38 if (!register_safe_in_group_begin(subobj, pd)) \
39 return EINA_FALSE; \
40 result = f ; \
41 return register_safe_group_end(subobj, pd, result);
42
43static void
44unpack_from_logical(Eo *obj, Efl_Ui_Radio_Box_Data *pd)
45{
46 int length = efl_content_count(obj);
47 for (int i = 0; i < length; ++i)
48 {
49 efl_ui_radio_group_unregister(pd->group, efl_pack_content_get(obj, i));
50 }
51}
52
53EOLIAN static Eina_Bool
54_efl_ui_radio_box_efl_pack_pack_clear(Eo *obj, Efl_Ui_Radio_Box_Data *pd)
55{
56 unpack_from_logical(obj, pd);
57 return efl_pack_clear(efl_super(obj, MY_CLASS));
58}
59
60EOLIAN static Eina_Bool
61_efl_ui_radio_box_efl_pack_unpack_all(Eo *obj, Efl_Ui_Radio_Box_Data *pd)
62{
63 unpack_from_logical(obj, pd);
64 return efl_pack_unpack_all(efl_super(obj, MY_CLASS));
65}
66
67EOLIAN static Eina_Bool
68_efl_ui_radio_box_efl_pack_unpack(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj)
69{
70 efl_ui_radio_group_unregister(pd->group, subobj);
71 return efl_pack_unpack(efl_super(obj, MY_CLASS), subobj);
72}
73
74EOLIAN static Efl_Gfx_Entity*
75_efl_ui_radio_box_efl_pack_linear_pack_unpack_at(Eo *obj, Efl_Ui_Radio_Box_Data *pd, int index)
76{
77 efl_ui_radio_group_unregister(pd->group, efl_pack_content_get(obj, index));
78 return efl_pack_unpack_at(efl_super(obj, MY_CLASS), index);
79}
80
81EOLIAN static Eina_Bool
82_efl_ui_radio_box_efl_pack_pack(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj)
83{
84 REGISTER_SAFE(efl_pack(efl_super(obj, MY_CLASS), subobj))
85}
86
87EOLIAN static Eina_Bool
88_efl_ui_radio_box_efl_pack_linear_pack_begin(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj)
89{
90 REGISTER_SAFE(efl_pack_begin(efl_super(obj, MY_CLASS), subobj))
91}
92
93EOLIAN static Eina_Bool
94_efl_ui_radio_box_efl_pack_linear_pack_end(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj)
95{
96 REGISTER_SAFE(efl_pack_end(efl_super(obj, MY_CLASS), subobj))
97}
98
99EOLIAN static Eina_Bool
100_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)
101{
102 REGISTER_SAFE(efl_pack_before(efl_super(obj, MY_CLASS), subobj, existing));
103}
104
105EOLIAN static Eina_Bool
106_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)
107{
108 REGISTER_SAFE(efl_pack_after(efl_super(obj, MY_CLASS), subobj, existing));
109}
110
111EOLIAN static Eina_Bool
112_efl_ui_radio_box_efl_pack_linear_pack_at(Eo *obj, Efl_Ui_Radio_Box_Data *pd, Efl_Gfx_Entity *subobj, int index)
113{
114 REGISTER_SAFE(efl_pack_at(efl_super(obj, MY_CLASS), subobj, index));
115}
116
117EOLIAN static Efl_Object*
118_efl_ui_radio_box_efl_object_constructor(Eo *obj, Efl_Ui_Radio_Box_Data *pd)
119{
120 pd->group = efl_new(EFL_UI_RADIO_GROUP_IMPL_CLASS, NULL);
121 efl_composite_attach(obj, pd->group);
122 efl_event_callback_forwarder_add(pd->group, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, obj);
123 return efl_constructor(efl_super(obj, MY_CLASS));
124}
125
126
127#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 @@
1class @beta Efl.Ui.Radio_Box extends Efl.Ui.Box implements Efl.Ui.Radio_Group
2{
3 methods {
4 }
5 implements {
6 Efl.Pack.pack_clear;
7 Efl.Pack.unpack_all;
8 Efl.Pack.unpack;
9 Efl.Pack.pack;
10 Efl.Pack_Linear.pack_begin;
11 Efl.Pack_Linear.pack_end;
12 Efl.Pack_Linear.pack_before;
13 Efl.Pack_Linear.pack_after;
14 Efl.Pack_Linear.pack_at;
15 Efl.Pack_Linear.pack_unpack_at;
16 Efl.Object.constructor;
17 }
18 composite {
19 Efl.Ui.Radio_Group;
20 }
21}
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 @@
1#define _EFL_UI_RADIO_EO_CLASS_TYPE
2typedef Eo Efl_Ui_Radio;
3
4#include "efl_ui_radio_group.eo.h"
5#include "efl_ui_radio_group_impl.eo.h"
1#include "efl_ui_radio.eo.h" 6#include "efl_ui_radio.eo.h"
7#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 @@
1interface @beta Efl.Ui.Radio_Group
2{
3 [[A object for organising a group of radio buttons
4
5 A group of radio buttons is a set of pair-wise different values. (Where values are the assosiated values of each radio button)
6 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.
7 ]]
8 methods {
9 @property selected_object {
10 [[Which object is currently selected in the group
11
12 $NULL if no object is selected.
13 ]]
14 values {
15 selected_object : Efl.Ui.Radio; [[The selected radio button in the group, $NULL for no object]]
16 }
17 }
18 @property selected_value {
19 [[Each group has a selected value, representing which radio group is selected.
20
21 A value of -1 here does represent that no button is selected.
22 Possible values here are only those that are assisiated with a registered radio button.
23 ]]
24 values {
25 selected_value : int; [[The value of the selection state]]
26 }
27 }
28 register {
29 [[Register a new radio button to this group.
30
31 The assosiated value of the radio button must not collide with any other assosiated value of registered buttons.
32 ]]
33 params {
34 radio : Efl.Ui.Radio; [[The radio button to regsiter]]
35 }
36 }
37 unregister {
38 [[Unregsiter a before registered button from this group.
39
40 if the button was selected before, no object will be selected afterwards.
41 ]]
42 params {
43 radio : Efl.Ui.Radio; [[The radio button to unregister]]
44 }
45 }
46 }
47 events {
48 value,changed : int; [[Emitted each time the $selected_value has changed.]]
49 }
50}
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 @@
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
10static Eina_Hash *radio_group_map;
11
12typedef struct {
13 Efl_Ui_Radio *selected;
14 Eina_List *registered_set;
15} Efl_Ui_Radio_Group_Impl_Data;
16
17EOLIAN static void
18_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)
19{
20 int new_value = -1;
21 Eo *old_selected;
22
23 if (pd->selected == selected_object) return;
24
25 old_selected = pd->selected;
26 pd->selected = selected_object;
27
28 //it is essential to *first* set pd->selected to the new state before calling this
29 //otherwise this here will be called again, and the event will get emitted twice
30 if (old_selected && efl_alive_get(old_selected))
31 efl_ui_check_selected_set(old_selected, EINA_FALSE);
32
33 if (pd->selected)
34 {
35 efl_ui_check_selected_set(pd->selected, EINA_TRUE);
36 new_value = efl_ui_radio_state_value_get(pd->selected);
37 }
38 efl_event_callback_call(obj, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, &new_value);
39}
40
41EOLIAN static Efl_Ui_Radio*
42_efl_ui_radio_group_impl_efl_ui_radio_group_selected_object_get(const Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd)
43{
44 return pd->selected;
45}
46
47EOLIAN static void
48_efl_ui_radio_group_impl_efl_ui_radio_group_selected_value_set(Eo *obj, Efl_Ui_Radio_Group_Impl_Data *pd, int selected_value)
49{
50 Efl_Ui_Radio *reged;
51 Eina_List *n;
52
53 EINA_LIST_FOREACH(pd->registered_set, n, reged)
54 {
55 if (efl_ui_radio_state_value_get(reged) == selected_value)
56 {
57 efl_ui_radio_group_selected_object_set(obj, reged);
58 return;
59 }
60 }
61 ERR("Value %d not assosiated with any radio button", selected_value);
62}
63
64EOLIAN static int
65_efl_ui_radio_group_impl_efl_ui_radio_group_selected_value_get(const Eo *obj EINA_UNUSED, Efl_Ui_Radio_Group_Impl_Data *pd)
66{
67 return pd->selected ? efl_ui_radio_state_value_get(pd->selected) : -1;
68}
69
70static void
71_selected_cb(void *data, const Efl_Event *ev)
72{
73 if (efl_ui_check_selected_get(ev->object))
74 {
75 efl_ui_radio_group_selected_object_set(data, ev->object);
76 }
77 else
78 {
79 //if something was unselected, we need to make sure that we are unsetting the internal pointer to NULL
80 if (efl_ui_radio_group_selected_object_get(data) == ev->object)
81 {
82 efl_ui_radio_group_selected_object_set(data, NULL);
83 }
84 }
85}
86
87static void
88_invalidate_cb(void *data, const Efl_Event *ev)
89{
90 efl_ui_radio_group_unregister(data, ev->object);
91}
92
93EFL_CALLBACKS_ARRAY_DEFINE(radio_btn_cb,
94 {EFL_UI_CHECK_EVENT_SELECTED_CHANGED, _selected_cb},
95 {EFL_EVENT_INVALIDATE, _invalidate_cb},
96)
97
98EOLIAN static void
99_efl_ui_radio_group_impl_efl_ui_radio_group_register(Eo *obj, Efl_Ui_Radio_Group_Impl_Data *pd, Efl_Ui_Radio *radio)
100{
101 Efl_Ui_Radio *reged;
102 Eina_List *n;
103
104 if (eina_hash_find(radio_group_map, &radio))
105 {
106 ERR("Radio button %p is already part of another group", radio);
107 return;
108 }
109
110 EINA_LIST_FOREACH(pd->registered_set, n, reged)
111 {
112 EINA_SAFETY_ON_TRUE_RETURN(radio == reged);
113 EINA_SAFETY_ON_TRUE_RETURN(efl_ui_radio_state_value_get(radio) == efl_ui_radio_state_value_get(reged));
114 }
115 EINA_SAFETY_ON_TRUE_RETURN(efl_ui_radio_state_value_get(radio) == -1);
116
117 pd->registered_set = eina_list_append(pd->registered_set, radio);
118 eina_hash_add(radio_group_map, &radio, obj);
119 efl_event_callback_array_add(radio, radio_btn_cb(), obj);
120}
121
122EOLIAN static void
123_efl_ui_radio_group_impl_efl_ui_radio_group_unregister(Eo *obj, Efl_Ui_Radio_Group_Impl_Data *pd, Efl_Ui_Radio *radio)
124{
125 if (pd->selected == radio)
126 efl_ui_radio_group_selected_object_set(obj, NULL);
127
128 efl_event_callback_array_del(radio, radio_btn_cb(), obj);
129 pd->registered_set = eina_list_remove(pd->registered_set, radio);
130 eina_hash_del(radio_group_map, &radio, obj);
131}
132
133EOLIAN static void
134_efl_ui_radio_group_impl_efl_object_destructor(Eo *obj, Efl_Ui_Radio_Group_Impl_Data *pd)
135{
136 Eo *radio;
137
138 EINA_LIST_FREE(pd->registered_set, radio)
139 {
140 efl_event_callback_array_del(radio, radio_btn_cb(), obj);
141 eina_hash_del(radio_group_map, &radio, obj);
142 }
143 efl_destructor(efl_super(obj, MY_CLASS));
144}
145
146void
147_efl_ui_radio_group_impl_class_constructor(Efl_Class *klass EINA_UNUSED)
148{
149 radio_group_map = eina_hash_pointer_new(NULL);
150}
151
152#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 @@
1class @beta Efl.Ui.Radio_Group_Impl extends Efl.Object implements Efl.Ui.Radio_Group
2{
3 implements {
4 class.constructor;
5 Efl.Object.destructor;
6 Efl.Ui.Radio_Group.selected_object {get; set;}
7 Efl.Ui.Radio_Group.selected_value {get; set;}
8 Efl.Ui.Radio_Group.register;
9 Efl.Ui.Radio_Group.unregister;
10 }
11}
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 = [
57 'efl_ui_panes.eo', 57 'efl_ui_panes.eo',
58 'efl_ui_progressbar.eo', 58 'efl_ui_progressbar.eo',
59 'efl_ui_radio.eo', 59 'efl_ui_radio.eo',
60 'efl_ui_radio_group.eo',
61 'efl_ui_radio_box.eo',
62 'efl_ui_radio_group_impl.eo',
60 'efl_ui_slider.eo', 63 'efl_ui_slider.eo',
61 'efl_ui_slider_interval.eo', 64 'efl_ui_slider_interval.eo',
62 'efl_ui_spin.eo', 65 'efl_ui_spin.eo',
@@ -813,6 +816,8 @@ elementary_src = [
813 'elm_prefs_data.c', 816 'elm_prefs_data.c',
814 'efl_ui_progressbar.c', 817 'efl_ui_progressbar.c',
815 'efl_ui_radio.c', 818 'efl_ui_radio.c',
819 'efl_ui_radio_group_impl.c',
820 'efl_ui_radio_box.c',
816 'elm_route.c', 821 'elm_route.c',
817 'elm_scroller.c', 822 'elm_scroller.c',
818 'elm_segment_control.c', 823 '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[] = {
27 { "efl_ui_widget", efl_ui_test_widget }, 27 { "efl_ui_widget", efl_ui_test_widget },
28 { "efl_ui_active_view", efl_ui_test_active_view}, 28 { "efl_ui_active_view", efl_ui_test_active_view},
29 { "efl_ui_check", efl_ui_test_check }, 29 { "efl_ui_check", efl_ui_test_check },
30 { "efl_ui_radio_group", efl_ui_test_radio_group },
30 { NULL, NULL } 31 { NULL, NULL }
31}; 32};
32 33
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);
36void efl_ui_test_widget(TCase *tc); 36void efl_ui_test_widget(TCase *tc);
37void efl_ui_test_active_view(TCase *tc); 37void efl_ui_test_active_view(TCase *tc);
38void efl_ui_test_check(TCase *tc); 38void efl_ui_test_check(TCase *tc);
39void efl_ui_test_radio_group(TCase *tc);
39 40
40void loop_timer_interval_set(Eo *obj, double in); 41void loop_timer_interval_set(Eo *obj, double in);
41 42
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 @@
1#ifdef HAVE_CONFIG_H
2# include "elementary_config.h"
3#endif
4
5#include <Efl_Ui.h>
6#include "efl_ui_suite.h"
7#include "suite_helpers.h"
8
9static Eo *win, *radio_group;
10
11int state_values = 0;
12
13typedef struct {
14 int called;
15 int value;
16} Group_Changed_Called;
17
18Group_Changed_Called changed_evt;
19
20#define RESET_EVT \
21 changed_evt.called = 0; \
22 changed_evt.value = 200000000;
23
24#define EXPECT_EVT(c, v) \
25 ck_assert_int_eq(changed_evt.called, c); \
26 ck_assert_int_eq(changed_evt.value, v);
27
28static void
29_group_value_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev)
30{
31 changed_evt.called ++;
32 changed_evt.value = *((int*)ev->info);
33}
34
35static void
36check_setup()
37{
38 win = win_add();
39 radio_group = efl_new(EFL_UI_RADIO_GROUP_IMPL_CLASS, NULL);
40 efl_event_callback_add(radio_group, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, _group_value_changed_cb, NULL);
41}
42
43static void
44check_teardown()
45{
46 efl_unref(radio_group);
47 if (win)
48 {
49 efl_del(win);
50 win = NULL;
51 }
52}
53
54static Eo*
55radio(void)
56{
57 state_values += 1;
58 return efl_add(EFL_UI_RADIO_CLASS, win, efl_ui_radio_state_value_set(efl_added, state_values));
59}
60
61EFL_START_TEST(active_selected_value_setting)
62{
63 Eo *r1 = radio();
64 Eo *r2 = radio();
65
66 efl_ui_radio_group_register(radio_group, radio());
67 efl_ui_radio_group_register(radio_group, radio());
68 efl_ui_radio_group_register(radio_group, r1);
69 efl_ui_radio_group_register(radio_group, r2);
70
71 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1);
72 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL);
73
74 RESET_EVT
75 efl_ui_radio_group_selected_value_set(radio_group, 1);
76 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1);
77 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r1);
78 ck_assert_int_eq(efl_ui_check_selected_get(r1), EINA_TRUE);
79 ck_assert_int_eq(efl_ui_check_selected_get(r2), EINA_FALSE);
80 EXPECT_EVT(1,1);
81
82 RESET_EVT
83 efl_ui_radio_group_selected_object_set(radio_group, r2);
84 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 2);
85 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r2);
86 ck_assert_int_eq(efl_ui_check_selected_get(r1), EINA_FALSE);
87 ck_assert_int_eq(efl_ui_check_selected_get(r2), EINA_TRUE);
88 EXPECT_EVT(1,2);
89}
90EFL_END_TEST
91
92EFL_START_TEST(active_selection_setting)
93{
94 Eo *r1 = radio();
95 Eo *r2 = radio();
96
97 efl_ui_radio_group_register(radio_group, radio());
98 efl_ui_radio_group_register(radio_group, radio());
99 efl_ui_radio_group_register(radio_group, r1);
100 efl_ui_radio_group_register(radio_group, r2);
101
102 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1);
103 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL);
104
105 RESET_EVT
106 efl_ui_radio_group_selected_object_set(radio_group, r1);
107 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1);
108 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r1);
109 ck_assert_int_eq(efl_ui_check_selected_get(r1), EINA_TRUE);
110 ck_assert_int_eq(efl_ui_check_selected_get(r2), EINA_FALSE);
111 EXPECT_EVT(1,1);
112
113 RESET_EVT
114 efl_ui_radio_group_selected_object_set(radio_group, r2);
115 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 2);
116 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r2);
117 ck_assert_int_eq(efl_ui_check_selected_get(r1), EINA_FALSE);
118 ck_assert_int_eq(efl_ui_check_selected_get(r2), EINA_TRUE);
119 EXPECT_EVT(1,2);
120}
121EFL_END_TEST
122
123EFL_START_TEST(active_selection_object_setting)
124{
125 Eo *r = radio();
126 efl_ui_radio_group_register(radio_group, radio());
127 efl_ui_radio_group_register(radio_group, radio());
128 efl_ui_radio_group_register(radio_group, r);
129 efl_ui_radio_group_register(radio_group, radio());
130
131 RESET_EVT
132 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1);
133 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL);
134 efl_ui_check_selected_set(r, EINA_TRUE);
135 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1);
136 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r);
137 EXPECT_EVT(1,1);
138}
139EFL_END_TEST
140
141EFL_START_TEST(unregister_setted)
142{
143 Eo *r = radio();
144 efl_ui_radio_group_register(radio_group, radio());
145 efl_ui_radio_group_register(radio_group, radio());
146 efl_ui_radio_group_register(radio_group, r);
147 efl_ui_radio_group_register(radio_group, radio());
148
149 RESET_EVT
150 efl_ui_radio_group_selected_object_set(radio_group, r);
151 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1);
152 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r);
153 EXPECT_EVT(1,1);
154 RESET_EVT
155 efl_ui_radio_group_unregister(radio_group, r);
156 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1);
157 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL);
158 EXPECT_EVT(1,-1);
159}
160EFL_END_TEST
161
162EFL_START_TEST(delete_setted)
163{
164 Eo *r = radio();
165 efl_ui_radio_group_register(radio_group, radio());
166 efl_ui_radio_group_register(radio_group, radio());
167 efl_ui_radio_group_register(radio_group, r);
168 efl_ui_radio_group_register(radio_group, radio());
169 RESET_EVT
170 efl_ui_radio_group_selected_object_set(radio_group, r);
171 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1);
172 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r);
173 EXPECT_EVT(1,1);
174 RESET_EVT
175 efl_del(r);
176 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1);
177 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL);
178 EXPECT_EVT(1,-1);
179}
180EFL_END_TEST
181
182EFL_START_TEST(external_setting)
183{
184 Eo *r = radio();
185 efl_ui_radio_group_register(radio_group, radio());
186 efl_ui_radio_group_register(radio_group, radio());
187 efl_ui_radio_group_register(radio_group, r);
188 efl_ui_radio_group_register(radio_group, radio());
189 RESET_EVT
190 efl_ui_check_selected_set(r, EINA_TRUE);
191 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), 1);
192 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), r);
193 EXPECT_EVT(1,1);
194 RESET_EVT
195 efl_ui_check_selected_set(r, EINA_FALSE);
196 ck_assert_int_eq(efl_ui_radio_group_selected_value_get(radio_group), -1);
197 ck_assert_ptr_eq(efl_ui_radio_group_selected_object_get(radio_group), NULL);
198 EXPECT_EVT(1,-1);
199}
200EFL_END_TEST
201
202EFL_START_TEST(pairwise_different_error)
203{
204 Eo *r = radio();
205 Eo *r1 = radio();
206 Eo *r2 = radio();
207 efl_ui_radio_state_value_set(r, -1);
208 efl_ui_radio_state_value_set(r1, 14);
209 efl_ui_radio_state_value_set(r2, 14);
210 EXPECT_ERROR_START;
211 efl_ui_radio_group_register(radio_group, r);
212 EXPECT_ERROR_END;
213 efl_ui_radio_group_register(radio_group, r1);
214 EXPECT_ERROR_START;
215 efl_ui_radio_group_register(radio_group, r2);
216 EXPECT_ERROR_END;
217}
218EFL_END_TEST
219
220EFL_START_TEST(group_double_registeration)
221{
222 Eo *r = radio();
223 efl_ui_radio_group_register(radio_group, r);
224 EXPECT_ERROR_START;
225 efl_ui_radio_group_register(radio_group, r);
226 EXPECT_ERROR_END;
227}
228EFL_END_TEST
229
230EFL_START_TEST(group_registeration_in_two_groups)
231{
232 Eo *radio_group2 = efl_new(EFL_UI_RADIO_GROUP_IMPL_CLASS, NULL);
233 Eo *r = radio();
234 efl_ui_radio_group_register(radio_group, r);
235 EXPECT_ERROR_START;
236 efl_ui_radio_group_register(radio_group2, r);
237 EXPECT_ERROR_END;
238}
239EFL_END_TEST
240
241EFL_START_TEST(group_invalid_value)
242{
243 Eo *radio_group2 = efl_new(EFL_UI_RADIO_GROUP_IMPL_CLASS, NULL);
244 Eo *r = radio();
245 efl_ui_radio_group_register(radio_group, r);
246 EXPECT_ERROR_START;
247 efl_ui_radio_group_selected_value_set(radio_group2, 1000);
248 EXPECT_ERROR_END;
249}
250EFL_END_TEST
251
252void efl_ui_test_radio_group(TCase *tc)
253{
254 tcase_add_checked_fixture(tc, fail_on_errors_setup, fail_on_errors_teardown);
255 tcase_add_checked_fixture(tc, check_setup, check_teardown);
256 tcase_add_test(tc, active_selected_value_setting);
257 tcase_add_test(tc, active_selection_setting);
258 tcase_add_test(tc, active_selection_object_setting);
259 tcase_add_test(tc, pairwise_different_error);
260 tcase_add_test(tc, group_double_registeration);
261 tcase_add_test(tc, group_registeration_in_two_groups);
262 tcase_add_test(tc, unregister_setted);
263 tcase_add_test(tc, external_setting);
264 tcase_add_test(tc, delete_setted);
265 tcase_add_test(tc, group_invalid_value);
266}
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 = [
140 'efl_ui_test_widget.c', 140 'efl_ui_test_widget.c',
141 'efl_ui_test_active_view.c', 141 'efl_ui_test_active_view.c',
142 'efl_ui_test_check.c', 142 'efl_ui_test_check.c',
143 'efl_ui_test_radio_group.c',
143] 144]
144 145
145efl_ui_suite = executable('efl_ui_suite', 146efl_ui_suite = executable('efl_ui_suite',