Table can now have custom widgets in cells

This commit is contained in:
Bertrand Songis
2020-10-05 23:12:25 +02:00
parent c16eb82122
commit c4ac2082ed
2 changed files with 128 additions and 32 deletions
+34 -8
View File
@@ -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();
}
+94 -24
View File
@@ -24,25 +24,88 @@
#include <vector>
#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<std::string()> 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<std::string()> getText;
};
class Line {
public:
explicit Line(uint8_t columnsCount):
values(columnsCount)
cells(columnsCount, nullptr)
{
}
std::vector<std::string> values;
~Line()
{
for (auto cell: cells) {
delete cell;
}
}
std::vector<Cell *> cells;
std::function<void()> onPress;
std::function<void()> 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<coord_t> & 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<coord_t> & columnsWidth;
std::vector<Line> lines;
std::vector<Line *> 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<void()> onPress = nullptr, std::function<void()> onSelect = nullptr)
{
line->onPress = std::move(onPress);
line->onSelect = std::move(onSelect);
body.addLine(line);
}
void addLine(const char * const values[], std::function<void()> onPress = nullptr, std::function<void()> 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