From 9a1f7f2fcbce7a682ab91d797a0adf6119bdaa57 Mon Sep 17 00:00:00 2001 From: Karijn Wessing Date: Wed, 18 Aug 2021 11:32:10 +0200 Subject: [PATCH] feat(obj) add lv_obj_swap() function (#2461) * proposal for lv_obj_swap() function * review issues applied * review changes for comments --- docs/CHANGELOG.md | 1 + docs/overview/layer.md | 3 +- docs/widgets/obj.md | 2 + examples/widgets/list/index.rst | 6 ++ examples/widgets/list/lv_example_list_2.c | 109 ++++++++++++++++++++++ examples/widgets/lv_example_widgets.h | 1 + src/core/lv_obj_tree.c | 24 +++++ src/core/lv_obj_tree.h | 8 ++ 8 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 examples/widgets/list/lv_example_list_2.c diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index ccd068ce1..443c8fb20 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## v8.1.0 (In progress) +- lv_obj_swap(obj1, obj2) added. (#2461) - feat(anim) add interface for handling lv_anim user data. (#2415) - feat(obj) add lv_is_initialized (#2402) - feat(obj) Backport keypad and encoder scrolling from v7 `lv_page` to v8 `lv_obj` (#2390) diff --git a/docs/overview/layer.md b/docs/overview/layer.md index 2c5e5e7dc..5be272e63 100644 --- a/docs/overview/layer.md +++ b/docs/overview/layer.md @@ -40,8 +40,9 @@ lv_obj_del(label2); ## Bring to the foreground -There are 2 explicit way to bring an object to the foreground: +There are 3 explicit way to bring an object to the foreground: - Use `lv_obj_move_foreground(obj)` to explicitly tell the library to bring an object to the foreground. Similarly, use `lv_obj_move_background(obj)` to move to the background. +- Use `lv_obj_swap(obj1, obj2)` to swap the relative position of two objects. - When `lv_obj_set_parent(obj, new_parent)` is used, `obj` will be on the foreground on the `new_parent`. ## Top and sys layers diff --git a/docs/widgets/obj.md b/docs/widgets/obj.md index 1a9483ff1..196c1555c 100644 --- a/docs/widgets/obj.md +++ b/docs/widgets/obj.md @@ -69,6 +69,8 @@ for(i = 0; i < lv_obj_get_child_cnt(parent); i++) { You can bring an object to the foreground or send it to the background with `lv_obj_move_foreground(obj)` and `lv_obj_move_background(obj)`. +You can swap the position of two objects with `lv_obj_swap(obj1, obj2)`. + ### Screens When you have created a screen like `lv_obj_t * screen = lv_obj_create(NULL)`, you can load it with `lv_scr_load(screen)`. The `lv_scr_act()` function gives you a pointer to the current screen. diff --git a/examples/widgets/list/index.rst b/examples/widgets/list/index.rst index 9e3e58bba..9b9affb6a 100644 --- a/examples/widgets/list/index.rst +++ b/examples/widgets/list/index.rst @@ -5,3 +5,9 @@ Simple List .. lv_example:: widgets/list/lv_example_list_1 :language: c + +Sorting a List using up and down buttons +"""""""""""""""" + +.. lv_example:: widgets/list/lv_example_list_2 + :language: c diff --git a/examples/widgets/list/lv_example_list_2.c b/examples/widgets/list/lv_example_list_2.c new file mode 100644 index 000000000..83cd03342 --- /dev/null +++ b/examples/widgets/list/lv_example_list_2.c @@ -0,0 +1,109 @@ +#include "../../lv_examples.h" +#if LV_USE_LIST && LV_BUILD_EXAMPLES + +static lv_obj_t* list2; +static lv_obj_t* buttonColumn; + +static lv_obj_t* currentButton = NULL; + +static void event_handler(lv_event_t* e) +{ + lv_event_code_t code = lv_event_get_code(e); + lv_obj_t* obj = lv_event_get_target(e); + if (code == LV_EVENT_CLICKED) + { + LV_LOG_USER("Clicked: %s", lv_list_get_btn_text(list2, obj)); + + if (currentButton == obj) + { + currentButton = NULL; + } + else + { + currentButton = obj; + } + lv_obj_t* parent = lv_obj_get_parent(obj); + uint32_t i; + for (i = 0; i < lv_obj_get_child_cnt(parent); i++) + { + lv_obj_t* child = lv_obj_get_child(parent, i); + if (child == currentButton) + { + lv_obj_add_state(child, LV_STATE_CHECKED); + } + else + { + lv_obj_clear_state(child, LV_STATE_CHECKED); + } + } + } +} + +static void event_handler_mu(lv_event_t* e) +{ + lv_event_code_t code = lv_event_get_code(e); + // lv_obj_t* obj = lv_event_get_target(e); + if ((code == LV_EVENT_CLICKED) || (code == LV_EVENT_LONG_PRESSED_REPEAT)) + { + if (currentButton == NULL) return; + lv_obj_t* parent = lv_obj_get_parent(currentButton); + uint_fast32_t i = lv_obj_get_child_id(currentButton); + if (i > 0) + { + lv_obj_swap(parent->spec_attr->children[i], parent->spec_attr->children[i - 1]); + } + } +} + +static void event_handler_dn(lv_event_t* e) +{ + lv_event_code_t code = lv_event_get_code(e); + // lv_obj_t* obj = lv_event_get_target(e); + if ((code == LV_EVENT_CLICKED) || (code == LV_EVENT_LONG_PRESSED_REPEAT)) + { + if (currentButton == NULL) return; + lv_obj_t* parent = lv_obj_get_parent(currentButton); + uint_fast32_t i = lv_obj_get_child_id(currentButton); + if (i < lv_obj_get_child_cnt(parent) - 1) + { + lv_obj_swap(parent->spec_attr->children[i], parent->spec_attr->children[i + 1]); + } + } +} + + +void lv_example_list_2(void) +{ + /*Create a list*/ + list2 = lv_list_create(lv_scr_act()); + lv_obj_set_size(list2, lv_obj_get_width(lv_scr_act()) - 90, lv_obj_get_height(lv_scr_act()) - 10); + lv_obj_set_align(list2, LV_ALIGN_TOP_LEFT); + lv_obj_set_pos(list2, 5, 5); + lv_obj_set_flex_flow(list2, LV_FLEX_FLOW_COLUMN); + + /*Add buttons to the list*/ + lv_obj_t* btn; + + for (int i = 0; i < 10; i++) + { + char szBuf[100]; + lv_snprintf(szBuf, sizeof(szBuf), " Item %d ", i); + btn = lv_btn_create(list2); + lv_obj_t* lab = lv_label_create(btn); + lv_label_set_text(lab, szBuf); + lv_obj_add_event_cb(btn, event_handler, LV_EVENT_CLICKED, NULL); + } + + buttonColumn = lv_obj_create(lv_scr_act()); + lv_obj_set_size(buttonColumn, 80, lv_obj_get_height(list2)); + lv_obj_set_align(buttonColumn, LV_ALIGN_TOP_RIGHT); + lv_obj_set_pos(buttonColumn, -5, 5); + lv_obj_set_flex_flow(buttonColumn, LV_FLEX_FLOW_COLUMN); + + btn = lv_list_add_btn(buttonColumn, LV_SYMBOL_UP, NULL); + lv_obj_add_event_cb(btn, event_handler_mu, LV_EVENT_ALL, NULL); + btn = lv_list_add_btn(buttonColumn, LV_SYMBOL_DOWN, NULL); + lv_obj_add_event_cb(btn, event_handler_dn, LV_EVENT_ALL, NULL); +} + +#endif \ No newline at end of file diff --git a/examples/widgets/lv_example_widgets.h b/examples/widgets/lv_example_widgets.h index 3c074dca8..763dd924b 100644 --- a/examples/widgets/lv_example_widgets.h +++ b/examples/widgets/lv_example_widgets.h @@ -84,6 +84,7 @@ void lv_example_led_1(void); void lv_example_line_1(void); void lv_example_list_1(void); +void lv_example_list_2(void); void lv_example_meter_1(void); void lv_example_meter_2(void); diff --git a/src/core/lv_obj_tree.c b/src/core/lv_obj_tree.c index a8e424890..a8141f617 100644 --- a/src/core/lv_obj_tree.c +++ b/src/core/lv_obj_tree.c @@ -235,6 +235,30 @@ void lv_obj_move_background(lv_obj_t * obj) lv_obj_invalidate(parent); } +void lv_obj_swap(lv_obj_t * obj1, lv_obj_t * obj2) +{ + LV_ASSERT_OBJ(obj1, MY_CLASS); + LV_ASSERT_OBJ(obj2, MY_CLASS); + + lv_obj_t* parent = lv_obj_get_parent(obj1); + lv_obj_t* parent2 = lv_obj_get_parent(obj2); + + uint_fast32_t index1 = lv_obj_get_child_id(obj1); + uint_fast32_t index2 = lv_obj_get_child_id(obj2); + + parent->spec_attr->children[index1] = obj2; + parent2->spec_attr->children[index2] = obj1; + + lv_event_send(parent, LV_EVENT_CHILD_CHANGED, obj2); + lv_event_send(parent2, LV_EVENT_CHILD_CHANGED, obj1); + + lv_obj_invalidate(parent); + if( parent != parent2) + { + lv_obj_invalidate(parent2); + } +} + lv_obj_t * lv_obj_get_screen(const lv_obj_t * obj) { LV_ASSERT_OBJ(obj, MY_CLASS); diff --git a/src/core/lv_obj_tree.h b/src/core/lv_obj_tree.h index 8071f31ab..7b916de5b 100644 --- a/src/core/lv_obj_tree.h +++ b/src/core/lv_obj_tree.h @@ -101,6 +101,14 @@ void lv_obj_move_foreground(struct _lv_obj_t * obj); */ void lv_obj_move_background(struct _lv_obj_t * obj); +/** + * Swap the positions of two objects. + * When used in listboxes, it can be used to sort the listbox items. + * @param obj1 pointer to the first object + * @param obj2 pointer to the second object + */ +void lv_obj_swap(struct _lv_obj_t* obj1, struct _lv_obj_t* obj2); + /** * Get the screen of an object * @param obj pointer to an object