From 1bd9a8f232ec1891cc396d13d7106aa7c255d78e Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Mon, 5 Aug 2019 19:07:29 +0200 Subject: [PATCH] introduce a new interface efl_ui_selectable this is meant to be implemented by entities that *can* be selectabled (not to be confused with containers that can have selected contents)! ref T8057 Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D9503 --- .../elementary/efl_ui_list_example_1.c | 4 +- src/lib/elementary/Efl_Ui.h | 1 + src/lib/elementary/efl_ui_collection.c | 54 +++++++++---------- src/lib/elementary/efl_ui_item.c | 14 ++--- src/lib/elementary/efl_ui_item.eo | 19 ++----- src/lib/elementary/efl_ui_selectable.eo | 21 ++++++++ src/lib/elementary/meson.build | 1 + .../efl_ui_test_collection_common.c | 46 ++++++++-------- 8 files changed, 87 insertions(+), 73 deletions(-) create mode 100644 src/lib/elementary/efl_ui_selectable.eo diff --git a/src/examples/elementary/efl_ui_list_example_1.c b/src/examples/elementary/efl_ui_list_example_1.c index a778617c93..bb8aa4011f 100644 --- a/src/examples/elementary/efl_ui_list_example_1.c +++ b/src/examples/elementary/efl_ui_list_example_1.c @@ -28,7 +28,7 @@ _list_selected(void *data EINA_UNUSED, const Efl_Event *ev) { Eo *list = ev->object; Eo *item = ev->info, *tmp; - printf("list item [%p:%d] is %s\n", item, efl_ui_item_index_get(item), (efl_ui_item_selected_get(item)? "selected" : "unselected")); + printf("list item [%p:%d] is %s\n", item, efl_ui_item_index_get(item), (efl_ui_selectable_selected_get(item)? "selected" : "unselected")); Eina_Iterator *selects = efl_ui_collection_selected_items_get(list); @@ -42,7 +42,7 @@ static void _list_unselected(void *data EINA_UNUSED, const Efl_Event *ev) { Eo *item = ev->info; - printf("list item [%p : %d] is %s\n", item, efl_ui_item_index_get(item), (efl_ui_item_selected_get(item)? "selected" : "unselected")); + printf("list item [%p : %d] is %s\n", item, efl_ui_item_index_get(item), (efl_ui_selectable_selected_get(item)? "selected" : "unselected")); } static void diff --git a/src/lib/elementary/Efl_Ui.h b/src/lib/elementary/Efl_Ui.h index 56fe6a7d5e..74003bd452 100644 --- a/src/lib/elementary/Efl_Ui.h +++ b/src/lib/elementary/Efl_Ui.h @@ -259,6 +259,7 @@ typedef Eo Efl_Ui_Spotlight_Indicator; # include # include # include +# include /** * Initialize Elementary diff --git a/src/lib/elementary/efl_ui_collection.c b/src/lib/elementary/efl_ui_collection.c index c637be0744..2241c5209d 100644 --- a/src/lib/elementary/efl_ui_collection.c +++ b/src/lib/elementary/efl_ui_collection.c @@ -371,7 +371,7 @@ deselect_all(Efl_Ui_Collection_Data *pd) while(pd->selected) { Eo *item = eina_list_data_get(pd->selected); - efl_ui_item_selected_set(item, EINA_FALSE); + efl_ui_selectable_selected_set(item, EINA_FALSE); EINA_SAFETY_ON_TRUE_RETURN(eina_list_data_get(pd->selected) == item); } } @@ -456,41 +456,40 @@ _efl_ui_collection_efl_ui_multi_selectable_select_mode_get(const Eo *obj EINA_UN } static void -_selected_cb(void *data, const Efl_Event *ev) +_selection_changed(void *data, const Efl_Event *ev) { + Eina_Bool selection = *((Eina_Bool*) ev->info); Eo *obj = data; MY_DATA_GET(obj, pd); - if (pd->mode == EFL_UI_SELECT_MODE_SINGLE_ALWAYS || pd->mode == EFL_UI_SELECT_MODE_SINGLE) + if (selection) { - //we might get the situation that the item is already in the list and selected again, so just free the list, it will be rebuild below - if (eina_list_data_get(pd->selected) == ev->object) + if (pd->mode == EFL_UI_SELECT_MODE_SINGLE_ALWAYS || pd->mode == EFL_UI_SELECT_MODE_SINGLE) { - pd->selected = eina_list_free(pd->selected); - } - else - { - deselect_all(pd); - } + //we might get the situation that the item is already in the list and selected again, so just free the list, it will be rebuild below + if (eina_list_data_get(pd->selected) == ev->object) + { + pd->selected = eina_list_free(pd->selected); + } + else + { + deselect_all(pd); + } + } + else if (pd->mode == EFL_UI_SELECT_MODE_NONE) + { + ERR("Selection while mode is NONE, uncaught state!"); + return; + } + pd->selected = eina_list_append(pd->selected, ev->object); + efl_event_callback_call(obj, EFL_UI_EVENT_ITEM_SELECTED, ev->object); } - else if (pd->mode == EFL_UI_SELECT_MODE_NONE) + else { - ERR("Selection while mode is NONE, uncaught state!"); - return; + pd->selected = eina_list_remove(pd->selected, ev->object); + efl_event_callback_call(obj, EFL_UI_EVENT_ITEM_UNSELECTED, ev->object); } - pd->selected = eina_list_append(pd->selected, ev->object); - efl_event_callback_call(obj, EFL_UI_EVENT_ITEM_SELECTED, ev->object); -} - -static void -_unselected_cb(void *data, const Efl_Event *ev) -{ - Eo *obj = data; - MY_DATA_GET(obj, pd); - - pd->selected = eina_list_remove(pd->selected, ev->object); - efl_event_callback_call(obj, EFL_UI_EVENT_ITEM_UNSELECTED, ev->object); } static void @@ -529,8 +528,7 @@ _redirect_cb(void *data, const Efl_Event *ev) EFL_CALLBACKS_ARRAY_DEFINE(active_item, {EFL_GFX_ENTITY_EVENT_HINTS_CHANGED, _hints_changed_cb}, - {EFL_UI_EVENT_ITEM_SELECTED, _selected_cb}, - {EFL_UI_EVENT_ITEM_UNSELECTED, _unselected_cb}, + {EFL_UI_EVENT_SELECTED_CHANGED, _selection_changed}, {EFL_INPUT_EVENT_PRESSED, _redirect_cb}, {EFL_INPUT_EVENT_UNPRESSED, _redirect_cb}, {EFL_INPUT_EVENT_LONGPRESSED, _redirect_cb}, diff --git a/src/lib/elementary/efl_ui_item.c b/src/lib/elementary/efl_ui_item.c index c0c863bf73..1ccc987759 100644 --- a/src/lib/elementary/efl_ui_item.c +++ b/src/lib/elementary/efl_ui_item.c @@ -142,6 +142,7 @@ static void _item_select(Eo *obj, Efl_Ui_Item_Data *pd) { Efl_Ui_Select_Mode m; + if (!pd->parent) return; m = efl_ui_select_mode_get(pd->parent); @@ -150,9 +151,9 @@ _item_select(Eo *obj, Efl_Ui_Item_Data *pd) ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); - pd->selected = EINA_TRUE; + Eina_Bool tmp = pd->selected = EINA_TRUE; edje_object_signal_emit(wd->resize_obj, "efl,state,selected", "efl"); - efl_event_callback_call(obj, EFL_UI_EVENT_ITEM_SELECTED, NULL); + efl_event_callback_call(obj, EFL_UI_EVENT_SELECTED_CHANGED, &tmp); } static void @@ -161,9 +162,9 @@ _item_unselect(Eo *obj, Efl_Ui_Item_Data *pd) if (!pd->selected) return; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); - pd->selected = EINA_FALSE; + Eina_Bool tmp = pd->selected =EINA_FALSE; edje_object_signal_emit(wd->resize_obj, "efl,state,unselected", "efl"); - efl_event_callback_call(obj, EFL_UI_EVENT_ITEM_UNSELECTED, NULL); + efl_event_callback_call(obj, EFL_UI_EVENT_SELECTED_CHANGED, &tmp); } /* Mouse Controls */ @@ -242,7 +243,7 @@ _efl_ui_item_index_get(const Eo *obj, Efl_Ui_Item_Data *pd) } EOLIAN static void -_efl_ui_item_selected_set(Eo *obj, Efl_Ui_Item_Data *pd, Eina_Bool select) +_efl_ui_item_efl_ui_selectable_selected_set(Eo *obj, Efl_Ui_Item_Data *pd, Eina_Bool select) { Eina_Bool selected = !!select; ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd); @@ -253,7 +254,7 @@ _efl_ui_item_selected_set(Eo *obj, Efl_Ui_Item_Data *pd, Eina_Bool select) } EOLIAN static Eina_Bool -_efl_ui_item_selected_get(const Eo *obj EINA_UNUSED, Efl_Ui_Item_Data *pd) +_efl_ui_item_efl_ui_selectable_selected_get(const Eo *obj EINA_UNUSED, Efl_Ui_Item_Data *pd) { return pd->selected; } @@ -271,3 +272,4 @@ _efl_ui_item_container_get(const Eo *obj EINA_UNUSED, Efl_Ui_Item_Data *pd) } #include "efl_ui_item.eo.c" +#include "efl_ui_selectable.eo.c" diff --git a/src/lib/elementary/efl_ui_item.eo b/src/lib/elementary/efl_ui_item.eo index 331f48a8e1..51c9100fec 100644 --- a/src/lib/elementary/efl_ui_item.eo +++ b/src/lib/elementary/efl_ui_item.eo @@ -1,4 +1,4 @@ -abstract @beta Efl.Ui.Item extends Efl.Ui.Layout_Base implements Efl.Ui.Container_Selectable, Efl.Input.Clickable +abstract @beta Efl.Ui.Item extends Efl.Ui.Layout_Base implements Efl.Ui.Selectable, Efl.Input.Clickable { [[Selectable Item abstraction. @@ -6,7 +6,7 @@ abstract @beta Efl.Ui.Item extends Efl.Ui.Layout_Base implements Efl.Ui.Containe like @Efl.Ui.List or @Efl.Ui.Grid, for example. @Efl.Ui.Item provides user interaction through the @Efl.Input.Clickable mixin. Items can be pressed, long-pressed, etc, and appropriate events are generated. - @Efl.Ui.Item also implements the @Efl.Ui.Container_Selectable interface, meaning that "selected" and + @Efl.Ui.Item also implements the @Efl.Ui.Selectable interface, meaning that "selected" and "unselected" events are automatically generated. Classes inheriting from this one only need to deal with the visual representation of the widget. @@ -15,8 +15,8 @@ abstract @beta Efl.Ui.Item extends Efl.Ui.Layout_Base implements Efl.Ui.Containe Some events are converted to edje signals so the theme can react to them: @[Efl.Input.Clickable.pressed] -> "efl,state,pressed", @[Efl.Input.Clickable.unpressed] -> "efl,state,unpressed", - @[Efl.Ui.Container_Selectable.item,selected] -> "efl,state,selected", - @[Efl.Ui.Container_Selectable.item,unselected] -> "efl,state,unselected". + @[Efl.Ui.Selectable.selected,changed] (true) -> "efl,state,selected", + @[Efl.Ui.Selectable.selected,changed] (false) -> "efl,state,unselected". ]] methods { @property index { @@ -28,16 +28,6 @@ abstract @beta Efl.Ui.Item extends Efl.Ui.Layout_Base implements Efl.Ui.Containe index : int; [[The index where to find this item in its $container.]] } } - @property selected { - [[Item selected state. - - The visual representation of the item will be adjusted accordingly to the new state. - This property is also automatically modified in response to user actions. - ]] - values { - select: bool; [[Whether this item is selected or not.]] - } - } @property container { [[The container this object is part of. @@ -55,5 +45,6 @@ abstract @beta Efl.Ui.Item extends Efl.Ui.Layout_Base implements Efl.Ui.Containe Efl.Object.constructor; Efl.Object.finalize; Efl.Object.destructor; + Efl.Ui.Selectable.selected {get; set;} } } diff --git a/src/lib/elementary/efl_ui_selectable.eo b/src/lib/elementary/efl_ui_selectable.eo new file mode 100644 index 0000000000..66a83ee347 --- /dev/null +++ b/src/lib/elementary/efl_ui_selectable.eo @@ -0,0 +1,21 @@ +interface Efl.Ui.Selectable { + [[Selectable interface for ui objects + + A object implementing this can be selected. When the selected property of this object changes, the selected,changed event is emitted. + ]] + event_prefix: efl_ui; + methods { + @property selected { + [[The selected state of this object + + A change to this property emits the changed event. + ]] + values { + selected : bool; [[The selected state of this object]] + } + } + } + events { + selected,changed : bool; [[Called when the selected state has changed]] + } +} diff --git a/src/lib/elementary/meson.build b/src/lib/elementary/meson.build index 0ca268998b..8f0c85a12a 100644 --- a/src/lib/elementary/meson.build +++ b/src/lib/elementary/meson.build @@ -182,6 +182,7 @@ pub_eo_files = [ 'efl_ui_position_manager_entity.eo', 'efl_ui_position_manager_list.eo', 'efl_ui_position_manager_grid.eo', + 'efl_ui_selectable.eo', ] foreach eo_file : pub_eo_files diff --git a/src/tests/elementary/efl_ui_test_collection_common.c b/src/tests/elementary/efl_ui_test_collection_common.c index c41946afbe..746b86d938 100644 --- a/src/tests/elementary/efl_ui_test_collection_common.c +++ b/src/tests/elementary/efl_ui_test_collection_common.c @@ -55,25 +55,25 @@ EFL_START_TEST(test_multi_select) efl_event_callback_add(item_container, EFL_UI_EVENT_ITEM_UNSELECTED, _set_pointer_quit, &unselected); fill_items(EFL_UI_LIST_DEFAULT_ITEM_CLASS); - efl_ui_item_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); ck_assert_ptr_eq(selected, efl_pack_content_get(item_container, 0)); ck_assert_ptr_eq(unselected, NULL); selected = NULL; unselected = NULL; - efl_ui_item_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); ck_assert_ptr_eq(selected, efl_pack_content_get(item_container, 2)); ck_assert_ptr_eq(unselected, NULL); selected = NULL; unselected = NULL; - ck_assert_int_eq(efl_ui_item_selected_get(efl_pack_content_get(item_container, 0)), EINA_TRUE); - ck_assert_int_eq(efl_ui_item_selected_get(efl_pack_content_get(item_container, 2)), EINA_TRUE); + ck_assert_int_eq(efl_ui_selectable_selected_get(efl_pack_content_get(item_container, 0)), EINA_TRUE); + ck_assert_int_eq(efl_ui_selectable_selected_get(efl_pack_content_get(item_container, 2)), EINA_TRUE); ck_assert_ptr_eq(efl_ui_collection_last_selected_item_get(item_container), efl_pack_content_get(item_container, 2)); _iterator_to_array(&arr_selected, efl_ui_collection_selected_items_get(item_container)); ck_assert_int_eq(eina_array_count(arr_selected), 2); ck_assert_ptr_eq(eina_array_data_get(arr_selected, 0), efl_pack_content_get(item_container, 0)); ck_assert_ptr_eq(eina_array_data_get(arr_selected, 1), efl_pack_content_get(item_container, 2)); - efl_ui_item_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); ck_assert_ptr_eq(selected, NULL); ck_assert_ptr_eq(unselected, NULL); selected = NULL; @@ -93,17 +93,17 @@ EFL_START_TEST(test_multi_select_removal) efl_event_callback_add(item_container, EFL_UI_EVENT_ITEM_UNSELECTED, _set_pointer_quit, &unselected); fill_items(EFL_UI_LIST_DEFAULT_ITEM_CLASS); - efl_ui_item_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); selected = NULL;//No need to ckeck the flag, we asserted in the tcase before - efl_ui_item_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); selected = NULL;//No need to ckeck the flag, we asserted in the tcase before unselected = NULL; - efl_ui_item_selected_set(efl_pack_content_get(item_container, 0), EINA_FALSE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 0), EINA_FALSE); ck_assert_ptr_eq(selected, NULL); ck_assert_ptr_eq(unselected, efl_pack_content_get(item_container, 0)); selected = NULL; unselected = NULL; - efl_ui_item_selected_set(efl_pack_content_get(item_container, 2), EINA_FALSE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 2), EINA_FALSE); ck_assert_ptr_eq(selected, NULL); ck_assert_ptr_eq(unselected, efl_pack_content_get(item_container, 2)); selected = NULL; @@ -128,24 +128,24 @@ EFL_START_TEST(test_single_select) efl_event_callback_add(item_container, EFL_UI_EVENT_ITEM_UNSELECTED, _set_pointer_quit, &unselected); fill_items(EFL_UI_LIST_DEFAULT_ITEM_CLASS); - efl_ui_item_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); ck_assert_ptr_eq(selected, efl_pack_content_get(item_container, 0)); ck_assert_ptr_eq(unselected, NULL); selected = NULL; unselected = NULL; - efl_ui_item_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); ck_assert_ptr_eq(selected, efl_pack_content_get(item_container, 2)); ck_assert_ptr_eq(unselected, efl_pack_content_get(item_container, 0)); selected = NULL; unselected = NULL; - ck_assert_int_eq(efl_ui_item_selected_get(efl_pack_content_get(item_container, 0)), EINA_FALSE); - ck_assert_int_eq(efl_ui_item_selected_get(efl_pack_content_get(item_container, 2)), EINA_TRUE); + ck_assert_int_eq(efl_ui_selectable_selected_get(efl_pack_content_get(item_container, 0)), EINA_FALSE); + ck_assert_int_eq(efl_ui_selectable_selected_get(efl_pack_content_get(item_container, 2)), EINA_TRUE); ck_assert_ptr_eq(efl_ui_collection_last_selected_item_get(item_container), efl_pack_content_get(item_container, 2)); _iterator_to_array(&arr_selected, efl_ui_collection_selected_items_get(item_container)); ck_assert_int_eq(eina_array_count(arr_selected), 1); ck_assert_ptr_eq(eina_array_data_get(arr_selected, 0), efl_pack_content_get(item_container, 2)); - efl_ui_item_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); ck_assert_ptr_eq(selected, NULL); ck_assert_ptr_eq(unselected, NULL); selected = NULL; @@ -166,23 +166,23 @@ EFL_START_TEST(test_single_select_always) efl_event_callback_add(item_container, EFL_UI_EVENT_ITEM_UNSELECTED, _set_pointer_quit, &unselected); fill_items(EFL_UI_LIST_DEFAULT_ITEM_CLASS); - efl_ui_item_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); ck_assert_ptr_eq(selected, efl_pack_content_get(item_container, 0)); ck_assert_ptr_eq(unselected, NULL); selected = NULL; unselected = NULL; - efl_ui_item_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); ck_assert_ptr_eq(selected, efl_pack_content_get(item_container, 2)); ck_assert_ptr_eq(unselected, efl_pack_content_get(item_container, 0)); selected = NULL; unselected = NULL; - efl_ui_item_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); ck_assert_ptr_eq(selected, efl_pack_content_get(item_container, 2)); ck_assert_ptr_eq(unselected, NULL); selected = NULL; unselected = NULL; - ck_assert_int_eq(efl_ui_item_selected_get(efl_pack_content_get(item_container, 0)), EINA_FALSE); - ck_assert_int_eq(efl_ui_item_selected_get(efl_pack_content_get(item_container, 2)), EINA_TRUE); + ck_assert_int_eq(efl_ui_selectable_selected_get(efl_pack_content_get(item_container, 0)), EINA_FALSE); + ck_assert_int_eq(efl_ui_selectable_selected_get(efl_pack_content_get(item_container, 2)), EINA_TRUE); ck_assert_ptr_eq(efl_ui_collection_last_selected_item_get(item_container), efl_pack_content_get(item_container, 2)); _iterator_to_array(&arr_selected, efl_ui_collection_selected_items_get(item_container)); ck_assert_int_eq(eina_array_count(arr_selected), 1); @@ -203,18 +203,18 @@ EFL_START_TEST(test_none_select) efl_event_callback_add(item_container, EFL_UI_EVENT_ITEM_UNSELECTED, _set_pointer_quit, &unselected); fill_items(EFL_UI_LIST_DEFAULT_ITEM_CLASS); - efl_ui_item_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 0), EINA_TRUE); ck_assert_ptr_eq(selected, NULL); ck_assert_ptr_eq(unselected, NULL); selected = NULL; unselected = NULL; - efl_ui_item_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); + efl_ui_selectable_selected_set(efl_pack_content_get(item_container, 2), EINA_TRUE); ck_assert_ptr_eq(selected, NULL); ck_assert_ptr_eq(unselected, NULL); selected = NULL; unselected = NULL; - ck_assert_int_eq(efl_ui_item_selected_get(efl_pack_content_get(item_container, 0)), EINA_FALSE); - ck_assert_int_eq(efl_ui_item_selected_get(efl_pack_content_get(item_container, 2)), EINA_FALSE); + ck_assert_int_eq(efl_ui_selectable_selected_get(efl_pack_content_get(item_container, 0)), EINA_FALSE); + ck_assert_int_eq(efl_ui_selectable_selected_get(efl_pack_content_get(item_container, 2)), EINA_FALSE); ck_assert_ptr_eq(efl_ui_collection_last_selected_item_get(item_container), NULL); _iterator_to_array(&arr_selected, efl_ui_collection_selected_items_get(item_container)); ck_assert_int_eq(eina_array_count(arr_selected), 0);