Refactor layout / widget interface
This allows to cut loose quite some dependencies on headers.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "widgets_container_implem.h"
|
||||
|
||||
class TimerWidget: public Widget
|
||||
{
|
||||
|
||||
@@ -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] = {};
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user