New TableField

This commit is contained in:
Raphael Coeffic
2022-06-11 15:13:11 +02:00
committed by Raphael Coeffic
parent 4a77acf6af
commit 2eef7755a5
4 changed files with 250 additions and 537 deletions
+50 -82
View File
@@ -23,54 +23,19 @@
#include <lvgl/lvgl.h>
static void menu_clicked(lv_event_t *e)
void MenuBody::onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc)
{
lv_obj_t* target = lv_event_get_target(e);
if (!target) return;
uint16_t row;
uint16_t col;
lv_table_get_selected_cell(target, &row, &col);
MenuBody* mb = (MenuBody*)lv_obj_get_user_data(target);
if (!mb) return;
mb->onPress(row);
}
void menu_draw_begin(lv_event_t* e)
{
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
if (dsc->part != LV_PART_ITEMS) return;
lv_obj_t* table = lv_event_get_target(e);
if (!table) return;
MenuBody* mb = (MenuBody*)lv_obj_get_user_data(table);
if (!mb) return;
uint16_t row = dsc->id;
lv_canvas_t* icon = (lv_canvas_t*)mb->lines[row].getIcon();
lv_canvas_t* icon = (lv_canvas_t*)lines[row].getIcon();
if (!icon) return;
lv_img_t* img = &icon->img;
lv_coord_t cell_left = lv_obj_get_style_pad_left(table, LV_PART_ITEMS);
lv_coord_t cell_left = lv_obj_get_style_pad_left(lvobj, LV_PART_ITEMS);
dsc->label_dsc->ofs_x = img->w + cell_left;
}
void menu_draw_end(lv_event_t* e)
void MenuBody::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc)
{
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
if (dsc->part != LV_PART_ITEMS) return;
lv_obj_t* table = lv_event_get_target(e);
if (!table) return;
MenuBody* mb = (MenuBody*)lv_obj_get_user_data(table);
if (!mb) return;
uint16_t row = dsc->id;
lv_obj_t* icon = mb->lines[row].getIcon();
lv_obj_t* icon = lines[row].getIcon();
if (!icon) return;
lv_draw_img_dsc_t img_dsc;
@@ -81,7 +46,7 @@ void menu_draw_end(lv_event_t* e)
lv_coord_t area_h = lv_area_get_height(dsc->draw_area);
lv_coord_t cell_left = lv_obj_get_style_pad_left(table, LV_PART_ITEMS);
lv_coord_t cell_left = lv_obj_get_style_pad_left(lvobj, LV_PART_ITEMS);
coords.x1 = dsc->draw_area->x1 + cell_left;
coords.x2 = coords.x1 + img->header.w - 1;
coords.y1 = dsc->draw_area->y1 + (area_h - img->header.h) / 2;
@@ -91,13 +56,10 @@ void menu_draw_end(lv_event_t* e)
}
MenuBody::MenuBody(Window * parent, const rect_t & rect):
Window(parent, rect, OPAQUE, 0, lv_table_create)
TableField(parent, rect)
{
lv_table_set_col_cnt(lvobj, 1);
lv_table_set_col_width(lvobj, 0, rect.w);
lv_obj_add_event_cb(lvobj, menu_clicked, LV_EVENT_VALUE_CHANGED, nullptr);
lv_obj_add_event_cb(lvobj, menu_draw_begin, LV_EVENT_DRAW_PART_BEGIN, nullptr);
lv_obj_add_event_cb(lvobj, menu_draw_end, LV_EVENT_DRAW_PART_END, nullptr);
setColumnCount(1);
setColumnWidth(0, rect.w);
}
void MenuBody::addLine(const std::string &text, std::function<void()> onPress,
@@ -128,7 +90,7 @@ void MenuBody::addLine(const uint8_t *icon_mask, const std::string &text,
void MenuBody::removeLines()
{
lines.clear();
lv_obj_clean(lvobj);
setRowCount(0);
}
coord_t MenuBody::getContentHeight()
@@ -200,6 +162,11 @@ void MenuBody::setIndex(int index)
}
}
void MenuBody::onPress(uint16_t row, uint16_t col)
{
onPress(row);
}
void MenuBody::selectNext(MENU_DIRECTION direction)
{
// look for the next non separator line
@@ -211,40 +178,41 @@ void MenuBody::selectNext(MENU_DIRECTION direction)
#if defined(HARDWARE_KEYS)
void MenuBody::onEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
// TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_ROTARY_RIGHT) {
if (!lines.empty()) {
selectNext(DIRECTION_UP);
onKeyPress();
}
}
else if (event == EVT_ROTARY_LEFT) {
if (!lines.empty()) {
selectNext(DIRECTION_DOWN);
onKeyPress();
}
}
else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
if (!lines.empty()) {
onKeyPress();
if (selectedIndex < 0) {
setIndex(0);
}
else {
Menu * menu = getParentMenu();
if (menu->multiple) {
lines[selectedIndex].onPress();
menu->invalidate();
}
else {
lines[selectedIndex].onPress();
menu->deleteLater();
}
}
}
}
else if (event == EVT_KEY_BREAK(KEY_EXIT)) {
// if (event == EVT_ROTARY_RIGHT) {
// if (!lines.empty()) {
// selectNext(DIRECTION_UP);
// onKeyPress();
// }
// }
// else if (event == EVT_ROTARY_LEFT) {
// if (!lines.empty()) {
// selectNext(DIRECTION_DOWN);
// onKeyPress();
// }
// }
// else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
// if (!lines.empty()) {
// onKeyPress();
// if (selectedIndex < 0) {
// setIndex(0);
// }
// else {
// Menu * menu = getParentMenu();
// if (menu->multiple) {
// lines[selectedIndex].onPress();
// menu->invalidate();
// }
// else {
// lines[selectedIndex].onPress();
// menu->deleteLater();
// }
// }
// }
// }
// else
if (event == EVT_KEY_BREAK(KEY_EXIT)) {
onKeyPress();
if (onCancel) {
onCancel();
@@ -252,7 +220,7 @@ void MenuBody::onEvent(event_t event)
Window::onEvent(event);
}
else {
Window::onEvent(event);
TableField::onEvent(event);
}
}
#endif
+6 -3
View File
@@ -23,7 +23,9 @@
#include <functional>
#include <utility>
#include <memory>
#include "modal_window.h"
#include "table.h"
class Menu;
class MenuWindowContent;
@@ -35,7 +37,7 @@ struct lvobj_delete {
}
};
class MenuBody: public Window
class MenuBody: public TableField
{
friend class MenuWindowContent;
friend class Menu;
@@ -113,8 +115,9 @@ class MenuBody: public Window
void onPress(size_t index);
protected:
friend void menu_draw_begin(lv_event_t *);
friend void menu_draw_end(lv_event_t *);
void onPress(uint16_t row, uint16_t col) override;
void onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override;
void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override;
void selectNext(MENU_DIRECTION direction);
int rangeCheck(int);
+170 -113
View File
@@ -18,146 +18,203 @@
*/
#include "table.h"
#include "font.h"
void Table::Header::paint(BitmapBuffer * dc)
void TableField::clicked(lv_event_t *e)
{
coord_t x = 10;
if (!cells.empty()) {
dc->clear(COLOR_THEME_FOCUS);
for (unsigned i = 0; i < cells.size(); i++) {
auto cell = cells[i];
if (cell) {
cell->paint(dc, x, 0, TABLE_HEADER_FONT);
}
x += static_cast<Table *>(parent)->columnsWidth[i];
}
}
lv_obj_t* target = lv_event_get_target(e);
if (!target) return;
uint16_t row;
uint16_t col;
lv_table_get_selected_cell(target, &row, &col);
TableField* tf = (TableField*)lv_obj_get_user_data(target);
if (!tf) return;
tf->onPress(row, col);
}
void Table::Body::checkEvents()
void TableField::draw_begin(lv_event_t* e)
{
Window::checkEvents();
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
if (dsc->part != LV_PART_ITEMS) return;
if (_deleted)
lv_obj_t* table = lv_event_get_target(e);
if (!table) return;
uint16_t cols = lv_table_get_col_cnt(table);
if (cols == 0) return;
TableField* tf = (TableField*)lv_obj_get_user_data(table);
if (!tf) return;
uint16_t row = dsc->id / cols;
uint16_t col = dsc->id % cols;
tf->onDrawBegin(row, col, dsc);
}
void TableField::draw_end(lv_event_t* e)
{
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
if (dsc->part != LV_PART_ITEMS) return;
lv_obj_t* table = lv_event_get_target(e);
if (!table) return;
uint16_t cols = lv_table_get_col_cnt(table);
if (cols == 0) return;
TableField* tf = (TableField*)lv_obj_get_user_data(table);
if (!tf) return;
uint16_t row = dsc->id / cols;
uint16_t col = dsc->id % cols;
tf->onDrawEnd(row, col, dsc);
}
TableField::TableField(Window* parent, const rect_t& rect, WindowFlags windowFlags) :
FormField(parent, rect, windowFlags, 0, lv_table_create)
{
lv_obj_add_event_cb(lvobj, TableField::clicked, LV_EVENT_VALUE_CHANGED, nullptr);
lv_obj_add_event_cb(lvobj, TableField::draw_begin, LV_EVENT_DRAW_PART_BEGIN, nullptr);
lv_obj_add_event_cb(lvobj, TableField::draw_end, LV_EVENT_DRAW_PART_END, nullptr);
}
void TableField::setColumnCount(uint16_t cols)
{
lv_table_set_col_cnt(lvobj, cols);
}
uint16_t TableField::getColumnCount() const
{
return lv_table_get_col_cnt(lvobj);
}
void TableField::setRowCount(uint16_t rows)
{
lv_table_set_row_cnt(lvobj, rows);
}
uint16_t TableField::getRowCount() const
{
return lv_table_get_row_cnt(lvobj);
}
void TableField::setColumnWidth(uint16_t col, coord_t w)
{
lv_table_set_col_width(lvobj, col, w);
}
coord_t TableField::getColumnWidth(uint16_t col) const
{
return lv_table_get_col_width(lvobj, col);
}
void TableField::select(uint16_t row, uint16_t col)
{
lv_table_t* table = (lv_table_t*)lvobj;
if (table->row_act == row && table->col_act == row) return;
if (row >= table->row_cnt || col >= table->col_cnt) {
table->col_act = LV_TABLE_CELL_NONE;
table->row_act = LV_TABLE_CELL_NONE;
return;
coord_t y = 0;
for (auto line: lines) {
coord_t x = 10;
for (unsigned i = 0; i < line->cells.size(); i++) {
auto cell = line->cells[i];
auto width = static_cast<Table *>(parent)->columnsWidth[i];
if (cell && cell->needsInvalidate()) {
invalidate({x, y, width, TABLE_LINE_HEIGHT - 2});
}
x += width;
}
y += TABLE_LINE_HEIGHT;
}
table->row_act = row;
table->col_act = col;
lv_obj_invalidate(lvobj);
adjustScroll();
}
void Table::Body::paint(BitmapBuffer * dc)
void TableField::adjustScroll()
{
coord_t y = 0;
int index = 0;
dc->clear(COLOR_THEME_SECONDARY3);
for (auto line: lines) {
bool highlight = (index == selection);
dc->drawSolidFilledRect(0, y, width(), TABLE_LINE_HEIGHT - 2, highlight ? COLOR_THEME_FOCUS : COLOR_THEME_SECONDARY3);
coord_t x = 10;
for (unsigned i = 0; i < line->cells.size(); i++) {
auto cell = line->cells[i];
if (cell) {
cell->paint(dc, x, y, line->flags + (highlight ? COLOR_THEME_PRIMARY2 - COLOR_MASK(line->flags) : COLOR_THEME_SECONDARY1));
}
x += static_cast<Table *>(parent)->columnsWidth[i];
}
y += TABLE_LINE_HEIGHT;
index += 1;
lv_table_t* table = (lv_table_t*)lvobj;
// only vertical scroll for now
lv_coord_t h_before = 0;
for (uint16_t i = 0; i < table->row_act; i++) h_before += table->row_h[i];
lv_coord_t row_h = table->row_h[table->row_act];
lv_coord_t scroll_y = lv_obj_get_scroll_y(lvobj);
lv_obj_update_layout(lvobj);
lv_coord_t h = lv_obj_get_height(lvobj);
lv_coord_t diff_y = 0;
if (h_before < scroll_y) {
diff_y = scroll_y - h_before;
} else if (scroll_y + h < h_before + row_h) {
diff_y = scroll_y + h - h_before - row_h;
} else {
return;
}
lv_obj_scroll_by_bounded(lvobj, 0, diff_y, LV_ANIM_OFF);
}
#if defined(HARDWARE_TOUCH)
bool Table::Body::onTouchEnd(coord_t x, coord_t y)
void TableField::selectNext(int16_t dir)
{
unsigned index = y / TABLE_LINE_HEIGHT;
if (index < lines.size()) {
onKeyPress();
setFocus(SET_FOCUS_DEFAULT);
auto onPress = lines[index]->onPress;
if (onPress)
onPress();
}
return true;
}
#endif
lv_table_t* table = (lv_table_t*)lvobj;
#if defined(HARDWARE_KEYS)
void Table::Body::onEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (table->col_act == LV_TABLE_CELL_NONE ||
table->row_act == LV_TABLE_CELL_NONE) {
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
if (selection >= 0) {
onKeyPress();
auto onPress = lines[selection]->onPress;
if (onPress)
onPress();
if (table->col_cnt > 0 && table->row_cnt > 0) {
table->col_act = 0;
table->row_act = 0;
}
}
if (event == EVT_ROTARY_RIGHT) {
onKeyPress();
auto table = static_cast<Table *>(parent);
if (table->getWindowFlags() & FORWARD_SCROLL) {
auto index = selection + 1;
if (index < int(lines.size())) {
select(index, true);
}
else {
auto next = table->getNextField();
if (next) {
next->setFocus(SET_FOCUS_FORWARD, this);
if (!hasFocus()) {
select(-1, false);
} else {
table->col_act += dir;
if (table->col_act >= table->col_cnt) {
table->col_act = 0;
table->row_act += dir;
if (table->row_act >= table->row_cnt) {
table->col_act = LV_TABLE_CELL_NONE;
table->row_act = LV_TABLE_CELL_NONE;
// wrap around
if (table->col_cnt > 0 && table->row_cnt > 0) {
if (dir < 0) {
table->col_act = table->col_cnt - 1;
table->row_act = table->row_cnt - 1;
} else {
table->col_act = 0;
table->row_act = 0;
}
}
}
}
else {
if (!lines.empty()) {
select((selection + 1) % lines.size(), true);
}
}
}
lv_obj_invalidate(lvobj);
adjustScroll();
}
void TableField::onEvent(event_t event)
{
if (event == EVT_ROTARY_RIGHT) {
onKeyPress();
selectNext(1);
}
else if (event == EVT_ROTARY_LEFT) {
onKeyPress();
auto table = static_cast<Table *>(parent);
if (table->getWindowFlags() & FORWARD_SCROLL) {
auto index = selection - 1;
if (index >= 0) {
select(index, true);
}
else {
auto previous = table->getPreviousField();
if (previous) {
select(-1, false);
previous->setFocus(SET_FOCUS_BACKWARD);
}
}
}
else {
if (!lines.empty()) {
select(selection <= 0 ? lines.size() - 1 : selection - 1, true);
}
}
selectNext(-1);
}
else if (event == EVT_KEY_BREAK(KEY_EXIT) && selection >= 0) {
select(-1, true);
Window::onEvent(event);
else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
onKeyPress();
uint16_t row;
uint16_t col;
lv_table_get_selected_cell(lvobj, &row, &col);
onPress(row, col);
}
else {
Window::onEvent(event);
}
}
}
#endif
+24 -339
View File
@@ -19,354 +19,39 @@
#pragma once
#include <utility>
#include <vector>
#include "form.h"
#include "libopenui_config.h"
#include "font.h"
class Table: public FormField
class TableField : 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 - 2 + (TABLE_LINE_HEIGHT - getFontHeight(TABLE_HEADER_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 - 2 + (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 CustomCell : public Cell
{
public:
explicit CustomCell(std::function<void(BitmapBuffer * /*dc*/, coord_t /*x*/, coord_t /*y*/, LcdFlags /*flags*/)> paintFunction):
paintFunction(std::move(paintFunction))
{
}
void paint(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags) override
{
paintFunction(dc, x, y, flags);
}
bool needsInvalidate() override
{
return true;
}
protected:
std::function<void(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags flags)> paintFunction;
};
class Line
{
public:
explicit Line(uint8_t columnsCount):
cells(columnsCount, nullptr)
{
}
~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, public Line
{
public:
Header(Table * parent, const rect_t & rect, uint8_t columnsCount):
Window(parent, rect, OPAQUE),
Line(columnsCount)
{
}
public:
TableField(Window* parent, const rect_t& rect,
WindowFlags windowFlags = OPAQUE | FORM_NO_BORDER);
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "Table::Header";
}
std::string getName() const override { return "Table"; }
#endif
void paint(BitmapBuffer * dc) override;
};
void setColumnCount(uint16_t cols);
uint16_t getColumnCount() const;
void setRowCount(uint16_t rows);
uint16_t getRowCount() const;
void setColumnWidth(uint16_t col, coord_t w);
coord_t getColumnWidth(uint16_t col) const;
class Body: public Window
{
friend class Table;
void select(uint16_t row, uint16_t col);
virtual void onPress(uint16_t row, uint16_t col) {}
public:
Body(Table * parent, const rect_t & rect, WindowFlags windowFlags):
Window(parent, rect, windowFlags)
{
}
protected:
void adjustScroll();
void selectNext(int16_t dir);
void onEvent(event_t event) override;
~Body() override
{
clear();
}
virtual void onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) {}
virtual void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) {}
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "Table::Body";
}
#endif
void addLine(Line * line)
{
lines.push_back(line);
if (hasFocus() && selection < 0) {
select(0, true);
}
}
void setLineFlags(uint8_t index, LcdFlags 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();
}
void select(int index, bool scroll)
{
selection = index;
if (scroll) {
coord_t y = index * TABLE_LINE_HEIGHT;
Window * window = this;
while (window->getWindowFlags() & FORWARD_SCROLL) {
y += window->top();
window = window->getParent();
}
const rect_t rect = {
0,
y,
width(),
TABLE_LINE_HEIGHT
};
window->scrollTo(rect);
}
invalidate();
if (index >= 0) {
auto onSelect = lines[index]->onSelect;
if (onSelect) {
onSelect();
}
}
}
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_KEYS)
void onEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
void checkEvents() override;
protected:
std::vector<Line *> lines;
int selection = -1;
};
public:
Table(Window * parent, const rect_t & rect, uint8_t columnsCount, WindowFlags windowFlags = OPAQUE | FORM_NO_BORDER):
FormField(parent, rect, windowFlags),
columnsCount(columnsCount),
columnsWidth(columnsCount, width() / columnsCount),
header(this, {0, 0, width(), 0}, columnsCount),
body(this, {0, 0, width(), height()}, windowFlags)
{
}
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "Table";
}
#endif
void deleteLater(bool detach = true, bool trash = true) override // NOLINT(google-default-arguments)
{
if (_deleted)
return;
header.deleteLater(true, false);
body.deleteLater(true, false);
FormField::deleteLater(detach, trash);
}
void setColumnsWidth(const coord_t values[])
{
int restColumn = -1;
coord_t restWidth = width();
for (uint8_t i = 0; i < columnsCount; i++) {
auto columnWidth = values[i];
columnsWidth[i] = columnWidth;
if (columnWidth == 0) {
restColumn = i;
}
else {
restWidth -= columnWidth;
}
}
if (restColumn >= 0) {
columnsWidth[restColumn] = restWidth;
}
}
int getSelection() const
{
return body.selection;
}
void clearSelection()
{
body.selection = -1;
body.invalidate();
}
void setFocus(uint8_t flag = SET_FOCUS_DEFAULT, Window * from = nullptr) override // NOLINT(google-default-arguments)
{
if (body.lines.empty()) {
if (flag == SET_FOCUS_BACKWARD) {
if (previous) {
previous->setFocus(flag, this);
}
}
else {
if (next) {
next->setFocus(flag, this);
}
}
}
else {
body.setFocus(flag, from);
if (body.selection < 0) {
select(flag == SET_FOCUS_BACKWARD ? (int)body.lines.size() - 1 : 0);
}
}
}
void select(int index, bool scroll = true)
{
body.select(index, scroll);
}
void setLineFlags(uint8_t index, LcdFlags flags)
{
body.setLineFlags(index, flags);
}
void setHeader(const char * const values[])
{
header.setHeight(TABLE_HEADER_HEIGHT);
body.setTop(TABLE_HEADER_HEIGHT);
body.setHeight(height() - TABLE_HEADER_HEIGHT);
for (uint8_t i = 0; i < columnsCount; i++) {
header.cells[i] = new StringCell(values[i]);
}
}
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 = new Line(columnsCount);
for (uint8_t i = 0; i < columnsCount; i++) {
line->cells[i] = new StringCell(values[i]);
}
addLine(line, std::move(onPress), std::move(onSelect));
}
void clear()
{
clearSelection();
body.clear();
}
uint8_t size() const
{
return body.lines.size();
}
protected:
uint8_t columnsCount;
std::vector<coord_t> columnsWidth;
Header header;
Body body;
static void clicked(lv_event_t *e);
static void draw_begin(lv_event_t *e);
static void draw_end(lv_event_t *e);
};