diff --git a/radio/src/audio.h b/radio/src/audio.h index c6d688434..e47c3cc53 100644 --- a/radio/src/audio.h +++ b/radio/src/audio.h @@ -25,6 +25,7 @@ #include #include "ff.h" #include "opentx_types.h" +#include "dataconstants.h" /* Implements a bit field, number of bits is set by the template, diff --git a/radio/src/datastructs.h b/radio/src/datastructs.h index ae07276b3..69bb23166 100644 --- a/radio/src/datastructs.h +++ b/radio/src/datastructs.h @@ -553,11 +553,11 @@ typedef uint8_t swarnenable_t; #define LAYOUT_ID_LEN 10 PACK(struct CustomScreenData { char LayoutId[LAYOUT_ID_LEN]; - Layout::PersistentData layoutData; + LayoutPersistentData layoutData; }); #define CUSTOM_SCREENS_DATA \ NOBACKUP(CustomScreenData screenData[MAX_CUSTOM_SCREENS]); \ - NOBACKUP(TopBar::PersistentData topbarData); \ + NOBACKUP(TopBarPersistentData topbarData); \ NOBACKUP(uint8_t view); #else #define CUSTOM_SCREENS_DATA \ @@ -921,7 +921,7 @@ static inline void check_struct() CHKSIZE(ModelHeader, 31); CHKSIZE(CurveHeader, 4); CHKSIZE(CustomScreenData, 850); - CHKSIZE(TopBar::PersistentData, 300); + CHKTYPE(TopBarPersistentData, 300); #elif defined(PCBNV14) // TODO #elif defined(PCBSKY9X) diff --git a/radio/src/gui/colorlcd/gui.h b/radio/src/gui/colorlcd/gui.h index 12f0e6682..4b38183cc 100644 --- a/radio/src/gui/colorlcd/gui.h +++ b/radio/src/gui/colorlcd/gui.h @@ -47,7 +47,7 @@ void drawCurveHorizontalScale(); void drawCurveCoord(int x, int y, const char * text, bool active=false); void drawCurvePoint(int x, int y, LcdFlags color); -extern Layout * customScreens[MAX_CUSTOM_SCREENS]; +extern WidgetsContainerInterface * customScreens[MAX_CUSTOM_SCREENS]; void drawAlertBox(const char * title, const char * text, const char * action); void showAlertBox(const char * title, const char * text, const char * action, uint8_t sound); diff --git a/radio/src/gui/colorlcd/layout.cpp b/radio/src/gui/colorlcd/layout.cpp index e1d3e1fbe..a9441b309 100644 --- a/radio/src/gui/colorlcd/layout.cpp +++ b/radio/src/gui/colorlcd/layout.cpp @@ -20,13 +20,8 @@ #include "opentx.h" #include "view_main.h" -#include "layouts/trims.h" -#include "layouts/sliders.h" -#include "view_main_decoration.h" -constexpr uint32_t LAYOUT_REFRESH = 1000 / 2; // 2 Hz - -Layout * customScreens[MAX_CUSTOM_SCREENS] = {}; +WidgetsContainerInterface * customScreens[MAX_CUSTOM_SCREENS] = {}; std::list & getRegisteredLayouts() { @@ -54,7 +49,8 @@ const LayoutFactory * getLayoutFactory(const char * name) // // Loads a layout, but does not attach it to any window // -Layout * loadLayout(const char * name, Layout::PersistentData * persistentData) +WidgetsContainerInterface * +loadLayout(const char * name, LayoutPersistentData * persistentData) { const LayoutFactory * factory = getLayoutFactory(name); if (factory) { @@ -127,6 +123,8 @@ void loadCustomScreens() } auto topbar = viewMain->getTopbar(); + + // TODO: how to reload this guy? topbar->load(); viewMain->setCurrentMainView(0); @@ -139,7 +137,8 @@ void loadCustomScreens() // - new screen is configured into g_model // - the new screen is returned (not attached) // -Layout* createCustomScreen(const LayoutFactory* factory, unsigned customScreenIndex) +WidgetsContainerInterface * +createCustomScreen(const LayoutFactory* factory, unsigned customScreenIndex) { if (!factory || (customScreenIndex >= MAX_CUSTOM_SCREENS)) return nullptr; @@ -180,104 +179,10 @@ void disposeCustomScreen(unsigned idx) memset(dst, 0, len); } -Layout::Layout(const LayoutFactory * factory, PersistentData * persistentData): - LayoutBase({0, 0, LCD_W, LCD_H}, persistentData), - factory(factory), - decoration(new ViewMainDecoration(this, getRect())) +LayoutFactory::LayoutFactory(const char * id, const char * name): + id(id), + name(name) { - decorate(); + registerLayout(this); } -void Layout::create() -{ - memset(persistentData, 0, sizeof(PersistentData)); - - getOptionValue(OPTION_TOPBAR)->boolValue = true; - getOptionValue(OPTION_FM)->boolValue = true; - getOptionValue(OPTION_SLIDERS)->boolValue = true; - getOptionValue(OPTION_TRIMS)->boolValue = true; - getOptionValue(OPTION_MIRRORED)->boolValue = false; -} - -#if defined(DEBUG_WINDOWS) -void Layout::paint(BitmapBuffer * dc) -{ - TRACE_WINDOWS("# painting -> %s", getWindowDebugString().c_str()); - LayoutBase::paint(dc); -} -#endif - -void Layout::checkEvents() -{ - LayoutBase::checkEvents(); - decorate(); - - uint32_t now = RTOS_GET_MS(); - if (now - lastRefresh >= LAYOUT_REFRESH) { - lastRefresh = now; - invalidate(); - -#if defined(DEBUG_WINDOWS) - TRACE_WINDOWS("# %s refresh: %s", factory->getId(), getWindowDebugString().c_str()); -#endif - } -} - -void Layout::setTrimsVisible(bool visible) -{ - decoration->setTrimsVisible(visible); -} - -void Layout::setSlidersVisible(bool visible) -{ - decoration->setSlidersVisible(visible); -} - -void Layout::setFlightModeVisible(bool visible) -{ - decoration->setFlightModeVisible(visible); -} - -void Layout::adjustDecoration() -{ - decoration->adjustDecoration(); -} - -void Layout::decorate() -{ - // Check if deco setting are still up-to-date - uint8_t checkSettings = - (hasTopbar() ? 1 << 0 : 0) | - (hasSliders() ? 1 << 1 : 0) | - (hasTrims() ? 1 << 2 : 0) | - (hasFlightMode() ? 1 << 3 : 0); - - if (checkSettings == decorationSettings) { - // everything ok, exit! - return; - } - - // Save settings - decorationSettings = checkSettings; - - // Set visible decoration - setSlidersVisible(hasSliders()); - setTrimsVisible(hasTrims()); - setFlightModeVisible(hasFlightMode()); - - // Re-compute positions - adjustDecoration(); - - // and update relevant windows - updateZones(); - - // probably not needed - //invalidate(); -} - -rect_t Layout::getMainZone() const -{ - rect_t zone = decoration->getMainZone(); - return ViewMain::instance()->getMainZone(zone, hasTopbar()); -} - diff --git a/radio/src/gui/colorlcd/layout.h b/radio/src/gui/colorlcd/layout.h index 81b095577..54d9d1b58 100644 --- a/radio/src/gui/colorlcd/layout.h +++ b/radio/src/gui/colorlcd/layout.h @@ -22,180 +22,35 @@ #include #include "widgets_container.h" -#include "lcd.h" -#include "topbar.h" #define MAX_LAYOUT_ZONES 10 #define MAX_LAYOUT_OPTIONS 10 constexpr coord_t TRIM_LINE_WIDTH = 8; constexpr coord_t TRIM_SQUARE_SIZE = 17; constexpr coord_t MAIN_ZONE_BORDER = 10; +constexpr uint32_t LAYOUT_REFRESH = 1000 / 2; // 2 Hz -class LayoutFactory; -class ViewMainDecoration; +class BitmapBuffer; -#define LAYOUT_COMMON_OPTIONS \ - { STR_TOP_BAR, ZoneOption::Bool }, \ - { STR_FLIGHT_MODE, ZoneOption::Bool }, \ - { STR_SLIDERS, ZoneOption::Bool }, \ - { STR_TRIMS, ZoneOption::Bool }, \ - { STR_MIRROR, ZoneOption::Bool } - -#define LAYOUT_OPTIONS_END \ - { nullptr, ZoneOption::Bool } - -typedef WidgetsContainer LayoutBase; - -class Layout: public LayoutBase -{ - friend class LayoutFactory; - - public: - - // Common 'ZoneOptionValue's among all layouts - enum { - OPTION_TOPBAR = 0, - OPTION_FM, - OPTION_SLIDERS, - OPTION_TRIMS, - OPTION_MIRRORED, - - OPTION_LAST_DEFAULT=OPTION_MIRRORED - }; - - Layout(const LayoutFactory * factory, PersistentData * persistentData); - -#if defined(DEBUG_WINDOWS) - std::string getName() const override - { - return "Layout"; - } - - void paint(BitmapBuffer * dc) override; -#endif - - void create() override; - - inline const LayoutFactory * getFactory() const - { - return factory; - } - - void checkEvents() override; - - bool hasTopbar() const { - return getOptionValue(OPTION_TOPBAR)->boolValue; - } - - bool hasFlightMode() const { - return getOptionValue(OPTION_FM)->boolValue; - } - - bool hasSliders() const { - return getOptionValue(OPTION_SLIDERS)->boolValue; - } - - bool hasTrims() const { - return getOptionValue(OPTION_TRIMS)->boolValue; - } - - bool isMirrored() const { - return getOptionValue(OPTION_MIRRORED)->boolValue; - } - - // Set decoration visibility - void setTrimsVisible(bool visible); - void setSlidersVisible(bool visible); - void setFlightModeVisible(bool visible); - - // Re-calculate positions - void adjustDecoration(); - - // Updates settings for trims, sliders, pots, etc... - void decorate(); - - protected: - const LayoutFactory * factory = nullptr; - ViewMainDecoration* decoration = nullptr; - - // Decoration settings bitmask to detect updates - uint8_t decorationSettings = 0; - - // Last time we refreshed the window - uint32_t lastRefresh = 0; - - // Get the available space for widgets - rect_t getMainZone() const; -}; - -void registerLayout(const LayoutFactory * factory); +typedef WidgetsContainerPersistentData LayoutPersistentData; class LayoutFactory { public: - LayoutFactory(const char * id, const char * name): - id(id), - name(name) - { - registerLayout(this); - } + LayoutFactory(const char * id, const char * name); const char * getId() const { return id; } const char * getName() const { return name; } virtual void drawThumb(BitmapBuffer * dc, uint16_t x, uint16_t y, LcdFlags flags) const = 0; virtual const ZoneOption * getOptions() const = 0; - virtual Layout * create(Layout::PersistentData * persistentData) const = 0; - virtual Layout * load(Layout::PersistentData * persistentData) const = 0; + virtual WidgetsContainerInterface * create(LayoutPersistentData * persistentData) const = 0; + virtual WidgetsContainerInterface * load(LayoutPersistentData * persistentData) const = 0; protected: const char * id; const char * name; }; -template -class BaseLayoutFactory: public LayoutFactory -{ - public: - BaseLayoutFactory(const char * id, const char * name, const uint8_t * bitmap, const ZoneOption * options): - LayoutFactory(id, name), - bitmap(bitmap), - options(options) - { - } - - void drawThumb(BitmapBuffer * dc, uint16_t x, uint16_t y, uint32_t flags) const override - { - dc->drawBitmapPattern(x, y, bitmap, flags); - } - - const ZoneOption * getOptions() const override - { - return options; - } - - Layout * create(Layout::PersistentData * persistentData) const override - { - Layout * layout = new T(this, persistentData); - if (layout) { - layout->create(); - } - return layout; - } - - Layout * load(Layout::PersistentData * persistentData) const override - { - Layout * layout = new T(this, persistentData); - if (layout) { - layout->load(); - } - return layout; - } - - protected: - const uint8_t * bitmap; - const ZoneOption * options; -}; - -Layout * loadLayout(const char * name, Layout::PersistentData * persistentData); +WidgetsContainerInterface * loadLayout(const char * name, LayoutPersistentData * persistentData); // intented for new models void loadDefaultLayout(); @@ -206,9 +61,14 @@ void loadCustomScreens(); // delete all custom screens from memory void deleteCustomScreens(); -Layout* createCustomScreen(const LayoutFactory* factory, unsigned customScreenIndex); +WidgetsContainerInterface * +createCustomScreen(const LayoutFactory* factory, unsigned customScreenIndex); // Remove custom screen from the model void disposeCustomScreen(unsigned idx); +// Layout must register to be found +void registerLayout(const LayoutFactory * factory); + +// List of registered layout factories std::list & getRegisteredLayouts(); diff --git a/radio/src/gui/colorlcd/layouts/layout1x1.cpp b/radio/src/gui/colorlcd/layouts/layout1x1.cpp index f2fc0524d..96296388f 100644 --- a/radio/src/gui/colorlcd/layouts/layout1x1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout1x1.cpp @@ -18,8 +18,8 @@ * GNU General Public License for more details. */ -#include "opentx.h" -#include "trims.h" +#include "layout.h" +#include "layout_factory_implem.h" const uint8_t LBM_LAYOUT_1x1[] = { #include "mask_layout1x1.lbm" diff --git a/radio/src/gui/colorlcd/layouts/layout2+1.cpp b/radio/src/gui/colorlcd/layouts/layout2+1.cpp index 29b8f7d5a..3977ecbdd 100644 --- a/radio/src/gui/colorlcd/layouts/layout2+1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2+1.cpp @@ -18,9 +18,8 @@ * GNU General Public License for more details. */ -#include "opentx.h" -#include "sliders.h" -#include "trims.h" +#include "layout.h" +#include "layout_factory_implem.h" const uint8_t LBM_LAYOUT_2P1[] = { #include "mask_layout2+1.lbm" diff --git a/radio/src/gui/colorlcd/layouts/layout2x1.cpp b/radio/src/gui/colorlcd/layouts/layout2x1.cpp index c9bd5831b..db38eaba3 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x1.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x1.cpp @@ -18,9 +18,8 @@ * GNU General Public License for more details. */ -#include "opentx.h" -#include "sliders.h" -#include "trims.h" +#include "layout.h" +#include "layout_factory_implem.h" const uint8_t LBM_LAYOUT_2x1[] = { #include "mask_layout2x1.lbm" diff --git a/radio/src/gui/colorlcd/layouts/layout2x2.cpp b/radio/src/gui/colorlcd/layouts/layout2x2.cpp index 6e8d78632..8b48adc46 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x2.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x2.cpp @@ -18,9 +18,8 @@ * GNU General Public License for more details. */ -#include "opentx.h" -#include "sliders.h" -#include "trims.h" +#include "layout.h" +#include "layout_factory_implem.h" const uint8_t LBM_LAYOUT_2x2[] = { #include "mask_layout2x2.lbm" diff --git a/radio/src/gui/colorlcd/layouts/layout2x4.cpp b/radio/src/gui/colorlcd/layouts/layout2x4.cpp index 618f98a6f..4b01e3ae2 100644 --- a/radio/src/gui/colorlcd/layouts/layout2x4.cpp +++ b/radio/src/gui/colorlcd/layouts/layout2x4.cpp @@ -18,7 +18,8 @@ * GNU General Public License for more details. */ -#include "opentx.h" +#include "layout.h" +#include "layout_factory_implem.h" const uint8_t LBM_LAYOUT_2x4[] = { #include "mask_layout2x4.lbm" @@ -38,7 +39,7 @@ class Layout2x4: public Layout public: enum { - OPTION_PANEL1_BACKGROUND = OPTION_LAST_DEFAULT + 1, + OPTION_PANEL1_BACKGROUND = LAYOUT_OPTION_LAST_DEFAULT + 1, OPTION_PANEL1_COLOR, OPTION_PANEL2_BACKGROUND, OPTION_PANEL2_COLOR diff --git a/radio/src/gui/colorlcd/layouts/layout_factory_implem.cpp b/radio/src/gui/colorlcd/layouts/layout_factory_implem.cpp new file mode 100644 index 000000000..c173f2524 --- /dev/null +++ b/radio/src/gui/colorlcd/layouts/layout_factory_implem.cpp @@ -0,0 +1,127 @@ +/* + * 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 "layout_factory_implem.h" +#include "layouts/trims.h" +#include "layouts/sliders.h" +#include "view_main_decoration.h" +#include "view_main.h" + +Layout::Layout(const LayoutFactory * factory, PersistentData * persistentData): + LayoutBase({0, 0, LCD_W, LCD_H}, persistentData), + factory(factory), + decoration(new ViewMainDecoration(this, getRect())) +{ + decorate(); +} + +void Layout::create() +{ + memset(persistentData, 0, sizeof(PersistentData)); + + getOptionValue(LAYOUT_OPTION_TOPBAR)->boolValue = true; + getOptionValue(LAYOUT_OPTION_FM)->boolValue = true; + getOptionValue(LAYOUT_OPTION_SLIDERS)->boolValue = true; + getOptionValue(LAYOUT_OPTION_TRIMS)->boolValue = true; + getOptionValue(LAYOUT_OPTION_MIRRORED)->boolValue = false; +} + +#if defined(DEBUG_WINDOWS) +void Layout::paint(BitmapBuffer * dc) +{ + TRACE_WINDOWS("# painting -> %s", getWindowDebugString().c_str()); + LayoutBase::paint(dc); +} +#endif + +void Layout::checkEvents() +{ + LayoutBase::checkEvents(); + decorate(); + + uint32_t now = RTOS_GET_MS(); + if (now - lastRefresh >= LAYOUT_REFRESH) { + lastRefresh = now; + invalidate(); + +#if defined(DEBUG_WINDOWS) + TRACE_WINDOWS("# %s refresh: %s", factory->getId(), getWindowDebugString().c_str()); +#endif + } +} + +void Layout::setTrimsVisible(bool visible) +{ + decoration->setTrimsVisible(visible); +} + +void Layout::setSlidersVisible(bool visible) +{ + decoration->setSlidersVisible(visible); +} + +void Layout::setFlightModeVisible(bool visible) +{ + decoration->setFlightModeVisible(visible); +} + +void Layout::adjustDecoration() +{ + decoration->adjustDecoration(); +} + +void Layout::decorate() +{ + // Check if deco setting are still up-to-date + uint8_t checkSettings = + (hasTopbar() ? 1 << 0 : 0) | + (hasSliders() ? 1 << 1 : 0) | + (hasTrims() ? 1 << 2 : 0) | + (hasFlightMode() ? 1 << 3 : 0); + + if (checkSettings == decorationSettings) { + // everything ok, exit! + return; + } + + // Save settings + decorationSettings = checkSettings; + + // Set visible decoration + setSlidersVisible(hasSliders()); + setTrimsVisible(hasTrims()); + setFlightModeVisible(hasFlightMode()); + + // Re-compute positions + adjustDecoration(); + + // and update relevant windows + updateZones(); + + // probably not needed + //invalidate(); +} + +rect_t Layout::getMainZone() const +{ + rect_t zone = decoration->getMainZone(); + return ViewMain::instance()->getMainZone(zone, hasTopbar()); +} + diff --git a/radio/src/gui/colorlcd/layouts/layout_factory_implem.h b/radio/src/gui/colorlcd/layouts/layout_factory_implem.h new file mode 100644 index 000000000..95a34c7f4 --- /dev/null +++ b/radio/src/gui/colorlcd/layouts/layout_factory_implem.h @@ -0,0 +1,161 @@ +/* + * 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. + */ + +#pragma once + +#include + +//#include "lcd.h" +//#include "topbar.h" + +#include "audio.h" +#include "translations.h" + +#include "layout.h" +#include "widgets/widgets_container_implem.h" + +#define LAYOUT_COMMON_OPTIONS \ + { STR_TOP_BAR, ZoneOption::Bool }, \ + { STR_FLIGHT_MODE, ZoneOption::Bool }, \ + { STR_SLIDERS, ZoneOption::Bool }, \ + { STR_TRIMS, ZoneOption::Bool }, \ + { STR_MIRROR, ZoneOption::Bool } + +#define LAYOUT_OPTIONS_END \ + { nullptr, ZoneOption::Bool } + +class ViewMainDecoration; + +typedef WidgetsContainer LayoutBase; + +class Layout: public LayoutBase +{ + friend class LayoutFactory; + + public: + + Layout(const LayoutFactory * factory, PersistentData * persistentData); + +#if defined(DEBUG_WINDOWS) + std::string getName() const override + { + return "Layout"; + } + + void paint(BitmapBuffer * dc) override; +#endif + + void create() override; + + const LayoutFactory * getFactory() const override + { + return factory; + } + + void checkEvents() override; + + bool hasTopbar() const { + return getOptionValue(LAYOUT_OPTION_TOPBAR)->boolValue; + } + + bool hasFlightMode() const { + return getOptionValue(LAYOUT_OPTION_FM)->boolValue; + } + + bool hasSliders() const { + return getOptionValue(LAYOUT_OPTION_SLIDERS)->boolValue; + } + + bool hasTrims() const { + return getOptionValue(LAYOUT_OPTION_TRIMS)->boolValue; + } + + bool isMirrored() const { + return getOptionValue(LAYOUT_OPTION_MIRRORED)->boolValue; + } + + // Set decoration visibility + void setTrimsVisible(bool visible); + void setSlidersVisible(bool visible); + void setFlightModeVisible(bool visible); + + // Re-calculate positions + void adjustDecoration(); + + // Updates settings for trims, sliders, pots, etc... + void decorate() override; + + protected: + const LayoutFactory * factory = nullptr; + ViewMainDecoration* decoration = nullptr; + + // Decoration settings bitmask to detect updates + uint8_t decorationSettings = 0; + + // Last time we refreshed the window + uint32_t lastRefresh = 0; + + // Get the available space for widgets + rect_t getMainZone() const; +}; + +template +class BaseLayoutFactory: public LayoutFactory +{ + public: + BaseLayoutFactory(const char * id, const char * name, const uint8_t * bitmap, const ZoneOption * options): + LayoutFactory(id, name), + bitmap(bitmap), + options(options) + { + } + + void drawThumb(BitmapBuffer * dc, uint16_t x, uint16_t y, uint32_t flags) const override + { + dc->drawBitmapPattern(x, y, bitmap, flags); + } + + const ZoneOption * getOptions() const override + { + return options; + } + + Layout * create(Layout::PersistentData * persistentData) const override + { + Layout * layout = new T(this, persistentData); + if (layout) { + layout->create(); + } + return layout; + } + + Layout * load(Layout::PersistentData * persistentData) const override + { + Layout * layout = new T(this, persistentData); + if (layout) { + layout->load(); + } + return layout; + } + + protected: + const uint8_t * bitmap; + const ZoneOption * options; +}; diff --git a/radio/src/gui/colorlcd/layouts/sliders.cpp b/radio/src/gui/colorlcd/layouts/sliders.cpp new file mode 100644 index 000000000..08a9fcc8c --- /dev/null +++ b/radio/src/gui/colorlcd/layouts/sliders.cpp @@ -0,0 +1,76 @@ +/* + * 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 "sliders.h" +#include "opentx.h" + +void MainViewHorizontalSlider::paint(BitmapBuffer * dc) +{ + // The ticks + int delta = (width() - TRIM_SQUARE_SIZE) / SLIDER_TICKS_COUNT; + coord_t x = TRIM_SQUARE_SIZE / 2; + for (uint8_t i = 0; i <= SLIDER_TICKS_COUNT; i++) { + if (i == 0 || i == SLIDER_TICKS_COUNT / 2 || i == SLIDER_TICKS_COUNT) + dc->drawSolidVerticalLine(x, 2, 13, DEFAULT_COLOR); + else + dc->drawSolidVerticalLine(x, 4, 9, DEFAULT_COLOR); + x += delta; + } + + // The square + x = width() - TRIM_SQUARE_SIZE - divRoundClosest((width() - TRIM_SQUARE_SIZE) * (value + RESX), 2 * RESX); + drawTrimSquare(dc, x, 0, TRIM_BGCOLOR); +} + +void MainView6POS::paint(BitmapBuffer * dc) +{ + // The ticks + int delta = (width() - TRIM_SQUARE_SIZE) / (XPOTS_MULTIPOS_COUNT - 1); + coord_t x = TRIM_SQUARE_SIZE / 2; + for (uint8_t i = 0; i <= XPOTS_MULTIPOS_COUNT; i++) { + dc->drawSolidVerticalLine(x, 4, 9, DEFAULT_COLOR); + x += delta; + } + + // The square + auto value = 1 + (potsPos[idx] & 0x0f); + x = TRIM_SQUARE_SIZE / 2 + divRoundClosest((width() - TRIM_SQUARE_SIZE) * (value -1) , 6); + drawTrimSquare(dc, x, 0, TRIM_BGCOLOR); + dc->drawNumber(x + 1, 0, value, FOCUS_COLOR); +} + +void MainViewVerticalSlider::paint(BitmapBuffer * dc) +{ + uint8_t slidersTick = height() / 5; + // The ticks + int delta = (height() - TRIM_SQUARE_SIZE) / slidersTick; + coord_t y = TRIM_SQUARE_SIZE / 2; + for (uint8_t i = 0; i <= slidersTick; i++) { + if (i == 0 || i == slidersTick / 2 || i == slidersTick) + dc->drawSolidHorizontalLine(2, y, 13, DEFAULT_COLOR); + else + dc->drawSolidHorizontalLine(4, y, 9, DEFAULT_COLOR); + y += delta; + } + + // The square + y = height() - TRIM_SQUARE_SIZE - divRoundClosest((height() - TRIM_SQUARE_SIZE) * (value + RESX), 2 * RESX); + drawTrimSquare(dc, 0, y, TRIM_BGCOLOR); +} diff --git a/radio/src/gui/colorlcd/layouts/sliders.h b/radio/src/gui/colorlcd/layouts/sliders.h index eae8b23bf..6043ef093 100644 --- a/radio/src/gui/colorlcd/layouts/sliders.h +++ b/radio/src/gui/colorlcd/layouts/sliders.h @@ -62,70 +62,19 @@ class MainViewHorizontalSlider : public MainViewSlider { public: using MainViewSlider::MainViewSlider; - - void paint(BitmapBuffer * dc) override - { - // The ticks - int delta = (width() - TRIM_SQUARE_SIZE) / SLIDER_TICKS_COUNT; - coord_t x = TRIM_SQUARE_SIZE / 2; - for (uint8_t i = 0; i <= SLIDER_TICKS_COUNT; i++) { - if (i == 0 || i == SLIDER_TICKS_COUNT / 2 || i == SLIDER_TICKS_COUNT) - dc->drawSolidVerticalLine(x, 2, 13, DEFAULT_COLOR); - else - dc->drawSolidVerticalLine(x, 4, 9, DEFAULT_COLOR); - x += delta; - } - - // The square - x = width() - TRIM_SQUARE_SIZE - divRoundClosest((width() - TRIM_SQUARE_SIZE) * (value + RESX), 2 * RESX); - drawTrimSquare(dc, x, 0, TRIM_BGCOLOR); - } + void paint(BitmapBuffer * dc) override; }; class MainView6POS : public MainViewSlider { public: using MainViewSlider::MainViewSlider; - - void paint(BitmapBuffer * dc) override - { - // The ticks - int delta = (width() - TRIM_SQUARE_SIZE) / (XPOTS_MULTIPOS_COUNT - 1); - coord_t x = TRIM_SQUARE_SIZE / 2; - for (uint8_t i = 0; i <= XPOTS_MULTIPOS_COUNT; i++) { - dc->drawSolidVerticalLine(x, 4, 9, DEFAULT_COLOR); - x += delta; - } - - // The square - auto value = 1 + (potsPos[idx] & 0x0f); - x = TRIM_SQUARE_SIZE / 2 + divRoundClosest((width() - TRIM_SQUARE_SIZE) * (value -1) , 6); - drawTrimSquare(dc, x, 0, TRIM_BGCOLOR); - dc->drawNumber(x + 1, 0, value, FOCUS_COLOR); - } + void paint(BitmapBuffer * dc) override; }; class MainViewVerticalSlider : public MainViewSlider { public: using MainViewSlider::MainViewSlider; - - void paint(BitmapBuffer * dc) override - { - uint8_t slidersTick = height() / 5; - // The ticks - int delta = (height() - TRIM_SQUARE_SIZE) / slidersTick; - coord_t y = TRIM_SQUARE_SIZE / 2; - for (uint8_t i = 0; i <= slidersTick; i++) { - if (i == 0 || i == slidersTick / 2 || i == slidersTick) - dc->drawSolidHorizontalLine(2, y, 13, DEFAULT_COLOR); - else - dc->drawSolidHorizontalLine(4, y, 9, DEFAULT_COLOR); - y += delta; - } - - // The square - y = height() - TRIM_SQUARE_SIZE - divRoundClosest((height() - TRIM_SQUARE_SIZE) * (value + RESX), 2 * RESX); - drawTrimSquare(dc, 0, y, TRIM_BGCOLOR); - } + void paint(BitmapBuffer * dc) override; }; diff --git a/radio/src/gui/colorlcd/layouts/topbar_impl.cpp b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp new file mode 100644 index 000000000..39d0631a0 --- /dev/null +++ b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp @@ -0,0 +1,195 @@ +/* + * 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 "topbar_impl.h" +#include "opentx.h" + +const char * const STR_MONTHS[] = TR_MONTHS; +constexpr uint32_t TOPBAR_REFRESH = 1000 / 2; // 2 Hz + +TopbarImpl::TopbarImpl(Window * parent) : + WidgetsContainer({0, 0, LCD_W, MENU_HEADER_HEIGHT}, &g_model.topbarData) +{ + attach(parent); +} + +unsigned int TopbarImpl::getZonesCount() const +{ + return MAX_TOPBAR_ZONES; +} + +rect_t TopbarImpl::getZone(unsigned int index) const +{ + return { + coord_t(49 + (TOPBAR_ZONE_WIDTH + 2 * TOPBAR_ZONE_MARGIN) * index), + TOPBAR_ZONE_MARGIN, + TOPBAR_ZONE_WIDTH, + TOPBAR_HEIGHT + }; +} + +void TopbarImpl::setVisible(float visible) // 0.0 -> 1.0 +{ + if (visible == 0.0) { + setTop(-(int)MENU_HEADER_HEIGHT); + } + else if (visible == 1.0) { + setTop(0); + } + else if (visible > 0.0 && visible < 1.0){ + float top = - (float)MENU_HEADER_HEIGHT * (1.0 - visible); + setTop((coord_t)top); + } +} + +coord_t TopbarImpl::getVisibleHeight(float visible) const // 0.0 -> 1.0 +{ + if (visible == 0.0) { + return 0; + } + else if (visible == 1.0) { + return MENU_HEADER_HEIGHT; + } + + float h = (float)MENU_HEADER_HEIGHT * visible; + return (coord_t)h; +} + +void TopbarImpl::paint(BitmapBuffer * dc) +{ + dc->drawSolidFilledRect(0, 0, width(), height(), MENU_BGCOLOR); + OpenTxTheme::instance()->drawTopLeftBitmap(dc); + + struct gtm t; + gettime(&t); + char str[10]; + + sprintf(str, "%d %s", t.tm_mday, STR_MONTHS[t.tm_mon]); + dc->drawSolidVerticalLine(DATETIME_SEPARATOR_X, 7, 31, MENU_COLOR); + dc->drawText(DATETIME_MIDDLE, DATETIME_LINE1, str, FONT(XS) | CENTERED| MENU_COLOR); + + getTimerString(str, getValue(MIXSRC_TX_TIME)); + dc->drawText(DATETIME_MIDDLE, DATETIME_LINE2, str, FONT(XS) | CENTERED | MENU_COLOR); + + // USB icon + if (usbPlugged()) { + dc->drawBitmapPattern(LCD_W - 98, 8, LBM_TOPMENU_USB, MENU_COLOR); + } + + // Logs + if (isFunctionActive(FUNCTION_LOGS) && !usbPlugged() && BLINK_ON_PHASE) { + dc->drawBitmapPattern(LCD_W - 98, 6, LBM_DOT, MENU_COLOR); + } + + // RSSI + const uint8_t rssiBarsValue[] = {30, 40, 50, 60, 80}; + const uint8_t rssiBarsHeight[] = {5, 10, 15, 21, 31}; + for (unsigned int i = 0; i < DIM(rssiBarsHeight); i++) { + uint8_t height = rssiBarsHeight[i]; + dc->drawSolidFilledRect(LCD_W - 90 + i * 6, 38 - height, 4, height, TELEMETRY_RSSI() >= rssiBarsValue[i] ? MENU_COLOR : MENU_TITLE_DISABLE_COLOR); + } + +#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) + if (isModuleXJT(INTERNAL_MODULE) && isExternalAntennaEnabled()) { + dc->drawBitmapPattern(LCD_W-94, 4, LBM_TOPMENU_ANTENNA, MENU_COLOR); + } +#endif + + /* Audio volume */ + dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_SCALE, MENU_TITLE_DISABLE_COLOR); + if (requiredSpeakerVolume == 0 || g_eeGeneral.beepMode == e_mode_quiet) + dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_0, MENU_COLOR); + else if (requiredSpeakerVolume < 7) + dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_1, MENU_COLOR); + else if (requiredSpeakerVolume < 13) + dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_2, MENU_COLOR); + else if (requiredSpeakerVolume < 19) + dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_3, MENU_COLOR); + else + dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_4, MENU_COLOR); + + /* Tx battery */ + uint8_t bars = GET_TXBATT_BARS(5); +#if defined(USB_CHARGER) + if (usbChargerLed()) { + dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT_CHARGING, MENU_COLOR); + } + else { + dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, MENU_COLOR); + } +#else + dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, MENU_COLOR); +#endif + for (unsigned int i = 0; i < 5; i++) { + dc->drawSolidFilledRect(LCD_W - 128 + 4 * i, 30, 2, 8, i >= bars ? MENU_TITLE_DISABLE_COLOR : MENU_COLOR); + } + +#if 0 + // Radio battery - TODO + // drawValueWithUnit(370, 8, g_vbat100mV, UNIT_VOLTS, PREC1|FONT(XS)|MENU_COLOR); + // lcdDrawSolidRect(300, 3, 20, 50, MENU_COLOR); + // lcdDrawRect(batt_icon_x+FW, BAR_Y+1, 13, 7); + // lcdDrawSolidVerticalLine(batt_icon_x+FW+13, BAR_Y+2, 5); + + // Rx battery + if (g_model.voltsSource) { + TelemetryItem & item = telemetryItems[g_model.voltsSource-1]; + if (item.isAvailable()) { + int32_t value = item.value; + TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.altitudeSource-1]; + LcdFlags att = 0; + if (sensor.prec == 2) { + att |= PREC1; + value /= 10; + } + else if (sensor.prec == 1) { + att |= PREC1; + } + att |= (item.isOld() ? ALARM_COLOR : DEFAULT_COLOR); + lcdDrawSolidFilledRect(ALTITUDE_X, VOLTS_Y, ALTITUDE_W, ALTITUDE_H, DEFAULT_BGCOLOR); + lcdDrawText(ALTITUDE_X+PADDING, VOLTS_Y+2, "Voltage", att); + drawValueWithUnit(ALTITUDE_X+PADDING, VOLTS_Y+12, value, UNIT_VOLTS, FONT(XL)|LEFT|att); + } + } + + // Model altitude + if (g_model.frsky.altitudeSource) { + TelemetryItem & item = telemetryItems[g_model.frsky.altitudeSource-1]; + if (item.isAvailable()) { + int32_t value = item.value; + TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.altitudeSource-1]; + if (sensor.prec) value /= sensor.prec == 2 ? 100 : 10; + LcdFlags att = (item.isOld() ? ALARM_COLOR : DEFAULT_COLOR); + lcdDrawSolidFilledRect(ALTITUDE_X, ALTITUDE_Y, ALTITUDE_W, ALTITUDE_H, DEFAULT_BGCOLOR); + lcdDrawText(ALTITUDE_X+PADDING, ALTITUDE_Y+2, "Alt", att); + drawValueWithUnit(ALTITUDE_X+PADDING, ALTITUDE_Y+12, value, UNIT_METERS, FONT(XL)|LEFT|att); + } + } +#endif +} + +void TopbarImpl::checkEvents() +{ + uint32_t now = RTOS_GET_MS(); + if (now - lastRefresh >= TOPBAR_REFRESH) { + lastRefresh = now; + invalidate(); + } +} diff --git a/radio/src/gui/colorlcd/layouts/topbar_impl.h b/radio/src/gui/colorlcd/layouts/topbar_impl.h new file mode 100644 index 000000000..2fb2af95e --- /dev/null +++ b/radio/src/gui/colorlcd/layouts/topbar_impl.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#pragma once + +#include "topbar.h" +#include "widgets/widgets_container_implem.h" + +typedef WidgetsContainer TopbarImplBase; + +class TopbarImpl: + public TopbarImplBase, + public Topbar +{ + public: + explicit TopbarImpl(Window * parent); + +#if defined(DEBUG_WINDOWS) + std::string getName() const override + { + return "TopBar"; + } +#endif + + void load() override + { + TopbarImplBase::load(); + } + + unsigned int getZonesCount() const override; + + rect_t getZone(unsigned int index) const override; + + void setVisible(float visible); + coord_t getVisibleHeight(float visible) const; // 0.0 -> 1.0 + + void paint(BitmapBuffer * dc) override; + + void checkEvents() override; + + // Fake implementation to satisfy WidgetsContainerInterface + // this should probably be get rid of (might be tricky + const LayoutFactory * getFactory() const override + { + return nullptr; + } + + protected: + uint32_t lastRefresh = 0; +}; diff --git a/radio/src/gui/colorlcd/screen_setup.cpp b/radio/src/gui/colorlcd/screen_setup.cpp index 111a74b4c..0faa8ab82 100644 --- a/radio/src/gui/colorlcd/screen_setup.cpp +++ b/radio/src/gui/colorlcd/screen_setup.cpp @@ -344,6 +344,8 @@ ScreenSetupPage::ScreenSetupPage(ScreenMenu * menu, unsigned pageIndex, unsigned { } + + static void updateLayoutOptions(FormGroup* optionsWindow, unsigned customScreenIndex) // TODO { FormGridLayout grid; @@ -354,7 +356,9 @@ static void updateLayoutOptions(FormGroup* optionsWindow, unsigned customScreenI auto factory = customScreens[customScreenIndex]->getFactory(); if (factory) { for (auto * option = factory->getOptions(); option->name; option++, index++) { - ZoneOptionValue * value = customScreens[customScreenIndex]->getOptionValue(index); + + auto layoutData = g_model.screenData[customScreenIndex].layoutData; + ZoneOptionValue * value = &layoutData.options[index].value; // Option label new StaticText(optionsWindow, grid.getLabelSlot(false), option->name); diff --git a/radio/src/gui/colorlcd/topbar.cpp b/radio/src/gui/colorlcd/topbar.cpp index 38b77befc..172f4f9cf 100644 --- a/radio/src/gui/colorlcd/topbar.cpp +++ b/radio/src/gui/colorlcd/topbar.cpp @@ -23,182 +23,15 @@ #include "view_main.h" #include "screen_setup.h" #include "storage/storage.h" +#include "topbar.h" +#include "topbar_impl.h" -constexpr uint32_t TOPBAR_REFRESH = 1000 / 2; // 2 Hz -TopBar::TopBar(Window * parent) : - WidgetsContainer({0, 0, LCD_W, MENU_HEADER_HEIGHT}, &g_model.topbarData) +Topbar * TopbarFactory::create(Window * parent) { - attach(parent); + return new TopbarImpl(parent); } -unsigned int TopBar::getZonesCount() const -{ - return MAX_TOPBAR_ZONES; -} - -rect_t TopBar::getZone(unsigned int index) const -{ - return { - coord_t(49 + (TOPBAR_ZONE_WIDTH + 2 * TOPBAR_ZONE_MARGIN) * index), - TOPBAR_ZONE_MARGIN, - TOPBAR_ZONE_WIDTH, - TOPBAR_HEIGHT - }; -} - -void TopBar::setVisible(float visible) // 0.0 -> 1.0 -{ - if (visible == 0.0) { - setTop(-(int)MENU_HEADER_HEIGHT); - } - else if (visible == 1.0) { - setTop(0); - } - else if (visible > 0.0 && visible < 1.0){ - float top = - (float)MENU_HEADER_HEIGHT * (1.0 - visible); - setTop((coord_t)top); - } -} - -coord_t TopBar::getVisibleHeight(float visible) const // 0.0 -> 1.0 -{ - if (visible == 0.0) { - return 0; - } - else if (visible == 1.0) { - return MENU_HEADER_HEIGHT; - } - - float h = (float)MENU_HEADER_HEIGHT * visible; - return (coord_t)h; -} - -const char * const STR_MONTHS[] = TR_MONTHS; - -void TopBar::paint(BitmapBuffer * dc) -{ - dc->drawSolidFilledRect(0, 0, width(), height(), MENU_BGCOLOR); - OpenTxTheme::instance()->drawTopLeftBitmap(dc); - - struct gtm t; - gettime(&t); - char str[10]; - - sprintf(str, "%d %s", t.tm_mday, STR_MONTHS[t.tm_mon]); - dc->drawSolidVerticalLine(DATETIME_SEPARATOR_X, 7, 31, MENU_COLOR); - dc->drawText(DATETIME_MIDDLE, DATETIME_LINE1, str, FONT(XS) | CENTERED| MENU_COLOR); - - getTimerString(str, getValue(MIXSRC_TX_TIME)); - dc->drawText(DATETIME_MIDDLE, DATETIME_LINE2, str, FONT(XS) | CENTERED | MENU_COLOR); - - // USB icon - if (usbPlugged()) { - dc->drawBitmapPattern(LCD_W - 98, 8, LBM_TOPMENU_USB, MENU_COLOR); - } - - // Logs - if (isFunctionActive(FUNCTION_LOGS) && !usbPlugged() && BLINK_ON_PHASE) { - dc->drawBitmapPattern(LCD_W - 98, 6, LBM_DOT, MENU_COLOR); - } - - // RSSI - const uint8_t rssiBarsValue[] = {30, 40, 50, 60, 80}; - const uint8_t rssiBarsHeight[] = {5, 10, 15, 21, 31}; - for (unsigned int i = 0; i < DIM(rssiBarsHeight); i++) { - uint8_t height = rssiBarsHeight[i]; - dc->drawSolidFilledRect(LCD_W - 90 + i * 6, 38 - height, 4, height, TELEMETRY_RSSI() >= rssiBarsValue[i] ? MENU_COLOR : MENU_TITLE_DISABLE_COLOR); - } - -#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA) - if (isModuleXJT(INTERNAL_MODULE) && isExternalAntennaEnabled()) { - dc->drawBitmapPattern(LCD_W-94, 4, LBM_TOPMENU_ANTENNA, MENU_COLOR); - } -#endif - - /* Audio volume */ - dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_SCALE, MENU_TITLE_DISABLE_COLOR); - if (requiredSpeakerVolume == 0 || g_eeGeneral.beepMode == e_mode_quiet) - dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_0, MENU_COLOR); - else if (requiredSpeakerVolume < 7) - dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_1, MENU_COLOR); - else if (requiredSpeakerVolume < 13) - dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_2, MENU_COLOR); - else if (requiredSpeakerVolume < 19) - dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_3, MENU_COLOR); - else - dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_4, MENU_COLOR); - - /* Tx battery */ - uint8_t bars = GET_TXBATT_BARS(5); -#if defined(USB_CHARGER) - if (usbChargerLed()) { - dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT_CHARGING, MENU_COLOR); - } - else { - dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, MENU_COLOR); - } -#else - dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, MENU_COLOR); -#endif - for (unsigned int i = 0; i < 5; i++) { - dc->drawSolidFilledRect(LCD_W - 128 + 4 * i, 30, 2, 8, i >= bars ? MENU_TITLE_DISABLE_COLOR : MENU_COLOR); - } - -#if 0 - // Radio battery - TODO - // drawValueWithUnit(370, 8, g_vbat100mV, UNIT_VOLTS, PREC1|FONT(XS)|MENU_COLOR); - // lcdDrawSolidRect(300, 3, 20, 50, MENU_COLOR); - // lcdDrawRect(batt_icon_x+FW, BAR_Y+1, 13, 7); - // lcdDrawSolidVerticalLine(batt_icon_x+FW+13, BAR_Y+2, 5); - - // Rx battery - if (g_model.voltsSource) { - TelemetryItem & item = telemetryItems[g_model.voltsSource-1]; - if (item.isAvailable()) { - int32_t value = item.value; - TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.altitudeSource-1]; - LcdFlags att = 0; - if (sensor.prec == 2) { - att |= PREC1; - value /= 10; - } - else if (sensor.prec == 1) { - att |= PREC1; - } - att |= (item.isOld() ? ALARM_COLOR : DEFAULT_COLOR); - lcdDrawSolidFilledRect(ALTITUDE_X, VOLTS_Y, ALTITUDE_W, ALTITUDE_H, DEFAULT_BGCOLOR); - lcdDrawText(ALTITUDE_X+PADDING, VOLTS_Y+2, "Voltage", att); - drawValueWithUnit(ALTITUDE_X+PADDING, VOLTS_Y+12, value, UNIT_VOLTS, FONT(XL)|LEFT|att); - } - } - - // Model altitude - if (g_model.frsky.altitudeSource) { - TelemetryItem & item = telemetryItems[g_model.frsky.altitudeSource-1]; - if (item.isAvailable()) { - int32_t value = item.value; - TelemetrySensor & sensor = g_model.telemetrySensors[g_model.frsky.altitudeSource-1]; - if (sensor.prec) value /= sensor.prec == 2 ? 100 : 10; - LcdFlags att = (item.isOld() ? ALARM_COLOR : DEFAULT_COLOR); - lcdDrawSolidFilledRect(ALTITUDE_X, ALTITUDE_Y, ALTITUDE_W, ALTITUDE_H, DEFAULT_BGCOLOR); - lcdDrawText(ALTITUDE_X+PADDING, ALTITUDE_Y+2, "Alt", att); - drawValueWithUnit(ALTITUDE_X+PADDING, ALTITUDE_Y+12, value, UNIT_METERS, FONT(XL)|LEFT|att); - } - } -#endif -} - -void TopBar::checkEvents() -{ - uint32_t now = RTOS_GET_MS(); - if (now - lastRefresh >= TOPBAR_REFRESH) { - lastRefresh = now; - invalidate(); - } -} - - SetupTopBarWidgetsPage::SetupTopBarWidgetsPage(ScreenMenu* menu): FormWindow(ViewMain::instance(), {0, 0, 0, 0}, FORM_FORWARD_FOCUS), menu(menu) @@ -218,7 +51,7 @@ SetupTopBarWidgetsPage::SetupTopBarWidgetsPage(ScreenMenu* menu): // adopt the dimensions of the main view setRect(viewMain->getRect()); - auto topbar = viewMain->getTopbar(); + auto topbar = dynamic_cast(viewMain->getTopbar()); for (unsigned i = 0; i < topbar->getZonesCount(); i++) { auto rect = topbar->getZone(i); auto widget = new SetupWidgetsPageSlot(this, rect, topbar, i); @@ -249,3 +82,4 @@ void SetupTopBarWidgetsPage::onEvent(event_t event) } } #endif + diff --git a/radio/src/gui/colorlcd/topbar.h b/radio/src/gui/colorlcd/topbar.h index 34679be65..d7b519b43 100644 --- a/radio/src/gui/colorlcd/topbar.h +++ b/radio/src/gui/colorlcd/topbar.h @@ -18,45 +18,28 @@ * GNU General Public License for more details. */ -#ifndef _TOPBAR_H_ -#define _TOPBAR_H_ +#pragma once -#include "widgets_container.h" +#include "layout.h" -#define MAX_TOPBAR_ZONES 4 -#define MAX_TOPBAR_OPTIONS 1 // just because of VC++ which doesn't like 0-size arrays :( -#define TOPBAR_ZONE_WIDTH 70 +constexpr coord_t TOPBAR_ZONE_WIDTH = 70; constexpr coord_t TOPBAR_ZONE_MARGIN = 3; constexpr coord_t TOPBAR_HEIGHT = MENU_HEADER_HEIGHT - 2 * TOPBAR_ZONE_MARGIN; -class TopBar: public WidgetsContainer +class ScreenMenu; +class TopbarImpl; + +class Topbar { public: - explicit TopBar(Window * parent); - -#if defined(DEBUG_WINDOWS) - std::string getName() const override - { - return "TopBar"; - } -#endif - - unsigned int getZonesCount() const override; - - rect_t getZone(unsigned int index) const override; - - void setVisible(float visible); - coord_t getVisibleHeight(float visible) const; // 0.0 -> 1.0 - - void paint(BitmapBuffer * dc) override; - - void checkEvents() override; - - protected: - uint32_t lastRefresh = 0; + virtual void load() = 0; }; -class ScreenMenu; +class TopbarFactory +{ +public: + static Topbar * create(Window * parent); +}; class SetupTopBarWidgetsPage: public FormWindow { @@ -80,5 +63,3 @@ class SetupTopBarWidgetsPage: public FormWindow ScreenMenu* menu; unsigned savedView = 0; }; - -#endif // _TOPBAR_H_ diff --git a/radio/src/gui/colorlcd/view_main.cpp b/radio/src/gui/colorlcd/view_main.cpp index 18c9b4c7c..849294d8b 100644 --- a/radio/src/gui/colorlcd/view_main.cpp +++ b/radio/src/gui/colorlcd/view_main.cpp @@ -25,17 +25,16 @@ #include "model_select.h" #include "view_channels.h" #include "view_statistics.h" -#include "topbar.h" -#include "layouts/sliders.h" -#include "layouts/trims.h" -#include "view_main_decoration.h" +#include "topbar_impl.h" +#include "menu.h" + #include "opentx.h" ViewMain * ViewMain::_instance = nullptr; ViewMain::ViewMain(): Window(MainWindow::instance(), MainWindow::instance()->getRect()), - topbar(new TopBar(this)) + topbar(dynamic_cast(TopbarFactory::create(this))) { #if defined(HARDWARE_TOUCH) && !defined(HARDWARE_KEYS) new FabButton(this, 50, 100, ICON_MODEL, @@ -144,18 +143,33 @@ void ViewMain::previousMainView() setCurrentMainView(view); } +Topbar* ViewMain::getTopbar() +{ + return topbar; +} + +static bool hasTopbar(unsigned view) +{ + if (view < sizeof(g_model.screenData)) { + const auto& layoutData = g_model.screenData[view].layoutData; + return layoutData.options[LAYOUT_OPTION_TOPBAR].value.boolValue; + } + + return false; +} + void ViewMain::updateTopbarVisibility() { // relative to left visible page int leftScroll = getScrollPositionX() % pageWidth; if (leftScroll == 0) { - setTopbarVisible(customScreens[g_model.view]->hasTopbar()); + setTopbarVisible(hasTopbar(g_model.view)); customScreens[g_model.view]->decorate(); } else { int leftIdx = getScrollPositionX() / pageWidth; - bool leftTopbar = customScreens[leftIdx]->hasTopbar(); - bool rightTopbar = customScreens[leftIdx+1]->hasTopbar(); + bool leftTopbar = hasTopbar(leftIdx); + bool rightTopbar = hasTopbar(leftIdx+1); if (leftTopbar != rightTopbar) { diff --git a/radio/src/gui/colorlcd/view_main.h b/radio/src/gui/colorlcd/view_main.h index 20f5ba610..3b57f611d 100644 --- a/radio/src/gui/colorlcd/view_main.h +++ b/radio/src/gui/colorlcd/view_main.h @@ -21,10 +21,11 @@ #ifndef _VIEW_MAIN_H_ #define _VIEW_MAIN_H_ -#include "form.h" #include +#include "form.h" +#include "topbar.h" + -class TopBar; class SetupWidgetsPage; class SetupTopBarWidgetsPage; @@ -68,16 +69,13 @@ class ViewMain: public Window void nextMainView(); void previousMainView(); - TopBar* getTopbar() const - { - return topbar; - } + Topbar* getTopbar(); protected: static ViewMain * _instance; - unsigned views = 0; - TopBar* topbar = nullptr; + unsigned views = 0; + TopbarImpl* topbar = nullptr; // Widget setup requires special permissions ;-) friend class SetupWidgetsPage; diff --git a/radio/src/gui/colorlcd/widget.cpp b/radio/src/gui/colorlcd/widget.cpp index a99a0f477..a9c9a1647 100644 --- a/radio/src/gui/colorlcd/widget.cpp +++ b/radio/src/gui/colorlcd/widget.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "widget.h" std::list & getRegisteredWidgets() { @@ -34,7 +35,7 @@ void registerWidget(const WidgetFactory * factory) const WidgetFactory * getWidgetFactory(const char * name) { - std::list::const_iterator it = getRegisteredWidgets().cbegin(); + auto it = getRegisteredWidgets().cbegin(); for (; it != getRegisteredWidgets().cend();++it) { if (!strcmp(name, (*it)->getName())) { return (*it); @@ -43,7 +44,7 @@ const WidgetFactory * getWidgetFactory(const char * name) return nullptr; } -Widget * loadWidget(const char * name, FormGroup * parent, const rect_t & rect, Widget::PersistentData * persistentData) +Widget * loadWidget(const char * name, FormGroup * parent, const rect_t & rect, WidgetPersistentData * persistentData) { const WidgetFactory * factory = getWidgetFactory(name); if (factory) { diff --git a/radio/src/gui/colorlcd/widget.h b/radio/src/gui/colorlcd/widget.h index c7e3c25a2..c7099d3be 100644 --- a/radio/src/gui/colorlcd/widget.h +++ b/radio/src/gui/colorlcd/widget.h @@ -23,25 +23,23 @@ #include #include #include "form.h" -#include "zone.h" +#include "widgets_container.h" #include "debug.h" -#define MAX_WIDGET_OPTIONS 5 - // YAML_GENERATOR defs #if !defined(USE_IDX) #define USE_IDX #endif class WidgetFactory; + class Widget : public Window { public: - struct PersistentData { - ZoneOptionValueTyped options[MAX_WIDGET_OPTIONS] USE_IDX; - }; - Widget(const WidgetFactory * factory, FormGroup * parent, const rect_t & rect, PersistentData * persistentData): + typedef WidgetPersistentData PersistentData; + + Widget(const WidgetFactory * factory, FormGroup * parent, const rect_t & rect, WidgetPersistentData * persistentData): Window(parent, rect), factory(factory), persistentData(persistentData) diff --git a/radio/src/gui/colorlcd/widgets/gauge.cpp b/radio/src/gui/colorlcd/widgets/gauge.cpp index f69978467..f5576bd8f 100644 --- a/radio/src/gui/colorlcd/widgets/gauge.cpp +++ b/radio/src/gui/colorlcd/widgets/gauge.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "widgets_container_implem.h" class GaugeWidget: public Widget { diff --git a/radio/src/gui/colorlcd/widgets/modelbmp.cpp b/radio/src/gui/colorlcd/widgets/modelbmp.cpp index fbcffd95c..39826b012 100644 --- a/radio/src/gui/colorlcd/widgets/modelbmp.cpp +++ b/radio/src/gui/colorlcd/widgets/modelbmp.cpp @@ -19,6 +19,8 @@ */ #include "opentx.h" +#include "widgets_container_implem.h" + #include class ModelBitmapWidget: public Widget diff --git a/radio/src/gui/colorlcd/widgets/outputs.cpp b/radio/src/gui/colorlcd/widgets/outputs.cpp index a6693902d..e665aecae 100644 --- a/radio/src/gui/colorlcd/widgets/outputs.cpp +++ b/radio/src/gui/colorlcd/widgets/outputs.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "widgets_container_implem.h" #define RECT_BORDER 1 #define ROW_HEIGHT 17 diff --git a/radio/src/gui/colorlcd/widgets/text.cpp b/radio/src/gui/colorlcd/widgets/text.cpp index 7fecda88a..a97eab9e9 100644 --- a/radio/src/gui/colorlcd/widgets/text.cpp +++ b/radio/src/gui/colorlcd/widgets/text.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "widgets_container_implem.h" #define TEXT_WIDGET_DEFAULT_LABEL 'M', 'y', ' ', 'L', 'a', 'b', 'e', 'l' // "My Label" diff --git a/radio/src/gui/colorlcd/widgets/timer.cpp b/radio/src/gui/colorlcd/widgets/timer.cpp index ffc0f850e..e7a4c5e0e 100644 --- a/radio/src/gui/colorlcd/widgets/timer.cpp +++ b/radio/src/gui/colorlcd/widgets/timer.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "widgets_container_implem.h" class TimerWidget: public Widget { diff --git a/radio/src/gui/colorlcd/widgets/value.cpp b/radio/src/gui/colorlcd/widgets/value.cpp index 99312d125..42921ac23 100644 --- a/radio/src/gui/colorlcd/widgets/value.cpp +++ b/radio/src/gui/colorlcd/widgets/value.cpp @@ -19,6 +19,7 @@ */ #include "opentx.h" +#include "widgets_container_implem.h" const coord_t NUMBERS_PADDING = 4; diff --git a/radio/src/gui/colorlcd/widgets/widgets_container_implem.h b/radio/src/gui/colorlcd/widgets/widgets_container_implem.h new file mode 100644 index 000000000..e0592227b --- /dev/null +++ b/radio/src/gui/colorlcd/widgets/widgets_container_implem.h @@ -0,0 +1,156 @@ +/* + * 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. + */ + +#pragma once + +#include "widget.h" +#include "widgets_container.h" + +template +class WidgetsContainer: public WidgetsContainerInterface +{ + public: + // struct ZonePersistentData { + // char widgetName[WIDGET_NAME_LEN]; + // Widget::PersistentData widgetData; + // }; + + // struct PersistentData { + // ZonePersistentData zones[N]; + // ZoneOptionValueTyped options[O]; + // }; + typedef WidgetsContainerPersistentData PersistentData; + + WidgetsContainer(const rect_t & rect, PersistentData * persistentData): + WidgetsContainerInterface(nullptr, rect, FORM_FORWARD_FOCUS), + persistentData(persistentData) + { + } + + Widget * createWidget(unsigned int index, const WidgetFactory * factory) override + { + if (index >= N) + return nullptr; + + // remove old one if existing + removeWidget(index); + + Widget * widget = nullptr; + if (factory) { + strncpy(persistentData->zones[index].widgetName, factory->getName(), sizeof(ZonePersistentData::widgetName)); + widget = factory->create(this, getZone(index), &persistentData->zones[index].widgetData); + } + widgets[index] = widget; + + if (widget) + widget->attach(this); + + return widget; + } + + void removeWidget(unsigned int index) override + { + if (index >= N) + return; + + if (widgets[index]) + widgets[index]->deleteLater(); + + widgets[index] = nullptr; + memset(persistentData->zones[index].widgetName, 0, sizeof(ZonePersistentData::widgetName)); + memset(&persistentData->zones[index].widgetData, 0, sizeof(Widget::PersistentData)); + } + + Widget * getWidget(unsigned int index) override + { + if (index < N) + return widgets[index]; + + return nullptr; + } + + virtual void create() + { + memset(persistentData, 0, sizeof(PersistentData)); + } + + virtual void load() + { + unsigned int count = getZonesCount(); + for (unsigned int i = 0; i < count; i++) { + + // remove old widget + if (widgets[i]) { + widgets[i]->deleteLater(); + widgets[i] = nullptr; + } + + // and load new one if required + if (persistentData->zones[i].widgetName[0]) { + char name[WIDGET_NAME_LEN + 1]; + memset(name, 0, sizeof(name)); + strncpy(name, persistentData->zones[i].widgetName, WIDGET_NAME_LEN); + widgets[i] = loadWidget(name, this, getZone(i), &persistentData->zones[i].widgetData); + } + } + } + + inline ZoneOptionValue * getOptionValue(unsigned int index) const + { + return &persistentData->options[index].value; + } + + inline void setOptionValue(unsigned int index, const ZoneOptionValue& value) + { + persistentData->options[index].value = value; + } + + unsigned int getZonesCount() const override = 0; + + rect_t getZone(unsigned int index) const override = 0; + + virtual void background() + { + for (int i = 0; i < N; i++) { + if (widgets[i]) { + widgets[i]->background(); + } + } + } + + void updateZones() + { + for (int i = 0; i < N; i++) { + if (widgets[i]) { + auto zone = getZone(i); + widgets[i]->setRect(zone); + widgets[i]->setInnerHeight(zone.h); + } + } + } + + void decorate() override + { + } + + protected: + PersistentData * persistentData; + Widget * widgets[N] = {}; +}; diff --git a/radio/src/gui/colorlcd/widgets_container.h b/radio/src/gui/colorlcd/widgets_container.h index 6276aeeb3..7ba7e1219 100644 --- a/radio/src/gui/colorlcd/widgets_container.h +++ b/radio/src/gui/colorlcd/widgets_container.h @@ -22,146 +22,63 @@ #define _WIDGETS_CONTAINER_H_ #include -#include -#include "widget.h" +#include "libopenui_types.h" +#include "form.h" +#include "zone.h" -class WidgetsContainerInterface +#define WIDGET_NAME_LEN 10 +#define MAX_WIDGET_OPTIONS 5 // Name? + +#define MAX_TOPBAR_ZONES 4 +#define MAX_TOPBAR_OPTIONS 1 // just because of VC++ which doesn't like 0-size arrays :( + +// Common 'ZoneOptionValue's among all layouts +enum { + LAYOUT_OPTION_TOPBAR = 0, + LAYOUT_OPTION_FM, + LAYOUT_OPTION_SLIDERS, + LAYOUT_OPTION_TRIMS, + LAYOUT_OPTION_MIRRORED, + + LAYOUT_OPTION_LAST_DEFAULT=LAYOUT_OPTION_MIRRORED +}; + +class Widget; +class WidgetFactory; +class LayoutFactory; + +struct WidgetPersistentData { + ZoneOptionValueTyped options[MAX_WIDGET_OPTIONS] USE_IDX; +}; + +struct ZonePersistentData { + char widgetName[WIDGET_NAME_LEN]; + WidgetPersistentData widgetData; +}; + +template +struct WidgetsContainerPersistentData { + ZonePersistentData zones[N]; + ZoneOptionValueTyped options[O]; +}; + +typedef WidgetsContainerPersistentData TopBarPersistentData; + +class WidgetsContainerInterface: public FormGroup { public: + using FormGroup::FormGroup; + virtual unsigned int getZonesCount() const = 0; virtual rect_t getZone(unsigned int index) const = 0; virtual Widget * createWidget(unsigned int index, const WidgetFactory * factory) = 0; virtual Widget * getWidget(unsigned int index) = 0; virtual void removeWidget(unsigned int index) = 0; + + // this should go away... + virtual const LayoutFactory * getFactory() const = 0; + virtual void decorate() = 0; }; -#define WIDGET_NAME_LEN 10 - -template -class WidgetsContainer: public FormGroup, public WidgetsContainerInterface -{ - public: - struct ZonePersistentData { - char widgetName[WIDGET_NAME_LEN]; - Widget::PersistentData widgetData; - }; - - struct PersistentData { - ZonePersistentData zones[N]; - ZoneOptionValueTyped options[O]; - }; - - WidgetsContainer(const rect_t & rect, PersistentData * persistentData): - FormGroup(nullptr, rect, FORM_FORWARD_FOCUS), - persistentData(persistentData) - { - } - - Widget * createWidget(unsigned int index, const WidgetFactory * factory) override - { - if (index >= N) - return nullptr; - - // remove old one if existing - removeWidget(index); - - Widget * widget = nullptr; - if (factory) { - strncpy(persistentData->zones[index].widgetName, factory->getName(), sizeof(ZonePersistentData::widgetName)); - widget = factory->create(this, getZone(index), &persistentData->zones[index].widgetData); - } - widgets[index] = widget; - - if (widget) - widget->attach(this); - - return widget; - } - - void removeWidget(unsigned int index) override - { - if (index >= N) - return; - - if (widgets[index]) - widgets[index]->deleteLater(); - - widgets[index] = nullptr; - memset(persistentData->zones[index].widgetName, 0, sizeof(ZonePersistentData::widgetName)); - memset(&persistentData->zones[index].widgetData, 0, sizeof(Widget::PersistentData)); - } - - Widget * getWidget(unsigned int index) override - { - if (index < N) - return widgets[index]; - - return nullptr; - } - - virtual void create() - { - memset(persistentData, 0, sizeof(PersistentData)); - } - - virtual void load() - { - unsigned int count = getZonesCount(); - for (unsigned int i = 0; i < count; i++) { - - // remove old widget - if (widgets[i]) { - widgets[i]->deleteLater(); - widgets[i] = nullptr; - } - - // and load new one if required - if (persistentData->zones[i].widgetName[0]) { - char name[WIDGET_NAME_LEN + 1]; - memset(name, 0, sizeof(name)); - strncpy(name, persistentData->zones[i].widgetName, WIDGET_NAME_LEN); - widgets[i] = loadWidget(name, this, getZone(i), &persistentData->zones[i].widgetData); - } - } - } - - inline ZoneOptionValue * getOptionValue(unsigned int index) const - { - return &persistentData->options[index].value; - } - - inline void setOptionValue(unsigned int index, const ZoneOptionValue& value) - { - persistentData->options[index].value = value; - } - - unsigned int getZonesCount() const override = 0; - - rect_t getZone(unsigned int index) const override = 0; - - virtual void background() - { - for (int i = 0; i < N; i++) { - if (widgets[i]) { - widgets[i]->background(); - } - } - } - - void updateZones() - { - for (int i = 0; i < N; i++) { - if (widgets[i]) { - auto zone = getZone(i); - widgets[i]->setRect(zone); - widgets[i]->setInnerHeight(zone.h); - } - } - } - - protected: - PersistentData * persistentData; - Widget * widgets[N] = {}; -}; #endif // _WIDGETS_CONTAINER_H_ diff --git a/radio/src/storage/conversions/datastructs_218.h b/radio/src/storage/conversions/datastructs_218.h index e21816d40..6a7638feb 100644 --- a/radio/src/storage/conversions/datastructs_218.h +++ b/radio/src/storage/conversions/datastructs_218.h @@ -398,11 +398,11 @@ PACK(struct TelemetrySensor_218 { #if defined(PCBHORUS) PACK(struct CustomScreenData_v218 { char LayoutId[10]; - Layout::PersistentData layoutData; + LayoutPersistentData layoutData; }); #define VIEW_DATA \ CustomScreenData screenData[MAX_CUSTOM_SCREENS]; \ - TopBar::PersistentData topbarData; \ + TopBarPersistentData topbarData; \ uint8_t view; #elif defined(PCBTARANIS) #define VIEW_DATA uint8_t view;