chore(color): LVGLify custom mixer scripts page (#3071)
* LVGL flex conversion for custom mixer scripts. * Adjust spacing for portrait layout and widest text value.
This commit is contained in:
@@ -28,11 +28,31 @@
|
||||
#include "translations.h"
|
||||
#include "menus.h"
|
||||
#include "libopenui.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "lvgl_widgets/input_mix_line.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
// Overview grid
|
||||
static const lv_coord_t col_dsc[] = {LV_GRID_CONTENT,
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
// Edit grid
|
||||
#if LCD_W > LCD_H
|
||||
static const lv_coord_t e_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
#else
|
||||
static const lv_coord_t e_col_dsc[] = {LV_GRID_FR(5), LV_GRID_FR(4),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
#endif
|
||||
|
||||
// Line button grid
|
||||
static const lv_coord_t b_col_dsc[] = {40, 84, 84, LV_GRID_FR(1),
|
||||
LV_GRID_TEMPLATE_LAST
|
||||
};
|
||||
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT,
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
class ScriptEditWindow : public Page {
|
||||
public:
|
||||
explicit ScriptEditWindow(uint8_t idx) :
|
||||
@@ -69,17 +89,21 @@ class ScriptEditWindow : public Page {
|
||||
|
||||
void buildBody(FormWindow * window, bool focusScript = false)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
auto form = new FormWindow(window, rect_t{});
|
||||
form->setFlexLayout();
|
||||
form->padAll(4);
|
||||
|
||||
FlexGridLayout grid(e_col_dsc, row_dsc, 2);
|
||||
|
||||
// the general pattern seems to be using capture-by-value for the closures: so need to copy the pointers, not the objects
|
||||
ScriptData* const sd = &(g_model.scriptsData[idx]);
|
||||
ScriptInputsOutputs* const sio = &(scriptInputsOutputs[idx]);
|
||||
bool* const updatePtr = &update;
|
||||
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SCRIPT, 0, COLOR_THEME_PRIMARY1);
|
||||
// File
|
||||
auto line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_SCRIPT, 0, COLOR_THEME_PRIMARY1);
|
||||
auto fc = new FileChoice(
|
||||
window, grid.getFieldSlot(), SCRIPTS_MIXES_PATH, SCRIPTS_EXT,
|
||||
line, rect_t{}, SCRIPTS_MIXES_PATH, SCRIPTS_EXT,
|
||||
LEN_SCRIPT_FILENAME,
|
||||
[=]() { return stringFromNtString(sd->file); },
|
||||
[=](std::string newValue) {
|
||||
@@ -90,61 +114,48 @@ class ScriptEditWindow : public Page {
|
||||
}
|
||||
storageDirty(EE_MODEL);
|
||||
LUA_LOAD_MODEL_SCRIPT(idx); // async reload ...
|
||||
*updatePtr = true; // TODO: sets update==true and afterwards calls rebuildBody() via checkEvents()
|
||||
update = true;
|
||||
}, true);
|
||||
grid.nextLine();
|
||||
|
||||
// Custom name
|
||||
new StaticText(window, grid.getLabelSlot(), STR_NAME, 0, COLOR_THEME_PRIMARY1);
|
||||
new ModelTextEdit(window, grid.getFieldSlot(), sd->name, sizeof(sd->name));
|
||||
grid.nextLine();
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1);
|
||||
new ModelTextEdit(line, rect_t{}, sd->name, sizeof(sd->name));
|
||||
|
||||
if (sio->inputsCount > 0) {
|
||||
new Subtitle(window, grid.getLineSlot(), STR_INPUTS, 0, COLOR_THEME_PRIMARY1);
|
||||
grid.nextLine();
|
||||
|
||||
auto gInputs = new FormGroup(window, grid.getFieldSlot(), FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST);
|
||||
GridLayout inputsGrid(gInputs);
|
||||
line = form->newLine(&grid);
|
||||
new Subtitle(line, rect_t{}, STR_INPUTS, 0, COLOR_THEME_PRIMARY1);
|
||||
|
||||
for (int i = 0; i < sio->inputsCount; i++) {
|
||||
line = form->newLine(&grid);
|
||||
ScriptInput& si = sio->inputs[i];
|
||||
new StaticText(window, grid.getLabelSlot(true), si.name, 0, COLOR_THEME_PRIMARY1);
|
||||
grid.nextLine();
|
||||
auto lbl = new StaticText(line, rect_t{}, si.name, 0, COLOR_THEME_PRIMARY1);
|
||||
lbl->padLeft(10);
|
||||
if (si.type == INPUT_TYPE_VALUE) {
|
||||
(new NumberEdit(gInputs, inputsGrid.getSlot(), si.min, si.max,
|
||||
(new NumberEdit(line, rect_t{}, si.min, si.max,
|
||||
GET_SET_WITH_OFFSET(sd->inputs[i].value, si.def)))->setDefault(si.def);
|
||||
} else {
|
||||
new SourceChoice(gInputs, inputsGrid.getSlot(), 0,
|
||||
MIXSRC_LAST_TELEM,
|
||||
new SourceChoice(line, rect_t{}, 0, MIXSRC_LAST_TELEM,
|
||||
GET_SET_DEFAULT(sd->inputs[i].source));
|
||||
}
|
||||
inputsGrid.nextLine();
|
||||
}
|
||||
gInputs->setHeight(inputsGrid.getWindowHeight());
|
||||
}
|
||||
|
||||
if (sio->outputsCount > 0) {
|
||||
new Subtitle(window, grid.getLabelSlot(), STR_OUTPUTS, 0, COLOR_THEME_PRIMARY1);
|
||||
grid.nextLine();
|
||||
|
||||
auto gOutputs =
|
||||
new FormGroup(window, grid.getLineSlot(),
|
||||
FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST);
|
||||
FormGridLayout outputsGrid(gOutputs->width());
|
||||
line = form->newLine(&grid);
|
||||
new Subtitle(line, rect_t{}, STR_OUTPUTS, 0, COLOR_THEME_PRIMARY1);
|
||||
|
||||
for (int i = 0; i < sio->outputsCount; i++) {
|
||||
line = form->newLine(&grid);
|
||||
ScriptOutput* so = &(sio->outputs[i]);
|
||||
new DynamicText(gOutputs, outputsGrid.getLabelSlot(), [=]() {
|
||||
auto lbl = new DynamicText(line, rect_t{}, [=]() {
|
||||
char s[16];
|
||||
getSourceString(s, MIXSRC_FIRST_LUA + (idx * MAX_SCRIPT_OUTPUTS) + i);
|
||||
return std::string(s, sizeof(s) - 1);
|
||||
}, COLOR_THEME_PRIMARY1);
|
||||
new DynamicNumber<int16_t>(gOutputs, outputsGrid.getFieldSlot(), [=]() { return calcRESXto1000(so->value); }, COLOR_THEME_PRIMARY1);
|
||||
|
||||
outputsGrid.nextLine();
|
||||
lbl->padLeft(10);
|
||||
new DynamicNumber<int16_t>(line, rect_t{}, [=]() { return calcRESXto1000(so->value); }, COLOR_THEME_PRIMARY1);
|
||||
}
|
||||
gOutputs->setHeight(outputsGrid.getWindowHeight());
|
||||
grid.addWindow(gOutputs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,61 +171,112 @@ class ScriptEditWindow : public Page {
|
||||
class ScriptLineButton : public Button
|
||||
{
|
||||
public:
|
||||
ScriptLineButton(FormGroup* parent, const rect_t& rect,
|
||||
ScriptLineButton(Window* parent, const rect_t& rect,
|
||||
const ScriptData& scriptData,
|
||||
const ScriptInternalData* runtimeData) :
|
||||
Button(parent, rect), scriptData(scriptData), runtimeData(runtimeData)
|
||||
const ScriptInternalData* runtimeData,
|
||||
uint8_t index) :
|
||||
Button(parent, rect, nullptr, 0, 0, input_mix_line_create),
|
||||
scriptData(scriptData),
|
||||
runtimeData(runtimeData),
|
||||
index(index)
|
||||
{
|
||||
#if LCD_H > LCD_W
|
||||
padTop(5);
|
||||
#endif
|
||||
padLeft(3);
|
||||
padRight(3);
|
||||
lv_obj_set_layout(lvobj, LV_LAYOUT_GRID);
|
||||
lv_obj_set_grid_dsc_array(lvobj, b_col_dsc, row_dsc);
|
||||
lv_obj_set_style_pad_row(lvobj, 0, 0);
|
||||
lv_obj_set_style_pad_column(lvobj, 4, 0);
|
||||
|
||||
lv_obj_update_layout(parent->getLvObj());
|
||||
if(lv_obj_is_visible(lvobj)) delayed_init(nullptr);
|
||||
|
||||
lv_obj_add_event_cb(lvobj, ScriptLineButton::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr);
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer* dc) override
|
||||
static void on_draw(lv_event_t * e)
|
||||
{
|
||||
LcdFlags textColor = COLOR_THEME_SECONDARY1;
|
||||
LcdFlags bgColor = COLOR_THEME_PRIMARY2;
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
auto line = (ScriptLineButton*)lv_obj_get_user_data(target);
|
||||
if (line) {
|
||||
if (!line->init)
|
||||
line->delayed_init(e);
|
||||
else
|
||||
line->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void delayed_init(lv_event_t* e)
|
||||
{
|
||||
auto lbl = lv_label_create(lvobj);
|
||||
lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_LEFT, 0);
|
||||
lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), bgColor);
|
||||
lv_label_set_text(lbl, (std::string("LUA") + std::to_string(index + 1)).c_str());
|
||||
|
||||
if (runtimeData) {
|
||||
coord_t x = 2*FIELD_PADDING_LEFT;
|
||||
coord_t y = FIELD_PADDING_TOP;
|
||||
char s[20];
|
||||
|
||||
x = dc->drawSizedText(x, y, scriptData.name, sizeof(scriptData.name), textColor);
|
||||
x += 4*FIELD_PADDING_LEFT;
|
||||
lbl = lv_label_create(lvobj);
|
||||
lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_LEFT, 0);
|
||||
lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
|
||||
dc->drawSizedText(x, y, scriptData.file, sizeof(scriptData.file), textColor);
|
||||
strAppend(s, scriptData.name, LEN_SCRIPT_NAME);
|
||||
lv_label_set_text(lbl, s);
|
||||
|
||||
lbl = lv_label_create(lvobj);
|
||||
lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_LEFT, 0);
|
||||
lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
|
||||
strAppend(s, scriptData.file, LEN_SCRIPT_FILENAME);
|
||||
lv_label_set_text(lbl, s);
|
||||
|
||||
lbl = lv_label_create(lvobj);
|
||||
lv_obj_set_style_text_align(lbl, LV_TEXT_ALIGN_LEFT, 0);
|
||||
lv_obj_set_grid_cell(lbl, LV_GRID_ALIGN_START, 3, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
|
||||
x = width() - 2*FIELD_PADDING_LEFT;
|
||||
y = FIELD_PADDING_TOP;
|
||||
textColor |= RIGHT;
|
||||
|
||||
// TODO: runtimeData->instructions has no value
|
||||
switch (runtimeData->state) {
|
||||
case SCRIPT_SYNTAX_ERROR:
|
||||
dc->drawSizedText(x, y, STR_SCRIPT_ERROR, strlen(STR_SCRIPT_ERROR), textColor);
|
||||
lv_label_set_text(lbl, STR_SCRIPT_ERROR);
|
||||
break;
|
||||
case SCRIPT_NOFILE:
|
||||
dc->drawSizedText(x, y, STR_NEEDS_FILE, strlen(STR_NEEDS_FILE), textColor);
|
||||
case SCRIPT_NOFILE:
|
||||
lv_label_set_text(lbl, STR_NEEDS_FILE);
|
||||
break;
|
||||
case SCRIPT_OK:
|
||||
dc->drawSizedText(x, y, "-", 1, textColor);
|
||||
case SCRIPT_OK:
|
||||
lv_label_set_text(lbl, "-");
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
lv_label_set_text(lbl, "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// bounding rect
|
||||
if (hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, COLOR_THEME_FOCUS);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, COLOR_THEME_SECONDARY2);
|
||||
init = true;
|
||||
refresh();
|
||||
lv_obj_update_layout(lvobj);
|
||||
|
||||
if(e) {
|
||||
auto param = lv_event_get_param(e);
|
||||
lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param);
|
||||
}
|
||||
}
|
||||
|
||||
void refresh()
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
bool init = false;
|
||||
uint8_t index;
|
||||
const ScriptData& scriptData;
|
||||
const ScriptInternalData* runtimeData;
|
||||
};
|
||||
|
||||
#define CM_BUTTON_H 34
|
||||
|
||||
ModelMixerScriptsPage::ModelMixerScriptsPage() :
|
||||
PageTab(STR_MENUCUSTOMSCRIPTS, ICON_MODEL_LUA_SCRIPTS)
|
||||
{
|
||||
@@ -230,13 +292,19 @@ void ModelMixerScriptsPage::rebuild(FormWindow * window, int8_t focusIdx)
|
||||
|
||||
void ModelMixerScriptsPage::build(FormWindow * window, int8_t focusIdx)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
grid.setLabelWidth(66);
|
||||
window->padAll(0);
|
||||
|
||||
auto form = new FormWindow(window, rect_t{});
|
||||
form->setFlexLayout();
|
||||
form->padAll(4);
|
||||
|
||||
FlexGridLayout grid(col_dsc, row_dsc, 2);
|
||||
|
||||
FormWindow::Line* line;
|
||||
|
||||
int8_t scriptIdx = 0;
|
||||
for (int8_t idx = 0; idx < MAX_SCRIPTS; idx++) {
|
||||
auto line = form->newLine(&grid);
|
||||
|
||||
ScriptInternalData* runtimeData = nullptr;
|
||||
ScriptData* const sd = &(g_model.scriptsData[idx]);
|
||||
@@ -246,12 +314,7 @@ void ModelMixerScriptsPage::build(FormWindow * window, int8_t focusIdx)
|
||||
runtimeData = &(scriptInternalData[scriptIdx++]);
|
||||
}
|
||||
|
||||
// LUAx label
|
||||
auto const txt = new StaticText(window, grid.getLabelSlot(),
|
||||
std::string("LUA") + std::to_string(idx + 1),
|
||||
BUTTON_BACKGROUND, COLOR_THEME_PRIMARY1 | CENTERED);
|
||||
|
||||
Button* const button = new ScriptLineButton(window, grid.getFieldSlot(), *sd, runtimeData);
|
||||
Button* const button = new ScriptLineButton(line, rect_t{0, 0, window->width() - 12, CM_BUTTON_H}, *sd, runtimeData, idx);
|
||||
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
Menu* const menu = new Menu(window);
|
||||
@@ -269,23 +332,7 @@ void ModelMixerScriptsPage::build(FormWindow * window, int8_t focusIdx)
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(COLOR_THEME_FOCUS);
|
||||
txt->setTextFlags(COLOR_THEME_PRIMARY2 | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(COLOR_THEME_SECONDARY2);
|
||||
txt->setTextFlags(COLOR_THEME_PRIMARY1 | CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
txt->setHeight(button->height());
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
|
||||
grid.nextLine();
|
||||
}
|
||||
|
||||
void ModelMixerScriptsPage::editLine(FormWindow * window, uint8_t idx)
|
||||
|
||||
Reference in New Issue
Block a user