Description
Im working on building a UI for a 128 X 64 ssd1206 monochrome display working with an encoder, i´ve successfully added the encoder and made it work with 3 button, my main menu is composed of a container at the top with a label and at some point i will add a battery voltage, wifi rssi and lora rssi( this takes 1/3 of my screen), then on the other 2/3 i have a panel with buttons that i can scroll to select a different menu.
The problem that i have is that it works great with 3 buttons, when i add a 4th button it wont scroll through the menu, when i add 5 button it work great again, when i add 6+ buttons it starts doing strange stuff like changing the encoder direction and skipping buttons but the encoder can scroll.
What MCU/Processor/Board and compiler are you using?
- ESP32S3, (Heltek Lora v3.2)
- EEZ studio for debeloping the UI
- PlatformIO with arfuino framework
- Create the panel and buttons my self
- Use squerline studio to se if it made a diference
What do you want to achieve?
Figure out why it doesn’t work with 4 buttons, and start to fail again with 6 + buttons
What have you tried so far?
- Change flags in the panel and the buttons
- Instead of using a panel, using a container
- Change the height of the panel
- Change
Code to reproduce
this is the code that EZZ provided.
void create_screen_main_menu() {
void *flowState = getFlowState(0, 0);
(void)flowState;
lv_obj_t *obj = lv_obj_create(0);
objects.main_menu = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, 128, 64);
lv_obj_add_event_cb(obj, event_handler_cb_main_menu_main_menu, LV_EVENT_ALL, flowState);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
lv_obj_set_style_bg_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT);
{
lv_obj_t *parent_obj = obj;
{
// Header
lv_obj_t *obj = lv_obj_create(parent_obj);
objects.header = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, 128, 22);
lv_obj_set_style_pad_left(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_top(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_bottom(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_radius(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICK_FOCUSABLE|LV_OBJ_FLAG_GESTURE_BUBBLE|LV_OBJ_FLAG_PRESS_LOCK|LV_OBJ_FLAG_SCROLLABLE|LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_CHAIN_VER|LV_OBJ_FLAG_SCROLL_ELASTIC|LV_OBJ_FLAG_SCROLL_MOMENTUM|LV_OBJ_FLAG_SCROLL_WITH_ARROW|LV_OBJ_FLAG_SNAPPABLE);
lv_obj_set_style_border_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(obj, 1, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_side(obj, LV_BORDER_SIDE_BOTTOM, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(obj, &ui_font_pixelade_18, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_opa(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
{
lv_obj_t *parent_obj = obj;
{
// menuName
lv_obj_t *obj = lv_label_create(parent_obj);
objects.menu_name = obj;
lv_obj_set_pos(obj, 0, -1);
lv_obj_set_size(obj, 70, 23);
lv_label_set_long_mode(obj, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICK_FOCUSABLE|LV_OBJ_FLAG_GESTURE_BUBBLE|LV_OBJ_FLAG_PRESS_LOCK|LV_OBJ_FLAG_SCROLLABLE|LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_CHAIN_VER|LV_OBJ_FLAG_SCROLL_ELASTIC|LV_OBJ_FLAG_SCROLL_MOMENTUM|LV_OBJ_FLAG_SCROLL_WITH_ARROW|LV_OBJ_FLAG_SNAPPABLE);
lv_label_set_text(obj, "Main Menu");
}
}
}
{
// mainmenuPanel
lv_obj_t *obj = lv_obj_create(parent_obj);
objects.mainmenu_panel = obj;
lv_obj_set_pos(obj, 0, 22);
lv_obj_set_size(obj, 128, 42);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICKABLE|LV_OBJ_FLAG_CLICK_FOCUSABLE|LV_OBJ_FLAG_GESTURE_BUBBLE|LV_OBJ_FLAG_PRESS_LOCK|LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_ELASTIC|LV_OBJ_FLAG_SCROLL_MOMENTUM|LV_OBJ_FLAG_SCROLL_WITH_ARROW|LV_OBJ_FLAG_SNAPPABLE);
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_OFF);
lv_obj_set_scroll_dir(obj, LV_DIR_VER);
lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_CENTER);
lv_obj_set_scroll_snap_y(obj, LV_SCROLL_SNAP_CENTER);
lv_obj_set_style_layout(obj, LV_LAYOUT_FLEX, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_flow(obj, LV_FLEX_FLOW_COLUMN, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_main_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_row(obj, 6, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_grow(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_text_font(obj, &ui_font_pixelade_14, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(obj, 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_track_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_cross_place(obj, LV_FLEX_ALIGN_START, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_bg_color(obj, lv_color_hex(0xffffffff), LV_PART_SCROLLBAR | LV_STATE_DEFAULT);
{
lv_obj_t *parent_obj = obj;
{
// wifiButton
lv_obj_t *obj = lv_btn_create(parent_obj);
objects.wifi_button = obj;
lv_obj_set_pos(obj, 42, 14);
lv_obj_set_size(obj, 100, 16);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICK_FOCUSABLE|LV_OBJ_FLAG_GESTURE_BUBBLE|LV_OBJ_FLAG_PRESS_LOCK|LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_ELASTIC|LV_OBJ_FLAG_SCROLL_MOMENTUM|LV_OBJ_FLAG_SCROLL_WITH_ARROW|LV_OBJ_FLAG_SNAPPABLE);
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_OFF);
lv_obj_set_scroll_dir(obj, LV_DIR_NONE);
lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_CENTER);
lv_obj_set_scroll_snap_y(obj, LV_SCROLL_SNAP_NONE);
lv_obj_set_style_bg_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(obj, 1, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_radius(obj, 3, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_layout(obj, LV_LAYOUT_FLEX, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_flow(obj, LV_FLEX_FLOW_ROW, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_main_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_track_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_column(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_outline_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_translate_x(obj, -9, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_outline_opa(obj, 255, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_outline_width(obj, 1, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_outline_pad(obj, 3, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
{
lv_obj_t *parent_obj = obj;
{
// wifiIcon
lv_obj_t *obj = lv_img_create(parent_obj);
objects.wifi_icon = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, 16, 16);
lv_img_set_src(obj, &img_wifi);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_ADV_HITTEST|LV_OBJ_FLAG_CLICK_FOCUSABLE|LV_OBJ_FLAG_GESTURE_BUBBLE|LV_OBJ_FLAG_PRESS_LOCK|LV_OBJ_FLAG_SCROLLABLE|LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_CHAIN_VER|LV_OBJ_FLAG_SCROLL_ELASTIC|LV_OBJ_FLAG_SCROLL_MOMENTUM|LV_OBJ_FLAG_SCROLL_WITH_ARROW|LV_OBJ_FLAG_SNAPPABLE);
lv_obj_set_style_img_recolor_opa(obj, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_img_recolor(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
}
{
// wifiLabel
lv_obj_t *obj = lv_label_create(parent_obj);
objects.wifi_label = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_label_set_long_mode(obj, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(obj, "Wifi");
}
}
}
{
// loraButton
lv_obj_t *obj = lv_btn_create(parent_obj);
objects.lora_button = obj;
lv_obj_set_pos(obj, 42, 14);
lv_obj_set_size(obj, 100, 16);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICK_FOCUSABLE|LV_OBJ_FLAG_GESTURE_BUBBLE|LV_OBJ_FLAG_PRESS_LOCK|LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_ELASTIC|LV_OBJ_FLAG_SCROLL_MOMENTUM|LV_OBJ_FLAG_SCROLL_WITH_ARROW|LV_OBJ_FLAG_SNAPPABLE);
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_OFF);
lv_obj_set_scroll_dir(obj, LV_DIR_NONE);
lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_CENTER);
lv_obj_set_scroll_snap_y(obj, LV_SCROLL_SNAP_NONE);
lv_obj_set_style_bg_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(obj, 1, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_radius(obj, 3, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_layout(obj, LV_LAYOUT_FLEX, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_flow(obj, LV_FLEX_FLOW_ROW, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_main_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_track_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_column(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_outline_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_translate_x(obj, -9, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_outline_width(obj, 1, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_outline_opa(obj, 255, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_outline_pad(obj, 3, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
{
lv_obj_t *parent_obj = obj;
{
// loraIcon
lv_obj_t *obj = lv_img_create(parent_obj);
objects.lora_icon = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, 16, 16);
lv_img_set_src(obj, &img_lora2);
lv_img_set_zoom(obj, 200);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_ADV_HITTEST|LV_OBJ_FLAG_CLICK_FOCUSABLE|LV_OBJ_FLAG_GESTURE_BUBBLE|LV_OBJ_FLAG_PRESS_LOCK|LV_OBJ_FLAG_SCROLLABLE|LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_CHAIN_VER|LV_OBJ_FLAG_SCROLL_ELASTIC|LV_OBJ_FLAG_SCROLL_MOMENTUM|LV_OBJ_FLAG_SCROLL_WITH_ARROW|LV_OBJ_FLAG_SNAPPABLE);
lv_obj_set_style_img_recolor(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_img_recolor_opa(obj, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
}
{
// loraLabel
lv_obj_t *obj = lv_label_create(parent_obj);
objects.lora_label = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_label_set_long_mode(obj, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(obj, "LoRa");
}
}
}
{
// settingsButton
lv_obj_t *obj = lv_btn_create(parent_obj);
objects.settings_button = obj;
lv_obj_set_pos(obj, 42, 14);
lv_obj_set_size(obj, 100, 16);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_CLICK_FOCUSABLE|LV_OBJ_FLAG_GESTURE_BUBBLE|LV_OBJ_FLAG_PRESS_LOCK|LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_ELASTIC|LV_OBJ_FLAG_SCROLL_MOMENTUM|LV_OBJ_FLAG_SCROLL_WITH_ARROW|LV_OBJ_FLAG_SNAPPABLE);
lv_obj_set_scrollbar_mode(obj, LV_SCROLLBAR_MODE_OFF);
lv_obj_set_scroll_dir(obj, LV_DIR_NONE);
lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_CENTER);
lv_obj_set_scroll_snap_y(obj, LV_SCROLL_SNAP_NONE);
lv_obj_set_style_bg_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(obj, 1, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_radius(obj, 3, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_layout(obj, LV_LAYOUT_FLEX, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_flow(obj, LV_FLEX_FLOW_ROW, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_main_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_flex_track_place(obj, LV_FLEX_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_pad_column(obj, 10, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_outline_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_translate_x(obj, -9, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_outline_width(obj, 1, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_outline_opa(obj, 255, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
lv_obj_set_style_outline_pad(obj, 3, LV_PART_MAIN | LV_STATE_FOCUS_KEY);
{
lv_obj_t *parent_obj = obj;
{
// settingsIcon
lv_obj_t *obj = lv_img_create(parent_obj);
objects.settings_icon = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, 16, 16);
lv_img_set_src(obj, &img_settings);
lv_obj_clear_flag(obj, LV_OBJ_FLAG_ADV_HITTEST|LV_OBJ_FLAG_CLICK_FOCUSABLE|LV_OBJ_FLAG_GESTURE_BUBBLE|LV_OBJ_FLAG_PRESS_LOCK|LV_OBJ_FLAG_SCROLLABLE|LV_OBJ_FLAG_SCROLL_CHAIN_HOR|LV_OBJ_FLAG_SCROLL_CHAIN_VER|LV_OBJ_FLAG_SCROLL_ELASTIC|LV_OBJ_FLAG_SCROLL_MOMENTUM|LV_OBJ_FLAG_SCROLL_WITH_ARROW|LV_OBJ_FLAG_SNAPPABLE);
lv_obj_set_style_img_recolor_opa(obj, 255, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_img_recolor(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT);
}
{
// settingsLabel
lv_obj_t *obj = lv_label_create(parent_obj);
objects.settings_label = obj;
lv_obj_set_pos(obj, 0, 0);
lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_label_set_long_mode(obj, LV_LABEL_LONG_SCROLL_CIRCULAR);
lv_obj_set_style_align(obj, LV_ALIGN_CENTER, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_label_set_text(obj, "Settings");
}
}
}
}
}
}
tick_screen_main_menu();
}
This is my display flush function. im ussing a double buffer
void display_flush(lv_disp_drv_t * disp_drv,const lv_area_t * area, lv_color_t *color_p){
for (int y = area->y1; y <= area->y2; y++) {
for (int x = area->x1; x <= area->x2; x++) {
// Convert LVGL color to SSD1306 monochrome
bool pixel_on = (color_p->full != 0);
display.drawPixel(x, y, pixel_on);
color_p++;
}
}
display.display();
lv_disp_flush_ready(disp_drv);
}
And my init disply Function
void init_display(){
//Turn on vext so display is powered by usbc
vext_ON();
//initialize i2c comunication with custom sda and scl pins
Wire.begin(SDA_OLED,SCL_OLED);
Wire.setClock(400000); // 400kHz I2C
//Initialize display and error if it doesent
if(!display.begin(SSD1306_SWITCHCAPVCC,0x3C)){
Serial.println("Diplay init Faild");
while(true);
}
display.invertDisplay(false);
display.setRotation(0); // Ensure native orientation
display.dim(false); // Ensure full brightness
display.clearDisplay();
display.display();
//Initialize lvgl
lv_init();
//Set up LVGL display buffer (Small buf for SSD1306)
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf1[SCREEN_WIDTH * 100]; // First buffer
static lv_color_t buf2[SCREEN_WIDTH * 100]; // Second buffer
lv_disp_draw_buf_init(&draw_buf,buf1,NULL,SCREEN_WIDTH * 100);
//Register display drivers
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = SCREEN_WIDTH;
disp_drv.ver_res = SCREEN_HEIGHT;
disp_drv.flush_cb = display_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);
};