From 0a9ac756d029b524f0cc5ac2b0f6ac5627e6ed47 Mon Sep 17 00:00:00 2001 From: Shobhit Date: Fri, 17 Apr 2015 17:11:28 +0900 Subject: [PATCH] checkbox: Adding third state (Indeterminate) support in checkbox Summary: Checkbox should support a third state "indeterminate" along with "Checked" and "Unchecked" This third state is a state of checkbox which is shown when checkbox is neither Checked nor Unchecked. - Added this new feature on the basis of a boolean variable's value. - By default this boolean variable is disabled and checkbox will treat like old way. - While adding this, I kept in mind, that applications which are already using checkbox, should not be affected, so I used 0=False=Unchecked, 1=True=Checked, and 2=Indeterminate - Also added an example check_example_o2.c, which is using checkbox with both ways, using boolean, and using enum. - Now also values can be set using boolean values, but it will give a type casting warning. As a boolean doen't support third state, so I used an enum int like. - Added APIs to enable disable third state mode. elm_check_three_state_mode_set(check_obj, bool_val), and elm_check_three_state_mode_get(check_obj) - Modified old APIs which were setting or getting states of checkbox. - Added a state in theme of checkbox, with third state image. Reviewers: seoz, raster, Sergeant_Whitespace, Hermet Subscribers: Hermet, Sergeant_Whitespace, sachin.dev Differential Revision: https://phab.enlightenment.org/D2249 --- legacy/elementary/data/themes/Makefile.am | 1 + legacy/elementary/data/themes/edc/elm/check.edc | 11 ++ .../data/themes/img/sym_check_indeterminate.png | Bin 0 -> 203 bytes legacy/elementary/src/examples/check_example_02.c | 111 ++++++++++++++ legacy/elementary/src/lib/elm_check.c | 169 +++++++++++++++++---- legacy/elementary/src/lib/elm_check.eo | 40 ++++- .../src/lib/elm_interface_atspi_accessible.h | 2 +- legacy/elementary/src/lib/elm_widget_check.h | 5 +- 8 files changed, 297 insertions(+), 42 deletions(-) create mode 100755 legacy/elementary/data/themes/img/sym_check_indeterminate.png create mode 100644 legacy/elementary/src/examples/check_example_02.c diff --git a/legacy/elementary/data/themes/Makefile.am b/legacy/elementary/data/themes/Makefile.am index 8237c67..64a1375 100644 --- a/legacy/elementary/data/themes/Makefile.am +++ b/legacy/elementary/data/themes/Makefile.am @@ -586,6 +586,7 @@ img/split_v_glow.png \ img/split_v_hilight.png \ img/split_v_inset.png \ img/sym_check_alum.png \ +img/sym_check_indeterminate.png \ img/sym_close_dark_normal.png \ img/sym_close_dark_selected.png \ img/sym_close_light_normal.png \ diff --git a/legacy/elementary/data/themes/edc/elm/check.edc b/legacy/elementary/data/themes/edc/elm/check.edc index 431cdc7..9b3068e 100644 --- a/legacy/elementary/data/themes/edc/elm/check.edc +++ b/legacy/elementary/data/themes/edc/elm/check.edc @@ -2,6 +2,7 @@ group { name: "elm/check/base/default"; images.image: "inset_shadow_tiny.png" COMP; images.image: "bevel_in.png" COMP; images.image: "sym_check_alum.png" COMP; + images.image: "sym_check_indeterminate.png" COMP; #define ICON 1 #define LABEL 2 #define MASK 3 @@ -144,6 +145,11 @@ group { name: "elm/check/base/default"; inherit: "default" 0.0; visible: 1; } + description { state: "mixed" 0.0; + inherit: "default" 0.0; + image.normal: "sym_check_indeterminate.png"; + visible: 1; + } } part { name: "clip"; type: RECT; description { state: "default" 0.0; @@ -270,6 +276,11 @@ group { name: "elm/check/base/default"; target: "indicator"; } program { + signal: "elm,state,check,indeterminate"; source: "elm"; + action: STATE_SET "mixed" 0.0; + target: "indicator"; + } + program { signal: "elm,state,text,visible"; source: "elm"; script { new m = get_int(btmode); diff --git a/legacy/elementary/data/themes/img/sym_check_indeterminate.png b/legacy/elementary/data/themes/img/sym_check_indeterminate.png new file mode 100755 index 0000000000000000000000000000000000000000..3b2c0eac9799425152aa71ca27ac20b6a8d0c6de GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhY)RhkExxkW7 zf4yT}r}9k*acqrF7N`l=lfAR##DTKIMt^!bJk0mLT=&DF;o7b09>MU{Tk9sIX)JwX q`Fuy!yS@1ZX*v~knvowrwaa7(ngvWVTk;HO2ZN`ppUXO@geCyl<3h{; literal 0 HcmV?d00001 diff --git a/legacy/elementary/src/examples/check_example_02.c b/legacy/elementary/src/examples/check_example_02.c new file mode 100644 index 0000000..6aa0a1c --- /dev/null +++ b/legacy/elementary/src/examples/check_example_02.c @@ -0,0 +1,111 @@ +//Compile with: +//gcc -o check_example_02 check_example_02.c -g `pkg-config --cflags --libs elementary` && ./check_example_02 + +#include + +Evas_Object *cb, *cb1, *cb2, *cb3; + +static void +_print(void *data, Evas_Object *obj, void *event_info) +{ + if (!elm_check_three_state_mode_get(cb)) + { + printf("check0 %smarked\n", *((Eina_Bool*)data) ? "" : "un"); + } + else + { + printf("check0 elm_check_state_get() value is %d (%s)\n", elm_check_state_get(cb), *((Eina_Bool*)data) ? "EINA_TRUE" : "EINA_FALSE"); + } +} + +static void +_print1(void *data, Evas_Object *obj, void *event_info) +{ + Check_State st = elm_check_state_get(cb1); + if (st == _CHECK_STATE_CHECKED) + printf("check1 elm_check_state_get() value is %d (%s)\n", st, "_CHECK_STATE_CHECKED"); + else if (st == _CHECK_STATE_INDETERMINATE) + printf("check1 elm_check_state_get() value is %d (%s)\n", st, "_CHECK_STATE_INDETERMINATE"); + else + printf("check1 elm_check_state_get() value is %d (%s)\n", st, "_CHECK_STATE_UNCHECKED"); +} + +static void +_print2(void *data, Evas_Object *obj, void *event_info) +{ + printf("Currently three state mode is: %s\n", elm_check_three_state_mode_get(cb) ? "On" : "Off"); + elm_check_three_state_mode_set(cb, elm_check_state_get(cb2)); + elm_check_three_state_mode_set(cb1, elm_check_state_get(cb2)); + printf("Three state mode is changed to: %s\n", elm_check_three_state_mode_get(cb) ? "On" : "Off"); +} + +static void +_print3(void *data, Evas_Object *obj, void *event_info) +{ + elm_object_disabled_set(cb, elm_check_state_get(cb3)); + elm_object_disabled_set(cb1, elm_check_state_get(cb3)); + printf("Checkbox disable mode is : %s\n", elm_check_state_get(cb3) ? "Enabled" : "Disabled"); +} + +EAPI_MAIN int +elm_main(int argc, char **argv) +{ + Evas_Object *win, *icon; + Eina_Bool value, *value2, *value3; + Check_State *value1; + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + + win = elm_win_util_standard_add("check", "Check"); + elm_win_autodel_set(win, EINA_TRUE); + + cb = elm_check_add(win); + elm_object_text_set(cb, "check0 using bool"); + elm_check_state_pointer_set(cb, &value); + elm_check_state_set(cb, EINA_FALSE); + evas_object_smart_callback_add(cb, "changed", _print, &value); + evas_object_move(cb, 10, 10); + evas_object_resize(cb, 250, 30); + evas_object_show(cb); + + cb1 = elm_check_add(win); + elm_object_text_set(cb1, "check1 using enum"); + elm_check_state_pointer_set(cb1, (Check_State *)&value1); + elm_check_state_set(cb1, (Check_State)_CHECK_STATE_CHECKED); + evas_object_smart_callback_add(cb1, "changed", _print1, &value1); + evas_object_move(cb1, 10, 50); + evas_object_resize(cb1, 250, 30); + evas_object_show(cb1); + + icon = evas_object_rectangle_add(evas_object_evas_get(win)); + evas_object_color_set(icon, 0, 255, 0, 255); + evas_object_resize(icon, 20, 20); + evas_object_show(icon); + + cb2 = elm_check_add(win); + elm_object_text_set(cb2, "Enable three state mode in above checkboxes"); + elm_check_state_pointer_set(cb2, (Check_State *)&value2); + elm_check_state_set(cb2, (Check_State)_CHECK_STATE_UNCHECKED); + evas_object_smart_callback_add(cb2, "changed", _print2, &value2); + elm_object_part_content_set(cb2, "icon", icon); + evas_object_move(cb2, 10, 90); + evas_object_resize(cb2, 250, 30); + evas_object_show(cb2); + + cb3 = elm_check_add(win); + elm_object_text_set(cb3, "Enable/Disable checkboxes"); + elm_check_state_pointer_set(cb3, (Check_State *)&value3); + elm_check_state_set(cb3, (Check_State)_CHECK_STATE_UNCHECKED); + evas_object_smart_callback_add(cb3, "changed", _print3, &value3); + evas_object_move(cb3, 10, 130); + evas_object_resize(cb3, 250, 30); + evas_object_show(cb3); + + evas_object_resize(win, 200, 190); + evas_object_show(win); + + elm_run(); + + return 0; +} +ELM_MAIN() diff --git a/legacy/elementary/src/lib/elm_check.c b/legacy/elementary/src/lib/elm_check.c index 27f38d0..a7bbfb5 100644 --- a/legacy/elementary/src/lib/elm_check.c +++ b/legacy/elementary/src/lib/elm_check.c @@ -53,19 +53,57 @@ _activate(Evas_Object *obj) { ELM_CHECK_DATA_GET(obj, sd); - sd->state = !sd->state; + if (!sd->three_state_mode) + { + sd->state = !sd->state; + } + else + { + if (sd->state == _CHECK_STATE_UNCHECKED) + sd->state = _CHECK_STATE_CHECKED; + else if (sd->state == _CHECK_STATE_CHECKED) + sd->state = _CHECK_STATE_INDETERMINATE; + else + sd->state = _CHECK_STATE_UNCHECKED; + } + if (sd->statep) *sd->statep = sd->state; - if (sd->state) + + if (!sd->three_state_mode) { - elm_layout_signal_emit(obj, "elm,state,check,on", "elm"); - if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF) - _elm_access_say(E_("State: On")); + if (sd->state) + { + elm_layout_signal_emit(obj, "elm,state,check,on", "elm"); + if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF) + _elm_access_say(E_("State: On")); + } + else + { + elm_layout_signal_emit(obj, "elm,state,check,off", "elm"); + if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF) + _elm_access_say(E_("State: Off")); + } } else { - elm_layout_signal_emit(obj, "elm,state,check,off", "elm"); - if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF) - _elm_access_say(E_("State: Off")); + if (sd->state == _CHECK_STATE_CHECKED) + { + elm_layout_signal_emit(obj, "elm,state,check,on", "elm"); + if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF) + _elm_access_say(E_("State: On")); + } + else if (sd->state == _CHECK_STATE_UNCHECKED) + { + elm_layout_signal_emit(obj, "elm,state,check,off", "elm"); + if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF) + _elm_access_say(E_("State: Off")); + } + else + { + elm_layout_signal_emit(obj, "elm,state,check,indeterminate", "elm"); + if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF) + _elm_access_say(E_("State: Indeterminate")); + } } evas_object_smart_callback_call(obj, SIG_CHANGED, NULL); @@ -99,8 +137,10 @@ _elm_check_elm_interface_atspi_accessible_state_set_get(Eo *obj, Elm_Check_Data eo_do_super(obj, ELM_CHECK_CLASS, states = elm_interface_atspi_accessible_state_set_get()); - if (elm_check_state_get(obj)) - STATE_TYPE_SET(states, ELM_ATSPI_STATE_CHECKED); + if (elm_check_state_get(obj) == _CHECK_STATE_CHECKED) + STATE_TYPE_SET(states, ELM_ATSPI_STATE_CHECKED); + else if (elm_check_state_get(obj) == _CHECK_STATE_INDETERMINATE) + STATE_TYPE_SET(states, ELM_ATSPI_STATE_INDETERMINATE); return states; } @@ -198,8 +238,9 @@ _elm_check_elm_widget_theme_apply(Eo *obj, Elm_Check_Data *sd) eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_theme_apply()); if (!int_ret) return EINA_FALSE; - if (!sd->state) elm_layout_signal_emit(obj, "elm,state,check,off", "elm"); - else elm_layout_signal_emit(obj, "elm,state,check,on", "elm"); + if (sd->state == _CHECK_STATE_UNCHECKED) elm_layout_signal_emit(obj, "elm,state,check,off", "elm"); + else if (sd->state == _CHECK_STATE_CHECKED) elm_layout_signal_emit(obj, "elm,state,check,on", "elm"); + else elm_layout_signal_emit(obj, "elm,state,check,indeterminate", "elm"); edje_object_message_signal_process(wd->resize_obj); @@ -228,11 +269,11 @@ static char * _access_state_cb(void *data, Evas_Object *obj) { Elm_Check_Data *sd = eo_data_scope_get(data, MY_CLASS); - const char *on_text, *off_text; + const char *on_text, *off_text, *indeterminate_text; if (elm_widget_disabled_get(obj)) return strdup(E_("State: Disabled")); - if (sd->state) + if (sd->state == _CHECK_STATE_CHECKED) { on_text = elm_layout_text_get(data, "on"); @@ -246,17 +287,30 @@ _access_state_cb(void *data, Evas_Object *obj) else return strdup(E_("State: On")); } + else if (sd->state == _CHECK_STATE_UNCHECKED) + { + off_text = elm_layout_text_get(data, "off"); - off_text = elm_layout_text_get(data, "off"); - - if (off_text) + if (off_text) + { + char buf[1024]; + snprintf(buf, sizeof(buf), "%s: %s", E_("State"), off_text); + return strdup(buf); + } + return strdup(E_("State: Off")); + } + else { - char buf[1024]; + indeterminate_text = elm_layout_text_get(data, "indeterminate"); - snprintf(buf, sizeof(buf), "%s: %s", E_("State"), off_text); - return strdup(buf); + if (indeterminate_text) + { + char buf[1024]; + snprintf(buf, sizeof(buf), "%s: %s", E_("State"), indeterminate_text); + return strdup(buf); + } + return strdup(E_("State: indeterminate")); } - return strdup(E_("State: Off")); } static void @@ -269,7 +323,7 @@ _on_check_off(void *data, ELM_CHECK_DATA_GET(obj, sd); - sd->state = EINA_FALSE; + sd->state = _CHECK_STATE_UNCHECKED; if (sd->statep) *sd->statep = sd->state; elm_layout_signal_emit(obj, "elm,state,check,off", "elm"); @@ -291,15 +345,36 @@ _on_check_on(void *data, ELM_CHECK_DATA_GET(obj, sd); - sd->state = EINA_TRUE; + sd->state = _CHECK_STATE_CHECKED; if (sd->statep) *sd->statep = sd->state; elm_layout_signal_emit(obj, "elm,state,check,on", "elm"); evas_object_smart_callback_call(data, SIG_CHANGED, NULL); if (_elm_config->atspi_mode) - elm_interface_atspi_accessible_state_changed_signal_emit(data, - ELM_ATSPI_STATE_CHECKED, - sd->state); + elm_interface_atspi_accessible_state_changed_signal_emit(data, + ELM_ATSPI_STATE_CHECKED, + sd->state); +} + +static void +_on_check_indeterminate(void *data, + Evas_Object *o EINA_UNUSED, + const char *emission EINA_UNUSED, + const char *source EINA_UNUSED) +{ + Evas_Object *obj = data; + + ELM_CHECK_DATA_GET(obj, sd); + + sd->state = _CHECK_STATE_INDETERMINATE; + if (sd->statep) *sd->statep = sd->state; + elm_layout_signal_emit(obj, "elm,state,check,indeterminate", "elm"); + evas_object_smart_callback_call(data, SIG_CHANGED, NULL); + + if (_elm_config->atspi_mode) + elm_interface_atspi_accessible_state_changed_signal_emit(data, + ELM_ATSPI_STATE_CHECKED, + sd->state); } static void @@ -326,6 +401,9 @@ _elm_check_evas_object_smart_add(Eo *obj, Elm_Check_Data *_pd EINA_UNUSED) (wd->resize_obj, "elm,action,check,off", "*", _on_check_off, obj); edje_object_signal_callback_add + (wd->resize_obj, "elm,action,check,indeterminate", "*", + _on_check_indeterminate, obj); + edje_object_signal_callback_add (wd->resize_obj, "elm,action,check,toggle", "*", _on_check_toggle, obj); @@ -376,7 +454,7 @@ _elm_check_eo_base_constructor(Eo *obj, Elm_Check_Data *_pd EINA_UNUSED) } EOLIAN static void -_elm_check_state_set(Eo *obj, Elm_Check_Data *sd, Eina_Bool state) +_elm_check_state_set(Eo *obj, Elm_Check_Data *sd, Check_State state) { ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); @@ -384,23 +462,25 @@ _elm_check_state_set(Eo *obj, Elm_Check_Data *sd, Eina_Bool state) { sd->state = state; if (sd->statep) *sd->statep = sd->state; - if (sd->state) + if (sd->state == _CHECK_STATE_UNCHECKED) + elm_layout_signal_emit(obj, "elm,state,check,off", "elm"); + else if ((sd->state == _CHECK_STATE_CHECKED) || (!sd->three_state_mode)) elm_layout_signal_emit(obj, "elm,state,check,on", "elm"); else - elm_layout_signal_emit(obj, "elm,state,check,off", "elm"); + elm_layout_signal_emit(obj, "elm,state,check,indeterminate", "elm"); } edje_object_message_signal_process(wd->resize_obj); } -EOLIAN static Eina_Bool +EOLIAN static Check_State _elm_check_state_get(Eo *obj EINA_UNUSED, Elm_Check_Data *sd) { return sd->state; } EOLIAN static void -_elm_check_state_pointer_set(Eo *obj, Elm_Check_Data *sd, Eina_Bool *statep) +_elm_check_state_pointer_set(Eo *obj, Elm_Check_Data *sd, Check_State *statep) { if (statep) { @@ -408,16 +488,39 @@ _elm_check_state_pointer_set(Eo *obj, Elm_Check_Data *sd, Eina_Bool *statep) if (*sd->statep != sd->state) { sd->state = *sd->statep; - if (sd->state) + if (sd->state == _CHECK_STATE_CHECKED) elm_layout_signal_emit(obj, "elm,state,check,on", "elm"); - else + else if (sd->state == _CHECK_STATE_UNCHECKED) elm_layout_signal_emit(obj, "elm,state,check,off", "elm"); + else + elm_layout_signal_emit(obj, "elm,state,check,indeterminate", "elm"); } } else sd->statep = NULL; } +EOLIAN static void +_elm_check_three_state_mode_set(Eo *obj, Elm_Check_Data *sd, Eina_Bool is_enabled) +{ + ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); + + if (is_enabled != sd->three_state_mode) + { + sd->three_state_mode = is_enabled; + if ((!sd->three_state_mode) && (sd->state == _CHECK_STATE_INDETERMINATE)) + elm_layout_signal_emit(obj, "elm,state,check,on", "elm"); + } + + edje_object_message_signal_process(wd->resize_obj); +} + +EOLIAN static Eina_Bool +_elm_check_three_state_mode_get(Eo *obj EINA_UNUSED, Elm_Check_Data *sd) +{ + return sd->three_state_mode; +} + EOLIAN static Eina_Bool _elm_check_elm_widget_focus_next_manager_is(Eo *obj EINA_UNUSED, Elm_Check_Data *_pd EINA_UNUSED) { diff --git a/legacy/elementary/src/lib/elm_check.eo b/legacy/elementary/src/lib/elm_check.eo index 17d49ee..f7d74df 100644 --- a/legacy/elementary/src/lib/elm_check.eo +++ b/legacy/elementary/src/lib/elm_check.eo @@ -1,3 +1,9 @@ + type Check_State: enum _Check_State { + Unchecked, + Checked, + Indeterminate + }; + class Elm_Check (Elm_Layout, Elm_Interface_Atspi_Widget_Action) { eo_prefix: elm_obj_check; @@ -17,30 +23,52 @@ class Elm_Check (Elm_Layout, Elm_Interface_Atspi_Widget_Action) /*@ @brief Get the state of the check object - @return The boolean state + @return The enum of states, first two states(Unchecked and checked) can be treated as boolean. @ingroup Check */ } values { - bool state; /*@ The state to use (1 == on, 0 == off) */ + Check_State state; /*@ The state to use (0 == off, 1 == on, 2 == indeterminate) */ } } state_pointer { set { /*@ - @brief Set a convenience pointer to a boolean to change + @brief Set a convenience pointer to a enum of state to change - This sets a pointer to a boolean, that, in addition to the check objects + This sets a pointer to a enum of state, that, in addition to the check objects state will also be modified directly. To stop setting the object pointed to simply use NULL as the @p statep parameter. If @p statep is not NULL, then when this is called, the check objects state will also be modified to - reflect the value of the boolean @p statep points to, just like calling + reflect the value of the enum of states @p statep points to, just like calling elm_check_state_set(). @ingroup Check */ } values { - bool *statep; /*@ Pointer to the boolean to modify */ + Check_State *statep; /*@ Pointer to the boolean to modify */ + } + } + three_state_mode { + set { + /*@ + @brief Set the enable/disable of three state mode of the check object + + This enables the three state mode. By default any checkbox will be changing states in two states. i.e. Checked and Unchecked + On enabling this, it will start rotation of states into three states. Checked, Unchecked and Indeterminate + + @ingroup Check */ + } + get { + /*@ + @brief Get the enable/disable of three state mode of the check object + + @return The boolean value of enable/disable of three mode state change. + + @ingroup Check */ + } + values { + bool three_state_mode; /*@ The state to use (0 == Disabled, 1 == Enabled) */ } } } diff --git a/legacy/elementary/src/lib/elm_interface_atspi_accessible.h b/legacy/elementary/src/lib/elm_interface_atspi_accessible.h index acd152e..da5a486 100644 --- a/legacy/elementary/src/lib/elm_interface_atspi_accessible.h +++ b/legacy/elementary/src/lib/elm_interface_atspi_accessible.h @@ -221,7 +221,7 @@ typedef enum _Elm_Atspi_Relation_Type Elm_Atspi_Relation_Type; struct _Elm_Atspi_Event_State_Changed_Data { Elm_Atspi_State_Type type; - Eina_Bool new_value; + int new_value; }; diff --git a/legacy/elementary/src/lib/elm_widget_check.h b/legacy/elementary/src/lib/elm_widget_check.h index bcf3eac..edeb376 100644 --- a/legacy/elementary/src/lib/elm_widget_check.h +++ b/legacy/elementary/src/lib/elm_widget_check.h @@ -26,8 +26,9 @@ typedef struct _Elm_Check_Data Elm_Check_Data; struct _Elm_Check_Data { - Eina_Bool state; - Eina_Bool *statep; + Check_State state; + Check_State *statep; + Eina_Bool three_state_mode; }; /** -- 2.7.4