diff --git a/examples/layouts/lv_example_layout.h b/examples/layouts/lv_example_layout.h index 2de368bc17..13846da340 100644 --- a/examples/layouts/lv_example_layout.h +++ b/examples/layouts/lv_example_layout.h @@ -15,6 +15,7 @@ extern "C" { *********************/ #include "flex/lv_example_flex.h" #include "grid/lv_example_grid.h" +#include "split/lv_example_split.h" /********************* * DEFINES diff --git a/examples/layouts/split/lv_example_split.c b/examples/layouts/split/lv_example_split.c new file mode 100644 index 0000000000..17b5817f8e --- /dev/null +++ b/examples/layouts/split/lv_example_split.c @@ -0,0 +1,84 @@ +/** + * @file lv_example_split.c + */ + +#include "../../lv_examples.h" +#if LV_USE_FLEX && LV_BUILD_EXAMPLES + +#define SPLIT_DIVIDER_W 12 +#define SPLIT_MIN_PANE 60 + +/* Drag the divider: resize the left pane; the right pane grows to fill the rest. */ +static void splitter_pressing_cb(lv_event_t * e) +{ + lv_obj_t * divider = lv_event_get_target_obj(e); + lv_obj_t * cont = lv_obj_get_parent(divider); + lv_obj_t * pane_left = lv_obj_get_child(cont, 0); + + lv_indev_t * indev = lv_indev_active(); + if(indev == NULL) return; + + lv_point_t p; + lv_indev_get_point(indev, &p); + + lv_area_t content; + lv_obj_get_content_coords(cont, &content); + int32_t avail = lv_area_get_width(&content) - SPLIT_DIVIDER_W; + if(avail <= 2 * SPLIT_MIN_PANE) return; + + int32_t left_w = (p.x - content.x1) - SPLIT_DIVIDER_W / 2; + if(left_w < SPLIT_MIN_PANE) left_w = SPLIT_MIN_PANE; + if(left_w > avail - SPLIT_MIN_PANE) left_w = avail - SPLIT_MIN_PANE; + + lv_obj_set_width(pane_left, left_w); +} + +/** + * @title Split view with a draggable divider + * @brief Two panes separated by a divider you can drag to resize them. + * + * A flex row holds a left pane (fixed width), a draggable divider, and a right + * pane that grows to fill the rest. Dragging the divider updates the left + * pane's width; the right pane follows automatically. A minimum width keeps + * either pane from collapsing. No custom widget is needed - just a flex + * container and a pointer event handler on the divider. + */ +void lv_example_split(void) +{ + lv_obj_t * cont = lv_obj_create(lv_screen_active()); + lv_obj_set_size(cont, lv_pct(100), lv_pct(100)); + lv_obj_remove_flag(cont, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_set_style_pad_all(cont, 0, 0); + lv_obj_set_style_border_width(cont, 0, 0); + lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW); + + /* Left pane: fixed width (changes while dragging) */ + lv_obj_t * pane_left = lv_obj_create(cont); + lv_obj_set_height(pane_left, lv_pct(100)); + lv_obj_set_width(pane_left, lv_pct(50)); + lv_obj_set_style_bg_color(pane_left, lv_color_hex(0xe8f0fe), 0); + lv_obj_t * label_left = lv_label_create(pane_left); + lv_label_set_text(label_left, "Left\n(drag the divider)"); + lv_obj_center(label_left); + + /* Divider: the draggable handle */ + lv_obj_t * divider = lv_obj_create(cont); + lv_obj_set_size(divider, SPLIT_DIVIDER_W, lv_pct(100)); + lv_obj_remove_flag(divider, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_add_flag(divider, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_style_radius(divider, 0, 0); + lv_obj_set_style_border_width(divider, 0, 0); + lv_obj_set_style_bg_color(divider, lv_palette_main(LV_PALETTE_GREY), 0); + lv_obj_add_event_cb(divider, splitter_pressing_cb, LV_EVENT_PRESSING, NULL); + + /* Right pane: grows to fill the remaining space */ + lv_obj_t * pane_right = lv_obj_create(cont); + lv_obj_set_height(pane_right, lv_pct(100)); + lv_obj_set_flex_grow(pane_right, 1); + lv_obj_set_style_bg_color(pane_right, lv_color_hex(0xe6f4ea), 0); + lv_obj_t * label_right = lv_label_create(pane_right); + lv_label_set_text(label_right, "Right"); + lv_obj_center(label_right); +} + +#endif diff --git a/examples/layouts/split/lv_example_split.h b/examples/layouts/split/lv_example_split.h new file mode 100644 index 0000000000..80a44295c9 --- /dev/null +++ b/examples/layouts/split/lv_example_split.h @@ -0,0 +1,20 @@ +/** + * @file lv_example_split.h + * + */ + +#ifndef LV_EXAMPLE_SPLIT_H +#define LV_EXAMPLE_SPLIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +void lv_example_split(void); +void lv_example_split_vertical(void); + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_EXAMPLE_SPLIT_H*/ diff --git a/examples/layouts/split/lv_example_split_vertical.c b/examples/layouts/split/lv_example_split_vertical.c new file mode 100644 index 0000000000..bf0dbf25fc --- /dev/null +++ b/examples/layouts/split/lv_example_split_vertical.c @@ -0,0 +1,83 @@ +/** + * @file lv_example_split_vertical.c + */ + +#include "../../lv_examples.h" +#if LV_USE_FLEX && LV_BUILD_EXAMPLES + +#define SPLIT_DIVIDER_H 12 +#define SPLIT_MIN_PANE 60 + +/* Drag the divider: resize the top pane; the bottom pane grows to fill the rest. */ +static void splitter_pressing_v_cb(lv_event_t * e) +{ + lv_obj_t * divider = lv_event_get_target_obj(e); + lv_obj_t * cont = lv_obj_get_parent(divider); + lv_obj_t * pane_top = lv_obj_get_child(cont, 0); + + lv_indev_t * indev = lv_indev_active(); + if(indev == NULL) return; + + lv_point_t p; + lv_indev_get_point(indev, &p); + + lv_area_t content; + lv_obj_get_content_coords(cont, &content); + int32_t avail = lv_area_get_height(&content) - SPLIT_DIVIDER_H; + if(avail <= 2 * SPLIT_MIN_PANE) return; + + int32_t top_h = (p.y - content.y1) - SPLIT_DIVIDER_H / 2; + if(top_h < SPLIT_MIN_PANE) top_h = SPLIT_MIN_PANE; + if(top_h > avail - SPLIT_MIN_PANE) top_h = avail - SPLIT_MIN_PANE; + + lv_obj_set_height(pane_top, top_h); +} + +/** + * @title Vertical split view with a draggable divider + * @brief Two stacked panes separated by a divider you can drag to resize them. + * + * Same idea as the horizontal split, but arranged in a flex column: a top pane + * (fixed height), a draggable divider, and a bottom pane that grows to fill the + * rest. Dragging the divider updates the top pane's height; the bottom pane + * follows. A minimum height keeps either pane from collapsing. + */ +void lv_example_split_vertical(void) +{ + lv_obj_t * cont = lv_obj_create(lv_screen_active()); + lv_obj_set_size(cont, lv_pct(100), lv_pct(100)); + lv_obj_remove_flag(cont, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_set_style_pad_all(cont, 0, 0); + lv_obj_set_style_border_width(cont, 0, 0); + lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN); + + /* Top pane: fixed height (changes while dragging) */ + lv_obj_t * pane_top = lv_obj_create(cont); + lv_obj_set_width(pane_top, lv_pct(100)); + lv_obj_set_height(pane_top, lv_pct(50)); + lv_obj_set_style_bg_color(pane_top, lv_color_hex(0xe8f0fe), 0); + lv_obj_t * label_top = lv_label_create(pane_top); + lv_label_set_text(label_top, "Top\n(drag the divider)"); + lv_obj_center(label_top); + + /* Divider: the draggable handle */ + lv_obj_t * divider = lv_obj_create(cont); + lv_obj_set_size(divider, lv_pct(100), SPLIT_DIVIDER_H); + lv_obj_remove_flag(divider, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_add_flag(divider, LV_OBJ_FLAG_CLICKABLE); + lv_obj_set_style_radius(divider, 0, 0); + lv_obj_set_style_border_width(divider, 0, 0); + lv_obj_set_style_bg_color(divider, lv_palette_main(LV_PALETTE_GREY), 0); + lv_obj_add_event_cb(divider, splitter_pressing_v_cb, LV_EVENT_PRESSING, NULL); + + /* Bottom pane: grows to fill the remaining space */ + lv_obj_t * pane_bottom = lv_obj_create(cont); + lv_obj_set_width(pane_bottom, lv_pct(100)); + lv_obj_set_flex_grow(pane_bottom, 1); + lv_obj_set_style_bg_color(pane_bottom, lv_color_hex(0xe6f4ea), 0); + lv_obj_t * label_bottom = lv_label_create(pane_bottom); + lv_label_set_text(label_bottom, "Bottom"); + lv_obj_center(label_bottom); +} + +#endif