chore(color): LVGLify model template selection pages (#3076)

* LVGL flex conversion for model template selection pages.
* chore: Formatting
This commit is contained in:
philmoz
2023-01-27 21:44:25 +10:00
committed by GitHub
parent d53b94d14c
commit 1dc422592d
2 changed files with 182 additions and 189 deletions
+166 -155
View File
@@ -20,24 +20,65 @@
*/
#include "model_templates.h"
#include "standalone_lua.h"
#include "str_functions.h"
char TemplatePage::path[LEN_PATH + 1];
std::function<void(void)> TemplatePage::update = nullptr;
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
LV_GRID_TEMPLATE_LAST};
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
TemplatePage::TemplatePage() : Page(ICON_MODEL_SELECT)
{
body.padAll(0);
auto form = new FormWindow(&body, rect_t{});
form->setFlexLayout();
form->padAll(4);
FlexGridLayout grid(col_dsc, row_dsc, 4);
auto line = form->newLine(&grid);
listWindow = new FormWindow(line, rect_t{});
listWindow->setFlexLayout(LV_FLEX_FLOW_COLUMN, 8);
listWindow->setHeight(body.height() - 16);
lv_obj_set_flex_align(listWindow->getLvObj(), LV_FLEX_ALIGN_START,
LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_SPACE_BETWEEN);
lv_obj_set_grid_cell(listWindow->getLvObj(), LV_GRID_ALIGN_STRETCH, 0, 1,
LV_GRID_ALIGN_START, 0, 1);
infoLabel = lv_label_create(line->getLvObj());
lv_obj_set_height(infoLabel, body.height() - 16);
lv_obj_set_style_text_align(infoLabel, LV_TEXT_ALIGN_LEFT, 0);
lv_obj_set_grid_cell(infoLabel, LV_GRID_ALIGN_STRETCH, 1, 1,
LV_GRID_ALIGN_CENTER, 0, 1);
}
void TemplatePage::updateInfo()
{
FIL fp;
FRESULT res = f_open (&fp, buffer, FA_READ);
unsigned int bytesRead = 0;
if (res == FR_OK) {
f_read (&fp, infoText, LEN_INFO_TEXT, &bytesRead);
f_close(&fp);
if (buffer[0]) {
FIL fp;
FRESULT res = f_open(&fp, buffer, FA_READ);
unsigned int bytesRead = 0;
if (res == FR_OK) {
f_read(&fp, infoText, LEN_INFO_TEXT, &bytesRead);
f_close(&fp);
}
infoText[bytesRead] = '\0';
}
if (infoText[0] == 0) {
lv_label_set_text(infoLabel, STR_NO_INFORMATION);
lv_obj_set_style_text_color(infoLabel, makeLvColor(COLOR_THEME_DISABLED),
0);
} else {
lv_label_set_text(infoLabel, infoText);
lv_obj_set_style_text_color(infoLabel, makeLvColor(COLOR_THEME_PRIMARY1),
0);
}
infoText[bytesRead] = '\0';
invalidate();
}
#if defined(HARDWARE_KEYS)
@@ -52,146 +93,118 @@ void TemplatePage::onEvent(event_t event)
}
#endif
void TemplatePage::paint(BitmapBuffer *dc)
class SelectTemplate : public TemplatePage
{
Page::paint(dc);
rect_t rect = body.getRect();
coord_t x = LCD_W / 2 + PAGE_PADDING;
coord_t y = rect.y + PAGE_PADDING;
coord_t w = LCD_W / 2 - 2 * PAGE_PADDING;
coord_t h = rect.h - 2 * PAGE_PADDING;
if (count > 0) {
if (infoText[0] == '\0')
drawTextLines(dc, x, y, w, h, STR_NO_INFORMATION, COLOR_THEME_DISABLED);
else
drawTextLines(dc, x, y, w, h, infoText, COLOR_THEME_PRIMARY1);
}
}
public:
SelectTemplate(TemplatePage* tp, std::string folder) : templateFolderPage(tp)
{
header.setTitle(STR_SELECT_TEMPLATE);
char path[LEN_PATH + 1];
snprintf(path, LEN_PATH, "%s/%s", TEMPLATES_PATH, folder.c_str());
SelectTemplate::SelectTemplate(TemplatePage* tp)
: templateFolderPage(tp)
{
rect_t rect = {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + 10, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT};
new StaticText(&header, rect, STR_SELECT_TEMPLATE, 0, COLOR_THEME_PRIMARY2);
std::list<std::string> files;
FILINFO fno;
DIR dir;
FRESULT res = f_opendir(&dir, path);
FormGridLayout grid;
grid.spacer(PAGE_PADDING);
std::list<std::string> files;
FILINFO fno;
DIR dir;
FRESULT res = f_opendir(&dir, path);
Button* firstButton = nullptr;
if (res == FR_OK) {
// read all entries
for (;;) {
res = f_readdir(&dir, &fno);
if (res != FR_OK || fno.fname[0] == 0)
break; // Break on error or end of dir
if (strlen((const char*)fno.fname) > SD_SCREEN_FILE_LENGTH)
continue;
if (fno.fattrib & (AM_DIR|AM_HID|AM_SYS)) continue; /* Ignore folders, hidden and system files */
if (fno.fname[0] == '.') continue; /* Ignore UNIX hidden files */
if (res == FR_OK) {
// read all entries
for (;;) {
res = f_readdir(&dir, &fno);
if (res != FR_OK || fno.fname[0] == 0)
break; // Break on error or end of dir
if (strlen((const char*)fno.fname) > SD_SCREEN_FILE_LENGTH) continue;
if (fno.fattrib & (AM_DIR | AM_HID | AM_SYS))
continue; /* Ignore folders, hidden and system files */
if (fno.fname[0] == '.') continue; /* Ignore UNIX hidden files */
const char *ext = getFileExtension(fno.fname);
if(ext && !strcasecmp(ext, YAML_EXT)) {
int len = ext - fno.fname;
if (len < FF_MAX_LFN) {
char name[FF_MAX_LFN] = { 0 };
strncpy(name, fno.fname, len);
files.push_back(name);
const char* ext = getFileExtension(fno.fname);
if (ext && !strcasecmp(ext, YAML_EXT)) {
int len = ext - fno.fname;
if (len < FF_MAX_LFN) {
char name[FF_MAX_LFN] = {0};
strncpy(name, fno.fname, len);
files.push_back(name);
}
}
}
files.sort(compare_nocase);
for (auto name : files) {
auto tb = new TextButton(
listWindow, rect_t{0, 0, lv_pct(100), PAGE_LINE_HEIGHT * 2}, name,
[=]() -> uint8_t {
// Read model template
loadModelTemplate((name + YAML_EXT).c_str(), path);
storageDirty(EE_MODEL);
storageCheck(true);
// Dismiss template pages
deleteLater();
templateFolderPage->deleteLater();
#if defined(LUA)
// If there is a wizard Lua script, fire it up
snprintf(buffer, LEN_BUFFER, "%s/%s%s", path, name.c_str(),
SCRIPT_EXT);
if (f_stat(buffer, 0) == FR_OK) {
luaExec(buffer);
// Need to update() the ModelCategoryPageBody before attaching
// StandaloneLuaWindow to not mess up focus
update();
update = nullptr;
StandaloneLuaWindow::instance()->attach();
}
#endif
return 0;
});
tb->setFocusHandler([=](bool active) {
if (active) {
snprintf(buffer, LEN_BUFFER, "%s/%s%s", path, name.c_str(),
TEXT_EXT);
updateInfo();
}
});
if (!firstButton) firstButton = tb;
}
}
files.sort(compare_nocase);
f_closedir(&dir);
for (auto name: files) {
auto tb = new TemplateButton(&body, grid.getLabelSlot(), name, [=]() -> uint8_t {
// Read model template
loadModelTemplate((name + YAML_EXT).c_str(), path);
storageDirty(EE_MODEL);
storageCheck(true);
// Dismiss template pages
deleteLater();
templateFolderPage->deleteLater();
#if defined(LUA)
// If there is a wizard Lua script, fire it up
snprintf(buffer, LEN_BUFFER, "%s%c%s%s", path, '/', name.c_str(), SCRIPT_EXT);
if (f_stat(buffer, 0) == FR_OK) {
luaExec(buffer);
// Need to update() the ModelCategoryPageBody before attaching StandaloneLuaWindow to not mess up focus
update();
update = nullptr;
StandaloneLuaWindow::instance()->attach();
}
#endif
return 0;
});
tb->setFocusHandler([=](bool active) {
if (active) {
snprintf(buffer, LEN_BUFFER, "%s%c%s%s", path, '/', name.c_str(), TEXT_EXT);
updateInfo();
}
});
tb->setHeight(PAGE_LINE_HEIGHT * 2);
grid.spacer(tb->height() + 5);
if (files.size() == 0) {
new StaticText(listWindow, rect_t{0, 0, lv_pct(100), lv_pct(50)},
STR_NO_TEMPLATES, 0, COLOR_THEME_PRIMARY1);
} else {
lv_group_focus_obj(firstButton->getLvObj());
}
}
f_closedir(&dir);
count = files.size();
if (count == 0) {
rect_t rect = body.getRect();
rect.x = PAGE_PADDING;
rect.y = PAGE_PADDING;
rect.w = rect.w - (2 * PAGE_PADDING);
#if LCD_W > LCD_H
rect.h = PAGE_LINE_HEIGHT;
int charBreak = 60;
#else
rect.h = PAGE_LINE_HEIGHT * 2;
int charBreak = 40;
#endif
new StaticText(&body, rect, wrap(STR_NO_TEMPLATES, charBreak), 0, COLOR_THEME_PRIMARY1);
// The following button is needed because the EXIT key does not work without...
rect = body.getRect();
rect.x = rect.w - PAGE_PADDING - 100;
rect.y = rect.h - PAGE_PADDING - (PAGE_LINE_HEIGHT * 2);
rect.w = 100;
rect.h = PAGE_LINE_HEIGHT * 2;
new TextButton(&body, rect, STR_EXIT, [=]() -> uint8_t { deleteLater(); return 0; });
} else {
snprintf(buffer, LEN_BUFFER, "%s%c%s%s", path, '/', files.front().c_str(), TEXT_EXT);
updateInfo();
}
}
protected:
TemplatePage* templateFolderPage;
};
SelectTemplateFolder::SelectTemplateFolder(std::function<void(void)> update)
{
TemplatePage::update = update;
rect_t rect = {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + 10, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT};
new StaticText(&header, rect, STR_SELECT_TEMPLATE_FOLDER, 0, COLOR_THEME_PRIMARY2);
FormGridLayout grid;
grid.spacer(PAGE_PADDING);
header.setTitle(STR_SELECT_TEMPLATE_FOLDER);
auto tfb = new TemplateButton(&body, grid.getLabelSlot(), STR_BLANK_MODEL, [=]() -> uint8_t {
deleteLater();
return 0;
});
snprintf(infoText, LEN_INFO_TEXT, "%s", STR_BLANK_MODEL_INFO);
auto tfb = new TextButton(listWindow,
rect_t{0, 0, lv_pct(100), PAGE_LINE_HEIGHT * 2},
STR_BLANK_MODEL, [=]() -> uint8_t {
deleteLater();
return 0;
});
tfb->setFocusHandler([=](bool active) {
if (active) {
snprintf(infoText, LEN_INFO_TEXT, "%s", STR_BLANK_MODEL_INFO);
invalidate();
buffer[0] = 0;
strcpy(infoText, STR_BLANK_MODEL_INFO);
updateInfo();
}
});
tfb->setHeight(PAGE_LINE_HEIGHT * 2);
grid.spacer(tfb->height() + 5);
std::list<std::string> directories;
FILINFO fno;
@@ -203,53 +216,51 @@ SelectTemplateFolder::SelectTemplateFolder(std::function<void(void)> update)
for (;;) {
res = f_readdir(&dir, &fno);
if (res != FR_OK || fno.fname[0] == 0)
break; // Break on error or end of dir
if (strlen((const char*)fno.fname) > SD_SCREEN_FILE_LENGTH)
continue;
if (fno.fattrib & (AM_HID|AM_SYS)) continue; /* Ignore hidden and system files */
if (fno.fname[0] == '.') continue; /* Ignore UNIX hidden files */
if (fno.fattrib & AM_DIR)
directories.push_back((char*)fno.fname);
break; // Break on error or end of dir
if (strlen((const char*)fno.fname) > SD_SCREEN_FILE_LENGTH) continue;
if (fno.fattrib & (AM_HID | AM_SYS))
continue; /* Ignore hidden and system files */
if (fno.fname[0] == '.') continue; /* Ignore UNIX hidden files */
if (fno.fattrib & AM_DIR) directories.push_back((char*)fno.fname);
}
directories.sort(compare_nocase);
for (auto name: directories) {
for (auto name : directories) {
#if not defined(LUA)
// Don't show wizards dir if no lua
if (!strcasecmp(name.c_str(), "WIZARD") == 0) {
#endif
auto tfb = new TemplateButton(&body, grid.getLabelSlot(), name,
[=]() -> uint8_t {
snprintf(path, LEN_PATH, "%s%c%s", TEMPLATES_PATH, '/', name.c_str());
new SelectTemplate(this);
return 0;
auto tfb = new TextButton(
listWindow, rect_t{0, 0, lv_pct(100), PAGE_LINE_HEIGHT * 2}, name,
[=]() -> uint8_t {
new SelectTemplate(this, name);
return 0;
});
tfb->setFocusHandler([=](bool active) {
if (active) {
snprintf(buffer, LEN_BUFFER, "%s/%s/about%s", TEMPLATES_PATH,
name.c_str(), TEXT_EXT);
updateInfo();
}
});
tfb->setFocusHandler([=](bool active) {
if (active) {
snprintf(buffer, LEN_BUFFER, "%s%c%s%c%s%s", TEMPLATES_PATH, '/', name.c_str(), '/', "about", TEXT_EXT);
updateInfo();
}
});
tfb->setHeight(PAGE_LINE_HEIGHT * 2);
grid.spacer(tfb->height() + 5);
}
#if not defined(LUA)
}
}
#endif
}
}
f_closedir(&dir);
count = directories.size();
if (count == 0) {
rect_t rect = grid.getLabelSlot();
rect.w = body.getRect().w - 2 * PAGE_PADDING;
new StaticText(&body, rect, STR_NO_TEMPLATES, 0, COLOR_THEME_PRIMARY1);
if (directories.size() == 0) {
new StaticText(listWindow, rect_t{0, 0, lv_pct(100), lv_pct(50)},
STR_NO_TEMPLATES, 0, COLOR_THEME_PRIMARY1);
}
lv_group_focus_obj(tfb->getLvObj());
}
SelectTemplateFolder::~SelectTemplateFolder()
{
if (update)
update();
if (update) update();
}
+16 -34
View File
@@ -22,18 +22,13 @@
#pragma once
#include <functional>
#include "opentx.h"
constexpr size_t LEN_INFO_TEXT = 300;
constexpr size_t LEN_PATH = sizeof(TEMPLATES_PATH) + TEXT_FILENAME_MAXLEN;
constexpr size_t LEN_BUFFER = sizeof(TEMPLATES_PATH) + 2 * TEXT_FILENAME_MAXLEN + 1;
#include "opentx.h"
class TemplatePage : public Page
{
public:
TemplatePage() : Page(ICON_MODEL_SELECT)
{ }
public:
TemplatePage();
void updateInfo();
@@ -45,37 +40,24 @@ class TemplatePage : public Page
std::string getName() const { return "TemplatePage"; }
#endif
protected:
protected:
FormWindow* listWindow = nullptr;
lv_obj_t* infoLabel = nullptr;
static char path[LEN_PATH + 1];
char buffer[LEN_BUFFER + 1];
char infoText[LEN_INFO_TEXT + 1] = { 0 };
unsigned int count = 0;
static constexpr size_t LEN_INFO_TEXT = 300;
static constexpr size_t LEN_PATH =
sizeof(TEMPLATES_PATH) + TEXT_FILENAME_MAXLEN;
static constexpr size_t LEN_BUFFER =
sizeof(TEMPLATES_PATH) + 2 * TEXT_FILENAME_MAXLEN + 1;
char buffer[LEN_BUFFER + 1] = "";
char infoText[LEN_INFO_TEXT + 1] = "";
static std::function<void(void)> update;
void paint(BitmapBuffer *dc) override;
};
class TemplateButton : public TextButton
{
public:
TemplateButton(FormGroup* parent, const rect_t& rect, std::string name, std::function<uint8_t(void)> pressHandler = nullptr)
: TextButton(parent, rect, name, pressHandler)
{ }
};
class SelectTemplate : public TemplatePage
{
public:
SelectTemplate(TemplatePage* tp);
protected:
TemplatePage* templateFolderPage;
};
class SelectTemplateFolder : public TemplatePage
{
public:
public:
SelectTemplateFolder(std::function<void(void)> update);
~SelectTemplateFolder();
};
};