menu: added support for icons rather than custom draw function

This commit is contained in:
Raphael Coeffic
2022-06-11 15:13:11 +02:00
committed by Raphael Coeffic
parent 44b508ebc8
commit a20792a211
2 changed files with 87 additions and 56 deletions
+51 -14
View File
@@ -21,6 +21,8 @@
#include "font.h"
#include "theme.h"
#include "lvgl/src/widgets/lv_canvas.h"
void menuBodyEventCallback(lv_event_t *e)
{
auto code = lv_event_get_code(e);
@@ -40,8 +42,8 @@ void menuBodyEventCallback(lv_event_t *e)
}
else {
mb->setIndex(index);
menu->deleteLater();
mb->lines[index].onPress();
menu->deleteLater();
}
}
}
@@ -58,19 +60,52 @@ MenuBody::MenuBody(Window * parent, const rect_t & rect):
void MenuBody::addLine(const std::string &text, std::function<void()> onPress,
std::function<bool()> isChecked)
{
lines.emplace_back(text, std::move(onPress), std::move(isChecked));
lines.emplace_back(std::move(onPress), std::move(isChecked), nullptr);
lv_obj_t *btn = lv_list_add_btn(lvobj, nullptr, text.c_str());
lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);
lv_obj_add_event_cb(btn, menuBodyEventCallback, LV_EVENT_CLICKED,
(void *)(lines.size() - 1));
}
void MenuBody::addLine(const uint8_t *icon_mask, const std::string &text,
std::function<void()> onPress,
std::function<bool()> isChecked)
{
lv_obj_t* canvas = lv_canvas_create(nullptr);
lines.emplace_back(std::move(onPress), std::move(isChecked), canvas);
lv_coord_t w = *((uint16_t *)icon_mask);
lv_coord_t h = *(((uint16_t *)icon_mask)+1);
void* buf = (void*)(icon_mask + 4);
lv_canvas_set_buffer(canvas, buf, w, h, LV_IMG_CF_ALPHA_8BIT);
lv_obj_t *btn = lv_list_add_btn(
lvobj, (const char *)lv_canvas_get_img(canvas), text.c_str());
lv_obj_add_flag(btn, LV_OBJ_FLAG_CHECKABLE);
lv_obj_add_event_cb(btn, menuBodyEventCallback, LV_EVENT_CLICKED,
(void *)(lines.size() - 1));
}
void MenuBody::removeLines()
{
lines.clear();
lv_obj_clean(lvobj);
}
coord_t MenuBody::getContentHeight()
{
coord_t h = 0;
lv_obj_update_layout(lvobj);
for(int i = 0; i < lv_obj_get_child_cnt(lvobj); i++) {
auto child = lv_obj_get_child(lvobj, i);
h += lv_obj_get_height(child);
}
return h;
}
// ensure index is in range and also handle wrapping index
int MenuBody::rangeCheck(int index)
{
@@ -88,6 +123,7 @@ void MenuBody::setIndex(int index)
lv_obj_t *btn = lv_obj_get_child(lvobj, selectedIndex);
if (btn != nullptr) {
lv_obj_clear_state(btn, LV_STATE_CHECKED);
lv_obj_clear_state(btn, LV_STATE_FOCUS_KEY);
}
selectedIndex = index;
@@ -95,6 +131,7 @@ void MenuBody::setIndex(int index)
btn = lv_obj_get_child(lvobj, selectedIndex);
if (btn != nullptr) {
lv_obj_add_state(btn, LV_STATE_CHECKED);
lv_obj_add_state(btn, LV_STATE_FOCUS_KEY);
lv_obj_scroll_to_view(btn, LV_ANIM_OFF);
}
}
@@ -156,8 +193,8 @@ void MenuBody::onEvent(event_t event)
menu->invalidate();
}
else {
menu->deleteLater();
lines[selectedIndex].onPress();
menu->deleteLater();
}
}
}
@@ -193,10 +230,7 @@ Menu::Menu(Window * parent, bool multiple):
void Menu::updatePosition()
{
// calcualte the correct menu height given that the line heights are variable
coord_t height = 0;
for (int i = 0; i < (signed)content->body.lines.size(); i++)
height += content->body.lines[i].lineHeight();
coord_t height = content->body.getContentHeight();
if (!toolbar) {
// there is no navigation bar at the left, we may center the window on screen
@@ -217,24 +251,27 @@ void Menu::setTitle(std::string text)
updatePosition();
}
void Menu::addLine(const std::string & text, std::function<void()> onPress, std::function<bool()> isChecked)
void Menu::addLine(const std::string &text, std::function<void()> onPress,
std::function<bool()> isChecked)
{
content->body.addLine(text, std::move(onPress), std::move(isChecked));
updatePosition();
}
void Menu::addLine(const uint8_t *icon_mask, const std::string &text,
std::function<void()> onPress,
std::function<bool()> isChecked)
{
content->body.addLine(icon_mask, text, std::move(onPress), std::move(isChecked));
updatePosition();
}
void Menu::addSeparator()
{
content->body.addSeparator();
updatePosition();
}
void Menu::addCustomLine(std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine, std::function<void()> onPress, std::function<bool()> isChecked)
{
content->body.addCustomLine(std::move(drawLine), std::move(onPress), std::move(isChecked));
updatePosition();
}
void Menu::removeLines()
{
content->body.removeLines();
+36 -42
View File
@@ -27,6 +27,13 @@
class Menu;
class MenuWindowContent;
struct lvobj_delete {
constexpr lvobj_delete() = default;
void operator()(lv_obj_t* obj) const {
lv_obj_del(obj);
}
};
class MenuBody: public Window
{
friend class MenuWindowContent;
@@ -38,44 +45,27 @@ class MenuBody: public Window
DIRECTION_DOWN = -1
};
class MenuLine {
class MenuLine
{
friend class MenuBody;
public:
MenuLine(std::string text, std::function<void()> onPress, std::function<bool()> isChecked):
text(std::move(text)),
onPress(std::move(onPress)),
isChecked(std::move(isChecked))
{
}
public:
MenuLine(std::function<void()> onPress, std::function<bool()> isChecked,
lv_obj_t *icon) :
onPress(std::move(onPress)), isChecked(std::move(isChecked)), icon(icon)
{
}
MenuLine(std::function<void(BitmapBuffer * /*dc*/, coord_t /*x*/, coord_t /*y*/, LcdFlags /*flags*/)> drawLine, std::function<void()> onPress, std::function<bool()> isChecked):
drawLine(std::move(drawLine)),
onPress(std::move(onPress)),
isChecked(std::move(isChecked))
{
}
MenuLine(bool isSeparator) : isSeparator(true) {}
MenuLine(MenuLine &) = delete;
MenuLine(MenuLine &&) = default;
MenuLine(bool isSeparator) :
isSeparator(true),
height(MENUS_SEPARATOR_HEIGHT)
{
}
inline coord_t lineHeight() { return height; }
MenuLine(MenuLine &) = delete;
MenuLine(MenuLine &&) = default;
protected:
friend void menuBodyEventCallback(lv_event_t *e);
bool isSeparator = false;
coord_t height = MENUS_LINE_HEIGHT + 10;
std::string text;
std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine;
std::function<void()> onPress;
std::function<bool()> isChecked;
protected:
friend void menuBodyEventCallback(lv_event_t *e);
bool isSeparator = false;
std::function<void()> onPress;
std::function<bool()> isChecked;
std::unique_ptr<lv_obj_t, lvobj_delete> icon;
};
public:
@@ -109,13 +99,12 @@ class MenuBody: public Window
void onEvent(event_t event) override;
#endif
void addLine(const std::string & text, std::function<void()> onPress, std::function<bool()> isChecked);
void addLine(const std::string &text, std::function<void()> onPress,
std::function<bool()> isChecked);
void addCustomLine(std::function<void(BitmapBuffer * /*dc*/, coord_t /*x*/, coord_t /*y*/, LcdFlags /*flags*/)> drawLine, std::function<void()> onPress, std::function<bool()> isChecked)
{
lines.emplace_back(std::move(drawLine), std::move(onPress), std::move(isChecked));
invalidate();
}
void addLine(const uint8_t *icon_mask, const std::string &text,
std::function<void()> onPress,
std::function<bool()> isChecked);
void addSeparator()
{
@@ -129,6 +118,8 @@ class MenuBody: public Window
onCancel = std::move(handler);
}
coord_t getContentHeight();
protected:
friend void menuBodyEventCallback(lv_event_t *);
void selectNext(MENU_DIRECTION direction);
@@ -208,9 +199,12 @@ class Menu: public ModalWindow
void setTitle(std::string text);
void addLine(const std::string & text, std::function<void()> onPress, std::function<bool()> isChecked = nullptr);
void addLine(const std::string &text, std::function<void()> onPress,
std::function<bool()> isChecked = nullptr);
void addCustomLine(std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> drawLine, std::function<void()> onPress, std::function<bool()> isChecked = nullptr);
void addLine(const uint8_t *icon_mask, const std::string &text,
std::function<void()> onPress,
std::function<bool()> isChecked = nullptr);
void addSeparator();