From 35f9fc26e3d3c08d1404184ad15ef4035dc3d896 Mon Sep 17 00:00:00 2001 From: Marcel Hollerbach Date: Tue, 20 Aug 2019 15:57:13 +0200 Subject: [PATCH] efl_ui_multi_selectable: add APIs for selecting this can be used to select / unselect a range or all selectables in a container. The range selectable APIs do not have a strong ordering on a and b, b does not have to come after a. ref T8057 Reviewed-by: Mike Blumenkrantz Differential Revision: https://phab.enlightenment.org/D9660 --- src/bin/elementary/test_ui_collection.c | 31 ++++++- src/lib/elementary/efl_ui_collection.c | 70 ++++++++++++++ src/lib/elementary/efl_ui_collection.eo | 4 + src/lib/elementary/efl_ui_multi_selectable.eo | 33 +++++++ .../spec/efl_test_multi_selectable.c | 91 +++++++++++++++++++ 5 files changed, 227 insertions(+), 2 deletions(-) diff --git a/src/bin/elementary/test_ui_collection.c b/src/bin/elementary/test_ui_collection.c index b60cf35f75..2dd2bc2c6e 100644 --- a/src/bin/elementary/test_ui_collection.c +++ b/src/bin/elementary/test_ui_collection.c @@ -4,6 +4,18 @@ #include +static void +_select_all(void *data, const Efl_Event *ev EINA_UNUSED) +{ + efl_ui_select_all(data); +} + +static void +_unselect_all(void *data, const Efl_Event *ev EINA_UNUSED) +{ + efl_ui_unselect_all(data); +} + static void _selection_changed_cb(void *data, const Efl_Event *ev EINA_UNUSED) { @@ -192,7 +204,7 @@ void create_item_container_ui(const Efl_Class *collection_class, const Efl_Class } } - efl_pack_table(tbl, o, 1, 0, 1, 12); + efl_pack_table(tbl, o, 1, 0, 1, 14); ctx->c = o; o = efl_add(EFL_UI_BUTTON_CLASS, tbl, @@ -269,11 +281,26 @@ void create_item_container_ui(const Efl_Class *collection_class, const Efl_Class efl_event_callback_add(o, EFL_INPUT_EVENT_CLICKED, _add_thousend_items, item_container); efl_pack_table(tbl, o, 0, 10, 1, 1); + o = efl_add(EFL_UI_BUTTON_CLASS, tbl, + efl_gfx_hint_weight_set(efl_added, 0.0, 0.0), + efl_gfx_hint_align_set(efl_added, 0, 0.5)); + efl_text_set(o, "Select All"); + efl_event_callback_add(o, EFL_INPUT_EVENT_CLICKED, _select_all, item_container); + efl_pack_table(tbl, o, 0, 11, 1, 1); + + o = efl_add(EFL_UI_BUTTON_CLASS, tbl, + efl_gfx_hint_weight_set(efl_added, 0.0, 0.0), + efl_gfx_hint_align_set(efl_added, 0, 0.5)); + efl_text_set(o, "Unselect All"); + efl_event_callback_add(o, EFL_INPUT_EVENT_CLICKED, _unselect_all, item_container); + efl_pack_table(tbl, o, 0, 12, 1, 1); + + bx = efl_add(EFL_UI_RADIO_BOX_CLASS, tbl, efl_gfx_hint_weight_set(efl_added, 0.0, 0.0), efl_gfx_hint_align_set(efl_added, 0, 0.5)); efl_event_callback_add(bx, EFL_UI_RADIO_GROUP_EVENT_VALUE_CHANGED, _select_value_cb, item_container); - efl_pack_table(tbl, bx, 0, 11, 1, 1); + efl_pack_table(tbl, bx, 0, 13, 1, 1); o = efl_add(EFL_UI_RADIO_CLASS, bx, efl_ui_radio_state_value_set(efl_added, EFL_UI_SELECT_MODE_SINGLE)); efl_text_set(o, "Singleselect"); diff --git a/src/lib/elementary/efl_ui_collection.c b/src/lib/elementary/efl_ui_collection.c index c7101fdbd5..0217d89e5d 100644 --- a/src/lib/elementary/efl_ui_collection.c +++ b/src/lib/elementary/efl_ui_collection.c @@ -940,6 +940,76 @@ _efl_ui_collection_efl_ui_focus_manager_move(Eo *obj, Efl_Ui_Collection_Data *pd return new_obj; } +static void +_selectable_range_apply(Eina_List *start, Eina_Bool flag) +{ + Efl_Ui_Selectable *sel; + Eina_List *n; + + EINA_LIST_FOREACH(start, n, sel) + { + efl_ui_selectable_selected_set(sel, flag); + } +} + +EOLIAN static void +_efl_ui_collection_efl_ui_multi_selectable_select_all(Eo *obj EINA_UNUSED, Efl_Ui_Collection_Data *pd) +{ + _selectable_range_apply(pd->items, EINA_TRUE); +} + +EOLIAN static void +_efl_ui_collection_efl_ui_multi_selectable_unselect_all(Eo *obj EINA_UNUSED, Efl_Ui_Collection_Data *pd) +{ + _selectable_range_apply(pd->items, EINA_FALSE); +} + +static void +_range_selection_find(Eo *obj, Efl_Ui_Collection_Data *pd, Efl_Ui_Selectable *a, Efl_Ui_Selectable *b, Eina_Bool flag) +{ + Eina_List *n; + Efl_Ui_Selectable *c; + Eina_List *start = NULL, *end = NULL; + + EINA_SAFETY_ON_FALSE_RETURN(efl_ui_widget_parent_get(a) == obj); + EINA_SAFETY_ON_FALSE_RETURN(efl_ui_widget_parent_get(b) == obj); + + EINA_LIST_FOREACH(pd->items, n, c) + { + if (!start) + { + if (c == a) + start = n; + else if (c == b) + start = n; + } + else if (!end) + { + if (c == a) + end = n; + else if (c == b) + end = n; + } + /* if we have found the first element, start applying the flag */ + if (start) + efl_ui_selectable_selected_set(c, flag); + if (end) + break; + } +} + +EOLIAN static void +_efl_ui_collection_efl_ui_multi_selectable_select_range(Eo *obj, Efl_Ui_Collection_Data *pd, Efl_Ui_Selectable *a, Efl_Ui_Selectable *b) +{ + _range_selection_find(obj, pd, a, b, EINA_TRUE); +} + +EOLIAN static void +_efl_ui_collection_efl_ui_multi_selectable_unselect_range(Eo *obj, Efl_Ui_Collection_Data *pd, Efl_Ui_Selectable *a, Efl_Ui_Selectable *b) +{ + _range_selection_find(obj, pd, a, b, EINA_FALSE); +} + #include "efl_ui_collection.eo.c" #define ITEM_IS_OUTSIDE_VISIBLE(id) id < collection_pd->start_id || id > collection_pd->end_id diff --git a/src/lib/elementary/efl_ui_collection.eo b/src/lib/elementary/efl_ui_collection.eo index a3e302e320..76c7fac4eb 100644 --- a/src/lib/elementary/efl_ui_collection.eo +++ b/src/lib/elementary/efl_ui_collection.eo @@ -67,6 +67,10 @@ class @beta Efl.Ui.Collection extends Efl.Ui.Layout_Base implements Efl.Ui.Single_Selectable.last_selected { get; } Efl.Ui.Multi_Selectable.selected_items_get; Efl.Ui.Multi_Selectable.select_mode {get; set;} + Efl.Ui.Multi_Selectable.select_all; + Efl.Ui.Multi_Selectable.unselect_all; + Efl.Ui.Multi_Selectable.select_range; + Efl.Ui.Multi_Selectable.unselect_range; } events { item,pressed : Efl.Ui.Item; [[A $press event occurred over an item.]] diff --git a/src/lib/elementary/efl_ui_multi_selectable.eo b/src/lib/elementary/efl_ui_multi_selectable.eo index 3957fe332e..a980389072 100644 --- a/src/lib/elementary/efl_ui_multi_selectable.eo +++ b/src/lib/elementary/efl_ui_multi_selectable.eo @@ -28,5 +28,38 @@ interface @beta Efl.Ui.Multi_Selectable extends Efl.Ui.Single_Selectable [[Get the selected items in a iterator. The iterator sequence will be decided by selection.]] return: iterator @owned @no_unused; [[User has to free the iterator after usage.]] } + select_range { + [[Select a range of @Efl.Ui.Selectable. + + This will select the range of selectables from a to b or from b to a depending on which one comes first. + If a or b are not part of the widget, a error is returned, and no change is applied. + $null is not allowed as either of the parameters. + Both of the passed values will also be selected. + ]] + params { + a : Efl.Ui.Selectable; [[One side of the range.]] + b : Efl.Ui.Selectable; [[The other side of the range.]] + } + } + unselect_range { + [[Unselect a range of @Efl.Ui.Selectable. + + This will unselect the range of selectables from a to b or from b to a depending on which one comes first. + If a or b are not part of the widget, a error is returned, and no change is applied. + $null is not allowed as either of the parameters. + Both of the passed values will also be unselected. + ]] + params { + a : Efl.Ui.Selectable; [[One side of the range.]] + b : Efl.Ui.Selectable; [[The other side of the range.]] + } + } + select_all { + [[Select all @Efl.Ui.Selectable]] + } + unselect_all { + [[Unselect all @Efl.Ui.Selectable]] + } + } } diff --git a/src/tests/elementary/spec/efl_test_multi_selectable.c b/src/tests/elementary/spec/efl_test_multi_selectable.c index 94a55749a0..5d5c1ed824 100644 --- a/src/tests/elementary/spec/efl_test_multi_selectable.c +++ b/src/tests/elementary/spec/efl_test_multi_selectable.c @@ -213,6 +213,91 @@ EFL_START_TEST(test_none_select) } EFL_END_TEST +EFL_START_TEST(select_all_api) +{ + Eina_Array *arr_selected; + + efl_ui_select_mode_set(widget, EFL_UI_SELECT_MODE_MULTI); + efl_ui_select_all(widget); + _iterator_to_array(&arr_selected, efl_ui_selected_items_get(widget)); + + ck_assert_int_eq(eina_array_count(arr_selected), 3); + + ck_assert_ptr_eq(eina_array_data_get(arr_selected, 0), efl_pack_content_get(widget, 0)); + ck_assert_ptr_eq(eina_array_data_get(arr_selected, 1), efl_pack_content_get(widget, 1)); + ck_assert_ptr_eq(eina_array_data_get(arr_selected, 2), efl_pack_content_get(widget, 2)); +} +EFL_END_TEST + +EFL_START_TEST(unselect_all_api) +{ + Eina_Array *arr_selected; + + efl_ui_select_mode_set(widget, EFL_UI_SELECT_MODE_MULTI); + efl_ui_selectable_selected_set(efl_pack_content_get(widget, 0), EINA_TRUE); + + efl_ui_unselect_all(widget); + _iterator_to_array(&arr_selected, efl_ui_selected_items_get(widget)); + + ck_assert_int_eq(eina_array_count(arr_selected), 0); + ck_assert_int_eq(efl_ui_selectable_selected_get(efl_pack_content_get(widget, 0)), EINA_FALSE); +} +EFL_END_TEST + +EFL_START_TEST(unselect_range) +{ + Eina_Array *arr_selected; + + efl_ui_select_mode_set(widget, EFL_UI_SELECT_MODE_MULTI); + efl_ui_select_all(widget); + + efl_ui_unselect_range(widget, efl_pack_content_get(widget, 1), efl_pack_content_get(widget, 2)); + _iterator_to_array(&arr_selected, efl_ui_selected_items_get(widget)); + 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(widget, 0)); +} +EFL_END_TEST + +EFL_START_TEST(unselect_range2) +{ + Eina_Array *arr_selected; + + efl_ui_select_mode_set(widget, EFL_UI_SELECT_MODE_MULTI); + efl_ui_select_all(widget); + + efl_ui_unselect_range(widget, efl_pack_content_get(widget, 2), efl_pack_content_get(widget, 1)); + _iterator_to_array(&arr_selected, efl_ui_selected_items_get(widget)); + 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(widget, 0)); +} +EFL_END_TEST + +EFL_START_TEST(select_range) +{ + Eina_Array *arr_selected; + + efl_ui_select_mode_set(widget, EFL_UI_SELECT_MODE_MULTI); + efl_ui_select_range(widget, efl_pack_content_get(widget, 1), efl_pack_content_get(widget, 2)); + _iterator_to_array(&arr_selected, efl_ui_selected_items_get(widget)); + 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(widget, 1)); + ck_assert_ptr_eq(eina_array_data_get(arr_selected, 1), efl_pack_content_get(widget, 2)); +} +EFL_END_TEST + +EFL_START_TEST(select_range2) +{ + Eina_Array *arr_selected; + + efl_ui_select_mode_set(widget, EFL_UI_SELECT_MODE_MULTI); + efl_ui_select_range(widget, efl_pack_content_get(widget, 2), efl_pack_content_get(widget, 1)); + _iterator_to_array(&arr_selected, efl_ui_selected_items_get(widget)); + 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(widget, 1)); + ck_assert_ptr_eq(eina_array_data_get(arr_selected, 1), efl_pack_content_get(widget, 2)); +} +EFL_END_TEST + void efl_ui_multi_selectable_behavior_test(TCase *tc) { @@ -222,5 +307,11 @@ efl_ui_multi_selectable_behavior_test(TCase *tc) tcase_add_test(tc, test_single_select); tcase_add_test(tc, test_none_select); tcase_add_test(tc, test_single_select_always); + tcase_add_test(tc, select_all_api); + tcase_add_test(tc, unselect_all_api); + tcase_add_test(tc, unselect_range); + tcase_add_test(tc, unselect_range2); + tcase_add_test(tc, select_range); + tcase_add_test(tc, select_range2); efl_ui_single_selectable_behavior_test(tc); }