chore(color): LVGLify model template selection pages (#3076)
* LVGL flex conversion for model template selection pages. * chore: Formatting
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user