From cf91c87c774a6bdaed676602aaa48c2f716ec649 Mon Sep 17 00:00:00 2001 From: eshifri <46511024+eshifri@users.noreply.github.com> Date: Tue, 31 Aug 2021 18:10:33 -0700 Subject: [PATCH 1/9] [Colorlcd] Pot and slider model setup settings implemented (#654) * Pots and sliders warning implemented. #647 * add slider definitions * Remove whitespace change causing merge conflict * add slider definitions Co-authored-by: Peter Feerick --- radio/src/gui/colorlcd/model_setup.cpp | 81 +++++++++++++++++++ radio/src/gui/colorlcd/switch_warn_dialog.cpp | 4 +- radio/src/targets/nv14/board.h | 3 + 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index f601fb88b..0db9ac37a 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -1432,8 +1432,89 @@ void ModelSetupPage::build(FormWindow * window) } } grid.addWindow(group); + + // Pots and sliders warning +#if NUM_POTS + NUM_SLIDERS + { + new StaticText(window, grid.getLabelSlot(true), STR_POTWARNINGSTATE); + new Choice(window, grid.getFieldSlot(), {"OFF", "ON", "AUTO"}, 0, 2, + GET_SET_DEFAULT(g_model.potsWarnMode)); + grid.nextLine(); + +#if (NUM_POTS) + { + new StaticText(window, grid.getLabelSlot(true), STR_POTWARNING); + auto group = + new FormGroup(window, grid.getFieldSlot(), + FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST); + GridLayout centerGrid(group); + for (int i = POT_FIRST, j = 0; i <= POT_LAST; i++) { + char s[8]; + if ((IS_POT(i) || IS_POT_MULTIPOS(i))) { + if (j > 0 && ((j % 4) == 0)) centerGrid.nextLine(); + + auto button = new TextButton( + group, centerGrid.getSlot(4, j % 4), + getStringAtIndex(s, STR_VSRCRAW, i + 1), nullptr, + OPAQUE | ((g_model.potsWarnEnabled & (1 << j)) ? BUTTON_CHECKED + : 0)); + button->setPressHandler([button, j] { + g_model.potsWarnEnabled ^= (1 << j); + if ((g_model.potsWarnMode == POTS_WARN_MANUAL) && + (g_model.potsWarnEnabled & (1 << j))) { + SAVE_POT_POSITION(j); + } + button->check(g_model.potsWarnEnabled & (1 << j)); + SET_DIRTY(); + return (g_model.potsWarnEnabled & (1 << j)); + }); + j++; + } + } + grid.addWindow(group); + } +#endif + +#if (NUM_SLIDERS) + { + new StaticText(window, grid.getLabelSlot(true), STR_SLIDERWARNING); + auto group = + new FormGroup(window, grid.getFieldSlot(), + FORM_BORDER_FOCUS_ONLY | PAINT_CHILDREN_FIRST); + GridLayout centerGrid(group); + for (int i = SLIDER_FIRST, j = 0; i <= SLIDER_LAST; i++) { + char s[8]; + if ((IS_SLIDER(i))) { + if (j > 0 && ((j % 4) == 0)) centerGrid.nextLine(); + + auto *button = new TextButton( + group, centerGrid.getSlot(4, j % 4), + getStringAtIndex(s, STR_VSRCRAW, i + 1), nullptr, + OPAQUE | ((g_model.potsWarnEnabled & (1 << (j + NUM_POTS))) + ? BUTTON_CHECKED + : 0)); + button->setPressHandler([button, j] { + g_model.potsWarnEnabled ^= (1 << (j + NUM_POTS)); + if ((g_model.potsWarnMode == POTS_WARN_MANUAL) && + (g_model.potsWarnEnabled & (1 << (j + NUM_POTS)))) { + SAVE_POT_POSITION(j + NUM_POTS); + } + button->check(g_model.potsWarnEnabled & (1 << (j + NUM_POTS))); + SET_DIRTY(); + return (g_model.potsWarnEnabled & (1 << (j + NUM_POTS))); + }); + j++; + } + } + grid.addWindow(group); + } +#endif + } + #endif } + grid.nextLine(); + // Center beeps { new StaticText(window, grid.getLabelSlot(false), STR_BEEPCTR, 0, COLOR_THEME_PRIMARY1); diff --git a/radio/src/gui/colorlcd/switch_warn_dialog.cpp b/radio/src/gui/colorlcd/switch_warn_dialog.cpp index 3c28e7c0d..aa066a320 100644 --- a/radio/src/gui/colorlcd/switch_warn_dialog.cpp +++ b/radio/src/gui/colorlcd/switch_warn_dialog.cpp @@ -42,7 +42,7 @@ bool SwitchWarnDialog::warningInactive() if (!IS_POT_SLIDER_AVAILABLE(POT1 + i)) { continue; } - if (!(g_model.potsWarnEnabled & (1 << i)) && (abs(g_model.potsWarnPosition[i] - GET_LOWRES_POT_POSITION(i)) > 1)) { + if ( (g_model.potsWarnEnabled & (1 << i)) && (abs(g_model.potsWarnPosition[i] - GET_LOWRES_POT_POSITION(i)) > 1)) { warn = true; bad_pots |= (1 << i); } @@ -96,7 +96,7 @@ void SwitchWarnDialog::paint(BitmapBuffer * dc) if (!IS_POT_SLIDER_AVAILABLE(POT1 + i)) { continue; } - if (!(g_model.potsWarnEnabled & (1 << i))) { + if ( (g_model.potsWarnEnabled & (1 << i))) { if (abs(g_model.potsWarnPosition[i] - GET_LOWRES_POT_POSITION(i)) > 1) { if (y < LCD_H) { char s[8]; diff --git a/radio/src/targets/nv14/board.h b/radio/src/targets/nv14/board.h index 3209b7270..c08564422 100644 --- a/radio/src/targets/nv14/board.h +++ b/radio/src/targets/nv14/board.h @@ -309,6 +309,9 @@ enum Analogs { NUM_ANALOGS }; +#define SLIDER_FIRST 0 +#define SLIDER_LAST -1 + #define DEFAULT_POTS_CONFIG (POT_WITHOUT_DETENT << 0) + (POT_WITHOUT_DETENT << 2) // 2 pots without detent enum CalibratedAnalogs { From cea723c56ea52db45911e4e5cbe4485cb40c23b4 Mon Sep 17 00:00:00 2001 From: Jesper Frickmann Date: Wed, 1 Sep 2021 03:10:52 +0200 Subject: [PATCH 2/9] Do not reload bitmps during theme update, unless reload argument is true (#661) * Do not reload bitmps during theme update, unless reload argument is true Trying to optimize speed for theme color changes. FlySky is not optimized yet. * Do not update theme from Lua lcd.setColor(CUSTOM_COLOR, x) Some widgets like e.g. Timer2 constantly change CUSTOM_COLOR, and this seems to slow down things * Lua function lcd.setColor() only updates if color is changed To avoid that scripts calling lcd.setColor() repeatedly trash performance --- radio/src/gui/colorlcd/theme.h | 2 +- radio/src/gui/colorlcd/themes/480_default.cpp | 146 +++++++++--------- radio/src/gui/colorlcd/themes/flysky.cpp | 2 +- radio/src/lua/api_colorlcd.cpp | 9 +- 4 files changed, 84 insertions(+), 75 deletions(-) diff --git a/radio/src/gui/colorlcd/theme.h b/radio/src/gui/colorlcd/theme.h index 9645a3084..58e262424 100644 --- a/radio/src/gui/colorlcd/theme.h +++ b/radio/src/gui/colorlcd/theme.h @@ -75,7 +75,7 @@ class OpenTxTheme: public Theme void init() const; - virtual void update() const + virtual void update(bool reload = true) const { } diff --git a/radio/src/gui/colorlcd/themes/480_default.cpp b/radio/src/gui/colorlcd/themes/480_default.cpp index 8a09c1eda..234372c8b 100644 --- a/radio/src/gui/colorlcd/themes/480_default.cpp +++ b/radio/src/gui/colorlcd/themes/480_default.cpp @@ -57,85 +57,92 @@ class Theme480: public OpenTxTheme lcdColorTable[CUSTOM_COLOR_INDEX] = RGB(170, 85, 0); } - void loadMenuIcon(uint8_t index, const uint8_t * lbm) const + void loadMenuIcon(uint8_t index, const uint8_t * lbm, bool reload) const { - BitmapBuffer * mask = BitmapBuffer::load8bitMask(lbm); - if (mask) { - delete iconMask[index]; - iconMask[index] = mask; + BitmapBuffer * mask; + + if (reload) { + mask = BitmapBuffer::load8bitMask(lbm); + if (mask) { + delete iconMask[index]; + iconMask[index] = mask; - delete menuIconNormal[index]; - menuIconNormal[index] = new BitmapBuffer(BMP_RGB565, mask->width(), mask->height()); - if (menuIconNormal[index]) { - menuIconNormal[index]->clear(COLOR_THEME_SECONDARY1); - menuIconNormal[index]->drawMask(0, 0, mask, COLOR_THEME_PRIMARY2); - } + delete menuIconNormal[index]; + menuIconNormal[index] = new BitmapBuffer(BMP_RGB565, mask->width(), mask->height()); - delete menuIconSelected[index]; - menuIconSelected[index] = new BitmapBuffer(BMP_RGB565, mask->width(), mask->height()); - if (menuIconSelected[index]) { - menuIconSelected[index]->clear(COLOR_THEME_FOCUS); - menuIconSelected[index]->drawMask(0, 0, mask, COLOR_THEME_PRIMARY2); + delete menuIconSelected[index]; + menuIconSelected[index] = new BitmapBuffer(BMP_RGB565, mask->width(), mask->height()); } + } else + mask = iconMask[index]; + + if (menuIconNormal[index]) { + menuIconNormal[index]->clear(COLOR_THEME_SECONDARY1); + menuIconNormal[index]->drawMask(0, 0, mask, COLOR_THEME_PRIMARY2); + } + + if (menuIconSelected[index]) { + menuIconSelected[index]->clear(COLOR_THEME_FOCUS); + menuIconSelected[index]->drawMask(0, 0, mask, COLOR_THEME_PRIMARY2); } } - void loadIcons() const + void loadIcons(bool reload) const { #if defined(LOG_TELEMETRY) || !defined(WATCHDOG) - loadMenuIcon(ICON_OPENTX, mask_opentx_testmode); + loadMenuIcon(ICON_OPENTX, mask_opentx_testmode, reload); #else - loadMenuIcon(ICON_OPENTX, mask_edgetx); + loadMenuIcon(ICON_OPENTX, mask_edgetx, reload); #endif #if defined(HARDWARE_TOUCH) //TODO: get rid of, and use a real hitbox instead... - loadMenuIcon(ICON_NEXT, mask_next); - loadMenuIcon(ICON_BACK, mask_back); + loadMenuIcon(ICON_NEXT, mask_next, reload); + loadMenuIcon(ICON_BACK, mask_back, reload); #endif - loadMenuIcon(ICON_RADIO, mask_menu_radio); - loadMenuIcon(ICON_RADIO_SETUP, mask_radio_setup); - loadMenuIcon(ICON_RADIO_SD_MANAGER, mask_radio_sd_browser); - loadMenuIcon(ICON_RADIO_TOOLS, mask_radio_tools); - //loadMenuIcon(ICON_RADIO_SPECTRUM_ANALYSER, mask_radio_spectrum_analyser); - loadMenuIcon(ICON_RADIO_GLOBAL_FUNCTIONS, mask_radio_global_functions); - loadMenuIcon(ICON_RADIO_TRAINER, mask_radio_trainer); - loadMenuIcon(ICON_RADIO_HARDWARE, mask_radio_hardware); - loadMenuIcon(ICON_RADIO_CALIBRATION, mask_radio_calibration); - loadMenuIcon(ICON_RADIO_VERSION, mask_radio_version); - loadMenuIcon(ICON_MODEL, mask_menu_model); - loadMenuIcon(ICON_MODEL_SETUP, mask_model_setup); - loadMenuIcon(ICON_MODEL_HELI, mask_model_heli); - loadMenuIcon(ICON_MODEL_FLIGHT_MODES, mask_model_flight_modes); - loadMenuIcon(ICON_MODEL_INPUTS, mask_model_inputs); - loadMenuIcon(ICON_MODEL_MIXER, mask_model_mixer); - loadMenuIcon(ICON_MODEL_NOTES, mask_menu_notes); - loadMenuIcon(ICON_MODEL_OUTPUTS, mask_model_outputs); - loadMenuIcon(ICON_MODEL_CURVES, mask_model_curves); - loadMenuIcon(ICON_MODEL_GVARS, mask_model_gvars); - loadMenuIcon(ICON_MODEL_LOGICAL_SWITCHES, mask_model_logical_switches); - loadMenuIcon(ICON_MODEL_SPECIAL_FUNCTIONS, mask_model_special_functions); - loadMenuIcon(ICON_MODEL_LUA_SCRIPTS, mask_model_lua_scripts); - loadMenuIcon(ICON_MODEL_TELEMETRY, mask_model_telemetry); - loadMenuIcon(ICON_MODEL_SELECT, mask_menu_model_select); - loadMenuIcon(ICON_MODEL_SELECT_CATEGORY, mask_model_select_category); - loadMenuIcon(ICON_STATS, mask_menu_stats); - loadMenuIcon(ICON_STATS_THROTTLE_GRAPH, mask_stats_throttle_graph); - loadMenuIcon(ICON_STATS_TIMERS, mask_stats_timers); - loadMenuIcon(ICON_STATS_ANALOGS, mask_stats_analogs); - loadMenuIcon(ICON_STATS_DEBUG, mask_stats_debug); - loadMenuIcon(ICON_THEME, mask_menu_theme); - loadMenuIcon(ICON_THEME_SETUP, mask_theme_setup); - loadMenuIcon(ICON_THEME_VIEW1, mask_theme_view1); - loadMenuIcon(ICON_THEME_VIEW2, mask_theme_view2); - loadMenuIcon(ICON_THEME_VIEW3, mask_theme_view3); - loadMenuIcon(ICON_THEME_VIEW4, mask_theme_view4); - loadMenuIcon(ICON_THEME_VIEW5, mask_theme_view5); - loadMenuIcon(ICON_THEME_ADD_VIEW, mask_theme_add_view); - loadMenuIcon(ICON_MONITOR, mask_monitor); - loadMenuIcon(ICON_MONITOR_CHANNELS1, mask_monitor_channels1); - loadMenuIcon(ICON_MONITOR_CHANNELS2, mask_monitor_channels2); - loadMenuIcon(ICON_MONITOR_CHANNELS3, mask_monitor_channels3); - loadMenuIcon(ICON_MONITOR_CHANNELS4, mask_monitor_channels4); - loadMenuIcon(ICON_MONITOR_LOGICAL_SWITCHES, mask_monitor_logsw); + loadMenuIcon(ICON_RADIO, mask_menu_radio, reload); + loadMenuIcon(ICON_RADIO_SETUP, mask_radio_setup, reload); + loadMenuIcon(ICON_RADIO_SD_MANAGER, mask_radio_sd_browser, reload); + loadMenuIcon(ICON_RADIO_TOOLS, mask_radio_tools, reload); + //loadMenuIcon(ICON_RADIO_SPECTRUM_ANALYSER, mask_radio_spectrum_analyser, reload); + loadMenuIcon(ICON_RADIO_GLOBAL_FUNCTIONS, mask_radio_global_functions, reload); + loadMenuIcon(ICON_RADIO_TRAINER, mask_radio_trainer, reload); + loadMenuIcon(ICON_RADIO_HARDWARE, mask_radio_hardware, reload); + loadMenuIcon(ICON_RADIO_CALIBRATION, mask_radio_calibration, reload); + loadMenuIcon(ICON_RADIO_VERSION, mask_radio_version, reload); + loadMenuIcon(ICON_MODEL, mask_menu_model, reload); + loadMenuIcon(ICON_MODEL_SETUP, mask_model_setup, reload); + loadMenuIcon(ICON_MODEL_HELI, mask_model_heli, reload); + loadMenuIcon(ICON_MODEL_FLIGHT_MODES, mask_model_flight_modes, reload); + loadMenuIcon(ICON_MODEL_INPUTS, mask_model_inputs, reload); + loadMenuIcon(ICON_MODEL_MIXER, mask_model_mixer, reload); + loadMenuIcon(ICON_MODEL_NOTES, mask_menu_notes, reload); + loadMenuIcon(ICON_MODEL_OUTPUTS, mask_model_outputs, reload); + loadMenuIcon(ICON_MODEL_CURVES, mask_model_curves, reload); + loadMenuIcon(ICON_MODEL_GVARS, mask_model_gvars, reload); + loadMenuIcon(ICON_MODEL_LOGICAL_SWITCHES, mask_model_logical_switches, reload); + loadMenuIcon(ICON_MODEL_SPECIAL_FUNCTIONS, mask_model_special_functions, reload); + loadMenuIcon(ICON_MODEL_LUA_SCRIPTS, mask_model_lua_scripts, reload); + loadMenuIcon(ICON_MODEL_TELEMETRY, mask_model_telemetry, reload); + loadMenuIcon(ICON_MODEL_SELECT, mask_menu_model_select, reload); + loadMenuIcon(ICON_MODEL_SELECT_CATEGORY, mask_model_select_category, reload); + loadMenuIcon(ICON_STATS, mask_menu_stats, reload); + loadMenuIcon(ICON_STATS_THROTTLE_GRAPH, mask_stats_throttle_graph, reload); + loadMenuIcon(ICON_STATS_TIMERS, mask_stats_timers, reload); + loadMenuIcon(ICON_STATS_ANALOGS, mask_stats_analogs, reload); + loadMenuIcon(ICON_STATS_DEBUG, mask_stats_debug, reload); + loadMenuIcon(ICON_THEME, mask_menu_theme, reload); + loadMenuIcon(ICON_THEME_SETUP, mask_theme_setup, reload); + loadMenuIcon(ICON_THEME_VIEW1, mask_theme_view1, reload); + loadMenuIcon(ICON_THEME_VIEW2, mask_theme_view2, reload); + loadMenuIcon(ICON_THEME_VIEW3, mask_theme_view3, reload); + loadMenuIcon(ICON_THEME_VIEW4, mask_theme_view4, reload); + loadMenuIcon(ICON_THEME_VIEW5, mask_theme_view5, reload); + loadMenuIcon(ICON_THEME_ADD_VIEW, mask_theme_add_view, reload); + loadMenuIcon(ICON_MONITOR, mask_monitor, reload); + loadMenuIcon(ICON_MONITOR_CHANNELS1, mask_monitor_channels1, reload); + loadMenuIcon(ICON_MONITOR_CHANNELS2, mask_monitor_channels2, reload); + loadMenuIcon(ICON_MONITOR_CHANNELS3, mask_monitor_channels3, reload); + loadMenuIcon(ICON_MONITOR_CHANNELS4, mask_monitor_channels4, reload); + loadMenuIcon(ICON_MONITOR_LOGICAL_SWITCHES, mask_monitor_logsw, reload); BitmapBuffer * background = BitmapBuffer::load8bitMask(mask_currentmenu_bg); BitmapBuffer * shadow = BitmapBuffer::load8bitMask(mask_currentmenu_shadow); @@ -280,10 +287,11 @@ class Theme480: public OpenTxTheme update(); } - void update() const override + void update(bool reload = true) const override { - loadIcons(); - loadThemeBitmaps(); + loadIcons(reload); + if (reload) + loadThemeBitmaps(); } void drawBackground(BitmapBuffer * dc) const override diff --git a/radio/src/gui/colorlcd/themes/flysky.cpp b/radio/src/gui/colorlcd/themes/flysky.cpp index cb5a8de55..9f91eca05 100644 --- a/radio/src/gui/colorlcd/themes/flysky.cpp +++ b/radio/src/gui/colorlcd/themes/flysky.cpp @@ -278,7 +278,7 @@ class FlyskyTheme: public OpenTxTheme update(); } - virtual void update() const override + virtual void update(bool reload = true) const override { TRACE("TODO THEME::UPDATE()"); diff --git a/radio/src/lua/api_colorlcd.cpp b/radio/src/lua/api_colorlcd.cpp index b15adbceb..5a9e71203 100644 --- a/radio/src/lua/api_colorlcd.cpp +++ b/radio/src/lua/api_colorlcd.cpp @@ -726,11 +726,12 @@ Please notice that changing theme colors affects not only other Lua widgets, but static int luaLcdSetColor(lua_State *L) { unsigned int index = COLOR_VAL(luaL_checkunsigned(L, 1)); - LcdFlags flags = luaL_checkunsigned(L, 2); + uint16_t color = COLOR_VAL(flagsRGB(luaL_checkunsigned(L, 2))); - if (index < LCD_COLOR_COUNT) { - lcdColorTable[index] = COLOR_VAL(flagsRGB(flags)); - OpenTxTheme::instance()->update(); + if (index < LCD_COLOR_COUNT && lcdColorTable[index] != color) { + lcdColorTable[index] = color; + if (index != CUSTOM_COLOR_INDEX) + OpenTxTheme::instance()->update(false); } return 0; } From 071ec6299f21f8f9e23d6dd0361269681a6eff42 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Wed, 1 Sep 2021 11:15:50 +1000 Subject: [PATCH 3/9] Make pots/sliders warnings not big. Still needs a proper helper though. --- radio/src/gui/colorlcd/switch_warn_dialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/radio/src/gui/colorlcd/switch_warn_dialog.cpp b/radio/src/gui/colorlcd/switch_warn_dialog.cpp index aa066a320..573609500 100644 --- a/radio/src/gui/colorlcd/switch_warn_dialog.cpp +++ b/radio/src/gui/colorlcd/switch_warn_dialog.cpp @@ -103,11 +103,11 @@ void SwitchWarnDialog::paint(BitmapBuffer * dc) // TODO add an helper strncpy(s, &STR_VSRCRAW[1 + (NUM_STICKS + 1 + i) * STR_VSRCRAW[0]], STR_VSRCRAW[0]); s[int(STR_VSRCRAW[0])] = '\0'; - dc->drawText(x, y, s, COLOR_THEME_WARNING | FONT(XL)); - y += 35; + dc->drawText(x, y, s, COLOR_THEME_WARNING | FONT(BOLD)); + y += 15; } else { - dc->drawText(x, y, "...", COLOR_THEME_WARNING | FONT(XL)); + dc->drawText(x, y, "...", COLOR_THEME_WARNING | FONT(BOLD)); } } } From 9a2461c7e9b90bbb26fa8ca8e5ad9188e1ec6573 Mon Sep 17 00:00:00 2001 From: Peter Feerick Date: Wed, 1 Sep 2021 14:10:40 +1000 Subject: [PATCH 4/9] Shows pot and sliders on own line, change colour Use theme primary colour (def. black) rather than warning (def. red) Show pot/slider list on own row, under switches --- radio/src/gui/colorlcd/switch_warn_dialog.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/radio/src/gui/colorlcd/switch_warn_dialog.cpp b/radio/src/gui/colorlcd/switch_warn_dialog.cpp index 573609500..1520b8298 100644 --- a/radio/src/gui/colorlcd/switch_warn_dialog.cpp +++ b/radio/src/gui/colorlcd/switch_warn_dialog.cpp @@ -80,11 +80,11 @@ void SwitchWarnDialog::paint(BitmapBuffer * dc) unsigned int state = ((g_model.switchWarningState >> (3 * i)) & 0x07); if (state && state - 1 != ((switches_states >> (i * 2)) & 0x03)) { if (y < LCD_H) { - x = drawSwitch(dc, x, y, SWSRC_FIRST_SWITCH + i * 3 + state - 1, FONT(BOLD)); + x = drawSwitch(dc, x, y, SWSRC_FIRST_SWITCH + i * 3 + state - 1, COLOR_THEME_PRIMARY1 | FONT(BOLD)); x += 5; } else { - dc->drawText(x, y, "...", FONT(BOLD)); + dc->drawText(x, y, "...", COLOR_THEME_PRIMARY1 | FONT(BOLD)); break; } } @@ -92,6 +92,8 @@ void SwitchWarnDialog::paint(BitmapBuffer * dc) } if (g_model.potsWarnMode) { + x = ALERT_MESSAGE_LEFT; + y += 20; for (int i = 0; i < NUM_POTS + NUM_SLIDERS; i++) { if (!IS_POT_SLIDER_AVAILABLE(POT1 + i)) { continue; @@ -103,11 +105,11 @@ void SwitchWarnDialog::paint(BitmapBuffer * dc) // TODO add an helper strncpy(s, &STR_VSRCRAW[1 + (NUM_STICKS + 1 + i) * STR_VSRCRAW[0]], STR_VSRCRAW[0]); s[int(STR_VSRCRAW[0])] = '\0'; - dc->drawText(x, y, s, COLOR_THEME_WARNING | FONT(BOLD)); - y += 15; + dc->drawText(x, y, s, COLOR_THEME_PRIMARY1 | FONT(BOLD)); + x += 40; } else { - dc->drawText(x, y, "...", COLOR_THEME_WARNING | FONT(BOLD)); + dc->drawText(x, y, "...", COLOR_THEME_PRIMARY1 | FONT(BOLD)); } } } From 88b8ac86fb2aadad402ce8455c3d32a611f25af7 Mon Sep 17 00:00:00 2001 From: eshifri <46511024+eshifri@users.noreply.github.com> Date: Wed, 1 Sep 2021 17:45:58 -0700 Subject: [PATCH 5/9] [Colorlcd] Support model notes with spaces and prevent radio crash due to filename (#645) * support both versions of model notes file name. Fix for #641 * Adding support for names with spaces * Fix compilation --- radio/src/audio.cpp | 2 +- radio/src/gui/colorlcd/view_text.cpp | 44 +++++++++++++++++++++++++++- radio/src/gui/gui_common.cpp | 8 ++++- radio/src/opentx.h | 10 +++---- radio/src/strhelpers.cpp | 4 +-- 5 files changed, 58 insertions(+), 10 deletions(-) diff --git a/radio/src/audio.cpp b/radio/src/audio.cpp index bbe59ff34..fb8714fda 100644 --- a/radio/src/audio.cpp +++ b/radio/src/audio.cpp @@ -303,7 +303,7 @@ char * getModelAudioPath(char * path) { strcpy(path, SOUNDS_PATH "/"); strncpy(path+SOUNDS_PATH_LNG_OFS, currentLanguagePack->id, 2); - char * result = strcat_currentmodelname(path+sizeof(SOUNDS_PATH)); + char * result = strcat_currentmodelname(path+sizeof(SOUNDS_PATH), 0); *result++ = '/'; *result = '\0'; return result; diff --git a/radio/src/gui/colorlcd/view_text.cpp b/radio/src/gui/colorlcd/view_text.cpp index 68e8e02cd..4c8fedc1c 100644 --- a/radio/src/gui/colorlcd/view_text.cpp +++ b/radio/src/gui/colorlcd/view_text.cpp @@ -428,15 +428,57 @@ void ViewTextWindow::drawVerticalScrollbar(BitmapBuffer *dc) #include "datastructs.h" +static void replaceSpaceWithUnderscore(std::string& name) +{ + size_t index; + do { + index = name.find(' '); + if(index != std::string::npos) + name[index] = '_'; + } while (index != std::string::npos); +} + +bool openNotes(const char buf[], std::string modelNotesName) +{ + if(isFileAvailable(modelNotesName.c_str())) { + new ViewTextWindow(std::string(buf), modelNotesName, ICON_MODEL); + return true; + } else { + return false; + } +} void readModelNotes() { + bool notesFound = false; LED_ERROR_BEGIN(); std::string modelNotesName(g_model.header.name); modelNotesName.append(TEXT_EXT); const char buf[] = {MODELS_PATH}; f_chdir((TCHAR*)buf); - new ViewTextWindow(std::string(buf), modelNotesName, ICON_MODEL); + + notesFound = openNotes(buf, modelNotesName); + if(!notesFound) { + replaceSpaceWithUnderscore(modelNotesName); + notesFound = openNotes(buf, modelNotesName); + } + +#if !defined(EEPROM) + if(!notesFound) { + modelNotesName.assign(g_eeGeneral.currModelFilename); + size_t index = modelNotesName.find(".bin"); + if(index != std::string::npos) + { + modelNotesName.erase(index); + modelNotesName.append(TEXT_EXT); + notesFound = openNotes(buf, modelNotesName); + } + if(!notesFound) { + replaceSpaceWithUnderscore(modelNotesName); + notesFound = openNotes(buf, modelNotesName); + } + } +#endif LED_ERROR_END(); } \ No newline at end of file diff --git a/radio/src/gui/gui_common.cpp b/radio/src/gui/gui_common.cpp index 4c15aecfa..969e0e623 100644 --- a/radio/src/gui/gui_common.cpp +++ b/radio/src/gui/gui_common.cpp @@ -830,7 +830,13 @@ bool isTrainerModeAvailable(int mode) bool modelHasNotes() { char filename[sizeof(MODELS_PATH)+1+sizeof(g_model.header.name)+sizeof(TEXT_EXT)] = MODELS_PATH "/"; - char *buf = strcat_currentmodelname(&filename[sizeof(MODELS_PATH)]); + char *buf = strcat_currentmodelname(&filename[sizeof(MODELS_PATH)], 0); + strcpy(buf, TEXT_EXT); + if (isFileAvailable(filename)) { + return true; + } + + buf = strcat_currentmodelname(&filename[sizeof(MODELS_PATH)], ' '); strcpy(buf, TEXT_EXT); if (isFileAvailable(filename)) { return true; diff --git a/radio/src/opentx.h b/radio/src/opentx.h index 26b7cfe05..1da964969 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -1182,13 +1182,13 @@ extern ReusableBuffer reusableBuffer; uint8_t zlen(const char *str, uint8_t size); bool zexist(const char *str, uint8_t size); unsigned int effectiveLen(const char * str, unsigned int size); -char * strcat_zchar(char *dest, const char *name, uint8_t size, const char *defaultName=nullptr, uint8_t defaultNameSize=0, uint8_t defaultIdx=0); -#define strcatFlightmodeName(dest, idx) strcat_zchar(dest, g_model.flightModeData[idx].name, LEN_FLIGHT_MODE_NAME, STR_FM, PSIZE(TR_FM), idx+1) +char * strcat_zchar(char *dest, const char *name, uint8_t size, const char spaceSym = 0, const char *defaultName=nullptr, uint8_t defaultNameSize=0, uint8_t defaultIdx=0); +#define strcatFlightmodeName(dest, idx) strcat_zchar(dest, g_model.flightModeData[idx].name, LEN_FLIGHT_MODE_NAME, 0, STR_FM, PSIZE(TR_FM), idx+1) #if defined(EEPROM) -#define strcat_modelname(dest, idx) strcat_zchar(dest, modelHeaders[idx].name, LEN_MODEL_NAME, STR_MODEL, PSIZE(TR_MODEL), idx+1) -#define strcat_currentmodelname(dest) strcat_modelname(dest, g_eeGeneral.currModel) +#define strcat_modelname(dest, idx) strcat_zchar(dest, modelHeaders[idx].name, LEN_MODEL_NAME, 0, STR_MODEL, PSIZE(TR_MODEL), idx+1) +#define strcat_currentmodelname(dest, foo) strcat_modelname(dest, g_eeGeneral.currModel) #else -#define strcat_currentmodelname(dest) strcat_zchar(dest, g_model.header.name, LEN_MODEL_NAME) +#define strcat_currentmodelname(dest, spaceSym) strcat_zchar(dest, g_model.header.name, LEN_MODEL_NAME, spaceSym) #endif #define ZLEN(s) zlen(s, sizeof(s)) #define ZEXIST(s) zexist(s, sizeof(s)) diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp index f5d1d5917..33541282b 100644 --- a/radio/src/strhelpers.cpp +++ b/radio/src/strhelpers.cpp @@ -128,7 +128,7 @@ uint8_t zlen(const char * str, uint8_t size) return 0; } -char * strcat_zchar(char * dest, const char * name, uint8_t size, const char * defaultName, uint8_t defaultNameSize, uint8_t defaultIdx) +char * strcat_zchar(char * dest, const char * name, uint8_t size, const char spaceSym, const char * defaultName, uint8_t defaultNameSize, uint8_t defaultIdx) { int8_t len = 0; @@ -142,7 +142,7 @@ char * strcat_zchar(char * dest, const char * name, uint8_t size, const char * d if (!len && dest[i]) len = i+1; if (len) { - if (!dest[i]) + if (dest[i] == spaceSym) dest[i] = '_'; } i--; From b100d9a1644522ff97095d27b2a233c23dbc53b2 Mon Sep 17 00:00:00 2001 From: jfrickmann Date: Thu, 2 Sep 2021 14:31:57 -0400 Subject: [PATCH 6/9] Add Lua function lcd.drawTextLines(...) drawing text across multiple lines inside bounding box --- radio/src/gui/colorlcd/draw_functions.cpp | 6 ++-- radio/src/gui/colorlcd/draw_functions.h | 2 +- radio/src/lua/api_colorlcd.cpp | 36 +++++++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/radio/src/gui/colorlcd/draw_functions.cpp b/radio/src/gui/colorlcd/draw_functions.cpp index 82536ddde..148b2ae9a 100644 --- a/radio/src/gui/colorlcd/draw_functions.cpp +++ b/radio/src/gui/colorlcd/draw_functions.cpp @@ -504,15 +504,15 @@ void drawHexNumber(BitmapBuffer * dc, coord_t x, coord_t y, uint32_t val, LcdFla } } -void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, coord_t height, char * str, LcdFlags flags) +void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, coord_t height, const char * str, LcdFlags flags) { coord_t x = left; coord_t y = top; coord_t line = getFontHeight(flags & 0xFFFF); coord_t space = getTextWidth(" ", 1, flags); coord_t word; - char * eos = str + strlen(str); - char * nxt; + const char * eos = str + strlen(str); + const char * nxt; while (str < eos) { nxt = strstr(str, " "); diff --git a/radio/src/gui/colorlcd/draw_functions.h b/radio/src/gui/colorlcd/draw_functions.h index 802310be2..3262bdcf8 100644 --- a/radio/src/gui/colorlcd/draw_functions.h +++ b/radio/src/gui/colorlcd/draw_functions.h @@ -72,7 +72,7 @@ void drawGPSPosition(BitmapBuffer * dc, coord_t x, coord_t y, int32_t longitude, void drawDate(BitmapBuffer * dc, coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags flags = 0); void drawValueWithUnit(BitmapBuffer * dc, coord_t x, coord_t y, int val, uint8_t unit, LcdFlags flags = 0); void drawHexNumber(BitmapBuffer * dc, coord_t x, coord_t y, uint32_t val, LcdFlags flags = 0); -void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, coord_t height, char * str, LcdFlags flags); +void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, coord_t height, const char * str, LcdFlags flags); inline void drawChn(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t idx, LcdFlags flags) { drawSource(dc, x, y, MIXSRC_CH1 + idx - 1, flags); diff --git a/radio/src/lua/api_colorlcd.cpp b/radio/src/lua/api_colorlcd.cpp index 5a9e71203..5213ac6cf 100644 --- a/radio/src/lua/api_colorlcd.cpp +++ b/radio/src/lua/api_colorlcd.cpp @@ -289,6 +289,41 @@ static int luaLcdSizeText(lua_State *L) return 2; } +/*luadoc +@function lcd.drawTextLines(x, y, w, h, text [, flags]) + +Draw text inside rectangle (x,y,w,h) with line breaks + +@param x,y (positive numbers) starting coordinate + +@param w,h (positive numbers) width and height of bounding rectangle + +@param text (string) text to display + +@param flags (optional) please see [Lcd functions overview](../lcd-functions-less-than-greater-than-luadoc-begin-lcd/lcd_functions-overview.html) for drawing flags and colors, and [Appendix](../../part_vii_-_appendix/fonts.md) for available characters in each font set. INVERS and BLINK are not implemented. + +@status current Introduced in 2.5.0 +*/ +static int luaLcdDrawTextLines(lua_State *L) +{ + if (!luaLcdAllowed || !luaLcdBuffer) + return 0; + + int x = luaL_checkinteger(L, 1); + int y = luaL_checkinteger(L, 2); + int w = luaL_checkinteger(L, 3); + int h = luaL_checkinteger(L, 4); + const char * s = luaL_checkstring(L, 5); + LcdFlags flags = luaL_optunsigned(L, 6, 0); + + // apply text offsets, needed to align 2.4.x to 2.3.x font baselines + x += getTextHorizontalOffset(flags); + y += getTextVerticalOffset(flags); + + drawTextLines(luaLcdBuffer, x, y, w, h, s, flags); + return 0; +} + /*luadoc @function lcd.drawTimer(x, y, value [, flags [, inversColor]]) @@ -1159,6 +1194,7 @@ const luaL_Reg lcdLib[] = { { "drawRectangle", luaLcdDrawRectangle }, { "drawFilledRectangle", luaLcdDrawFilledRectangle }, { "drawText", luaLcdDrawText }, + { "drawTextLines", luaLcdDrawTextLines }, { "sizeText", luaLcdSizeText }, { "drawTimer", luaLcdDrawTimer }, { "drawNumber", luaLcdDrawNumber }, From e700870f70965215724556b79cc9859bfcd258d0 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Fri, 3 Sep 2021 09:49:14 +0200 Subject: [PATCH 7/9] Updated libopenui to fix crash with software keyboard --- radio/src/thirdparty/libopenui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radio/src/thirdparty/libopenui b/radio/src/thirdparty/libopenui index 88ff6b8e7..4d9234835 160000 --- a/radio/src/thirdparty/libopenui +++ b/radio/src/thirdparty/libopenui @@ -1 +1 @@ -Subproject commit 88ff6b8e7152537804497f86202a2b92c17187ad +Subproject commit 4d9234835a4735ab1ff274f3bbdcb59efe8c4e7a From c1cd083476231a38dabbbc4b1e5e12f3b1446a11 Mon Sep 17 00:00:00 2001 From: eshifri <46511024+eshifri@users.noreply.github.com> Date: Fri, 3 Sep 2021 02:05:54 -0700 Subject: [PATCH 8/9] allow mixes without source (#665) --- radio/src/gui/colorlcd/model_mixes.cpp | 7 +++++-- radio/src/mixer.cpp | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/radio/src/gui/colorlcd/model_mixes.cpp b/radio/src/gui/colorlcd/model_mixes.cpp index 3d1682417..01bc01170 100644 --- a/radio/src/gui/colorlcd/model_mixes.cpp +++ b/radio/src/gui/colorlcd/model_mixes.cpp @@ -24,6 +24,7 @@ #include "bitfield.h" #include "model_inputs.h" #include "gvar_numberedit.h" +#include "dataconstants.h" #define SET_DIRTY() storageDirty(EE_MODEL) @@ -374,7 +375,7 @@ void ModelMixesPage::build(FormWindow * window, int8_t focusMixIndex) int mixIndex = 0; MixData * mix = g_model.mixData; for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) { - if (mixIndex < MAX_MIXERS && mix->srcRaw > 0 && mix->destCh == ch) { + if (mixIndex < MAX_MIXERS && mix->destCh == ch) { coord_t h = grid.getWindowHeight(); auto txt = new MixLineTitle(window, grid.getLabelSlot(), @@ -382,7 +383,9 @@ void ModelMixesPage::build(FormWindow * window, int8_t focusMixIndex) BUTTON_BACKGROUND, COLOR_THEME_PRIMARY1 | CENTERED); uint8_t count = 0; - while (mixIndex < MAX_MIXERS && mix->srcRaw > 0 && mix->destCh == ch) { + while (mixIndex < MAX_MIXERS && mix->destCh == ch) { + // First mix cannot be empty + if(!mixIndex && !mix->srcRaw) break; Button * button = new MixLineButton(window, grid.getFieldSlot(), mixIndex); button->setPressHandler([=]() -> uint8_t { button->bringToTop(); diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index 118305c4a..1960c4bba 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -648,7 +648,11 @@ void evalFlightModeMixes(uint8_t mode, uint8_t tick10ms) MixData * md = mixAddress(i); if (md->srcRaw == 0) +#if defined(COLORLCD) + continue; +#else break; +#endif mixsrc_t stickIndex = md->srcRaw - MIXSRC_Rud; From 3fd323a93f4ad6ef1a4e32c37847398f513b1108 Mon Sep 17 00:00:00 2001 From: eshifri Date: Fri, 3 Sep 2021 16:44:22 -0700 Subject: [PATCH 9/9] Add line to the bottom of the model_setup screen for NV!4 --- radio/src/gui/colorlcd/model_setup.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index 0db9ac37a..a5aea3cf7 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -592,6 +592,9 @@ class TrainerModuleWindow : public FormGroup { new Choice(this, grid.getFieldSlot(3, 2), STR_PPM_POL, 0, 1, GET_SET_DEFAULT(g_model.trainerData.pulsePol )); grid.nextLine(); } +#if defined(PCBNV14) + new StaticText(this, grid.getLabelSlot(true) ); +#endif getParent()->moveWindowsTop(top() + 1, adjustHeight()); } @@ -1565,9 +1568,6 @@ void ModelSetupPage::build(FormWindow * window) grid.addWindow(new TrainerModuleWindow(window, {0, grid.getWindowHeight(), LCD_W, 0})); } -#if defined(PCBNV14) - grid.nextLine(); -#endif window->setInnerHeight(grid.getWindowHeight()); }