Model Select cosmetics
This commit is contained in:
@@ -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<ModelselectButton *>(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)
|
||||
{
|
||||
}
|
||||
for (auto category: modelslist.getCategories()) {
|
||||
addTab(new ModelCategoryPage(category));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
|
||||
#include "tabsgroup.h"
|
||||
|
||||
class ModelselectMenu: public TabsGroup {
|
||||
class ModelSelectMenu: public TabsGroup {
|
||||
public:
|
||||
ModelselectMenu();
|
||||
ModelSelectMenu();
|
||||
};
|
||||
|
||||
#endif // _MODEL_SELECT_H_
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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; i<NUM_MODULES; i++) {
|
||||
ModuleData modData;
|
||||
if ((f_read(&file, &modData, NUM_MODULES, &read) != FR_OK) || (read != NUM_MODULES))
|
||||
goto error;
|
||||
|
||||
setRfModuleData(i, &modData);
|
||||
}
|
||||
|
||||
valid_rfData = true;
|
||||
f_close(&file);
|
||||
return true;
|
||||
|
||||
error:
|
||||
f_close(&file);
|
||||
return false;
|
||||
}
|
||||
|
||||
ModelsCategory::ModelsCategory(const char * name)
|
||||
{
|
||||
strncpy(this->name, name, sizeof(this->name));
|
||||
}
|
||||
|
||||
ModelsCategory::~ModelsCategory()
|
||||
{
|
||||
for (list<ModelCell *>::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<ModelCell *>::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<ModelsCategory *>::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<ModelsCategory *>::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<ModelsCategory*>& cats = modelslist.getCategories();
|
||||
std::list<ModelsCategory*>::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<size_t>(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<ModelsCategory*>& cats = modelslist.getCategories();
|
||||
std::list<ModelsCategory*>::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);
|
||||
}
|
||||
@@ -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 <stdint.h>
|
||||
#include <list>
|
||||
#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<ModelCell *>
|
||||
{
|
||||
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<ModelsCategory *> categories;
|
||||
ModelsCategory * currentCategory;
|
||||
ModelCell * currentModel;
|
||||
unsigned int modelsCount;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
|
||||
ModelsList();
|
||||
~ModelsList();
|
||||
|
||||
bool load();
|
||||
void save();
|
||||
void clear();
|
||||
|
||||
const std::list<ModelsCategory *>& 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_
|
||||
@@ -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, [=]() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
@@ -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<ModelCell *>::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) {
|
||||
|
||||
@@ -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<ModelCell *>
|
||||
@@ -70,7 +68,7 @@ class ModelsCategory: public std::list<ModelCell *>
|
||||
public:
|
||||
char name[LEN_MODEL_FILENAME+1];
|
||||
|
||||
ModelsCategory(const char * name);
|
||||
explicit ModelsCategory(const char * name);
|
||||
~ModelsCategory();
|
||||
|
||||
ModelCell * addModel(const char * name);
|
||||
|
||||
@@ -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));
|
||||
|
||||
Vendored
+1
-1
Submodule radio/src/thirdparty/libopenui updated: 6320418717...6865ad710f
Reference in New Issue
Block a user