diff --git a/demos/stress/lv_demo_stress.c b/demos/stress/lv_demo_stress.c index 470370035..cf699a36c 100644 --- a/demos/stress/lv_demo_stress.c +++ b/demos/stress/lv_demo_stress.c @@ -95,7 +95,8 @@ static void obj_test_task_cb(lv_timer_t * tmr) break; case 1: { - obj = lv_tabview_create(lv_screen_active(), LV_DIR_TOP, 50); + obj = lv_tabview_create(lv_screen_active()); + lv_tabview_set_tab_bar_size(obj, 50); lv_obj_set_size(obj, LV_HOR_RES / 2, LV_VER_RES / 2); lv_obj_align(obj, LV_ALIGN_BOTTOM_RIGHT, 0, 0); lv_obj_t * t = lv_tabview_add_tab(obj, "First"); diff --git a/demos/widgets/lv_demo_widgets.c b/demos/widgets/lv_demo_widgets.c index b2a9cdac0..808d34e27 100644 --- a/demos/widgets/lv_demo_widgets.c +++ b/demos/widgets/lv_demo_widgets.c @@ -177,33 +177,38 @@ void lv_demo_widgets(void) lv_style_set_border_width(&style_bullet, 0); lv_style_set_radius(&style_bullet, LV_RADIUS_CIRCLE); - tv = lv_tabview_create(lv_screen_active(), LV_DIR_TOP, tab_h); + tv = lv_tabview_create(lv_screen_active()); + lv_tabview_set_tab_bar_size(tv, tab_h); lv_obj_add_event(tv, tabview_delete_event_cb, LV_EVENT_DELETE, NULL); lv_obj_set_style_text_font(lv_screen_active(), font_normal, 0); + lv_obj_t * t1 = lv_tabview_add_tab(tv, "Profile"); + lv_obj_t * t2 = lv_tabview_add_tab(tv, "Analytics"); + lv_obj_t * t3 = lv_tabview_add_tab(tv, "Shop"); + if(disp_size == DISP_LARGE) { - lv_obj_t * tab_buttons = lv_tabview_get_tab_buttons(tv); - lv_obj_set_style_pad_left(tab_buttons, LV_HOR_RES / 2, 0); - lv_obj_t * logo = lv_image_create(tab_buttons); + lv_obj_t * tab_bar = lv_tabview_get_tab_bar(tv); + lv_obj_set_style_pad_left(tab_bar, LV_HOR_RES / 2, 0); + lv_obj_t * logo = lv_image_create(tab_bar); + lv_obj_add_flag(logo, LV_OBJ_FLAG_IGNORE_LAYOUT); LV_IMAGE_DECLARE(img_lvgl_logo); lv_image_set_src(logo, &img_lvgl_logo); lv_obj_align(logo, LV_ALIGN_LEFT_MID, -LV_HOR_RES / 2 + 25, 0); - lv_obj_t * label = lv_label_create(tab_buttons); + lv_obj_t * label = lv_label_create(tab_bar); lv_obj_add_style(label, &style_title, 0); + lv_obj_add_flag(label, LV_OBJ_FLAG_IGNORE_LAYOUT); lv_label_set_text_fmt(label, "LVGL v%d.%d.%d", lv_version_major(), lv_version_minor(), lv_version_patch()); lv_obj_align_to(label, logo, LV_ALIGN_OUT_RIGHT_TOP, 10, 0); - label = lv_label_create(tab_buttons); + label = lv_label_create(tab_bar); lv_label_set_text(label, "Widgets demo"); + lv_obj_add_flag(label, LV_OBJ_FLAG_IGNORE_LAYOUT); lv_obj_add_style(label, &style_text_muted, 0); lv_obj_align_to(label, logo, LV_ALIGN_OUT_RIGHT_BOTTOM, 10, 0); } - lv_obj_t * t1 = lv_tabview_add_tab(tv, "Profile"); - lv_obj_t * t2 = lv_tabview_add_tab(tv, "Analytics"); - lv_obj_t * t3 = lv_tabview_add_tab(tv, "Shop"); profile_create(t1); analytics_create(t2); shop_create(t3); diff --git a/docs/ROADMAP.rst b/docs/ROADMAP.rst index 7c1d50103..c92ba147d 100644 --- a/docs/ROADMAP.rst +++ b/docs/ROADMAP.rst @@ -52,12 +52,14 @@ Architecture - |check| Replace the `read_line_cb` of the image decoders with `get_area_cb` - |check| Limit the image caching size in bytes instead of image count - |check| lv_draw_buf for unified stride, buffer and cache invalidation management. `4241 `__ +- |check| Add vector graphics support via ThorVG - |uncheck| SVG support: integrate an SVG render library `4388 `__ - |check| Introduce optional ``float`` support. `4648 `__ - |uncheck| Introduce support layer for 3D GPUs (OpenGL, SDL, Vulkan, etc). `4622 `__ Styles ~~~~~~ + - |check| non-uniform scale of images: scale width and height differently - |uncheck| Scroll anim settings should come from styles to allow customization @@ -67,9 +69,7 @@ Widgets - |check| Universal scale widget/support - |check| `lv_img`: Reconsider image sizing models (when the image size is not content): center, top-left, zoom, tile, other? -- |uncheck| `lv_tabview` Replace button matrix with real buttons for more flexibility -- |uncheck| `lv_label` reconsider label long modes. (support min/max-width/height too) #3420 -- |uncheck| `lv_roller` make it more flexible #4009 +- |check| `lv_tabview` Replace button matrix with real buttons for more flexibility (see `here `__ and #4043) - |check| Disabled widgets should absorb indev actions without sending events. `#3860 `__ @@ -141,6 +141,8 @@ Widgets - |uncheck| `lv_bar`, `lv_arc`: handle max < min for fill direction swapping #4039 - |uncheck| `lv_bar`, `lv_slider`, `lv_arc`: make possible to move the knob only inside the background (see `here `__) - |uncheck| Improve `lv_label_align_t` #1656 +- |uncheck| `lv_label` reconsider label long modes. (support min/max-width/height too) #3420 +- |uncheck| `lv_roller` make it more flexible #4009 Others ~~~~~~ diff --git a/examples/widgets/slider/lv_example_slider_1.c b/examples/widgets/slider/lv_example_slider_1.c index 0c8acf6ec..bad320f0b 100644 --- a/examples/widgets/slider/lv_example_slider_1.c +++ b/examples/widgets/slider/lv_example_slider_1.c @@ -14,6 +14,7 @@ void lv_example_slider_1(void) lv_obj_center(slider); lv_obj_add_event(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL); + lv_obj_set_style_anim_time(slider, 2000, 0); /*Create a label below the slider*/ slider_label = lv_label_create(lv_screen_active()); lv_label_set_text(slider_label, "0%"); diff --git a/examples/widgets/tabview/lv_example_tabview_1.c b/examples/widgets/tabview/lv_example_tabview_1.c index c37cb520a..fe84d71ea 100644 --- a/examples/widgets/tabview/lv_example_tabview_1.c +++ b/examples/widgets/tabview/lv_example_tabview_1.c @@ -5,7 +5,7 @@ void lv_example_tabview_1(void) { /*Create a Tab view object*/ lv_obj_t * tabview; - tabview = lv_tabview_create(lv_screen_active(), LV_DIR_TOP, 50); + tabview = lv_tabview_create(lv_screen_active()); /*Add 3 tabs (the tabs are page (lv_page) and can be scrolled*/ lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); diff --git a/examples/widgets/tabview/lv_example_tabview_2.c b/examples/widgets/tabview/lv_example_tabview_2.c index 346fc13a6..7585b3f31 100644 --- a/examples/widgets/tabview/lv_example_tabview_2.c +++ b/examples/widgets/tabview/lv_example_tabview_2.c @@ -1,15 +1,18 @@ #include "../../lv_examples.h" #if LV_USE_TABVIEW && LV_BUILD_EXAMPLES +/*A vertical tab view with disabled scrolling and some styling*/ void lv_example_tabview_2(void) { /*Create a Tab view object*/ lv_obj_t * tabview; - tabview = lv_tabview_create(lv_screen_active(), LV_DIR_LEFT, 80); + tabview = lv_tabview_create(lv_screen_active()); + lv_tabview_set_tab_position(tabview, LV_DIR_LEFT); + lv_tabview_set_tab_bar_size(tabview, 80); lv_obj_set_style_bg_color(tabview, lv_palette_lighten(LV_PALETTE_RED, 2), 0); - lv_obj_t * tab_buttons = lv_tabview_get_tab_buttons(tabview); + lv_obj_t * tab_buttons = lv_tabview_get_tab_bar(tabview); lv_obj_set_style_bg_color(tab_buttons, lv_palette_darken(LV_PALETTE_GREY, 3), 0); lv_obj_set_style_text_color(tab_buttons, lv_palette_lighten(LV_PALETTE_GREY, 5), 0); lv_obj_set_style_border_side(tab_buttons, LV_BORDER_SIDE_RIGHT, LV_PART_ITEMS | LV_STATE_CHECKED); diff --git a/src/themes/default/lv_theme_default.c b/src/themes/default/lv_theme_default.c index 51f44aaa0..ef496cde7 100644 --- a/src/themes/default/lv_theme_default.c +++ b/src/themes/default/lv_theme_default.c @@ -608,6 +608,7 @@ static void style_init(struct _my_theme_t * theme) lv_style_set_border_color(&theme->styles.tab_btn, theme->base.color_primary); lv_style_set_border_width(&theme->styles.tab_btn, BORDER_WIDTH * 2); lv_style_set_border_side(&theme->styles.tab_btn, LV_BORDER_SIDE_BOTTOM); + lv_style_set_pad_top(&theme->styles.tab_btn, BORDER_WIDTH * 2); style_init_reset(&theme->styles.tab_bg_focus); lv_style_set_outline_pad(&theme->styles.tab_bg_focus, -BORDER_WIDTH); @@ -758,11 +759,18 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj) #if LV_USE_TABVIEW lv_obj_t * parent = lv_obj_get_parent(obj); /*Tabview content area*/ - if(lv_obj_check_type(parent, &lv_tabview_class)) { + if(parent && lv_obj_check_type(parent, &lv_tabview_class) && lv_obj_get_index(obj) == 1) { + return; + } + /*Tabview button container*/ + else if(lv_obj_check_type(parent, &lv_tabview_class) && lv_obj_get_index(obj) == 0) { + lv_obj_add_style(obj, &theme->styles.bg_color_white, 0); + lv_obj_add_style(obj, &theme->styles.outline_primary, LV_STATE_FOCUS_KEY); + lv_obj_add_style(obj, &theme->styles.tab_bg_focus, LV_STATE_FOCUS_KEY); return; } /*Tabview pages*/ - else if(lv_obj_check_type(lv_obj_get_parent(parent), &lv_tabview_class)) { + else if(parent && lv_obj_check_type(lv_obj_get_parent(parent), &lv_tabview_class)) { lv_obj_add_style(obj, &theme->styles.pad_normal, 0); lv_obj_add_style(obj, &theme->styles.scrollbar, LV_PART_SCROLLBAR); lv_obj_add_style(obj, &theme->styles.scrollbar_scrolled, LV_PART_SCROLLBAR | LV_STATE_SCROLLED); @@ -800,6 +808,20 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj) } #if LV_USE_BTN else if(lv_obj_check_type(obj, &lv_button_class)) { + +#if LV_USE_TABVIEW + lv_obj_t * parent = lv_obj_get_parent(obj); + if(parent && lv_obj_check_type(lv_obj_get_parent(parent), &lv_tabview_class)) { + lv_obj_add_style(obj, &theme->styles.pressed, LV_STATE_PRESSED); + lv_obj_add_style(obj, &theme->styles.bg_color_primary_muted, LV_STATE_CHECKED); + lv_obj_add_style(obj, &theme->styles.tab_btn, LV_STATE_CHECKED); + lv_obj_add_style(obj, &theme->styles.outline_primary, LV_STATE_FOCUS_KEY); + lv_obj_add_style(obj, &theme->styles.outline_secondary, LV_STATE_EDITED); + lv_obj_add_style(obj, &theme->styles.tab_bg_focus, LV_STATE_FOCUS_KEY); + return; + } + +#endif lv_obj_add_style(obj, &theme->styles.btn, 0); lv_obj_add_style(obj, &theme->styles.bg_color_primary, 0); lv_obj_add_style(obj, &theme->styles.transition_delayed, 0); @@ -843,20 +865,6 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj) return; } #endif -#if LV_USE_TABVIEW - if(lv_obj_check_type(lv_obj_get_parent(obj), &lv_tabview_class)) { - lv_obj_add_style(obj, &theme->styles.bg_color_white, 0); - lv_obj_add_style(obj, &theme->styles.outline_primary, LV_STATE_FOCUS_KEY); - lv_obj_add_style(obj, &theme->styles.tab_bg_focus, LV_STATE_FOCUS_KEY); - lv_obj_add_style(obj, &theme->styles.pressed, LV_PART_ITEMS | LV_STATE_PRESSED); - lv_obj_add_style(obj, &theme->styles.bg_color_primary_muted, LV_PART_ITEMS | LV_STATE_CHECKED); - lv_obj_add_style(obj, &theme->styles.tab_btn, LV_PART_ITEMS | LV_STATE_CHECKED); - lv_obj_add_style(obj, &theme->styles.outline_primary, LV_PART_ITEMS | LV_STATE_FOCUS_KEY); - lv_obj_add_style(obj, &theme->styles.outline_secondary, LV_PART_ITEMS | LV_STATE_EDITED); - lv_obj_add_style(obj, &theme->styles.tab_bg_focus, LV_PART_ITEMS | LV_STATE_FOCUS_KEY); - return; - } -#endif #if LV_USE_CALENDAR if(lv_obj_check_type(lv_obj_get_parent(obj), &lv_calendar_class)) { diff --git a/src/widgets/tabview/lv_tabview.c b/src/widgets/tabview/lv_tabview.c index 829fde18e..b9d850147 100644 --- a/src/widgets/tabview/lv_tabview.c +++ b/src/widgets/tabview/lv_tabview.c @@ -25,9 +25,8 @@ * STATIC PROTOTYPES **********************/ static void lv_tabview_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); -static void lv_tabview_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_tabview_event(const lv_obj_class_t * class_p, lv_event_t * e); -static void buttons_value_changed_event_cb(lv_event_t * e); +static void button_clicked_event_cb(lv_event_t * e); static void cont_scroll_end_event_cb(lv_event_t * e); /********************** @@ -35,7 +34,6 @@ static void cont_scroll_end_event_cb(lv_event_t * e); **********************/ const lv_obj_class_t lv_tabview_class = { .constructor_cb = lv_tabview_constructor, - .destructor_cb = lv_tabview_destructor, .event_cb = lv_tabview_event, .width_def = LV_PCT(100), .height_def = LV_PCT(100), @@ -49,9 +47,6 @@ typedef struct { int32_t tab_size; } lv_tabview_create_info_t; -// only used in lv_obj_class_create_obj, no affect multiple instances -static lv_tabview_create_info_t create_info; - /********************** * MACROS **********************/ @@ -60,11 +55,9 @@ static lv_tabview_create_info_t create_info; * GLOBAL FUNCTIONS **********************/ -lv_obj_t * lv_tabview_create(lv_obj_t * parent, lv_dir_t tab_pos, int32_t tab_size) +lv_obj_t * lv_tabview_create(lv_obj_t * parent) { LV_LOG_INFO("begin"); - create_info.tab_pos = tab_pos; - create_info.tab_size = tab_size; lv_obj_t * obj = lv_obj_class_create_obj(&lv_tabview_class, parent); lv_obj_class_init_obj(obj); @@ -74,138 +67,94 @@ lv_obj_t * lv_tabview_create(lv_obj_t * parent, lv_dir_t tab_pos, int32_t tab_si lv_obj_t * lv_tabview_add_tab(lv_obj_t * obj, const char * name) { LV_ASSERT_OBJ(obj, MY_CLASS); - lv_tabview_t * tabview = (lv_tabview_t *)obj; lv_obj_t * cont = lv_tabview_get_content(obj); lv_obj_t * page = lv_obj_create(cont); - lv_obj_set_size(page, LV_PCT(100), LV_PCT(100)); - uint32_t tab_id = lv_obj_get_child_cnt(cont); + lv_obj_set_size(page, lv_pct(100), lv_pct(100)); + uint32_t tab_idx = lv_obj_get_child_cnt(cont); - lv_obj_t * buttons = lv_tabview_get_tab_buttons(obj); + lv_obj_t * tab_bar = lv_tabview_get_tab_bar(obj); - char ** old_map = tabview->map; - char ** new_map; + lv_obj_t * button = lv_button_create(tab_bar); + lv_obj_set_flex_grow(button, 1); + lv_obj_set_size(button, lv_pct(100), lv_pct(100)); + lv_obj_add_event(button, button_clicked_event_cb, LV_EVENT_CLICKED, NULL); + lv_group_t * g = lv_group_get_default(); + if(g) lv_group_add_obj(g, button); - /*top or bottom dir*/ - if(tabview->tab_pos & LV_DIR_VER) { - new_map = lv_malloc((tab_id + 1) * sizeof(const char *)); - lv_memcpy(new_map, old_map, sizeof(const char *) * (tab_id - 1)); - new_map[tab_id - 1] = lv_strdup(name); - LV_ASSERT_MALLOC(new_map[tab_id - 1]); - new_map[tab_id] = (char *)""; - } - /*left or right dir*/ - else { - new_map = lv_malloc((tab_id * 2) * sizeof(const char *)); - lv_memcpy(new_map, old_map, sizeof(const char *) * (tab_id - 1) * 2); - if(tabview->tab_cnt == 0) { - new_map[0] = lv_strdup(name); - LV_ASSERT_MALLOC(new_map[0]); - new_map[1] = (char *)""; - } - else { - new_map[tab_id * 2 - 3] = (char *)"\n"; - new_map[tab_id * 2 - 2] = lv_strdup(name); - new_map[tab_id * 2 - 1] = (char *)""; - } - } - tabview->map = new_map; - lv_buttonmatrix_set_map(buttons, (const char **)new_map); - lv_free(old_map); + lv_obj_t * label = lv_label_create(button); + lv_label_set_text(label, name); + lv_obj_center(label); - lv_buttonmatrix_set_button_ctrl_all(buttons, LV_BUTTONMATRIX_CTRL_CHECKABLE | LV_BUTTONMATRIX_CTRL_CLICK_TRIG | - LV_BUTTONMATRIX_CTRL_NO_REPEAT); - - tabview->tab_cnt++; - if(tabview->tab_cnt == 1) { + if(tab_idx == 1) { lv_tabview_set_active(obj, 0, LV_ANIM_OFF); } - lv_buttonmatrix_set_button_ctrl(buttons, tabview->tab_cur, LV_BUTTONMATRIX_CTRL_CHECKED); - return page; } -void lv_tabview_rename_tab(lv_obj_t * obj, uint32_t id, const char * new_name) +void lv_tabview_rename_tab(lv_obj_t * obj, uint32_t idx, const char * new_name) { LV_ASSERT_OBJ(obj, MY_CLASS); - lv_tabview_t * tabview = (lv_tabview_t *)obj; - if(id >= tabview->tab_cnt) return; - if(tabview->tab_pos & LV_DIR_HOR) id *= 2; - - lv_free(tabview->map[id]); - tabview->map[id] = lv_strdup(new_name); - LV_ASSERT_MALLOC(tabview->map[id]); - lv_obj_invalidate(obj); + lv_obj_t * tab_bar = lv_tabview_get_tab_bar(obj); + lv_obj_t * button = lv_obj_get_child_by_type(tab_bar, idx, &lv_button_class); + lv_obj_t * label = lv_obj_get_child_by_type(button, 0, &lv_label_class); + lv_label_set_text(label, new_name); } -void lv_tabview_set_active(lv_obj_t * obj, uint32_t id, lv_anim_enable_t anim_en) +void lv_tabview_set_active(lv_obj_t * obj, uint32_t idx, lv_anim_enable_t anim_en) { LV_ASSERT_OBJ(obj, MY_CLASS); lv_tabview_t * tabview = (lv_tabview_t *)obj; - if(id >= tabview->tab_cnt) { - id = tabview->tab_cnt - 1; + lv_obj_t * cont = lv_tabview_get_content(obj); + lv_obj_t * tab_bar = lv_tabview_get_tab_bar(obj); + + uint32_t tab_cnt = lv_tabview_get_tab_count(obj); + if(idx >= tab_cnt) { + idx = tab_cnt - 1; } /*To be sure lv_obj_get_content_width will return valid value*/ lv_obj_update_layout(obj); - lv_obj_t * cont = lv_tabview_get_content(obj); if(cont == NULL) return; if((tabview->tab_pos & LV_DIR_VER) != 0) { int32_t gap = lv_obj_get_style_pad_column(cont, LV_PART_MAIN); int32_t w = lv_obj_get_content_width(cont); if(lv_obj_get_style_base_dir(obj, LV_PART_MAIN) != LV_BASE_DIR_RTL) { - lv_obj_scroll_to_x(cont, id * (gap + w), anim_en); + lv_obj_scroll_to_x(cont, idx * (gap + w), anim_en); } else { - int32_t id_rtl = -(int32_t)id; + int32_t id_rtl = -(int32_t)idx; lv_obj_scroll_to_x(cont, (gap + w) * id_rtl, anim_en); } } else { int32_t gap = lv_obj_get_style_pad_row(cont, LV_PART_MAIN); int32_t h = lv_obj_get_content_height(cont); - lv_obj_scroll_to_y(cont, id * (gap + h), anim_en); + lv_obj_scroll_to_y(cont, idx * (gap + h), anim_en); } - lv_obj_t * buttons = lv_tabview_get_tab_buttons(obj); - lv_buttonmatrix_set_button_ctrl(buttons, id, LV_BUTTONMATRIX_CTRL_CHECKED); - tabview->tab_cur = id; + uint32_t i = 0; + lv_obj_t * button = lv_obj_get_child_by_type(tab_bar, i, &lv_button_class); + while(button) { + lv_obj_set_state(button, LV_STATE_CHECKED, i == idx); + i++; + button = lv_obj_get_child_by_type(tab_bar, (int32_t)i, &lv_button_class); + } + + tabview->tab_cur = idx; } -uint32_t lv_tabview_get_tab_active(lv_obj_t * obj) +void lv_tabview_set_tab_position(lv_obj_t * obj, lv_dir_t dir) { LV_ASSERT_OBJ(obj, MY_CLASS); lv_tabview_t * tabview = (lv_tabview_t *)obj; - return tabview->tab_cur; -} -lv_obj_t * lv_tabview_get_content(lv_obj_t * tv) -{ - return lv_obj_get_child(tv, 1); -} - -lv_obj_t * lv_tabview_get_tab_buttons(lv_obj_t * tv) -{ - return lv_obj_get_child(tv, 0); -} - -/********************** - * STATIC FUNCTIONS - **********************/ - -static void lv_tabview_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) -{ - LV_UNUSED(class_p); - lv_tabview_t * tabview = (lv_tabview_t *)obj; - - tabview->tab_pos = create_info.tab_pos; - - switch(tabview->tab_pos) { + switch(dir) { case LV_DIR_TOP: lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_COLUMN); break; @@ -220,75 +169,108 @@ static void lv_tabview_constructor(const lv_obj_class_t * class_p, lv_obj_t * ob break; } - lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100)); + lv_obj_t * tab_bar = lv_tabview_get_tab_bar(obj); + lv_obj_t * cont = lv_tabview_get_content(obj); - lv_obj_t * btnm; - lv_obj_t * cont; - - btnm = lv_buttonmatrix_create(obj); - cont = lv_obj_create(obj); - - lv_buttonmatrix_set_one_checked(btnm, true); - tabview->map = lv_malloc(sizeof(const char *)); - tabview->map[0] = (char *)""; - lv_buttonmatrix_set_map(btnm, (const char **)tabview->map); - lv_obj_add_event(btnm, buttons_value_changed_event_cb, LV_EVENT_VALUE_CHANGED, NULL); - lv_obj_add_flag(btnm, LV_OBJ_FLAG_EVENT_BUBBLE); - - lv_obj_add_event(cont, cont_scroll_end_event_cb, LV_EVENT_ALL, NULL); - lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_OFF); - - switch(tabview->tab_pos) { + switch(dir) { case LV_DIR_TOP: case LV_DIR_BOTTOM: - lv_obj_set_size(btnm, LV_PCT(100), create_info.tab_size); lv_obj_set_width(cont, LV_PCT(100)); lv_obj_set_flex_grow(cont, 1); + lv_obj_set_flex_flow(tab_bar, LV_FLEX_FLOW_ROW); + lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW); + lv_obj_set_scroll_snap_x(cont, LV_SCROLL_SNAP_CENTER); + lv_obj_set_scroll_snap_y(cont, LV_SCROLL_SNAP_NONE); break; case LV_DIR_LEFT: case LV_DIR_RIGHT: - lv_obj_set_size(btnm, create_info.tab_size, LV_PCT(100)); lv_obj_set_height(cont, LV_PCT(100)); lv_obj_set_flex_grow(cont, 1); + lv_obj_set_flex_flow(tab_bar, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN); + lv_obj_set_scroll_snap_x(cont, LV_SCROLL_SNAP_NONE); + lv_obj_set_scroll_snap_y(cont, LV_SCROLL_SNAP_CENTER); break; } - lv_group_t * g = lv_group_get_default(); - if(g) lv_group_add_obj(g, btnm); + bool was_ver = tabview->tab_pos & LV_DIR_VER; + bool now_ver = dir & LV_DIR_VER; - if((tabview->tab_pos & LV_DIR_VER) != 0) { - lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW); - lv_obj_set_scroll_snap_x(cont, LV_SCROLL_SNAP_CENTER); + if(was_ver != now_ver) { + int32_t dpi = lv_display_get_dpi(lv_obj_get_disp(obj)); + if(now_ver) { + lv_obj_set_size(tab_bar, lv_pct(100), dpi / 2); + } + else { + lv_obj_set_size(tab_bar, dpi, lv_pct(100)); + } } - else { - lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN); - lv_obj_set_scroll_snap_y(cont, LV_SCROLL_SNAP_CENTER); - } - lv_obj_add_flag(cont, LV_OBJ_FLAG_SCROLL_ONE); - lv_obj_remove_flag(cont, LV_OBJ_FLAG_SCROLL_ON_FOCUS); + tabview->tab_pos = dir; } -static void lv_tabview_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) +void lv_tabview_set_tab_bar_size(lv_obj_t * obj, int32_t size) +{ + LV_ASSERT_OBJ(obj, MY_CLASS); + lv_tabview_t * tabview = (lv_tabview_t *)obj; + + lv_obj_t * tab_bar = lv_tabview_get_tab_bar(obj); + if(tabview->tab_pos & LV_DIR_VER) { + lv_obj_set_height(tab_bar, size); + } + else { + lv_obj_set_width(tab_bar, size); + } + +} + +uint32_t lv_tabview_get_tab_active(lv_obj_t * obj) +{ + LV_ASSERT_OBJ(obj, MY_CLASS); + lv_tabview_t * tabview = (lv_tabview_t *)obj; + return tabview->tab_cur; +} + +uint32_t lv_tabview_get_tab_count(lv_obj_t * obj) +{ + LV_ASSERT_OBJ(obj, MY_CLASS); + lv_obj_t * tab_bar = lv_tabview_get_tab_bar(obj); + return lv_obj_get_child_count_by_type(tab_bar, &lv_button_class); +} + +lv_obj_t * lv_tabview_get_content(lv_obj_t * tv) +{ + return lv_obj_get_child(tv, 1); +} + +lv_obj_t * lv_tabview_get_tab_bar(lv_obj_t * tv) +{ + return lv_obj_get_child(tv, 0); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void lv_tabview_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) { LV_UNUSED(class_p); lv_tabview_t * tabview = (lv_tabview_t *)obj; + tabview->tab_pos = LV_DIR_NONE; /*Invalid value to apply the default TOP direction correctly*/ - uint32_t i; - if(tabview->tab_pos & LV_DIR_VER) { - for(i = 0; i < tabview->tab_cnt; i++) { - lv_free(tabview->map[i]); - tabview->map[i] = NULL; - } - } - if(tabview->tab_pos & LV_DIR_HOR) { - for(i = 0; i < tabview->tab_cnt; i++) { - lv_free(tabview->map[i * 2]); - tabview->map[i * 2] = NULL; - } - } + lv_obj_set_size(obj, LV_PCT(100), LV_PCT(100)); - lv_free(tabview->map); - tabview->map = NULL; + lv_obj_t * cont; + + lv_obj_create(obj); + cont = lv_obj_create(obj); + lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW); + + lv_obj_add_event(cont, cont_scroll_end_event_cb, LV_EVENT_ALL, NULL); + lv_obj_set_scrollbar_mode(cont, LV_SCROLLBAR_MODE_OFF); + lv_tabview_set_tab_position(obj, LV_DIR_TOP); + + lv_obj_add_flag(cont, LV_OBJ_FLAG_SCROLL_ONE); + lv_obj_remove_flag(cont, LV_OBJ_FLAG_SCROLL_ON_FOCUS); } static void lv_tabview_event(const lv_obj_class_t * class_p, lv_event_t * e) @@ -305,13 +287,13 @@ static void lv_tabview_event(const lv_obj_class_t * class_p, lv_event_t * e) } } -static void buttons_value_changed_event_cb(lv_event_t * e) +static void button_clicked_event_cb(lv_event_t * e) { - lv_obj_t * buttons = lv_event_get_target(e); + lv_obj_t * button = lv_event_get_target(e); - lv_obj_t * tv = lv_obj_get_parent(buttons); - uint32_t id = lv_buttonmatrix_get_selected_button(buttons); - lv_tabview_set_active(tv, id, LV_ANIM_OFF); + lv_obj_t * tv = lv_obj_get_parent(lv_obj_get_parent(button)); + int32_t idx = lv_obj_get_index_by_type(button, &lv_button_class); + lv_tabview_set_active(tv, idx, LV_ANIM_OFF); } static void cont_scroll_end_event_cb(lv_event_t * e) diff --git a/src/widgets/tabview/lv_tabview.h b/src/widgets/tabview/lv_tabview.h index 3bfe738be..b04d441a2 100644 --- a/src/widgets/tabview/lv_tabview.h +++ b/src/widgets/tabview/lv_tabview.h @@ -27,8 +27,6 @@ extern "C" { typedef struct { lv_obj_t obj; - char ** map; - uint32_t tab_cnt; uint32_t tab_cur; lv_dir_t tab_pos; } lv_tabview_t; @@ -38,20 +36,29 @@ LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_tabview_class; /********************** * GLOBAL PROTOTYPES **********************/ -lv_obj_t * lv_tabview_create(lv_obj_t * parent, lv_dir_t tab_pos, int32_t tab_size); + +lv_obj_t * lv_tabview_create(lv_obj_t * parent); lv_obj_t * lv_tabview_add_tab(lv_obj_t * tv, const char * name); void lv_tabview_rename_tab(lv_obj_t * obj, uint32_t tab_id, const char * new_name); -lv_obj_t * lv_tabview_get_content(lv_obj_t * tv); - -lv_obj_t * lv_tabview_get_tab_buttons(lv_obj_t * tv); - void lv_tabview_set_active(lv_obj_t * obj, uint32_t id, lv_anim_enable_t anim_en); +void lv_tabview_set_tab_position(lv_obj_t * obj, lv_dir_t dir); + +void lv_tabview_set_tab_bar_size(lv_obj_t * obj, int32_t size); + +uint32_t lv_tabview_get_tab_count(lv_obj_t * tv); + uint32_t lv_tabview_get_tab_active(lv_obj_t * tv); +uint32_t lv_tabview_get_tab_count(lv_obj_t * tv); + +lv_obj_t * lv_tabview_get_content(lv_obj_t * tv); + +lv_obj_t * lv_tabview_get_tab_bar(lv_obj_t * tv); + /********************** * MACROS **********************/ diff --git a/tests/ref_imgs/widgets/tabview_05.png b/tests/ref_imgs/widgets/tabview_05.png index c04457a33..81b1194cc 100644 Binary files a/tests/ref_imgs/widgets/tabview_05.png and b/tests/ref_imgs/widgets/tabview_05.png differ diff --git a/tests/ref_imgs/widgets/tabview_06.png b/tests/ref_imgs/widgets/tabview_06.png index db6e15375..3f892ba71 100644 Binary files a/tests/ref_imgs/widgets/tabview_06.png and b/tests/ref_imgs/widgets/tabview_06.png differ diff --git a/tests/ref_imgs/widgets/tabview_07.png b/tests/ref_imgs/widgets/tabview_07.png index a3b4fa6ff..d5ba73297 100644 Binary files a/tests/ref_imgs/widgets/tabview_07.png and b/tests/ref_imgs/widgets/tabview_07.png differ diff --git a/tests/ref_imgs/widgets/tabview_08.png b/tests/ref_imgs/widgets/tabview_08.png index 0aa9189ab..ec0e6a8a2 100644 Binary files a/tests/ref_imgs/widgets/tabview_08.png and b/tests/ref_imgs/widgets/tabview_08.png differ diff --git a/tests/ref_imgs/widgets/tabview_09.png b/tests/ref_imgs/widgets/tabview_09.png index 754f6303c..d5ba73297 100644 Binary files a/tests/ref_imgs/widgets/tabview_09.png and b/tests/ref_imgs/widgets/tabview_09.png differ diff --git a/tests/ref_imgs/widgets/tabview_10.png b/tests/ref_imgs/widgets/tabview_10.png index 3be2a0334..4f22a90b5 100644 Binary files a/tests/ref_imgs/widgets/tabview_10.png and b/tests/ref_imgs/widgets/tabview_10.png differ diff --git a/tests/src/test_cases/widgets/test_tabview.c b/tests/src/test_cases/widgets/test_tabview.c index d45759772..bfa52a043 100644 --- a/tests/src/test_cases/widgets/test_tabview.c +++ b/tests/src/test_cases/widgets/test_tabview.c @@ -1,4 +1,4 @@ -#if LV_BUILD_TEST +#if LV_BUILD_TEST || 1 #include "../lvgl.h" #include "unity/unity.h" @@ -18,7 +18,7 @@ void test_tabview_add_several_tabs_no_scroll(void); void test_tabview_rename_tab(void); void test_tabview_add_several_tabs_hor(void); void test_tabview_get_content(void); -void test_tabview_get_tab_buttons(void); +void test_tabview_get_tab_bar(void); void test_tabview_set_act_non_existent(void); void test_tabview_tab2_selected_event(void); void test_tabview_update_on_external_scroll(void); @@ -38,7 +38,8 @@ void tearDown(void) void test_tabview_create_successful_dir_top(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_bar_size(tabview, 50); TEST_ASSERT_NOT_NULL(tabview); @@ -47,7 +48,9 @@ void test_tabview_create_successful_dir_top(void) void test_tabview_create_successful_dir_bottom(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_BOTTOM, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_BOTTOM); + lv_tabview_set_tab_bar_size(tabview, 50); TEST_ASSERT_NOT_NULL(tabview); @@ -56,7 +59,9 @@ void test_tabview_create_successful_dir_bottom(void) void test_tabview_create_successful_dir_left(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_LEFT, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_LEFT); + lv_tabview_set_tab_bar_size(tabview, 50); TEST_ASSERT_NOT_NULL(tabview); @@ -65,7 +70,9 @@ void test_tabview_create_successful_dir_left(void) void test_tabview_create_successful_dir_right(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_RIGHT, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_RIGHT); + lv_tabview_set_tab_bar_size(tabview, 50); TEST_ASSERT_NOT_NULL(tabview); @@ -74,7 +81,9 @@ void test_tabview_create_successful_dir_right(void) void test_tabview_add_one_tab_empty(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_TOP); + lv_tabview_set_tab_bar_size(tabview, 50); lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); @@ -83,7 +92,9 @@ void test_tabview_add_one_tab_empty(void) void test_tabview_add_one_tab_empty_hor(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_LEFT, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_LEFT); + lv_tabview_set_tab_bar_size(tabview, 50); lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); @@ -92,7 +103,9 @@ void test_tabview_add_one_tab_empty_hor(void) void test_tabview_add_one_tab_no_scroll(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_TOP); + lv_tabview_set_tab_bar_size(tabview, 50); lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); @@ -105,7 +118,9 @@ void test_tabview_add_one_tab_no_scroll(void) void test_tabview_add_one_tab_with_scroll(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_TOP); + lv_tabview_set_tab_bar_size(tabview, 50); lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); @@ -131,7 +146,9 @@ void test_tabview_add_one_tab_with_scroll(void) void test_tabview_add_several_tabs_no_scroll(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_TOP); + lv_tabview_set_tab_bar_size(tabview, 50); lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); lv_obj_t * tab2 = lv_tabview_add_tab(tabview, "Tab 2"); @@ -149,7 +166,9 @@ void test_tabview_add_several_tabs_no_scroll(void) void test_tabview_rename_tab(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_TOP); + lv_tabview_set_tab_bar_size(tabview, 50); lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); lv_obj_t * tab2 = lv_tabview_add_tab(tabview, "Tab 2"); @@ -168,7 +187,9 @@ void test_tabview_rename_tab(void) void test_tabview_add_several_tabs_hor(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_LEFT, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_TOP); + lv_tabview_set_tab_bar_size(tabview, 50); lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); lv_obj_t * tab2 = lv_tabview_add_tab(tabview, "Tab 2"); @@ -186,25 +207,25 @@ void test_tabview_add_several_tabs_hor(void) void test_tabview_get_content(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); lv_obj_t * content = lv_tabview_get_content(tabview); TEST_ASSERT_NOT_NULL(content); } -void test_tabview_get_tab_buttons(void) +void test_tabview_get_tab_bar(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); - lv_obj_t * buttons = lv_tabview_get_tab_buttons(tabview); + lv_obj_t * tab_bar = lv_tabview_get_tab_bar(tabview); - TEST_ASSERT_NOT_NULL(buttons); + TEST_ASSERT_NOT_NULL(tab_bar); } void test_tabview_set_act_non_existent(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); lv_tabview_set_active(tabview, 1, LV_ANIM_ON); @@ -213,7 +234,9 @@ void test_tabview_set_act_non_existent(void) void test_tabview_tab2_selected_event(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_TOP); + lv_tabview_set_tab_bar_size(tabview, 50); lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); lv_obj_t * tab2 = lv_tabview_add_tab(tabview, "Tab 2"); @@ -229,7 +252,9 @@ void test_tabview_tab2_selected_event(void) void test_tabview_update_on_external_scroll(void) { - tabview = lv_tabview_create(active_screen, LV_DIR_TOP, 50); + tabview = lv_tabview_create(active_screen); + lv_tabview_set_tab_position(tabview, LV_DIR_TOP); + lv_tabview_set_tab_bar_size(tabview, 50); lv_obj_t * tab1 = lv_tabview_add_tab(tabview, "Tab 1"); lv_obj_t * tab2 = lv_tabview_add_tab(tabview, "Tab 2");