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
This commit is contained in:
Shobhit 2015-04-17 17:11:28 +09:00 committed by ChunEon Park
parent 8e61552bc5
commit 0a9ac756d0
8 changed files with 299 additions and 44 deletions

View File

@ -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 \

View File

@ -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;
@ -269,6 +275,11 @@ group { name: "elm/check/base/default";
action: STATE_SET "default" 0.0;
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 {

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

View File

@ -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 <Elementary.h>
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()

View File

@ -53,19 +53,57 @@ _activate(Evas_Object *obj)
{
ELM_CHECK_DATA_GET(obj, sd);
sd->state = !sd->state;
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"));
sd->state = !sd->state;
}
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_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->three_state_mode)
{
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
{
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"));
}
off_text = elm_layout_text_get(data, "off");
if (off_text)
else if (sd->state == _CHECK_STATE_UNCHECKED)
{
char buf[1024];
off_text = elm_layout_text_get(data, "off");
snprintf(buf, sizeof(buf), "%s: %s", E_("State"), off_text);
return strdup(buf);
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
{
indeterminate_text = elm_layout_text_get(data, "indeterminate");
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
@ -325,6 +400,9 @@ _elm_check_evas_object_smart_add(Eo *obj, Elm_Check_Data *_pd EINA_UNUSED)
edje_object_signal_callback_add
(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)
{

View File

@ -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) */
}
}
}

View File

@ -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;
};

View File

@ -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;
};
/**