diff --git a/radio/src/gui/horus/bitmaps.cpp b/radio/src/gui/horus/bitmaps.cpp index 04c6cb5fc..9cdfe8361 100644 --- a/radio/src/gui/horus/bitmaps.cpp +++ b/radio/src/gui/horus/bitmaps.cpp @@ -181,3 +181,7 @@ const uint8_t LBM_SWIPE_RIGHT[] = { }; BitmapBuffer * modelselIconBitmap = NULL; +BitmapBuffer * modelselSdFreeBitmap = NULL; +BitmapBuffer * modelselModelQtyBitmap = NULL; +BitmapBuffer * modelselModelMoveBackground = NULL; +BitmapBuffer * modelselModelMoveIcon = NULL; diff --git a/radio/src/gui/horus/bitmaps.h b/radio/src/gui/horus/bitmaps.h index 6411f2e7a..dea1eef29 100644 --- a/radio/src/gui/horus/bitmaps.h +++ b/radio/src/gui/horus/bitmaps.h @@ -72,5 +72,9 @@ extern const uint8_t LBM_SWIPE_LEFT[]; extern const uint8_t LBM_SWIPE_RIGHT[]; extern BitmapBuffer * modelselIconBitmap; +extern BitmapBuffer * modelselSdFreeBitmap; +extern BitmapBuffer * modelselModelQtyBitmap; +extern BitmapBuffer * modelselModelMoveBackground; +extern BitmapBuffer * modelselModelMoveIcon; #endif // _BITMAPS_H_ diff --git a/radio/src/gui/horus/menu_model_select.cpp b/radio/src/gui/horus/menu_model_select.cpp index cbbf537c7..88cb73752 100644 --- a/radio/src/gui/horus/menu_model_select.cpp +++ b/radio/src/gui/horus/menu_model_select.cpp @@ -28,6 +28,7 @@ enum ModelSelectMode { MODE_SELECT_MODEL, MODE_RENAME_CATEGORY, + MODE_MOVE_MODEL, }; uint8_t selectMode; @@ -57,6 +58,10 @@ void drawModel(coord_t x, coord_t y, ModelCell * model, bool current, bool selec if (selected) { lcdDrawSolidRect(x, y, MODELCELL_WIDTH+2, MODELCELL_HEIGHT+2, 1, TITLE_BGCOLOR); drawShadow(x, y, MODELCELL_WIDTH+2, MODELCELL_HEIGHT+2); + if (selectMode == MODE_MOVE_MODEL) { + lcd->drawMask(x+MODELCELL_WIDTH+2-modelselModelMoveBackground->getWidth(), y, modelselModelMoveBackground, TITLE_BGCOLOR); + lcd->drawMask(x+MODELCELL_WIDTH+2-modelselModelMoveBackground->getWidth()+12, y+5, modelselModelMoveIcon, TEXT_BGCOLOR); + } } } @@ -122,6 +127,9 @@ void onModelSelectMenu(const char * result) POPUP_WARNING("Invalid File"); } } + else if (result == STR_MOVE_MODEL) { + selectMode = MODE_MOVE_MODEL; + } else if (result == STR_CREATE_CATEGORY) { currentCategory = modelslist.createCategory(); setCurrentCategory(modelslist.categories.size() - 1); @@ -134,7 +142,7 @@ void onModelSelectMenu(const char * result) else if (result == STR_DELETE_CATEGORY) { modelslist.removeCategory(currentCategory); modelslist.save(); - setCurrentCategory(currentCategoryIndex-1); + setCurrentCategory(currentCategoryIndex > 0 ? currentCategoryIndex-1 : currentCategoryIndex); } } @@ -197,6 +205,9 @@ bool menuModelSelect(evt_t event) case EVT_KEY_FIRST(KEY_EXIT): switch (selectMode) { + case MODE_MOVE_MODEL: + selectMode = MODE_SELECT_MODEL; + break; case MODE_SELECT_MODEL: chainMenu(menuMainView); return false; @@ -241,6 +252,7 @@ bool menuModelSelect(evt_t event) POPUP_MENU_ADD_ITEM(STR_CREATE_MODEL); if (currentModel) { POPUP_MENU_ADD_ITEM(STR_DUPLICATE_MODEL); + POPUP_MENU_ADD_ITEM(STR_MOVE_MODEL); } POPUP_MENU_ADD_ITEM(STR_CREATE_CATEGORY); POPUP_MENU_ADD_ITEM(STR_RENAME_CATEGORY); @@ -248,7 +260,6 @@ bool menuModelSelect(evt_t event) POPUP_MENU_ADD_ITEM(STR_DELETE_CATEGORY); } // POPUP_MENU_ADD_SD_ITEM(STR_BACKUP_MODEL); - // POPUP_MENU_ADD_ITEM(STR_MOVE_MODEL); // POPUP_MENU_ADD_ITEM(STR_CHANGE_CATEGORY); if (currentModel && currentModel != modelslist.currentModel) { POPUP_MENU_ADD_ITEM(STR_DELETE_MODEL); @@ -291,7 +302,7 @@ bool menuModelSelect(evt_t event) y = 5; for (ModelsCategory::iterator it = currentCategory->begin(); it != currentCategory->end(); ++it, ++index) { if (index >= menuVerticalOffset*2 && index < (menuVerticalOffset+4)*2) { - bool selected = (selectMode==MODE_SELECT_MODEL && index==menuVerticalPosition*2+menuHorizontalPosition); + bool selected = ((selectMode==MODE_SELECT_MODEL || selectMode==MODE_MOVE_MODEL) && index==menuVerticalPosition*2+menuHorizontalPosition); bool current = !strncmp((*it)->name, g_eeGeneral.currModelFilename, LEN_MODEL_FILENAME); if (index & 1) { drawModel(MODELS_LEFT + MODELS_COLUMN_WIDTH, y, *it, current, selected); @@ -304,14 +315,30 @@ bool menuModelSelect(evt_t event) } // Navigation - if (selectMode == MODE_SELECT_MODEL && currentModel) { - if (navigate(event, index, 4, 2)) { - putEvent(EVT_REFRESH); - setCurrentModel(MODEL_INDEX()); + if (currentModel) { + if (selectMode == MODE_SELECT_MODEL) { + if (navigate(event, index, 4, 2) != 0) { + setCurrentModel(MODEL_INDEX()); + putEvent(EVT_REFRESH); + } + } + else if (selectMode == MODE_MOVE_MODEL) { + int8_t direction = navigate(event, index, 4, 2, false); + if (direction) { + modelslist.moveModel(currentCategory, currentModel, direction); + setCurrentModel(MODEL_INDEX()); + putEvent(EVT_REFRESH); + } } } + drawVerticalScrollbar(DEFAULT_SCROLLBAR_X, 7, LCD_H - 15, menuVerticalOffset, (index + 1) / 2, 4); - drawVerticalScrollbar(DEFAULT_SCROLLBAR_X, 7, LCD_H-15, menuVerticalOffset, (index+1)/2, 4); + // Footer + lcd->drawBitmap(5, LCD_H-FH, modelselSdFreeBitmap); + uint32_t size = sdGetSize() / 100; + lcdDrawNumber(22, LCD_H-FH-1, size, PREC1, 0, NULL, "GB"); + lcd->drawBitmap(80, LCD_H-FH, modelselModelQtyBitmap); + lcdDrawNumber(105, LCD_H-FH-1, modelslist.modelsCount); return true; } diff --git a/radio/src/gui/horus/menus.h b/radio/src/gui/horus/menus.h index 5398571d6..1027f6efe 100644 --- a/radio/src/gui/horus/menus.h +++ b/radio/src/gui/horus/menus.h @@ -349,7 +349,7 @@ swsrc_t checkIncDecMovedSwitch(swsrc_t val); #define CHECK_INCDEC_PARAM(event, var, min, max) \ checkIncDec(event, var, min, max, incdecFlag, isValueAvailable) -bool navigate(evt_t event, int count, int rows, int columns=1); +int8_t navigate(evt_t event, int count, int rows, int columns=1, bool loop=true); bool check(check_event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t menuTabSize, const pm_uint8_t *horTab, uint8_t horTabMax, int maxrow, uint8_t flags=0); bool check_simple(check_event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t menuTabSize, int maxrow); bool check_submenu_simple(check_event_t event, uint8_t maxrow); diff --git a/radio/src/gui/horus/navigation.cpp b/radio/src/gui/horus/navigation.cpp index 0c175ba96..beae9f2ef 100644 --- a/radio/src/gui/horus/navigation.cpp +++ b/radio/src/gui/horus/navigation.cpp @@ -298,8 +298,10 @@ uint8_t menuPageIndex; uint8_t menuPageCount; uint16_t linesCount; -bool navigate(evt_t event, int count, int rows, int columns) +int8_t navigate(evt_t event, int count, int rows, int columns, bool loop) { + int8_t result = 0; + int prevPosHorz = menuHorizontalPosition; int prevPosVert = menuVerticalPosition; @@ -313,51 +315,34 @@ bool navigate(evt_t event, int count, int rows, int columns) } switch (event) { - /*case EVT_KEY_FIRST(KEY_RIGHT): - case EVT_KEY_REPT(KEY_RIGHT): - INC(menuHorizontalPosition, 0, maxcol); - break; - - case EVT_KEY_FIRST(KEY_LEFT): - case EVT_KEY_REPT(KEY_LEFT): - DEC(menuHorizontalPosition, 0, maxcol); - break; - - case EVT_KEY_FIRST(KEY_DOWN): - case EVT_KEY_REPT(KEY_DOWN): - INC(menuVerticalPosition, 0, maxrow); - if (menuVerticalPosition == maxrow && menuHorizontalPosition > maxlastcol) { - menuHorizontalPosition = maxlastcol; - } - break; - - case EVT_KEY_FIRST(KEY_UP): - case EVT_KEY_REPT(KEY_UP): - DEC(menuVerticalPosition, 0, maxrow); - if (menuVerticalPosition == maxrow && menuHorizontalPosition > maxlastcol) { - menuHorizontalPosition = maxlastcol; - } - break; - */ - case EVT_ROTARY_LEFT: + result = -1; if (menuHorizontalPosition > 0) { menuHorizontalPosition--; } - else { + else if (loop) { DEC(menuVerticalPosition, 0, maxrow); menuHorizontalPosition = (menuVerticalPosition != maxrow ? columns-1 : maxlastcol); } + else if (menuVerticalPosition > 0) { + menuVerticalPosition -= 1; + menuHorizontalPosition = columns-1; + } break; case EVT_ROTARY_RIGHT: + result = +1; if (menuHorizontalPosition < maxcol) { menuHorizontalPosition++; } - else { + else if (loop) { INC(menuVerticalPosition, 0, maxrow); menuHorizontalPosition = 0; } + else if (menuVerticalPosition < maxrow) { + menuVerticalPosition += 1; + menuHorizontalPosition = 0; + } break; } @@ -368,7 +353,7 @@ bool navigate(evt_t event, int count, int rows, int columns) menuVerticalOffset = menuVerticalPosition - rows + 1; } - return (prevPosHorz != menuHorizontalPosition || prevPosVert != menuVerticalPosition); + return (prevPosHorz != menuHorizontalPosition || prevPosVert != menuVerticalPosition) ? result : 0; } bool check(check_event_t event, uint8_t curr, const MenuHandlerFunc * menuTab, uint8_t menuTabSize, const pm_uint8_t * horTab, uint8_t horTabMax, int rowcount, uint8_t flags) diff --git a/radio/src/gui/horus/themes/default.cpp b/radio/src/gui/horus/themes/default.cpp index 47c46ccd1..74ef66a15 100644 --- a/radio/src/gui/horus/themes/default.cpp +++ b/radio/src/gui/horus/themes/default.cpp @@ -26,6 +26,19 @@ const ZoneOption OPTIONS_THEME_DEFAULT[] = { { NULL, ZoneOption::Bool } }; +BitmapBuffer * loadMaskOnBackground(const char * filename, LcdFlags foreground, LcdFlags background) +{ + BitmapBuffer * result = NULL; + BitmapBuffer * mask = BitmapBuffer::loadMask(getThemePath(filename)); + if (mask) { + result = new BitmapBuffer(BMP_RGB565, mask->getWidth(), mask->getHeight()); + result->clear(background); + result->drawMask(0, 0, mask, foreground); + delete mask; + } + return result; +} + class DefaultTheme: public Theme { public: @@ -131,7 +144,7 @@ class DefaultTheme: public Theme loadMenuIcon(ICON_MONITOR_CHANNELS3, "mask_monitor_channels3.png"); loadMenuIcon(ICON_MONITOR_CHANNELS4, "mask_monitor_channels4.png"); loadMenuIcon(ICON_MONITOR_LOGICAL_SWITCHES, "/mask_monitor_logsw.png"); - + BitmapBuffer * background = BitmapBuffer::loadMask(getThemePath("mask_currentmenu_bg.png")); BitmapBuffer * shadow = BitmapBuffer::loadMask(getThemePath("mask_currentmenu_shadow.png")); BitmapBuffer * dot = BitmapBuffer::loadMask(getThemePath("mask_currentmenu_dot.png")); @@ -144,32 +157,29 @@ class DefaultTheme: public Theme currentMenuBackground->drawMask(0, 0, shadow, TRIM_SHADOW_COLOR); currentMenuBackground->drawMask(10, 39, dot, MENU_TITLE_COLOR); - { - delete topleftBitmap; - topleftBitmap = NULL; - BitmapBuffer * mask = BitmapBuffer::loadMask(getThemePath("topleft.png")); - if (mask) { - topleftBitmap = new BitmapBuffer(BMP_RGB565, mask->getWidth(), MENU_HEADER_HEIGHT); - topleftBitmap->clear(HEADER_BGCOLOR); - topleftBitmap->drawMask(0, 0, mask, TITLE_BGCOLOR); - delete mask; - } + delete topleftBitmap; + topleftBitmap = loadMaskOnBackground("topleft.png", TITLE_BGCOLOR, HEADER_BGCOLOR); + + // Model Selection screen + delete modelselIconBitmap; + modelselIconBitmap = loadMaskOnBackground("modelsel/mask_iconback.png", TITLE_BGCOLOR, TEXT_BGCOLOR); + if (modelselIconBitmap) { + BitmapBuffer * bitmap = BitmapBuffer::load(getThemePath("modelsel/icon_default.png")); + modelselIconBitmap->drawBitmap(25, 8, bitmap); + delete bitmap; } - { - delete modelselIconBitmap; - modelselIconBitmap = NULL; - BitmapBuffer * mask = BitmapBuffer::loadMask(getThemePath("modelsel/mask_iconback.png")); - if (mask) { - modelselIconBitmap = new BitmapBuffer(BMP_RGB565, mask->getWidth(), mask->getHeight()); - modelselIconBitmap->clear(TEXT_BGCOLOR); - modelselIconBitmap->drawMask(0, 0, mask, TITLE_BGCOLOR); - BitmapBuffer * bitmap = BitmapBuffer::load(getThemePath("modelsel/icon_default.png")); - modelselIconBitmap->drawBitmap(25, 8, bitmap); - delete bitmap; - delete mask; - } - } + delete modelselSdFreeBitmap; + modelselSdFreeBitmap = loadMaskOnBackground("modelsel/mask_sdfree.png", TEXT_COLOR, TEXT_BGCOLOR); + + delete modelselModelQtyBitmap; + modelselModelQtyBitmap = loadMaskOnBackground("modelsel/mask_modelqty.png", TEXT_COLOR, TEXT_BGCOLOR); + + delete modelselModelMoveBackground; + modelselModelMoveBackground = BitmapBuffer::loadMask(getThemePath("modelsel/mask_moveback.png")); + + delete modelselModelMoveIcon; + modelselModelMoveIcon = BitmapBuffer::loadMask(getThemePath("modelsel/mask_moveico.png")); delete background; delete shadow; diff --git a/radio/src/storage/modelslist.h b/radio/src/storage/modelslist.h index 944518739..1e3c0d8a9 100644 --- a/radio/src/storage/modelslist.h +++ b/radio/src/storage/modelslist.h @@ -95,6 +95,33 @@ class ModelsCategory: public std::list remove(model); } + void 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 save(FIL * file) { f_puts("[", file); @@ -130,6 +157,7 @@ class ModelsList categories.clear(); currentCategory = NULL; currentModel = NULL; + modelsCount = 0; } bool load() @@ -159,6 +187,7 @@ class ModelsList currentCategory = category; currentModel = model; } + modelsCount += 1; } } f_close(&file); @@ -221,12 +250,14 @@ class ModelsList ModelCell * addModel(ModelsCategory * category, const char * name) { ModelCell * result = category->addModel(name); + modelsCount++; save(); return result; } void removeCategory(ModelsCategory * category) { + modelsCount -= category->size(); delete category; categories.remove(category); } @@ -234,12 +265,20 @@ class ModelsList void removeModel(ModelsCategory * category, ModelCell * model) { category->removeModel(model); + modelsCount--; + save(); + } + + void moveModel(ModelsCategory * category, ModelCell * model, int8_t step) + { + category->moveModel(model, step); save(); } std::list categories; ModelsCategory * currentCategory; ModelCell * currentModel; + unsigned int modelsCount; protected: FIL file;