What do you want to achieve?
I want to navigate through a lv_menu with a keypad. I do not have a touch screen.
The lv_menu is built dynamically and it is imho working fine.
Though, I cannot navigate with the up/down buttons
What have you tried so far?
Code to reproduce
void Screen::initKeypadInput()
{
_keypadIndev = lv_indev_create();
lv_indev_set_type(_keypadIndev, LV_INDEV_TYPE_KEYPAD);
lv_indev_set_read_cb(_keypadIndev, read_keypad);
lv_indev_set_user_data(_keypadIndev, this);
_menuGroup = lv_group_create();
lv_indev_set_group(_keypadIndev, _menuGroup);
}
void Screen::read_keypad(lv_indev_t *indev, lv_indev_data_t *data)
{
static uint32_t last_key = 0;
Screen *screen = static_cast<Screen *>(lv_indev_get_user_data(indev));
if (!screen || !screen->_registry)
return;
bool leftPressed = screen->_registry->getLeftButton()->isPressed();
bool rightPressed = screen->_registry->getRightButton()->isPressed();
bool actionPressed = screen->_registry->getActionButton()->isPressed();
if (leftPressed && rightPressed)
{
data->state = LV_INDEV_STATE_PRESSED;
data->key = LV_KEY_ESC;
last_key = LV_KEY_ESC;
}
else if (leftPressed)
{
data->state = LV_INDEV_STATE_PRESSED;
data->key = LV_KEY_UP;
last_key = LV_KEY_UP;
}
else if (rightPressed)
{
data->state = LV_INDEV_STATE_PRESSED;
data->key = LV_KEY_DOWN;
last_key = LV_KEY_DOWN;
}
else if (actionPressed)
{
data->state = LV_INDEV_STATE_PRESSED;
data->key = LV_KEY_ENTER;
last_key = LV_KEY_ENTER;
}
else
{
data->state = LV_INDEV_STATE_RELEASED;
data->key = last_key;
}
}
void Screen::createMenuItem(lv_obj_t *parent, std::shared_ptr<MenuData> item)
{
lv_obj_t *cont = lv_menu_cont_create(parent);
lv_obj_add_flag(cont, LV_OBJ_FLAG_CLICKABLE);
lv_obj_add_flag(cont, LV_OBJ_FLAG_SCROLLABLE);
lv_group_add_obj(_menuGroup, cont);
lv_obj_add_event_cb(cont, item_event_handler, LV_EVENT_CLICKED, this);
lv_obj_set_user_data(cont, item.get());
lv_obj_set_layout(cont, LV_LAYOUT_FLEX);
lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_ROW);
lv_obj_set_flex_align(cont, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_pad_all(cont, 8, LV_PART_MAIN);
lv_obj_t *nameLabel = lv_label_create(cont);
lv_label_set_text(nameLabel, item->getName().c_str());
lv_obj_set_style_text_font(nameLabel, &lv_font_montserrat_medium_14, LV_PART_MAIN);
switch (item->getType())
{
case MenuItemType::ACTION:
// No right content for actions
break;
case MenuItemType::INFO:
{
lv_obj_t *valueLabel = lv_label_create(cont);
lv_label_set_text(valueLabel, item->getValue().c_str());
lv_obj_set_style_text_font(valueLabel, &lv_font_montserrat_medium_14, LV_PART_MAIN);
lv_obj_set_style_text_color(valueLabel, lv_color_hex(0x666666), LV_PART_MAIN);
break;
}
case MenuItemType::BOOLEAN_EDIT:
case MenuItemType::BOOLEAN_READONLY:
{
lv_obj_t *checkbox = lv_checkbox_create(cont);
lv_checkbox_set_text(checkbox, "");
bool isChecked = item->getBoolValue();
if (isChecked)
{
lv_obj_add_state(checkbox, LV_STATE_CHECKED);
}
if (item->getType() == MenuItemType::BOOLEAN_READONLY)
{
lv_obj_add_state(checkbox, LV_STATE_DISABLED);
lv_obj_set_style_opa(checkbox, LV_OPA_50, LV_PART_MAIN);
}
break;
}
case MenuItemType::SUBMENU:
{
lv_obj_t *submenuPage = lv_menu_page_create(_menu, item->getName().c_str());
buildMenuPage(submenuPage, item->getSubItems());
lv_menu_set_load_page_event(_menu, cont, submenuPage);
lv_obj_t *arrowLabel = lv_label_create(cont);
lv_label_set_text(arrowLabel, ">");
lv_obj_set_style_text_font(arrowLabel, &lv_font_montserrat_medium_14, LV_PART_MAIN);
lv_obj_set_style_text_color(arrowLabel, lv_color_hex(0x007BFF), LV_PART_MAIN);
break;
}
}
}
When pressing the ACTION button, I see that the entry is highlighted for the press event.
But I cannot navigate with the up/down keys. I was expecting that the menu items will be selected accordingly and at the beginning the very first item is automatically selected.
Environment
- MCU/MPU/Board: macOS SDL Simulator
- LVGL version: v9.3 - platform.io