Refactor layout / widget interface

This allows to cut loose quite some dependencies on headers.
This commit is contained in:
Raphael Coeffic
2021-04-18 07:58:28 +02:00
parent 3c4047bb8d
commit 413b97c9d6
32 changed files with 942 additions and 693 deletions
+1
View File
@@ -25,6 +25,7 @@
#include <string.h>
#include "ff.h"
#include "opentx_types.h"
#include "dataconstants.h"
/*
Implements a bit field, number of bits is set by the template,
+3 -3
View File
@@ -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)
+1 -1
View File
@@ -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);
+11 -106
View File
@@ -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<const LayoutFactory *> & 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());
}
+13 -153
View File
@@ -22,180 +22,35 @@
#include <list>
#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<MAX_LAYOUT_ZONES, MAX_LAYOUT_OPTIONS> 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<MAX_LAYOUT_ZONES,MAX_LAYOUT_OPTIONS> 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 T>
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<const LayoutFactory *> & getRegisteredLayouts();
+2 -2
View File
@@ -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"
+2 -3
View File
@@ -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"
+2 -3
View File
@@ -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"
+2 -3
View File
@@ -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"
+3 -2
View File
@@ -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
@@ -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());
}
@@ -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 <list>
//#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<MAX_LAYOUT_ZONES, MAX_LAYOUT_OPTIONS> 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 T>
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;
};
@@ -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);
}
+3 -54
View File
@@ -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;
};
@@ -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<MAX_TOPBAR_ZONES, MAX_TOPBAR_OPTIONS>({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();
}
}
@@ -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<MAX_TOPBAR_ZONES, MAX_TOPBAR_OPTIONS> 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;
};
+5 -1
View File
@@ -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);
+6 -172
View File
@@ -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<MAX_TOPBAR_ZONES, MAX_TOPBAR_OPTIONS>({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<TopbarImpl*>(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
+13 -32
View File
@@ -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<MAX_TOPBAR_ZONES, MAX_TOPBAR_OPTIONS>
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_
+22 -8
View File
@@ -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<TopbarImpl*>(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) {
+6 -8
View File
@@ -21,10 +21,11 @@
#ifndef _VIEW_MAIN_H_
#define _VIEW_MAIN_H_
#include "form.h"
#include <memory>
#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;
+3 -2
View File
@@ -19,6 +19,7 @@
*/
#include "opentx.h"
#include "widget.h"
std::list<const WidgetFactory *> & getRegisteredWidgets()
{
@@ -34,7 +35,7 @@ void registerWidget(const WidgetFactory * factory)
const WidgetFactory * getWidgetFactory(const char * name)
{
std::list<const WidgetFactory *>::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) {
+5 -7
View File
@@ -23,25 +23,23 @@
#include <list>
#include <string.h>
#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)
+1
View File
@@ -19,6 +19,7 @@
*/
#include "opentx.h"
#include "widgets_container_implem.h"
class GaugeWidget: public Widget
{
@@ -19,6 +19,8 @@
*/
#include "opentx.h"
#include "widgets_container_implem.h"
#include <memory>
class ModelBitmapWidget: public Widget
@@ -19,6 +19,7 @@
*/
#include "opentx.h"
#include "widgets_container_implem.h"
#define RECT_BORDER 1
#define ROW_HEIGHT 17
+1
View File
@@ -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"
+1
View File
@@ -19,6 +19,7 @@
*/
#include "opentx.h"
#include "widgets_container_implem.h"
class TimerWidget: public Widget
{
+1
View File
@@ -19,6 +19,7 @@
*/
#include "opentx.h"
#include "widgets_container_implem.h"
const coord_t NUMBERS_PADDING = 4;
@@ -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<int N, int O>
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<N,O> 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] = {};
};
+48 -131
View File
@@ -22,146 +22,63 @@
#define _WIDGETS_CONTAINER_H_
#include <stdlib.h>
#include <window.h>
#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<int N, int O>
struct WidgetsContainerPersistentData {
ZonePersistentData zones[N];
ZoneOptionValueTyped options[O];
};
typedef WidgetsContainerPersistentData<MAX_TOPBAR_ZONES, MAX_TOPBAR_OPTIONS> 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<int N, int O>
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_
@@ -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;