From 8528d542a6d62289b3c3cf9a3eeb5c8506f816bf Mon Sep 17 00:00:00 2001 From: Bertrand Songis Date: Mon, 28 Oct 2019 18:00:11 +0100 Subject: [PATCH] Model Select cosmetics --- radio/src/gui/colorlcd/model_select.cpp | 325 ++++++++------ radio/src/gui/colorlcd/model_select.h | 4 +- radio/src/gui/colorlcd/model_setup.cpp | 15 +- radio/src/gui/colorlcd/modelslist.cpp | 572 ------------------------ radio/src/gui/colorlcd/modelslist.h | 141 ------ radio/src/gui/colorlcd/view_main.cpp | 2 +- radio/src/sdcard.cpp | 4 +- radio/src/sdcard.h | 2 +- radio/src/storage/modelslist.cpp | 130 ++---- radio/src/storage/modelslist.h | 36 +- radio/src/storage/sdcard_raw.cpp | 2 +- radio/src/thirdparty/libopenui | 2 +- 12 files changed, 256 insertions(+), 979 deletions(-) delete mode 100644 radio/src/gui/colorlcd/modelslist.cpp delete mode 100644 radio/src/gui/colorlcd/modelslist.h diff --git a/radio/src/gui/colorlcd/model_select.cpp b/radio/src/gui/colorlcd/model_select.cpp index 93a775efe..b31f04308 100644 --- a/radio/src/gui/colorlcd/model_select.cpp +++ b/radio/src/gui/colorlcd/model_select.cpp @@ -41,9 +41,9 @@ enum ModelDeleteMode { uint8_t selectMode, deleteMode; //ModelsList modelslist; -ModelsCategory * currentCategory; -int currentCategoryIndex; -ModelCell * currentModel; +//ModelsCategory * currentCategory; +//int currentCategoryIndex; +//ModelCell * currentModel; /* void drawCategory(BitmapBuffer * dc, coord_t y, const char * name, bool selected) @@ -74,8 +74,8 @@ void drawModel(coord_t x, coord_t y, ModelCell * model, bool current, bool selec } */ -uint16_t categoriesVerticalOffset = 0; -uint16_t categoriesVerticalPosition = 0; +//uint16_t categoriesVerticalOffset = 0; +//uint16_t categoriesVerticalPosition = 0; #define MODEL_INDEX() (menuVerticalPosition*2+menuHorizontalPosition) #if 0 @@ -87,7 +87,7 @@ void setCurrentModel(unsigned int index) } #endif - +#if 0 void setCurrentCategory(unsigned int index) { currentCategoryIndex = index; @@ -101,182 +101,245 @@ void setCurrentCategory(unsigned int index) else currentModel = NULL;*/ } +#endif -void initModelsList() -{ - modelslist.load(); - - categoriesVerticalOffset = 0; - bool found = false; - int index = 0; - for (auto & category : modelslist.getCategories()) { - if (category == modelslist.getCurrentCategory()) { - setCurrentCategory(index); - found = true; - break; - } - index++; - } - if (!found) { - setCurrentCategory(0); - } - - menuVerticalOffset = 0; - found = false; - index = 0; - for (auto & cell : *currentCategory) { - if (cell == modelslist.getCurrentModel()) { - // setCurrentModel(index); - found = true; - break; - } - } - if (!found) { - // setCurrentModel(0); - } -} - -class ModelselectButton: public Button { +class ModelButton: public Button { public: - ModelselectButton(FormGroup * parent, const rect_t & rect, ModelCell * modelCell, Window * footer); + ModelButton(FormGroup * parent, const rect_t & rect, ModelCell * modelCell, Window * footer) : + Button(parent, rect), + modelCell(modelCell) + { + load(); + } + + void load() + { + uint8_t version; + + PACK(struct { + ModelHeader header; + TimerData timers[MAX_TIMERS]; + }) partialModel; + const char * error = nullptr; + + if (strncmp(modelCell->modelFilename, g_eeGeneral.currModelFilename, LEN_MODEL_FILENAME) == 0) { + memcpy(&partialModel.header, &g_model.header, sizeof(partialModel)); + } + else { + error = readModel(modelCell->modelFilename, (uint8_t *)&partialModel.header, sizeof(partialModel), &version); + // LEN_BITMAP_NAME has now 4 bytes more + if (version <= 218) { + memmove(partialModel.timers, &(partialModel.header.bitmap[10]), sizeof(TimerData)*MAX_TIMERS); + memclear(&(partialModel.header.bitmap[10]), 4); + } + } + +// if (modelCell->modelName[0] == '\0' && !error) +// setModelName(partialModel.header.name); // resets buffer!!! + + buffer = new BitmapBuffer(BMP_RGB565, MODELCELL_WIDTH, MODELCELL_HEIGHT); + if (buffer == nullptr) { + return; + } + buffer->clear(DEFAULT_BGCOLOR); + + if (error) { + buffer->drawText(5, 2, "(Invalid Model)", DEFAULT_COLOR); + buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, DEFAULT_COLOR); + } + else { + char timerName[LEN_TIMER_STRING]; + buffer->drawSizedText(5, 2, modelCell->modelName, LEN_MODEL_NAME, FONT(XS) | DEFAULT_COLOR); + getTimerString(timerName, 0); + for (auto & timer : partialModel.timers) { + if (timer.mode > 0 && timer.persistent) { + getTimerString(timerName, timer.value); + break; + } + } + buffer->drawText(101, 40, timerName, DEFAULT_COLOR); + for (int i = 0; i < 4; i++) { + buffer->drawBitmapPattern(104+i*11, 25, LBM_SCORE0, TITLE_BGCOLOR); + } + GET_FILENAME(filename, BITMAPS_PATH, partialModel.header.bitmap, ""); + const BitmapBuffer * bitmap = BitmapBuffer::loadBitmap(filename); + if (bitmap) { + buffer->drawScaledBitmap(bitmap, 5, 24, 56, 32); + delete bitmap; + } + else { + buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, DEFAULT_COLOR); + } + } + buffer->drawSolidHorizontalLine(5, 19, 143, LINE_COLOR); + } void paint(BitmapBuffer * dc) override { - dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? SCROLLBOX_COLOR : CURVE_AXIS_COLOR); - dc->drawBitmap(10, 2, modelCell->getBuffer()); + FormField::paint(dc); + dc->drawBitmap(10, 2, buffer); if (modelCell == modelslist.getCurrentModel()) { dc->drawBitmapPattern(112, 71, LBM_ACTIVE_MODEL, TITLE_BGCOLOR); } } - const char * modelFilename() { + const char * modelFilename() + { return modelCell->modelFilename; } protected: ModelCell * modelCell; + BitmapBuffer * buffer = nullptr; }; -class ModelselectFooter: public Window { +class ModelSelectFooter: public Window { public: - ModelselectFooter(Window * parent, const rect_t & rect): + ModelSelectFooter(Window * parent, const rect_t & rect): Window(parent, rect) { } + void setCurrentModel(ModelCell * model) + { + currentModel = model; + invalidate(); + } + void paint(BitmapBuffer * dc) override { - dc->drawSolidFilledRect(0, 5, rect.w, 2, CURVE_AXIS_COLOR); + dc->drawSolidFilledRect(0, 0, width(), height(), DISABLE_COLOR); dc->drawBitmap(7, 12, modelselSdFreeBitmap); uint32_t size = sdGetSize() / 100; dc->drawNumber(24, 11, size, PREC1|FONT(XS), 0, NULL, "GB"); dc->drawBitmap(77, 12, modelselModelQtyBitmap); dc->drawNumber(99, 11, modelslist.getModelsCount(), FONT(XS)); - ModelselectButton * selectedModel = dynamic_cast(focusWindow); - if (selectedModel) { + if (currentModel) { dc->drawBitmap(7, 37, modelselModelNameBitmap); - dc->drawText(24, 32, selectedModel->modelFilename(), FONT(XS) | DEFAULT_COLOR); + dc->drawText(24, 32, currentModel->modelFilename, FONT(XS) | DEFAULT_COLOR); } } + + protected: + ModelCell * currentModel = nullptr; }; -class ModelselectPage: public PageTab { +class ModelCategoryPageBody: public FormWindow { public: - ModelselectPage() : - PageTab(STR_MODEL_SELECT, ICON_MODEL_CURVES /*ICON_MODEL_SELECT*/) + ModelCategoryPageBody(FormWindow * parent, const rect_t & rect, ModelsCategory * category, ModelSelectFooter * footer): + FormWindow(parent, rect, FORM_FORWARD_FOCUS), + category(category), + footer(footer) { + update(); } - static void updateModels(FormGroup * window, Window * footer, int selected = -1) + void update(int selected = 0) { - window->clear(); + clear(); + int index = 0; - for (auto it = currentCategory->begin(); it != currentCategory->end(); ++it, ++index) { - Button * button = new ModelselectButton(window, {10, 10 + index * 104, LCD_W - 20, 94}, *it, footer); + for (auto & model: * category) { + auto button = new ModelButton(this, {10, 10 + index * 104, LCD_W - 20, 94}, model, nullptr); + + button->setFocusHandler([=] { + footer->setCurrentModel(model); + }); + + button->setPressHandler([=]() -> uint8_t { + if (button->hasFocus()) { + Menu * menu = new Menu(); + if (model != modelslist.getCurrentModel()) { + menu->addLine(STR_SELECT_MODEL, [=]() { + // we store the latest changes if any + storageFlushCurrentModel(); + storageCheck(true); + memcpy(g_eeGeneral.currModelFilename, model->modelFilename, LEN_MODEL_FILENAME); + loadModel(g_eeGeneral.currModelFilename, false); + storageDirty(EE_GENERAL); + storageCheck(true); + // chainMenu(menuMainView); + postModelLoad(true); + modelslist.setCurrentModel(model); + update(); // modelslist.getModelIndex(modelCell)); + }); + } + menu->addLine(STR_CREATE_MODEL, [=]() { + storageCheck(true); + modelslist.setCurrentModel(modelslist.addModel(category, createModel())); +#if defined(LUA) + // chainMenu(menuModelWizard); +#endif + update(category->size() - 1); + }); + 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_MOVE_MODEL); + if (model != modelslist.getCurrentModel()) { + menu->addLine(STR_DELETE_MODEL, [=]() { + new ConfirmDialog(STR_DELETE_MODEL, std::string(model->modelName, sizeof(model->modelName)).c_str(), [=] { + modelslist.removeModel(category, model); + update(index > 0 ? index - 1 : 0); + }); + }); + } + } + else { + button->setFocus(); +// footer->invalidate(); + } + return 1; + }); + if (selected == index) { button->setFocus(); } + index++; } - window->adjustInnerHeight(); + + adjustInnerHeight(); } + protected: + ModelsCategory * category; + ModelSelectFooter * footer; +}; + +class ModelCategoryPage: public PageTab { + public: + explicit ModelCategoryPage(ModelsCategory * category) : + PageTab(category->name, ICON_MODEL), + category(category) + { + } + + protected: + ModelsCategory * category; + void build(FormWindow * window) override { - initModelsList(); - FormWindow * body = new FormWindow(window, {0, 0, LCD_W, window->height() - 55}); - Window * footer = new ModelselectFooter(window, {0, window->height() - 55, LCD_W, 55}); - updateModels(body, footer); + auto footer = new ModelSelectFooter(window, {0, window->height() - 55, LCD_W, 55}); + new ModelCategoryPageBody(window, {0, 0, LCD_W, window->height() - 55}, category, footer); } }; -ModelselectMenu::ModelselectMenu(): - TabsGroup(ICON_MODEL_CURVES) +ModelSelectMenu::ModelSelectMenu(): + TabsGroup(ICON_MODEL) { - addTab(new ModelselectPage()); -} + modelslist.load(); -ModelselectButton::ModelselectButton(FormGroup * parent, const rect_t & rect, ModelCell * modelCell, Window * footer): - Button(parent, rect, - [=]() -> uint8_t { - if (hasFocus()) { - Menu * menu = new Menu(); - if (modelCell && modelCell != modelslist.getCurrentModel()) { - menu->addLine(STR_SELECT_MODEL, [=]() { - // we store the latest changes if any - storageFlushCurrentModel(); - storageCheck(true); - memcpy(g_eeGeneral.currModelFilename, modelCell->modelFilename, LEN_MODEL_FILENAME); - loadModel(g_eeGeneral.currModelFilename, false); - storageDirty(EE_GENERAL); - storageCheck(true); - // chainMenu(menuMainView); - postModelLoad(true); - modelslist.setCurrentModel(modelCell); - // TODO ModelselectPage::updateModels(parent, footer, modelslist.getModelIndex(modelCell)); - }); - } - menu->addLine(STR_CREATE_MODEL, [=]() { - storageCheck(true); - modelslist.setCurrentModel(modelslist.addModel(currentCategory, createModel())); -#if defined(LUA) - // chainMenu(menuModelWizard); -#endif - ModelselectPage::updateModels(parent, footer, currentCategory->size() - 1); - }); - if (modelCell) { - menu->addLine(STR_DUPLICATE_MODEL, [=]() { - char duplicatedFilename[LEN_MODEL_FILENAME + 1]; - memcpy(duplicatedFilename, modelCell->modelFilename, sizeof(duplicatedFilename)); - if (findNextFileIndex(duplicatedFilename, LEN_MODEL_FILENAME, MODELS_PATH)) { - sdCopyFile(modelCell->modelFilename, MODELS_PATH, duplicatedFilename, MODELS_PATH); - modelslist.addModel(currentCategory, duplicatedFilename); - ModelselectPage::updateModels(parent, footer, currentCategory->size() - 1); - } - else { - POPUP_WARNING("Invalid File"); - } - }); - } - // menu->addLine(STR_MOVE_MODEL); - if (modelCell && modelCell != modelslist.getCurrentModel()) { - menu->addLine(STR_DELETE_MODEL, [=]() { - // POPUP_CONFIRMATION(STR_DELETEMODEL); - // SET_WARNING_INFO(modelCell->modelName, LEN_MODEL_NAME, 0); - unsigned int index = 0; // TODOmodelslist.getModelIndex(modelCell); - if (index > 0) - --index; - modelslist.removeModel(currentCategory, modelCell); - ModelselectPage::updateModels(parent, footer, index); - }); - } - } - else { - setFocus(); - footer->invalidate(); - } - return 1; - }, BUTTON_CHECKED_ON_FOCUS), - modelCell(modelCell) -{ -} \ No newline at end of file + for (auto category: modelslist.getCategories()) { + addTab(new ModelCategoryPage(category)); + } +} diff --git a/radio/src/gui/colorlcd/model_select.h b/radio/src/gui/colorlcd/model_select.h index 33b977807..05ad387bf 100644 --- a/radio/src/gui/colorlcd/model_select.h +++ b/radio/src/gui/colorlcd/model_select.h @@ -23,9 +23,9 @@ #include "tabsgroup.h" -class ModelselectMenu: public TabsGroup { +class ModelSelectMenu: public TabsGroup { public: - ModelselectMenu(); + ModelSelectMenu(); }; #endif // _MODEL_SELECT_H_ diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index 2a08469ed..f65da7bab 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -21,6 +21,7 @@ #include "model_setup.h" #include "opentx.h" #include "libopenui.h" +#include "storage/modelslist.h" #define SET_DIRTY() storageDirty(EE_MODEL) @@ -835,14 +836,22 @@ void ModelSetupPage::build(FormWindow * window) // Model name new StaticText(window, grid.getLabelSlot(), STR_MODELNAME); - new TextEdit(window, grid.getFieldSlot(), g_model.header.name, sizeof(g_model.header.name)); + auto text = new TextEdit(window, grid.getFieldSlot(), g_model.header.name, sizeof(g_model.header.name)); + text->setChangeHandler([=] { + modelslist.load(); + auto model = modelslist.getCurrentModel(); + if (model) { + model->setModelName(g_model.header.name); + } + SET_DIRTY(); + }); grid.nextLine(); // Bitmap new StaticText(window, grid.getLabelSlot(), STR_BITMAP); - new FileChoice(window, grid.getFieldSlot(), BITMAPS_PATH, BITMAPS_EXT, sizeof(g_model.header.bitmap) - LEN_BITMAPS_EXT, + new FileChoice(window, grid.getFieldSlot(), BITMAPS_PATH, BITMAPS_EXT, sizeof(g_model.header.bitmap), [=]() { - return std::string(g_model.header.bitmap, ZLEN(g_model.header.bitmap)); + return std::string(g_model.header.bitmap, sizeof(g_model.header.bitmap)); }, [=](std::string newValue) { strncpy(g_model.header.bitmap, newValue.c_str(), sizeof(g_model.header.bitmap)); diff --git a/radio/src/gui/colorlcd/modelslist.cpp b/radio/src/gui/colorlcd/modelslist.cpp deleted file mode 100644 index f70bc536e..000000000 --- a/radio/src/gui/colorlcd/modelslist.cpp +++ /dev/null @@ -1,572 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "modelslist.h" -using std::list; - -ModelsList modelslist; - -ModelCell::ModelCell(const char * name) - : buffer(NULL), valid_rfData(false) -{ - strncpy(modelFilename, name, sizeof(modelFilename)); - memset(modelName, 0, sizeof(modelName)); -} - -ModelCell::~ModelCell() -{ - resetBuffer(); -} - -void ModelCell::setModelName(char* name) -{ - zchar2str(modelName, name, LEN_MODEL_NAME); - if (modelName[0] == 0) { - char * tmp; - strncpy(modelName, modelFilename, LEN_MODEL_NAME); - tmp = (char *) memchr(modelName, '.', LEN_MODEL_NAME); - if (tmp != NULL) - *tmp = 0; - } - - resetBuffer(); -} - -void ModelCell::setModelId(uint8_t moduleIdx, uint8_t id) -{ - modelId[moduleIdx] = id; -} - -void ModelCell::resetBuffer() -{ - if (buffer) { - delete buffer; - buffer = NULL; - } -} - -const BitmapBuffer * ModelCell::getBuffer() -{ - if (!buffer) { - loadBitmap(); - } - return buffer; -} - -void ModelCell::loadBitmap() -{ - uint8_t version; - - PACK(struct { - ModelHeader header; - TimerData timers[MAX_TIMERS]; - }) partialmodel; - const char * error = NULL; - - if (strncmp(modelFilename, g_eeGeneral.currModelFilename, LEN_MODEL_FILENAME) == 0) { - memcpy(&partialmodel.header, &g_model.header, sizeof(partialmodel)); - } - else { - error = readModel(modelFilename, (uint8_t *)&partialmodel.header, sizeof(partialmodel), &version); - // LEN_BITMAP_NAME has now 4 bytes more - if (version <= 218) { - memmove(partialmodel.timers, &(partialmodel.header.bitmap[10]), sizeof(TimerData)*MAX_TIMERS); - memclear(&(partialmodel.header.bitmap[10]), 4); - } - } - - if ((modelName[0] == 0) && ! error) - setModelName(partialmodel.header.name); // resets buffer!!! - - buffer = new BitmapBuffer(BMP_RGB565, MODELCELL_WIDTH, MODELCELL_HEIGHT); - if (buffer == NULL) { - return; - } - buffer->clear(DEFAULT_BGCOLOR); - - if (error) { - buffer->drawText(5, 2, "(Invalid Model)", DEFAULT_COLOR); - buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, DEFAULT_COLOR); - } - else { - char timer[LEN_TIMER_STRING]; - buffer->drawSizedText(5, 2, modelName, LEN_MODEL_NAME, FONT(XS)|DEFAULT_COLOR); - getTimerString(timer, 0); - for (uint8_t i = 0; i < MAX_TIMERS; i++) { - if (partialmodel.timers[i].mode > 0 && partialmodel.timers[i].persistent) { - getTimerString(timer, partialmodel.timers[i].value); - break; - } - } - buffer->drawText(101, 40, timer, DEFAULT_COLOR); - for (int i=0; i<4; i++) { - buffer->drawBitmapPattern(104+i*11, 25, LBM_SCORE0, TITLE_BGCOLOR); - } - GET_FILENAME(filename, BITMAPS_PATH, partialmodel.header.bitmap, ""); - const BitmapBuffer * bitmap = BitmapBuffer::load(filename); - if (bitmap) { - buffer->drawScaledBitmap(bitmap, 5, 24, 56, 32); - delete bitmap; - } - else { - buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, DEFAULT_COLOR); - } - } - buffer->drawSolidHorizontalLine(5, 19, 143, LINE_COLOR); -} - -void ModelCell::save(FIL* file) -{ - f_puts(modelFilename, file); - f_putc('\n', file); -} - -void ModelCell::setRfData(ModelData* model) -{ - for (uint8_t i = 0; i < NUM_MODULES; i++) { - modelId[i] = model->header.modelId[i]; - setRfModuleData(i, &(model->moduleData[i])); - TRACE("<%s/%i> : %X,%X,%X", - strlen(modelName) ? modelName : modelFilename, - i, moduleData[i].type, moduleData[i].rfProtocol, modelId[i]); - } - valid_rfData = true; -} - -void ModelCell::setRfModuleData(uint8_t moduleIdx, ModuleData* modData) -{ - moduleData[moduleIdx].type = modData->type; - if (modData->type != MODULE_TYPE_MULTIMODULE) { - moduleData[moduleIdx].rfProtocol = (uint8_t)modData->rfProtocol; - } - else { - // do we care here about MM_RF_CUSTOM_SELECTED? probably not... - moduleData[moduleIdx].rfProtocol = modData->getMultiProtocol(false); - } -} - -bool ModelCell::fetchRfData() -{ - //TODO: use g_model in case fetching data for current model - // - char buf[256]; - getModelPath(buf, modelFilename); - - FIL file; - uint16_t size; - uint8_t version; - - const char * err = openFile(buf, &file, &size, &version); - if (err || version != EEPROM_VER) return false; - - FSIZE_t start_offset = f_tell(&file); - - UINT read; - if ((f_read(&file, buf, LEN_MODEL_NAME, &read) != FR_OK) || (read != LEN_MODEL_NAME)) - goto error; - - setModelName(buf); - - // 1. fetch modelId: NUM_MODULES @ offsetof(ModelHeader, modelId) - // if (f_lseek(&file, start_offset + offsetof(ModelHeader, modelId)) != FR_OK) - // goto error; - if ((f_read(&file, modelId, NUM_MODULES, &read) != FR_OK) || (read != NUM_MODULES)) - goto error; - - // 2. fetch ModuleData: sizeof(ModuleData)*NUM_MODULES @ offsetof(ModelData, moduleData) - if (f_lseek(&file, start_offset + offsetof(ModelData, moduleData)) != FR_OK) - goto error; - - for(uint8_t i=0; iname, name, sizeof(this->name)); -} - -ModelsCategory::~ModelsCategory() -{ - for (list::iterator it = begin(); it != end(); ++it) { - delete *it; - } -} - - -ModelCell * ModelsCategory::addModel(const char * name) -{ - ModelCell * result = new ModelCell(name); - push_back(result); - return result; -} - -void ModelsCategory::removeModel(ModelCell * model) -{ - delete model; - remove(model); -} - -void ModelsCategory::moveModel(ModelCell * model, int8_t step) -{ - ModelsCategory::iterator current = begin(); - for (; current != end(); current++) { - if (*current == model) { - break; - } - } - - ModelsCategory::iterator new_position = current; - if (step > 0) { - while (step >= 0 && new_position != end()) { - new_position++; - step--; - } - } - else { - while (step < 0 && new_position != begin()) { - new_position--; - step++; - } - } - - insert(new_position, 1, *current); - erase(current); -} - -void ModelsCategory::save(FIL * file) -{ - f_puts("[", file); - f_puts(name, file); - f_puts("]", file); - f_putc('\n', file); - for (list::iterator it = begin(); it != end(); ++it) { - (*it)->save(file); - } -} - -ModelsList::ModelsList() -{ - init(); -} - -ModelsList::~ModelsList() -{ - clear(); -} - -void ModelsList::init() -{ - loaded = false; - currentCategory = NULL; - currentModel = NULL; - modelsCount = 0; -} - -void ModelsList::clear() -{ - for (list::iterator it = categories.begin(); it != categories.end(); ++it) { - delete *it; - } - categories.clear(); - init(); -} - -bool ModelsList::load() -{ - char line[LEN_MODELS_IDX_LINE+1]; - ModelsCategory * category = NULL; - - if (loaded) - return true; - - FRESULT result = f_open(&file, RADIO_MODELSLIST_PATH, FA_OPEN_EXISTING | FA_READ); - if (result == FR_OK) { - while (readNextLine(line, LEN_MODELS_IDX_LINE)) { - int len = strlen(line); // TODO could be returned by readNextLine - if (len > 2 && line[0] == '[' && line[len-1] == ']') { - line[len-1] = '\0'; - category = new ModelsCategory(&line[1]); - categories.push_back(category); - } - else if (len > 0) { - - //char* rf_data_str = cutModelFilename(line); - ModelCell * model = new ModelCell(line); - if (!category) { - category = new ModelsCategory("Models"); - categories.push_back(category); - } - category->push_back(model); - if (!strncmp(line, g_eeGeneral.currModelFilename, LEN_MODEL_FILENAME)) { - currentCategory = category; - currentModel = model; - } - //parseModulesData(model, rf_data_str); - //TRACE("model=<%s>, valid_rfData=<%i>",model->modelFilename,model->valid_rfData); - model->fetchRfData(); - modelsCount += 1; - } - } - f_close(&file); - - if (!getCurrentModel()) { - TRACE("currentModel is NULL"); - } - } - - if (categories.size() == 0) { - category = new ModelsCategory("Models"); - categories.push_back(category); - } - - loaded = true; - return true; -} - -void ModelsList::save() -{ - FRESULT result = f_open(&file, RADIO_MODELSLIST_PATH, FA_CREATE_ALWAYS | FA_WRITE); - if (result != FR_OK) { - return; - } - - for (list::iterator it = categories.begin(); it != categories.end(); ++it) { - (*it)->save(&file); - } - - f_close(&file); -} - -void ModelsList::setCurrentCategorie(ModelsCategory* cat) -{ - currentCategory = cat; -} - -void ModelsList::setCurrentModel(ModelCell* cell) -{ - currentModel = cell; - if (!currentModel->valid_rfData) - currentModel->fetchRfData(); -} - -bool ModelsList::readNextLine(char * line, int maxlen) -{ - if (f_gets(line, maxlen, &file) != NULL) { - int curlen = strlen(line) - 1; - if (line[curlen] == '\n') { // remove unwanted chars if file was edited using windows - if (line[curlen - 1] == '\r') { - line[curlen - 1] = 0; - } - else { - line[curlen] = 0; - } - } - return true; - } - return false; -} - -ModelsCategory * ModelsList::createCategory() -{ - ModelsCategory * result = new ModelsCategory("Category"); - categories.push_back(result); - save(); - return result; -} - -ModelCell * ModelsList::addModel(ModelsCategory * category, const char * name) -{ - ModelCell * result = category->addModel(name); - modelsCount++; - save(); - return result; -} - -void ModelsList::removeCategory(ModelsCategory * category) -{ - modelsCount -= category->size(); - delete category; - categories.remove(category); -} - -void ModelsList::removeModel(ModelsCategory * category, ModelCell * model) -{ - category->removeModel(model); - modelsCount--; - save(); -} - -void ModelsList::moveModel(ModelsCategory * category, ModelCell * model, int8_t step) -{ - category->moveModel(model, step); - save(); -} - -void ModelsList::moveModel(ModelCell * model, ModelsCategory * previous_category, ModelsCategory * new_category) -{ - previous_category->remove(model); - new_category->push_back(model); - save(); -} - -bool ModelsList::isModelIdUnique(uint8_t moduleIdx, char* warn_buf, size_t warn_buf_len) -{ - ModelCell* mod_cell = modelslist.getCurrentModel(); - if (!mod_cell || !mod_cell->valid_rfData) { - // in doubt, pretend it's unique - return true; - } - - uint8_t modelId = mod_cell->modelId[moduleIdx]; - uint8_t type = mod_cell->moduleData[moduleIdx].type; - uint8_t rfProtocol = mod_cell->moduleData[moduleIdx].rfProtocol; - - uint8_t additionalOnes = 0; - char* curr = warn_buf; - curr[0] = 0; - - bool hit_found = false; - const std::list& cats = modelslist.getCategories(); - std::list::const_iterator cat_it = cats.begin(); - for (;cat_it != cats.end(); cat_it++) { - for (ModelsCategory::const_iterator it = (*cat_it)->begin(); it != (*cat_it)->end(); it++) { - if (mod_cell == *it) - continue; - - if (!(*it)->valid_rfData) - continue; - - if ((type != MODULE_TYPE_NONE) && - (type == (*it)->moduleData[moduleIdx].type) && - (rfProtocol == (*it)->moduleData[moduleIdx].rfProtocol) && - (modelId == (*it)->modelId[moduleIdx])) { - - // Hit found! - hit_found = true; - - const char* modelName = (*it)->modelName; - const char* modelFilename = (*it)->modelFilename; - - // you cannot rely exactly on WARNING_LINE_LEN so using WARNING_LINE_LEN-2 (-2 for the ",") - if ((warn_buf_len - 2 - (curr - warn_buf)) > LEN_MODEL_NAME) { - if (warn_buf[0] != 0) - curr = strAppend(curr, ", "); - if (modelName[0] == 0) { - size_t len = min(strlen(modelFilename),LEN_MODEL_NAME); - curr = strAppendFilename(curr, modelFilename, len); - } - else - curr = strAppend(curr, modelName, LEN_MODEL_NAME); - } - else { - additionalOnes++; - } - } - } - } - - if (additionalOnes && (warn_buf_len - (curr - warn_buf) >= 7)) { - curr = strAppend(curr, " (+"); - curr = strAppendUnsigned(curr, additionalOnes); - curr = strAppend(curr, ")"); - } - - return !hit_found; -} - -uint8_t ModelsList::findNextUnusedModelId(uint8_t moduleIdx) -{ - ModelCell* mod_cell = modelslist.getCurrentModel(); - if (!mod_cell || !mod_cell->valid_rfData) { - return 0; - } - - uint8_t type = mod_cell->moduleData[moduleIdx].type; - uint8_t rfProtocol = mod_cell->moduleData[moduleIdx].rfProtocol; - - // assume 63 is the highest Model ID - // and use 64 bits - uint8_t usedModelIds[8]; - memset(usedModelIds, 0, sizeof(usedModelIds)); - - const std::list& cats = modelslist.getCategories(); - std::list::const_iterator cat_it = cats.begin(); - for (;cat_it != cats.end(); cat_it++) { - for (ModelsCategory::const_iterator it = (*cat_it)->begin(); it != (*cat_it)->end(); it++) { - if (mod_cell == *it) - continue; - - if (!(*it)->valid_rfData) - continue; - - // match module type and RF protocol - if ((type != MODULE_TYPE_NONE) && - (type == (*it)->moduleData[moduleIdx].type) && - (rfProtocol == (*it)->moduleData[moduleIdx].rfProtocol)) { - - uint8_t id = (*it)->modelId[moduleIdx]; - - uint8_t mask = 1; - for (uint8_t i = 1; i < (id & 7); i++) - mask <<= 1; - - usedModelIds[id >> 3] |= mask; - } - } - } - - uint8_t new_id = 1; - uint8_t tst_mask = 1; - for (;new_id < getMaxRxNum(moduleIdx); new_id++) { - if (!(usedModelIds[new_id >> 3] & tst_mask)) { - // found free ID - return new_id; - } - if ((tst_mask <<= 1) == 0) - tst_mask = 1; - } - - // failed finding something... - return 0; -} - -void ModelsList::onNewModelCreated(ModelCell* cell, ModelData* model) -{ - cell->setModelName(model->header.name); - cell->setRfData(model); - - uint8_t new_id = findNextUnusedModelId(INTERNAL_MODULE); - model->header.modelId[INTERNAL_MODULE] = new_id; - cell->setModelId(INTERNAL_MODULE, new_id); -} diff --git a/radio/src/gui/colorlcd/modelslist.h b/radio/src/gui/colorlcd/modelslist.h deleted file mode 100644 index c5a157207..000000000 --- a/radio/src/gui/colorlcd/modelslist.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _MODELSLIST_H_ -#define _MODELSLIST_H_ - -#include -#include -#include "sdcard.h" - -#define MODELCELL_WIDTH 172 -#define MODELCELL_HEIGHT 59 - -// modelXXXXXXX.bin F,FF F,3F,FF\r\n -#define LEN_MODELS_IDX_LINE (LEN_MODEL_FILENAME + sizeof(" F,FF F,3F,FF\r\n")-1) - -struct SimpleModuleData -{ - uint8_t type; - uint8_t rfProtocol; -}; - -class ModelCell -{ -public: - char modelFilename[LEN_MODEL_FILENAME+1]; - char modelName[LEN_MODEL_NAME+1]; - BitmapBuffer * buffer; - - bool valid_rfData; - uint8_t modelId[NUM_MODULES]; - SimpleModuleData moduleData[NUM_MODULES]; - - ModelCell(const char * name); - ~ModelCell(); - - void save(FIL* file); - - void setModelName(char* name); - void setRfData(ModelData* model); - - void setModelId(uint8_t moduleIdx, uint8_t id); - void setRfModuleData(uint8_t moduleIdx, ModuleData* modData); - - bool fetchRfData(); - void loadBitmap(); - const BitmapBuffer * getBuffer(); - void resetBuffer(); -}; - -class ModelsCategory: public std::list -{ -public: - char name[LEN_MODEL_FILENAME+1]; - - ModelsCategory(const char * name); - ~ModelsCategory(); - - ModelCell * addModel(const char * name); - void removeModel(ModelCell * model); - void moveModel(ModelCell * model, int8_t step); - void save(FIL * file); -}; - -class ModelsList -{ - bool loaded; - std::list categories; - ModelsCategory * currentCategory; - ModelCell * currentModel; - unsigned int modelsCount; - - void init(); - -public: - - ModelsList(); - ~ModelsList(); - - bool load(); - void save(); - void clear(); - - const std::list& getCategories() const { - return categories; - } - - void setCurrentCategorie(ModelsCategory* cat); - ModelsCategory* getCurrentCategory() const { - return currentCategory; - } - - void setCurrentModel(ModelCell* cell); - ModelCell* getCurrentModel() const { - return currentModel; - } - - unsigned int getModelsCount() const { - return modelsCount; - } - - bool readNextLine(char * line, int maxlen); - - ModelsCategory * createCategory(); - void removeCategory(ModelsCategory * category); - - ModelCell * addModel(ModelsCategory * category, const char * name); - void removeModel(ModelsCategory * category, ModelCell * model); - void moveModel(ModelsCategory * category, ModelCell * model, int8_t step); - void moveModel(ModelCell * model, ModelsCategory * previous_category, ModelsCategory * new_category); - - bool isModelIdUnique(uint8_t moduleIdx, char* warn_buf, size_t warn_buf_len); - uint8_t findNextUnusedModelId(uint8_t moduleIdx); - - void onNewModelCreated(ModelCell* cell, ModelData* model); - -protected: - FIL file; - -}; - -extern ModelsList modelslist; - -#endif // _MODELSLIST_H_ diff --git a/radio/src/gui/colorlcd/view_main.cpp b/radio/src/gui/colorlcd/view_main.cpp index d46a67115..c52f2259d 100644 --- a/radio/src/gui/colorlcd/view_main.cpp +++ b/radio/src/gui/colorlcd/view_main.cpp @@ -200,7 +200,7 @@ void ViewMain::openMenu() { Menu * menu = new Menu(); menu->addLine(STR_MODEL_SELECT, [=]() { - new ModelselectMenu(); + new ModelSelectMenu(); }); if (modelHasNotes()) { menu->addLine(STR_VIEW_NOTES, [=]() { diff --git a/radio/src/sdcard.cpp b/radio/src/sdcard.cpp index 77453b15d..8f01bf37e 100644 --- a/radio/src/sdcard.cpp +++ b/radio/src/sdcard.cpp @@ -174,7 +174,7 @@ uint8_t getDigitsCount(unsigned int value) return count; } -int findNextFileIndex(char * filename, uint8_t size, const char * directory) +unsigned int findNextFileIndex(char * filename, uint8_t size, const char * directory) { unsigned int index; uint8_t extlen; @@ -182,7 +182,7 @@ int findNextFileIndex(char * filename, uint8_t size, const char * directory) char extension[LEN_FILE_EXTENSION_MAX+1] = "\0"; char * p = (char *)getFileExtension(filename, 0, 0, nullptr, &extlen); if (p) strncat(extension, p, sizeof(extension)-1); - while (1) { + while (true) { index++; if ((indexPos - filename) + getDigitsCount(index) + extlen > size) { return 0; diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index 2f33534b3..6ebbd5bd0 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -145,7 +145,7 @@ const char * getBasename(const char * path); #endif bool isFileAvailable(const char * filename, bool exclDir = false); -int findNextFileIndex(char * filename, uint8_t size, const char * directory); +unsigned int findNextFileIndex(char * filename, uint8_t size, const char * directory); const char * sdCopyFile(const char * src, const char * dest); const char * sdCopyFile(const char * srcFilename, const char * srcDir, const char * destFilename, const char * destDir); diff --git a/radio/src/storage/modelslist.cpp b/radio/src/storage/modelslist.cpp index cef111363..e7a4a2d59 100644 --- a/radio/src/storage/modelslist.cpp +++ b/radio/src/storage/modelslist.cpp @@ -23,30 +23,26 @@ using std::list; ModelsList modelslist; -ModelCell::ModelCell(const char * name) - : buffer(NULL), valid_rfData(false) +ModelCell::ModelCell(const char * name): + valid_rfData(false) { strncpy(modelFilename, name, sizeof(modelFilename)); - memset(modelName, 0, sizeof(modelName)); } ModelCell::~ModelCell() { - resetBuffer(); } -void ModelCell::setModelName(char* name) +void ModelCell::setModelName(char * name) { - zchar2str(modelName, name, LEN_MODEL_NAME); + strncpy(modelName, name, LEN_MODEL_NAME); if (modelName[0] == 0) { char * tmp; strncpy(modelName, modelFilename, LEN_MODEL_NAME); tmp = (char *) memchr(modelName, '.', LEN_MODEL_NAME); - if (tmp != NULL) + if (tmp) *tmp = 0; } - - resetBuffer(); } void ModelCell::setModelId(uint8_t moduleIdx, uint8_t id) @@ -54,84 +50,6 @@ void ModelCell::setModelId(uint8_t moduleIdx, uint8_t id) modelId[moduleIdx] = id; } -void ModelCell::resetBuffer() -{ - if (buffer) { - delete buffer; - buffer = NULL; - } -} - -const BitmapBuffer * ModelCell::getBuffer() -{ - if (!buffer) { - loadBitmap(); - } - return buffer; -} - -void ModelCell::loadBitmap() -{ -/* uint8_t version; - - PACK(struct { - ModelHeader header; - TimerData timers[MAX_TIMERS]; - }) partialmodel; - const char * error = NULL; - - if (strncmp(modelFilename, g_eeGeneral.currModelFilename, LEN_MODEL_FILENAME) == 0) { - memcpy(&partialmodel.header, &g_model.header, sizeof(partialmodel)); - } - else { - error = readModel(modelFilename, (uint8_t *)&partialmodel.header, sizeof(partialmodel), &version); - // LEN_BITMAP_NAME has now 4 bytes more - if (version <= 218) { - memmove(partialmodel.timers, &(partialmodel.header.bitmap[10]), sizeof(TimerData)*MAX_TIMERS); - memclear(&(partialmodel.header.bitmap[10]), 4); - } - } - - if ((modelName[0] == 0) && ! error) - setModelName(partialmodel.header.name); // resets buffer!!! - - buffer = new BitmapBuffer(BMP_RGB565, MODELCELL_WIDTH, MODELCELL_HEIGHT); - if (buffer == NULL) { - return; - } - buffer->clear(TEXT_BGCOLOR); - - if (error) { - buffer->drawText(5, 2, "(Invalid Model)", TEXT_COLOR); - buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, TEXT_COLOR); - } - else { - char timer[LEN_TIMER_STRING]; - buffer->drawSizedText(5, 2, modelName, LEN_MODEL_NAME, SMLSIZE|TEXT_COLOR); - getTimerString(timer, 0); - for (uint8_t i = 0; i < MAX_TIMERS; i++) { - if (partialmodel.timers[i].mode > 0 && partialmodel.timers[i].persistent) { - getTimerString(timer, partialmodel.timers[i].value); - break; - } - } - buffer->drawText(101, 40, timer, TEXT_COLOR); - for (int i=0; i<4; i++) { - buffer->drawBitmapPattern(104+i*11, 25, LBM_SCORE0, TITLE_BGCOLOR); - } - GET_FILENAME(filename, BITMAPS_PATH, partialmodel.header.bitmap, ""); - const BitmapBuffer * bitmap = BitmapBuffer::load(filename); - if (bitmap) { - buffer->drawScaledBitmap(bitmap, 5, 24, 56, 32); - delete bitmap; - } - else { - buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, TEXT_COLOR); - } - } - buffer->drawSolidHorizontalLine(5, 19, 143, LINE_COLOR);*/ -} - void ModelCell::save(FIL* file) { f_puts(modelFilename, file); @@ -218,12 +136,11 @@ ModelsCategory::ModelsCategory(const char * name) ModelsCategory::~ModelsCategory() { - for (list::iterator it = begin(); it != end(); ++it) { - delete *it; + for (auto * model: *this) { + delete model; } } - ModelCell * ModelsCategory::addModel(const char * name) { ModelCell * result = new ModelCell(name); @@ -288,8 +205,8 @@ ModelsList::~ModelsList() void ModelsList::init() { loaded = false; - currentCategory = NULL; - currentModel = NULL; + currentCategory = nullptr; + currentModel = nullptr; modelsCount = 0; } @@ -305,7 +222,8 @@ void ModelsList::clear() bool ModelsList::load() { char line[LEN_MODELS_IDX_LINE+1]; - ModelsCategory * category = NULL; + ModelsCategory * category = nullptr; + ModelCell * model = nullptr; if (loaded) return true; @@ -320,9 +238,7 @@ bool ModelsList::load() categories.push_back(category); } else if (len > 0) { - - //char* rf_data_str = cutModelFilename(line); - ModelCell * model = new ModelCell(line); + model = new ModelCell(line); if (!category) { category = new ModelsCategory("Models"); categories.push_back(category); @@ -339,15 +255,19 @@ bool ModelsList::load() } } f_close(&file); - - if (!getCurrentModel()) { - TRACE("currentModel is NULL"); - } } - if (categories.size() == 0) { - category = new ModelsCategory("Models"); - categories.push_back(category); + if (!currentModel) { + if (model) { + currentModel = model; + currentCategory = category; + } + else { + model = new ModelCell(line); + category = new ModelsCategory("Models"); + categories.push_back(category); + category->push_back(model); + } } loaded = true; @@ -475,8 +395,8 @@ bool ModelsList::isModelIdUnique(uint8_t moduleIdx, char* warn_buf, size_t warn_ // Hit found! hit_found = true; - const char* modelName = (*it)->modelName; - const char* modelFilename = (*it)->modelFilename; + const char * modelName = (*it)->modelName; + const char * modelFilename = (*it)->modelFilename; // you cannot rely exactly on WARNING_LINE_LEN so using WARNING_LINE_LEN-2 (-2 for the ",") if ((warn_buf_len - 2 - (curr - warn_buf)) > LEN_MODEL_NAME) { diff --git a/radio/src/storage/modelslist.h b/radio/src/storage/modelslist.h index fa0adb540..4593399d3 100644 --- a/radio/src/storage/modelslist.h +++ b/radio/src/storage/modelslist.h @@ -39,30 +39,28 @@ struct SimpleModuleData class ModelCell { -public: - char modelFilename[LEN_MODEL_FILENAME+1]; - char modelName[LEN_MODEL_NAME+1]; - BitmapBuffer * buffer; + public: + char modelFilename[LEN_MODEL_FILENAME+1]; + char modelName[LEN_MODEL_NAME+1] = {}; - bool valid_rfData; - uint8_t modelId[NUM_MODULES]; - SimpleModuleData moduleData[NUM_MODULES]; + bool valid_rfData; + uint8_t modelId[NUM_MODULES]; + SimpleModuleData moduleData[NUM_MODULES]; - ModelCell(const char * name); - ~ModelCell(); + explicit ModelCell(const char * name); + ~ModelCell(); - void save(FIL* file); + void save(FIL* file); - void setModelName(char* name); - void setRfData(ModelData* model); + void setModelName(char* name); + void setRfData(ModelData* model); - void setModelId(uint8_t moduleIdx, uint8_t id); - void setRfModuleData(uint8_t moduleIdx, ModuleData* modData); + void setModelId(uint8_t moduleIdx, uint8_t id); + void setRfModuleData(uint8_t moduleIdx, ModuleData* modData); - bool fetchRfData(); - void loadBitmap(); - const BitmapBuffer * getBuffer(); - void resetBuffer(); + bool fetchRfData(); + // void loadBitmap(); + // void resetBuffer(); }; class ModelsCategory: public std::list @@ -70,7 +68,7 @@ class ModelsCategory: public std::list public: char name[LEN_MODEL_FILENAME+1]; - ModelsCategory(const char * name); + explicit ModelsCategory(const char * name); ~ModelsCategory(); ModelCell * addModel(const char * name); diff --git a/radio/src/storage/sdcard_raw.cpp b/radio/src/storage/sdcard_raw.cpp index 70f960a53..5e86b0901 100644 --- a/radio/src/storage/sdcard_raw.cpp +++ b/radio/src/storage/sdcard_raw.cpp @@ -263,7 +263,7 @@ const char * createModel() memset(filename, 0, sizeof(filename)); strcpy(filename, "model.bin"); - int index = findNextFileIndex(filename, LEN_MODEL_FILENAME, MODELS_PATH); + unsigned int index = findNextFileIndex(filename, LEN_MODEL_FILENAME, MODELS_PATH); if (index > 0) { modelDefault(index); memcpy(g_eeGeneral.currModelFilename, filename, sizeof(g_eeGeneral.currModelFilename)); diff --git a/radio/src/thirdparty/libopenui b/radio/src/thirdparty/libopenui index 632041871..6865ad710 160000 --- a/radio/src/thirdparty/libopenui +++ b/radio/src/thirdparty/libopenui @@ -1 +1 @@ -Subproject commit 632041871793be362ac65644786797476e2d7efd +Subproject commit 6865ad710f307cb5308f4994c4ae881940b98c7f