/* * 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 "sdcard.h" #define MODELCELL_WIDTH 151 #define MODELCELL_HEIGHT 59 class ModelCell { public: ModelCell(const char * name): buffer(BMP_RGB565, MODELCELL_WIDTH, MODELCELL_HEIGHT) { buffer.clear(TEXT_BGCOLOR); strncpy(this->name, name, sizeof(this->name)); ModelHeader header; const char * error = readModel(name, (uint8_t *)&header, sizeof(header)); 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, header.name, LEN_MODEL_NAME, ZCHAR|TEXT_COLOR); getTimerString(timer, 0); buffer.drawText(104, 41, 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, header.bitmap, BITMAPS_EXT); 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); } char name[LEN_MODEL_FILENAME+1]; BitmapBuffer buffer; }; class ModelsCategory: public std::list { public: ModelsCategory(const char * name) { strncpy(this->name, name, sizeof(this->name)); } ModelCell * addModel(const char * name) { ModelCell * result = new ModelCell(name); push_back(result); return result; } void removeModel(ModelCell * model) { delete model; remove(model); } void save(FIL * file) { f_puts("[", file); f_puts(name, file); f_puts("]", file); f_putc('\n', file); for (std::list::iterator it = begin(); it != end(); ++it) { f_puts((*it)->name, file); f_putc('\n', file); } } char name[LEN_MODEL_FILENAME+1]; }; class ModelsList { public: ModelsList() { } ~ModelsList() { clear(); } void clear() { for (std::list::iterator it = categories.begin(); it != categories.end(); ++it) { delete *it; } categories.clear(); } bool load() { char line[LEN_MODEL_FILENAME+1]; clear(); FRESULT result = f_open(&file, RADIO_MODELSLIST_PATH, FA_OPEN_EXISTING | FA_READ); if (result != FR_OK) { return false; } while (readNextLine(line, LEN_MODEL_FILENAME)) { int len = strlen(line); // TODO could be returned by readNextLine if (len > 2 && line[0] == '[' && line[len-1] == ']') { line[len-1] = '\0'; currentCategory = new ModelsCategory(&line[1]); categories.push_back(currentCategory); } else if (len > 0) { ModelCell * model = new ModelCell(line); currentCategory->push_back(model); } } f_close(&file); return true; } void save() { FRESULT result = f_open(&file, RADIO_MODELSLIST_PATH, FA_CREATE_ALWAYS | FA_WRITE); if (result != FR_OK) { return; } for (std::list::iterator it = categories.begin(); it != categories.end(); ++it) { (*it)->save(&file); } f_close(&file); } bool readNextLine(char * line, int maxlen) { char c; unsigned int read; int len=0; while (1) { FRESULT result = f_read(&file, (uint8_t *)&c, 1, &read); if (result != FR_OK || read != 1) { line[len] = '\0'; return false; } if (c == '\n') { if (len > 0) { // we skip empty lines line[len] = '\0'; return true; } } else if (c != '\r' && len < maxlen) { line[len++] = c; } } } ModelsCategory * createCategory() { ModelsCategory * result = new ModelsCategory("Category"); categories.push_back(result); save(); return result; } ModelCell * addModel(ModelsCategory * category, const char * name) { ModelCell * result = category->addModel(name); save(); return result; } void removeCategory(ModelsCategory * category) { delete category; categories.remove(category); } void removeModel(ModelsCategory * category, ModelCell * model) { category->removeModel(model); save(); } std::list categories; protected: FIL file; ModelsCategory * currentCategory; }; #endif // _MODELSLIST_H_