From c4ac2082edb6e957afa741552ef6dc64357087f4 Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 5 Oct 2020 23:12:25 +0200 Subject: [PATCH] Table can now have custom widgets in cells --- radio/src/thirdparty/libopenui/src/table.cpp | 42 +++++-- radio/src/thirdparty/libopenui/src/table.h | 118 +++++++++++++++---- 2 files changed, 128 insertions(+), 32 deletions(-) diff --git a/radio/src/thirdparty/libopenui/src/table.cpp b/radio/src/thirdparty/libopenui/src/table.cpp index 3067b485b..3d2f021d1 100644 --- a/radio/src/thirdparty/libopenui/src/table.cpp +++ b/radio/src/thirdparty/libopenui/src/table.cpp @@ -23,26 +23,52 @@ void Table::Header::paint(BitmapBuffer * dc) { coord_t x = 10; - if (!header.values.empty()) { + if (!cells.empty()) { dc->clear(TABLE_HEADER_BGCOLOR); - for (unsigned i = 0; i < header.values.size(); i++) { - dc->drawText(x, (TABLE_LINE_HEIGHT - getFontHeight(TABLE_HEADER_FONT)) / 2, header.values[i].c_str(), TABLE_HEADER_FONT); + for (unsigned i = 0; i < cells.size(); i++) { + auto cell = cells[i]; + if (cell) { + cell->paint(dc, x, 0, TABLE_HEADER_FONT); + } x += columnsWidth[i]; } } } +void Table::Body::checkEvents() +{ + Window::checkEvents(); + + coord_t y = 0; + coord_t x; + for (auto line: lines) { + x = 10; + for (unsigned i = 0; i < line->cells.size(); i++) { + auto cell = line->cells[i]; + auto width = columnsWidth[i]; + if (cell && cell->needsInvalidate()) { + invalidate({x, y, width, TABLE_LINE_HEIGHT - 2}); + } + x += width; + } + } +} + void Table::Body::paint(BitmapBuffer * dc) { coord_t y = 0; coord_t x; int index = 0; - for (auto & line: lines) { + dc->clear(DEFAULT_BGCOLOR); + for (auto line: lines) { bool highlight = (index == selection); dc->drawSolidFilledRect(0, y, width(), TABLE_LINE_HEIGHT - 2, highlight ? MENU_HIGHLIGHT_BGCOLOR : TABLE_BGCOLOR); x = 10; - for (unsigned i = 0; i < line.values.size(); i++) { - dc->drawText(x, y + (TABLE_LINE_HEIGHT - getFontHeight(TABLE_BODY_FONT)) / 2 + 3, line.values[i].c_str(), line.flags | (highlight ? MENU_HIGHLIGHT_COLOR : DEFAULT_COLOR)); + for (unsigned i = 0; i < line->cells.size(); i++) { + auto cell = line->cells[i]; + if (cell) { + cell->paint(dc, x, y, line->flags | (highlight ? MENU_HIGHLIGHT_COLOR : DEFAULT_COLOR)); + } x += columnsWidth[i]; } y += TABLE_LINE_HEIGHT; @@ -56,7 +82,7 @@ bool Table::Body::onTouchEnd(coord_t x, coord_t y) unsigned index = y / TABLE_LINE_HEIGHT; if (index < lines.size()) { setFocus(SET_FOCUS_DEFAULT); - auto onPress = lines[index].onPress; + auto onPress = lines[index]->onPress; if (onPress) onPress(); } @@ -71,7 +97,7 @@ void Table::Body::onEvent(event_t event) if (event == EVT_KEY_BREAK(KEY_ENTER)) { if (selection >= 0) { - auto onPress = lines[selection].onPress; + auto onPress = lines[selection]->onPress; if (onPress) onPress(); } diff --git a/radio/src/thirdparty/libopenui/src/table.h b/radio/src/thirdparty/libopenui/src/table.h index ddaa710ea..6c2a21f74 100644 --- a/radio/src/thirdparty/libopenui/src/table.h +++ b/radio/src/thirdparty/libopenui/src/table.h @@ -24,25 +24,88 @@ #include #include "form.h" #include "libopenui_config.h" +#include "font.h" class Table: public FormField { + public: + class Cell { + public: + virtual ~Cell() = default; + + virtual void paint(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags) = 0; + + virtual bool needsInvalidate() = 0; + }; + + class StringCell : public Cell { + public: + StringCell() = default; + + explicit StringCell(std::string value): + value(std::move(value)) + { + } + + void paint(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags) override + { + dc->drawText(x, y + (TABLE_LINE_HEIGHT - getFontHeight(TABLE_BODY_FONT)) / 2 + 3, value.c_str(), flags); + } + + bool needsInvalidate() override + { + return false; + } + + protected: + std::string value; + }; + + class DynamicStringCell : public Cell { + public: + explicit DynamicStringCell(std::function getText): + getText(std::move(getText)) + { + } + + void paint(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags) override + { + auto text = getText(); + dc->drawText(x, y + (TABLE_LINE_HEIGHT - getFontHeight(TABLE_BODY_FONT)) / 2 + 3, text.c_str(), SPACING_NUMBERS_CONST | flags); + } + + bool needsInvalidate() override + { + return true; // TODO optimize this + } + + protected: + std::function getText; + }; + class Line { public: explicit Line(uint8_t columnsCount): - values(columnsCount) + cells(columnsCount, nullptr) { } - std::vector values; + + ~Line() + { + for (auto cell: cells) { + delete cell; + } + } + std::vector cells; std::function onPress; std::function onSelect; LcdFlags flags = TABLE_BODY_FONT; }; - class Header: public Window { + class Header: public Window, public Line { public: Header(Table * parent, const rect_t & rect, uint8_t columnsCount): Window(parent, rect, OPAQUE), - header(columnsCount), + Line(columnsCount), columnsWidth(parent->columnsWidth) { } @@ -54,15 +117,9 @@ class Table: public FormField { } #endif - void setLine(const Line & line) - { - header = line; - } - void paint(BitmapBuffer * dc) override; protected: - Line header; std::vector & columnsWidth; }; @@ -76,6 +133,11 @@ class Table: public FormField { { } + ~Body() override + { + clear(); + } + #if defined(DEBUG_WINDOWS) std::string getName() const override { @@ -83,7 +145,7 @@ class Table: public FormField { } #endif - void addLine(const Line & line) + void addLine(Line * line) { lines.push_back(line); setInnerHeight(lines.size() * TABLE_LINE_HEIGHT - 2); @@ -94,14 +156,17 @@ class Table: public FormField { void setLineFlags(uint8_t index, LcdFlags flags) { - if (lines[index].flags != flags) { - lines[index].flags = flags; + if (lines[index]->flags != flags) { + lines[index]->flags = flags; invalidate({0, index * TABLE_LINE_HEIGHT, width(), TABLE_LINE_HEIGHT}); } } void clear() { + for (auto line: lines) { + delete line; + } lines.clear(); } @@ -119,7 +184,7 @@ class Table: public FormField { } invalidate(); if (index >= 0) { - auto onSelect = lines[index].onSelect; + auto onSelect = lines[index]->onSelect; if (onSelect) { onSelect(); } @@ -136,9 +201,11 @@ class Table: public FormField { bool onTouchEnd(coord_t x, coord_t y) override; #endif + void checkEvents() override; + protected: std::vector & columnsWidth; - std::vector lines; + std::vector lines; int selection = -1; }; @@ -209,28 +276,31 @@ class Table: public FormField { header.setHeight(TABLE_HEADER_HEIGHT); body.setTop(TABLE_HEADER_HEIGHT); body.setHeight(height() - TABLE_HEADER_HEIGHT); - Line line(columnsCount); for (uint8_t i = 0; i < columnsCount; i++) { - line.values[i] = values[i]; + header.cells[i] = new StringCell(values[i]); } - header.setLine(line); + } + + void addLine(Line * line, std::function onPress = nullptr, std::function onSelect = nullptr) + { + line->onPress = std::move(onPress); + line->onSelect = std::move(onSelect); + body.addLine(line); } void addLine(const char * const values[], std::function onPress = nullptr, std::function onSelect = nullptr) { - Line line(columnsCount); + Line * line = new Line(columnsCount); for (uint8_t i = 0; i < columnsCount; i++) { - line.values[i] = values[i]; + line->cells[i] = new StringCell(values[i]); } - line.onPress = std::move(onPress); - line.onSelect = std::move(onSelect); - body.addLine(line); + addLine(line, std::move(onPress), std::move(onSelect)); } void clear() { - body.clear(); clearSelection(); + body.clear(); } uint8_t size() const