mirror of
https://github.com/opentx/opentx.git
synced 2025-07-23 16:25:16 +03:00
[Horus] Model Selection menu started
This commit is contained in:
parent
7e5374f31d
commit
03fabd95ac
7 changed files with 258 additions and 8 deletions
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1 KiB |
|
@ -212,6 +212,22 @@ const uint8_t * const LBM_MODEL_ICONS[] = {
|
||||||
LBM_TELEMETRY_ICON
|
LBM_TELEMETRY_ICON
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Model selection screen bitmaps
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint8_t LBM_LIBRARY_ICON[] = {
|
||||||
|
#include "../../bitmaps/Horus/mask_library.lbm"
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t LBM_LIBRARY_SLOT[] = {
|
||||||
|
#include "../../bitmaps/Horus/mask_library_slot.lbm"
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Other
|
||||||
|
*/
|
||||||
|
|
||||||
const uint16_t LBM_ASTERISK[] = {
|
const uint16_t LBM_ASTERISK[] = {
|
||||||
#include "../../bitmaps/Horus/asterisk.lbm"
|
#include "../../bitmaps/Horus/asterisk.lbm"
|
||||||
};
|
};
|
||||||
|
|
|
@ -98,5 +98,10 @@ extern const uint8_t LBM_RSCALE[];
|
||||||
extern const uint8_t * const LBM_RADIO_ICONS[];
|
extern const uint8_t * const LBM_RADIO_ICONS[];
|
||||||
extern const uint8_t * const LBM_MODEL_ICONS[];
|
extern const uint8_t * const LBM_MODEL_ICONS[];
|
||||||
|
|
||||||
|
// Model selection icons
|
||||||
|
extern const uint8_t LBM_LIBRARY_ICON[];
|
||||||
|
extern const uint8_t LBM_LIBRARY_SLOT[];
|
||||||
|
|
||||||
|
// Other icons
|
||||||
extern const uint16_t LBM_ASTERISK[];
|
extern const uint16_t LBM_ASTERISK[];
|
||||||
|
|
||||||
|
|
|
@ -37,19 +37,76 @@
|
||||||
|
|
||||||
#define CATEGORIES_WIDTH 140
|
#define CATEGORIES_WIDTH 140
|
||||||
|
|
||||||
|
void drawModel(coord_t x, coord_t y, const char * name)
|
||||||
|
{
|
||||||
|
lcdDrawSolidRect(x, y, 153, 61, LINE_COLOR);
|
||||||
|
lcdDrawText(x+5, y+2, name, TEXT_COLOR);
|
||||||
|
lcdDrawSolidHorizontalLine(x+5, y+19, 143, LINE_COLOR);
|
||||||
|
lcdDrawBitmapPattern(x+5, y+23, LBM_LIBRARY_SLOT, TEXT_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
void menuModelSelect(evt_t event)
|
void menuModelSelect(evt_t event)
|
||||||
{
|
{
|
||||||
|
switch(event) {
|
||||||
|
case 0:
|
||||||
|
// no need to refresh the screen
|
||||||
|
return;
|
||||||
|
|
||||||
|
case EVT_KEY_FIRST(KEY_EXIT):
|
||||||
|
chainMenu(menuMainView);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
lcdDrawSolidFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, HEADER_BGCOLOR);
|
lcdDrawSolidFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, HEADER_BGCOLOR);
|
||||||
lcdDrawBitmapPattern(0, 0, LBM_TOPMENU_POLYGON, TITLE_BGCOLOR);
|
lcdDrawBitmapPattern(0, 0, LBM_TOPMENU_POLYGON, TITLE_BGCOLOR);
|
||||||
// lcdDrawBitmapPattern(4, 10, LBM_TOPMENU_OPENTX, MENU_TITLE_COLOR);
|
lcdDrawBitmapPattern(5, 7, LBM_LIBRARY_ICON, MENU_TITLE_COLOR);
|
||||||
drawTopmenuDatetime();
|
drawTopmenuDatetime();
|
||||||
|
|
||||||
// Categories
|
// Categories
|
||||||
lcdDrawSolidFilledRect(0, MENU_HEADER_HEIGHT, CATEGORIES_WIDTH, LCD_H-MENU_HEADER_HEIGHT-MENU_FOOTER_HEIGHT, TITLE_BGCOLOR);
|
lcdDrawSolidFilledRect(0, MENU_HEADER_HEIGHT, CATEGORIES_WIDTH, LCD_H-MENU_HEADER_HEIGHT-MENU_FOOTER_HEIGHT, TITLE_BGCOLOR);
|
||||||
|
|
||||||
|
StorageModelsList storage;
|
||||||
|
const char * error = storageOpenModelsList(&storage);
|
||||||
|
if (!error) {
|
||||||
|
bool result = true;
|
||||||
|
coord_t y = MENU_HEADER_HEIGHT+10;
|
||||||
|
while (y < LCD_H) {
|
||||||
|
char line[256];
|
||||||
|
result = storageReadNextCategory(&storage, line, sizeof(line)-1);
|
||||||
|
if (!result)
|
||||||
|
break;
|
||||||
|
lcdDrawText(MENUS_MARGIN_LEFT, y, line, MENU_TITLE_COLOR);
|
||||||
|
y += FH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Models
|
// Models
|
||||||
lcdDrawSolidFilledRect(CATEGORIES_WIDTH, MENU_HEADER_HEIGHT, LCD_W-CATEGORIES_WIDTH, LCD_H-MENU_HEADER_HEIGHT-MENU_FOOTER_HEIGHT, TEXT_BGCOLOR);
|
lcdDrawSolidFilledRect(CATEGORIES_WIDTH, MENU_HEADER_HEIGHT, LCD_W-CATEGORIES_WIDTH, LCD_H-MENU_HEADER_HEIGHT-MENU_FOOTER_HEIGHT, TEXT_BGCOLOR);
|
||||||
|
if (!error) {
|
||||||
|
bool result = storageSeekCategory(&storage, 0);
|
||||||
|
coord_t y = MENU_HEADER_HEIGHT+7;
|
||||||
|
unsigned int i = 0;
|
||||||
|
while (result) {
|
||||||
|
char line[256];
|
||||||
|
result = storageReadNextModel(&storage, line, sizeof(line)-1);
|
||||||
|
if (!result)
|
||||||
|
break;
|
||||||
|
if (y < LCD_H) {
|
||||||
|
coord_t x;
|
||||||
|
if (i & 1) {
|
||||||
|
drawModel(CATEGORIES_WIDTH+MENUS_MARGIN_LEFT+162, y, line);
|
||||||
|
y += 66;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
drawModel(CATEGORIES_WIDTH+MENUS_MARGIN_LEFT+1, y, line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawScrollbar(DEFAULT_SCROLLBAR_X, MENU_HEADER_HEIGHT+7, MENU_FOOTER_TOP-MENU_HEADER_HEIGHT-15, 0, 4, 2);
|
||||||
|
|
||||||
// Footer
|
// Footer
|
||||||
lcdDrawSolidFilledRect(0, MENU_FOOTER_TOP, LCD_W, MENU_FOOTER_HEIGHT, HEADER_BGCOLOR);
|
lcdDrawSolidFilledRect(0, MENU_FOOTER_TOP, LCD_W, MENU_FOOTER_HEIGHT, HEADER_BGCOLOR);
|
||||||
|
|
|
@ -38,13 +38,10 @@
|
||||||
|
|
||||||
void menuStatisticsView(evt_t event)
|
void menuStatisticsView(evt_t event)
|
||||||
{
|
{
|
||||||
drawMenuTemplate("Statistics", event);
|
switch(event) {
|
||||||
|
|
||||||
switch(event)
|
|
||||||
{
|
|
||||||
case EVT_KEY_FIRST(KEY_UP):
|
case EVT_KEY_FIRST(KEY_UP):
|
||||||
chainMenu(menuStatisticsDebug);
|
chainMenu(menuStatisticsDebug);
|
||||||
break;
|
return;
|
||||||
|
|
||||||
case EVT_KEY_LONG(KEY_MENU):
|
case EVT_KEY_LONG(KEY_MENU):
|
||||||
g_eeGeneral.globalTimer = 0;
|
g_eeGeneral.globalTimer = 0;
|
||||||
|
@ -54,9 +51,11 @@ void menuStatisticsView(evt_t event)
|
||||||
|
|
||||||
case EVT_KEY_FIRST(KEY_EXIT):
|
case EVT_KEY_FIRST(KEY_EXIT):
|
||||||
chainMenu(menuMainView);
|
chainMenu(menuMainView);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drawMenuTemplate("Statistics", event);
|
||||||
|
|
||||||
lcdDrawText( 10, MENU_CONTENT_TOP + FH*0, "\037\145TOT:\037\317BATT:", HEADER_COLOR);
|
lcdDrawText( 10, MENU_CONTENT_TOP + FH*0, "\037\145TOT:\037\317BATT:", HEADER_COLOR);
|
||||||
lcdDrawText( 10, MENU_CONTENT_TOP + FH*1, "TM1:\037\145TM2:", HEADER_COLOR);
|
lcdDrawText( 10, MENU_CONTENT_TOP + FH*1, "TM1:\037\145TM2:", HEADER_COLOR);
|
||||||
lcdDrawText( 10, MENU_CONTENT_TOP + FH*2, "THR:\037\145TH%:", HEADER_COLOR);
|
lcdDrawText( 10, MENU_CONTENT_TOP + FH*2, "THR:\037\145TH%:", HEADER_COLOR);
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
#define MAX_INPUTS 32
|
#define MAX_INPUTS 32
|
||||||
#define NUM_TRAINER 16
|
#define NUM_TRAINER 16
|
||||||
#define NUM_POTS 3
|
#define NUM_POTS 3
|
||||||
#define NUM_XPOTS 0
|
#define NUM_XPOTS 3
|
||||||
#define MAX_SENSORS 32
|
#define MAX_SENSORS 32
|
||||||
#elif defined(PCBFLAMENCO)
|
#elif defined(PCBFLAMENCO)
|
||||||
#define MAX_MODELS 60
|
#define MAX_MODELS 60
|
||||||
|
|
|
@ -143,6 +143,7 @@ const char * loadModel(const char * filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
const char RADIO_SETTINGS_PATH[] = RADIO_PATH "/radio.bin";
|
const char RADIO_SETTINGS_PATH[] = RADIO_PATH "/radio.bin";
|
||||||
|
const char RADIO_MODELSLIST_PATH[] = RADIO_PATH "/models.txt";
|
||||||
|
|
||||||
const char * loadGeneralSettings()
|
const char * loadGeneralSettings()
|
||||||
{
|
{
|
||||||
|
@ -215,3 +216,175 @@ void storageFormat()
|
||||||
sdCheckAndCreateDirectory(RADIO_PATH);
|
sdCheckAndCreateDirectory(RADIO_PATH);
|
||||||
sdCheckAndCreateDirectory(MODELS_PATH);
|
sdCheckAndCreateDirectory(MODELS_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct StorageModelsList {
|
||||||
|
FIL file;
|
||||||
|
};
|
||||||
|
|
||||||
|
const char * storageOpenModelsList(StorageModelsList * storage)
|
||||||
|
{
|
||||||
|
FRESULT result = f_open(&storage->file, RADIO_MODELSLIST_PATH, FA_OPEN_EXISTING | FA_READ);
|
||||||
|
if (result != FR_OK) {
|
||||||
|
return SDCARD_ERROR(result);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storageReadNextLine(StorageModelsList * storage, char * line, int maxlen)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
unsigned int read;
|
||||||
|
int len=0;
|
||||||
|
while (1) {
|
||||||
|
FRESULT result = f_read(&storage->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int storageGetCategoryLength(const char * line)
|
||||||
|
{
|
||||||
|
int len = strlen(line);
|
||||||
|
if (len > 2 && line[0] == '[' && line[len-1] == ']') {
|
||||||
|
return len-2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storageReadNextCategory(StorageModelsList * storage, char * line, int maxlen)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
while (result) {
|
||||||
|
result = storageReadNextLine(storage, line, maxlen);
|
||||||
|
int len = storageGetCategoryLength(line);
|
||||||
|
if (len > 0) {
|
||||||
|
memmove(line, &line[1], len);
|
||||||
|
line[len] = '\0';
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line[0] = '\0';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storageSeekCategory(StorageModelsList * storage, int category)
|
||||||
|
{
|
||||||
|
f_lseek(&storage->file, 0);
|
||||||
|
char line[256] = "";
|
||||||
|
int result = true;
|
||||||
|
for (int i=0; result && i<=category; i++) {
|
||||||
|
result = storageReadNextCategory(storage, line, sizeof(line)-1);
|
||||||
|
}
|
||||||
|
return line[0] != '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool storageReadNextModel(StorageModelsList * storage, char * line, int maxlen)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
while (result) {
|
||||||
|
result = storageReadNextLine(storage, line, maxlen);
|
||||||
|
if (line[0] == '[')
|
||||||
|
return false;
|
||||||
|
else if (line[0] != '\0')
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
line[0] = '\0';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STORAGE_INSERT 1
|
||||||
|
#define STORAGE_REMOVE 2
|
||||||
|
#define STORAGE_RENAME 3
|
||||||
|
|
||||||
|
const char * storageModifyModel(unsigned int operation, int category, int position, const char * name="")
|
||||||
|
{
|
||||||
|
StorageModelsList storage;
|
||||||
|
FIL file;
|
||||||
|
const char * error = storageOpenModelsList(&storage);
|
||||||
|
if (error) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
FRESULT result = f_open(&file, RADIO_PATH "/models.tmp", FA_CREATE_ALWAYS | FA_WRITE);
|
||||||
|
if (result != FR_OK) {
|
||||||
|
return SDCARD_ERROR(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operationdone = false;
|
||||||
|
bool result = true;
|
||||||
|
int categoryindex = -1;
|
||||||
|
int modelindex = 0;
|
||||||
|
|
||||||
|
while (result) {
|
||||||
|
char line[256];
|
||||||
|
result = storageReadNextLine(&storage, line, sizeof(line)-1);
|
||||||
|
if (!operationdone) {
|
||||||
|
int len = storageGetCategoryLength(line);
|
||||||
|
if (len > 0) {
|
||||||
|
if (categoryindex++ == category) {
|
||||||
|
operationdone = true;
|
||||||
|
if (operation == STORAGE_INSERT) {
|
||||||
|
f_puts(name, &file);
|
||||||
|
f_putc('\n', &file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (categoryindex == category) {
|
||||||
|
if (modelindex++ == position) {
|
||||||
|
operationdone = true;
|
||||||
|
if (operation == STORAGE_INSERT) {
|
||||||
|
f_puts(name, &file);
|
||||||
|
f_putc('\n', &file);
|
||||||
|
}
|
||||||
|
else if (operation == STORAGE_RENAME) {
|
||||||
|
f_puts(name, &file);
|
||||||
|
f_putc('\n', &file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f_puts(line, &file);
|
||||||
|
f_putc('\n', &file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!operationdone && categoryindex>=0 && operation==STORAGE_INSERT) {
|
||||||
|
f_puts(name, &file);
|
||||||
|
f_putc('\n', &file);
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&file);
|
||||||
|
f_rename(RADIO_PATH "/models.tmp", RADIO_MODELSLIST_PATH);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * storageInsertModel(const char * name, int category, int position)
|
||||||
|
{
|
||||||
|
return storageModifyModel(STORAGE_INSERT, category, position, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * storageRemoveModel(int category, int position)
|
||||||
|
{
|
||||||
|
return storageModifyModel(STORAGE_REMOVE, category, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * storageRenameModel(const char * name, int category, int position)
|
||||||
|
{
|
||||||
|
return storageModifyModel(STORAGE_RENAME, category, position, name);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue