From c222d668557b83ec295eb04d47058b75b572c603 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Mon, 30 May 2022 18:29:12 +0200 Subject: [PATCH] model select: simpler implementation Use `LV_FLEX_FLOW_ROW_WRAP` to get all the buttons laid out properly. --- radio/src/gui/colorlcd/model_select.cpp | 345 ++++++++++-------------- 1 file changed, 149 insertions(+), 196 deletions(-) diff --git a/radio/src/gui/colorlcd/model_select.cpp b/radio/src/gui/colorlcd/model_select.cpp index d04a8f186..9ceb296e5 100644 --- a/radio/src/gui/colorlcd/model_select.cpp +++ b/radio/src/gui/colorlcd/model_select.cpp @@ -37,8 +37,8 @@ constexpr coord_t MODEL_SELECT_CELL_WIDTH = (LCD_W - (MODEL_CELLS_PER_LINE + 1) * MODEL_CELL_PADDING) / MODEL_CELLS_PER_LINE; constexpr coord_t MODEL_SELECT_CELL_HEIGHT = 92; -constexpr coord_t MODEL_IMAGE_WIDTH = MODEL_SELECT_CELL_WIDTH; -constexpr coord_t MODEL_IMAGE_HEIGHT = 72; +// constexpr coord_t MODEL_IMAGE_WIDTH = MODEL_SELECT_CELL_WIDTH; +// constexpr coord_t MODEL_IMAGE_HEIGHT = 72; 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; @@ -87,7 +87,7 @@ class TemplatePage : public Page unsigned int count = 0; static std::function update; - void paint(BitmapBuffer *dc) + void paint(BitmapBuffer *dc) override { Page::paint(dc); rect_t rect = body.getRect(); @@ -321,6 +321,9 @@ class ModelButton : public Button ModelButton(FormGroup *parent, const rect_t &rect, ModelCell *modelCell) : Button(parent, rect), modelCell(modelCell) { + setWidth(MODEL_SELECT_CELL_WIDTH); + setHeight(MODEL_SELECT_CELL_HEIGHT); + load(); } @@ -439,229 +442,181 @@ class ModelButton : public Button } } - const char *modelFilename() { return modelCell->modelFilename; } + const char* modelFilename() { return modelCell->modelFilename; } + ModelCell* getModelCell() const { return modelCell; } protected: ModelCell *modelCell; BitmapBuffer *buffer = nullptr; }; +static void _saveTemplate(ModelCell* model) +{ + storageDirty(EE_MODEL); + storageCheck(true); + constexpr size_t size = sizeof(model->modelName) + sizeof(YAML_EXT); + char modelName[size]; + snprintf(modelName, size, "%s%s", model->modelName, YAML_EXT); + char templatePath[FF_MAX_LFN]; + snprintf(templatePath, FF_MAX_LFN, "%s%c%s", PERS_TEMPL_PATH, '/', modelName); + sdCheckAndCreateDirectory(TEMPLATES_PATH); + sdCheckAndCreateDirectory(PERS_TEMPL_PATH); + if (isFileAvailable(templatePath)) { + new ConfirmDialog(Layer::back(), STR_FILE_EXISTS, STR_ASK_OVERWRITE, [=] { + sdCopyFile(model->modelFilename, MODELS_PATH, modelName, PERS_TEMPL_PATH); + }); + } else { + sdCopyFile(model->modelFilename, MODELS_PATH, modelName, PERS_TEMPL_PATH); + } +} + class ModelCategoryPageBody : public FormWindow { public: - ModelCategoryPageBody(FormWindow *parent, const rect_t &rect, - ModelsCategory *category) : - FormWindow(parent, rect//, FORM_FORWARD_FOCUS - ), category(category) + ModelCategoryPageBody(Window* parent, ModelsCategory* category) : + FormWindow(parent, rect_t{}), category(category) { - update(); + setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, MODEL_CELL_PADDING); + lv_obj_set_style_pad_row(lvobj, MODEL_CELL_PADDING, 0); + lv_obj_set_style_pad_all(lvobj, MODEL_CELL_PADDING, 0); + + for (auto &model : *category) + addModelButton(model); } - void update(int selected = -1) + protected: + ModelsCategory *category; + + void addModelButton(ModelCell *model) { - clear(); + auto btn = new ModelButton(this, rect_t{}, model); + btn->setPressHandler([=]() -> uint8_t { + modelMenu(btn); + return 0; + }); + } - if (selected < 0) { - auto model = modelslist.getCurrentModel(); - selected = category->getModelIndex(model); - if (selected < 0) selected = 0; + void modelMenu(ModelButton* btn) + { + Menu *menu = new Menu(parent); + ModelCell* model = btn->getModelCell(); + if (model != modelslist.getCurrentModel()) { + menu->addLine(STR_SELECT_MODEL, [=]() { selectModel(btn); }); + } + menu->addLine(STR_CREATE_MODEL, [=]() { createModel(); }); + menu->addLine(STR_DUPLICATE_MODEL, [=]() { duplicateModel(model); }); + menu->addLine(STR_SAVE_TEMPLATE, std::bind(_saveTemplate, model)); + if (model != modelslist.getCurrentModel()) { + // Move + if(modelslist.getCategories().size() > 1) { + menu->addLine(STR_MOVE_MODEL, [=]() { moveModel(btn); }); + } + menu->addLine(STR_DELETE_MODEL, [=]() { deleteModel(btn); }); + } + } + + void selectModel(ModelButton* btn) + { + bool modelConnected = + TELEMETRY_STREAMING() && !g_eeGeneral.disableRssiPoweroffAlarm; + if (modelConnected) { + AUDIO_ERROR_MESSAGE(AU_MODEL_STILL_POWERED); + if (!confirmationDialog(STR_MODEL_STILL_POWERED, nullptr, false, []() { + tmr10ms_t startTime = getTicks(); + while (!TELEMETRY_STREAMING()) { + if (getTicks() - startTime > TELEMETRY_CHECK_DELAY10ms) break; + } + return !TELEMETRY_STREAMING() || + g_eeGeneral.disableRssiPoweroffAlarm; + })) { + return; // stop if connected but not confirmed + } } - int index = 0; - coord_t y = MODEL_CELL_PADDING; - coord_t x = MODEL_CELL_PADDING; + // store changes (if any) and load selected model + storageFlushCurrentModel(); + storageCheck(true); + memcpy(g_eeGeneral.currModelFilename, btn->modelFilename(), + LEN_MODEL_FILENAME); - ModelButton* selectButton = nullptr; - for (auto &model : *category) { - auto button = new ModelButton( - this, {x, y, MODEL_SELECT_CELL_WIDTH, MODEL_SELECT_CELL_HEIGHT}, - model); - button->setPressHandler([=]() -> uint8_t { - Menu *menu = new Menu(parent); - if (model != modelslist.getCurrentModel()) { - menu->addLine(STR_SELECT_MODEL, [=]() { - bool modelConnected = TELEMETRY_STREAMING() && - !g_eeGeneral.disableRssiPoweroffAlarm; - if (modelConnected) { - AUDIO_ERROR_MESSAGE(AU_MODEL_STILL_POWERED); - if (!confirmationDialog( - STR_MODEL_STILL_POWERED, nullptr, false, []() { - tmr10ms_t startTime = getTicks(); - while (!TELEMETRY_STREAMING()) { - if (getTicks() - startTime > TELEMETRY_CHECK_DELAY10ms) - break; - } - return !TELEMETRY_STREAMING() || - g_eeGeneral.disableRssiPoweroffAlarm; - })) { - return; // stop if connected but not confirmed - } - } + loadModel(g_eeGeneral.currModelFilename, false); + storageDirty(EE_GENERAL); + storageCheck(true); - // store changes (if any) and load selected model - storageFlushCurrentModel(); - storageCheck(true); - memcpy(g_eeGeneral.currModelFilename, model->modelFilename, - LEN_MODEL_FILENAME); + modelslist.setCurrentModel(btn->getModelCell()); + modelslist.setCurrentCategory(category); + checkAll(); - loadModel(g_eeGeneral.currModelFilename, false); - storageDirty(EE_GENERAL); - storageCheck(true); + // Exit to main view + auto w = Layer::back(); + if (w) w->onCancel(); + } - modelslist.setCurrentModel(model); - modelslist.setCurrentCategory(category); - menu->deleteLater(); - onEvent(EVT_KEY_FIRST(KEY_EXIT)); - checkAll(); - }); - } - menu->addLine(STR_CREATE_MODEL, getCreateModelAction()); - menu->addLine(STR_DUPLICATE_MODEL, [=]() { - char duplicatedFilename[LEN_MODEL_FILENAME + 1]; - memcpy(duplicatedFilename, model->modelFilename, - sizeof(duplicatedFilename)); - if (findNextFileIndex(duplicatedFilename, LEN_MODEL_FILENAME, - MODELS_PATH)) { - sdCopyFile(model->modelFilename, MODELS_PATH, duplicatedFilename, - MODELS_PATH); - modelslist.addModel(category, duplicatedFilename); - update(index); - } else { - POPUP_WARNING("Invalid File"); - } - }); - menu->addLine(STR_SAVE_TEMPLATE, [=]() { - storageDirty(EE_MODEL); - storageCheck(true); - constexpr size_t size = sizeof(model->modelName) + sizeof(YAML_EXT); - char modelName[size]; - snprintf(modelName, size, "%s%s", model->modelName, YAML_EXT); - char templatePath[FF_MAX_LFN]; - snprintf(templatePath, FF_MAX_LFN, "%s%c%s", PERS_TEMPL_PATH, '/', modelName); - sdCheckAndCreateDirectory(TEMPLATES_PATH); - sdCheckAndCreateDirectory(PERS_TEMPL_PATH); - if (isFileAvailable(templatePath)) { - new ConfirmDialog(parent, STR_FILE_EXISTS, STR_ASK_OVERWRITE, - [=] { - sdCopyFile(model->modelFilename, MODELS_PATH, modelName, PERS_TEMPL_PATH); - }); - } else { - sdCopyFile(model->modelFilename, MODELS_PATH, modelName, PERS_TEMPL_PATH); - } - }); - if (model != modelslist.getCurrentModel()) { - // Move - if(modelslist.getCategories().size() > 1) { - menu->addLine(STR_MOVE_MODEL, [=]() { - auto moveToMenu = new Menu(parent); - moveToMenu->setTitle(STR_MOVE_MODEL); - for (auto newcategory: modelslist.getCategories()) { - if(category != newcategory) { - moveToMenu->addLine(std::string(newcategory->name, sizeof(newcategory->name)), [=]() { - modelslist.moveModel(model, category, newcategory); - update(index < (int)category->size() - 1 ? index : index - 1); - modelslist.save(); - }); - } - } - }); - } - menu->addLine(STR_DELETE_MODEL, [=]() { - new ConfirmDialog( - parent, STR_DELETE_MODEL, - std::string(model->modelName, sizeof(model->modelName)) - .c_str(), - [=] { - modelslist.removeModel(category, model); - update(index < (int)category->size() - 1 ? index : index - 1); - }); - }); - } - return 1; + void createModel() + { + storageCheck(true); + auto model = modelslist.addModel(category, ::createModel(), false); + modelslist.setCurrentModel(model); + new SelectTemplateFolder([=]() { + model->setModelName(g_model.header.name); + modelslist.save(); + addModelButton(model); }); + } - if (selected == index) { - selectButton = button; - } - - index++; - - if (index % MODEL_CELLS_PER_LINE == 0) { - x = MODEL_CELL_PADDING; - y += MODEL_SELECT_CELL_HEIGHT + MODEL_CELL_PADDING; - } else { - x += MODEL_CELL_PADDING + MODEL_SELECT_CELL_WIDTH; - } + void duplicateModel(ModelCell* model) + { + char duplicatedFilename[LEN_MODEL_FILENAME + 1]; + memcpy(duplicatedFilename, model->modelFilename, + sizeof(duplicatedFilename)); + if (findNextFileIndex(duplicatedFilename, LEN_MODEL_FILENAME, + MODELS_PATH)) { + sdCopyFile(model->modelFilename, MODELS_PATH, duplicatedFilename, + MODELS_PATH); + auto new_model = modelslist.addModel(category, duplicatedFilename); + addModelButton(new_model); + } else { + POPUP_WARNING("Invalid File"); // TODO: translation } + } - if (index % MODEL_CELLS_PER_LINE != 0) { - y += MODEL_SELECT_CELL_HEIGHT + MODEL_CELL_PADDING; - } + void deleteModel(ModelButton* btn) + { + ModelCell* model = btn->getModelCell(); + new ConfirmDialog( + parent, STR_DELETE_MODEL, + std::string(model->modelName, sizeof(model->modelName)).c_str(), [=] { + modelslist.removeModel(category, model); + btn->deleteLater(); + }); + } - // if (category->empty()) { - // setFocus(); - // } else - if (selectButton) { - lv_group_focus_obj(selectButton->getLvObj()); - // selectButton->setFocus(); + void moveModel(ModelButton* btn) + { + auto moveToMenu = new Menu(parent); + moveToMenu->setTitle(STR_MOVE_MODEL); + + auto model = btn->getModelCell(); + for (auto newcategory : modelslist.getCategories()) { + if (category != newcategory) { + moveToMenu->addLine( + std::string(newcategory->name, sizeof(newcategory->name)), [=]() { + modelslist.moveModel(model, category, newcategory); + modelslist.save(); + btn->deleteLater(); + }); + } } } void addFirstModel() { Menu *menu = new Menu(this); - menu->addLine(STR_CREATE_MODEL, getCreateModelAction()); + menu->addLine(STR_CREATE_MODEL, [=]() { createModel(); }); } -#if defined(HARDWARE_KEYS) - void onEvent(event_t event) override + void onClicked() override { - if (event == EVT_KEY_BREAK(KEY_ENTER)) { - addFirstModel(); - } else { - FormWindow::onEvent(event); - } - } -#endif - -#if defined(HARDWARE_TOUCH) - bool onTouchEnd(coord_t x, coord_t y) override - { - if(category->size() == 0) - addFirstModel(); - else - FormWindow::onTouchEnd(x,y); - return true; - } -#endif - - - // void setFocus(uint8_t flag = SET_FOCUS_DEFAULT, - // Window *from = nullptr) override - // { - // if (category->empty()) { - // // use Window::setFocus() to avoid forwarding focus to nowhere - // // this crashes currently in libopenui - // Window::setFocus(flag, from); - // } else { - // FormWindow::setFocus(flag, from); - // } - // } - - protected: - ModelsCategory *category; - - std::function getCreateModelAction() - { - return [=]() { - storageCheck(true); - auto model = modelslist.addModel(category, createModel(), false); - modelslist.setCurrentModel(model); - new SelectTemplateFolder([=]() { - model->setModelName(g_model.header.name); - modelslist.save(); - update(category->size() - 1); - }); - }; + if (category->size() == 0) addFirstModel(); } }; @@ -678,9 +633,7 @@ class ModelCategoryPage : public PageTab void build(FormWindow *window) override { - new ModelCategoryPageBody( - window, {0, 0, LCD_W, window->height()}, - category); + new ModelCategoryPageBody(window, category); } };