1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-16 12:55:12 +03:00

[CLI] reboot command added

This commit is contained in:
Bertrand Songis 2016-02-20 16:55:05 +01:00
parent 0f4f49b64e
commit 67a599e0b9
45 changed files with 920 additions and 605 deletions

View file

@ -80,6 +80,7 @@ if(PCB STREQUAL HORUS)
view_text.cpp view_text.cpp
screens_setup.cpp screens_setup.cpp
theme.cpp theme.cpp
topbar.cpp
layout.cpp layout.cpp
widget.cpp widget.cpp
${THEMES_SRC} ${THEMES_SRC}
@ -256,6 +257,7 @@ if(CPU_TYPE STREQUAL STM32F4)
include_directories(${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/inc) include_directories(${STM32LIB_DIR}/STM32F4xx_StdPeriph_Driver/inc)
include_directories(${STM32LIB_DIR}/CMSIS/Device/ST/STM32F4xx/Include) include_directories(${STM32LIB_DIR}/CMSIS/Device/ST/STM32F4xx/Include)
include_directories(${STM32LIB_DIR}/CMSIS/include) include_directories(${STM32LIB_DIR}/CMSIS/include)
# add_definitions(-DSTM32F4)
set(STM32LIB_SRC set(STM32LIB_SRC
${STM32LIB_SRC} ${STM32LIB_SRC}
CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc_ride7/startup_stm32f40_41xxx.s CMSIS/Device/ST/STM32F4xx/Source/Templates/gcc_ride7/startup_stm32f40_41xxx.s

View file

@ -249,8 +249,6 @@ void referenceSystemAudioFiles()
fn = *fno.lfname ? fno.lfname : fno.fname; fn = *fno.lfname ? fno.lfname : fno.fname;
uint8_t len = strlen(fn); uint8_t len = strlen(fn);
TRACE("%s", fn);
// Eliminates directories / non wav files // Eliminates directories / non wav files
if (len < 5 || strcasecmp(fn+len-4, SOUNDS_EXT) || (fno.fattrib & AM_DIR)) continue; if (len < 5 || strcasecmp(fn+len-4, SOUNDS_EXT) || (fno.fattrib & AM_DIR)) continue;
@ -509,7 +507,7 @@ void audioTask(void * pdata)
AUDIO_TADA(); AUDIO_TADA();
#elif defined(SDCARD) #elif defined(SDCARD)
if (!unexpectedShutdown) { if (!unexpectedShutdown) {
sdInit(); // sdInit();
AUDIO_TADA(); AUDIO_TADA();
} }
#endif #endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -204,22 +204,36 @@ const uint8_t LBM_MAINVIEWS_TOPBAR_ICON[] = {
#include "mask_mainviews_topbar.lbm" #include "mask_mainviews_topbar.lbm"
}; };
const uint8_t LBM_MAINVIEWS_ITEM_OUT_ICON[] = { const uint8_t LBM_MAINVIEWS_1_ICON[] = {
#include "mask_mainviews_item_out.lbm" #include "mask_mainviews_1.lbm"
};
const uint8_t LBM_MAINVIEWS_2_ICON[] = {
#include "mask_mainviews_2.lbm"
};
const uint8_t LBM_MAINVIEWS_3_ICON[] = {
#include "mask_mainviews_3.lbm"
};
const uint8_t LBM_MAINVIEWS_4_ICON[] = {
#include "mask_mainviews_4.lbm"
};
const uint8_t LBM_MAINVIEWS_5_ICON[] = {
#include "mask_mainviews_5.lbm"
}; };
const uint8_t LBM_MAINVIEWS_ADD_ICON[] = { const uint8_t LBM_MAINVIEWS_ADD_ICON[] = {
#include "mask_mainviews_add.lbm" #include "mask_mainviews_add.lbm"
}; };
const uint8_t * LBM_MAINVIEWS_ICONS[] = { const uint8_t * const LBM_MAINVIEWS_ICONS[] = {
LBM_MAINVIEWS_ICON, LBM_MAINVIEWS_1_ICON,
LBM_MAINVIEWS_TOPBAR_ICON, LBM_MAINVIEWS_2_ICON,
LBM_MAINVIEWS_ITEM_OUT_ICON, LBM_MAINVIEWS_3_ICON,
LBM_MAINVIEWS_ITEM_OUT_ICON, LBM_MAINVIEWS_4_ICON,
LBM_MAINVIEWS_ITEM_OUT_ICON, LBM_MAINVIEWS_5_ICON
LBM_MAINVIEWS_ITEM_OUT_ICON,
LBM_MAINVIEWS_ITEM_OUT_ICON
}; };
/* /*
@ -299,7 +313,7 @@ const uint8_t LBM_SHUTDOWN[] __DMA = {
}; };
const uint8_t LBM_SLEEP[] __DMA = { const uint8_t LBM_SLEEP[] __DMA = {
#include "alpha_sleep.lbm" #include "bmp_sleep.lbm"
}; };
const uint8_t LBM_SHUTDOWN_CIRCLE[] __DMA = { const uint8_t LBM_SHUTDOWN_CIRCLE[] __DMA = {

View file

@ -53,9 +53,8 @@ extern const uint8_t LBM_TELEMETRY_ICON[];
// UI (theme / layout / widgets bitmaps // UI (theme / layout / widgets bitmaps
extern const uint8_t LBM_MAINVIEWS_ICON[]; extern const uint8_t LBM_MAINVIEWS_ICON[];
extern const uint8_t LBM_MAINVIEWS_TOPBAR_ICON[]; extern const uint8_t LBM_MAINVIEWS_TOPBAR_ICON[];
extern const uint8_t LBM_MAINVIEWS_ITEM_OUT_ICON[];
extern const uint8_t LBM_MAINVIEWS_ADD_ICON[]; extern const uint8_t LBM_MAINVIEWS_ADD_ICON[];
extern const uint8_t * LBM_MAINVIEWS_ICONS[]; extern const uint8_t * const LBM_MAINVIEWS_ICONS[];
// Model selection icons // Model selection icons
extern const uint8_t LBM_LIBRARY_ICON[]; extern const uint8_t LBM_LIBRARY_ICON[];

View file

@ -81,5 +81,5 @@ void drawCurveHorizontalScale();
void drawCurveCoord(int x, int y, const char * text, bool active=false); void drawCurveCoord(int x, int y, const char * text, bool active=false);
void drawCurvePoint(int x, int y, LcdFlags color); void drawCurvePoint(int x, int y, LcdFlags color);
// TODO one screen for now
extern Layout * customScreens[MAX_CUSTOM_SCREENS]; extern Layout * customScreens[MAX_CUSTOM_SCREENS];
extern Topbar * topbar;

View file

@ -20,40 +20,12 @@
#include "opentx.h" #include "opentx.h"
void Layout::createWidget(unsigned int index, const WidgetFactory * factory)
{
memset(persistentData->zones[index].widgetName, 0, sizeof(persistentData->zones[index].widgetName));
strncpy(persistentData->zones[index].widgetName, factory->getName(), sizeof(persistentData->zones[index].widgetName));
widgets[index] = factory->create(getZone(index), &persistentData->zones[index].widgetData);
}
void Layout::load()
{
unsigned int count = getZonesCount();
for (unsigned int i=0; i<count; i++) {
if (persistentData->zones[i].widgetName[0]) {
char name[sizeof(persistentData->zones[i].widgetName)+1];
memset(name, 0, sizeof(name));
strncpy(name, persistentData->zones[i].widgetName, sizeof(persistentData->zones[i].widgetName));
widgets[i] = loadWidget(name, getZone(i), &persistentData->zones[i].widgetData);
}
}
}
void Layout::refresh(bool setup)
{
for (int i = 0; i < MAX_LAYOUT_ZONES; i++) {
if (widgets[i]) {
widgets[i]->refresh();
}
}
}
const LayoutFactory * registeredLayouts[MAX_REGISTERED_LAYOUTS]; // TODO dynamic const LayoutFactory * registeredLayouts[MAX_REGISTERED_LAYOUTS]; // TODO dynamic
unsigned int countRegisteredLayouts = 0; unsigned int countRegisteredLayouts = 0;
void registerLayout(const LayoutFactory * factory) void registerLayout(const LayoutFactory * factory)
{ {
if (countRegisteredLayouts < MAX_REGISTERED_LAYOUTS) { if (countRegisteredLayouts < MAX_REGISTERED_LAYOUTS) {
TRACE("register layout %s", factory->getName());
registeredLayouts[countRegisteredLayouts++] = factory; registeredLayouts[countRegisteredLayouts++] = factory;
} }
} }
@ -90,4 +62,6 @@ void loadCustomScreens()
if (customScreens[0] == NULL) { if (customScreens[0] == NULL) {
customScreens[0] = registeredLayouts[0]->create(&g_model.screenData[0].layoutData); customScreens[0] = registeredLayouts[0]->create(&g_model.screenData[0].layoutData);
} }
topbar->load();
} }

View file

@ -21,86 +21,31 @@
#ifndef _LAYOUT_H_ #ifndef _LAYOUT_H_
#define _LAYOUT_H_ #define _LAYOUT_H_
#include "widget.h" #include "widgets_container.h"
#define MAX_LAYOUT_ZONES 10 #define MAX_LAYOUT_ZONES 10
#define MAX_LAYOUT_OPTIONS 10 #define MAX_LAYOUT_OPTIONS 10
class LayoutFactory; class LayoutFactory;
class Layout
class Layout: public WidgetsContainer<MAX_LAYOUT_ZONES, MAX_LAYOUT_OPTIONS>
{ {
friend class LayoutFactory; friend class LayoutFactory;
public:
struct ZonePersistentData {
char widgetName[10];
Widget::PersistentData widgetData;
};
struct PersistentData {
ZonePersistentData zones[MAX_LAYOUT_ZONES];
ZoneOptionValue options[MAX_LAYOUT_OPTIONS];
};
public: public:
Layout(const LayoutFactory * factory, PersistentData * persistentData): Layout(const LayoutFactory * factory, PersistentData * persistentData):
factory(factory), WidgetsContainer<MAX_LAYOUT_ZONES, MAX_LAYOUT_OPTIONS>(persistentData),
persistentData(persistentData) factory(factory)
{ {
memset(widgets, 0, sizeof(widgets));
} }
virtual ~Layout() inline const LayoutFactory * getFactory() const
{
for (uint8_t i=0; i<MAX_LAYOUT_ZONES; i++) {
delete widgets[i];
}
memset(widgets, 0, sizeof(widgets));
}
const LayoutFactory * getFactory() const
{ {
return factory; return factory;
} }
Widget * getWidget(unsigned int index)
{
return widgets[index];
}
void setWidget(unsigned int index, Widget * widget)
{
widgets[index] = widget;
}
void createWidget(unsigned int index, const WidgetFactory * factory);
virtual void create()
{
memset(persistentData, 0, sizeof(PersistentData));
}
virtual void load();
ZoneOptionValue getOptionValue(unsigned int index) const
{
return persistentData->options[index];
}
void setOptionValue(unsigned int index, ZoneOptionValue value) const
{
persistentData->options[index] = value;
}
virtual unsigned int getZonesCount() const = 0;
virtual Zone getZone(unsigned int index) const = 0;
virtual void refresh(bool setup=false);
protected: protected:
const LayoutFactory * factory; const LayoutFactory * factory;
Widget * widgets[MAX_LAYOUT_ZONES];
PersistentData * persistentData;
}; };
void registerLayout(const LayoutFactory * factory); void registerLayout(const LayoutFactory * factory);

View file

@ -20,6 +20,16 @@
#include "opentx.h" #include "opentx.h"
const uint8_t LBM_LAYOUT_1x1[] = {
#include "mask_layout1x1.lbm"
};
const ZoneOption OPTIONS_LAYOUT_1x1[] = {
{ "Top bar", ZoneOption::Bool },
{ "Sliders+Trims", ZoneOption::Bool },
{ NULL, ZoneOption::Bool }
};
class Layout1x1: public Layout class Layout1x1: public Layout
{ {
public: public:
@ -55,25 +65,15 @@ class Layout1x1: public Layout
return zone; return zone;
} }
virtual void refresh(bool setup=false); virtual void refresh();
static const ZoneOption options[];
}; };
const ZoneOption Layout1x1::options[] = { void Layout1x1::refresh()
{ "Top bar", ZoneOption::Bool },
{ "Sliders+Trims", ZoneOption::Bool },
{ NULL, ZoneOption::Bool }
};
void Layout1x1::refresh(bool setup)
{ {
theme->drawBackground(); theme->drawBackground();
if (persistentData->options[0].boolValue) { if (persistentData->options[0].boolValue) {
// Top Bar drawTopBar();
drawMainViewTopBar();
} }
if (persistentData->options[1].boolValue) { if (persistentData->options[1].boolValue) {
@ -86,11 +86,7 @@ void Layout1x1::refresh(bool setup)
drawTrims(mixerCurrentFlightMode); drawTrims(mixerCurrentFlightMode);
} }
Layout::refresh(setup); Layout::refresh();
} }
const uint8_t LBM_LAYOUT_1x1[] __DMA = { BaseLayoutFactory<Layout1x1> layout1x1("Layout1x1", LBM_LAYOUT_1x1, OPTIONS_LAYOUT_1x1);
#include "mask_layout1x1.lbm"
};
BaseLayoutFactory<Layout1x1> layout1x1("Layout1x1", LBM_LAYOUT_1x1, Layout1x1::options);

View file

@ -20,6 +20,24 @@
#include "opentx.h" #include "opentx.h"
const uint8_t LBM_LAYOUT_2P1[] = {
#include "mask_layout2+1.lbm"
};
const ZoneOption OPTIONS_LAYOUT_2P1[] = {
{ "Top bar", ZoneOption::Bool },
{ "Flight mode", ZoneOption::Bool },
{ "Sliders", ZoneOption::Bool },
{ "Trims", ZoneOption::Bool },
{ NULL, ZoneOption::Bool }
};
const Zone ZONES_LAYOUT_2P1[3] = {
{ 240, 60, 192, 152 },
{ 48, 60, 180, 70 },
{ 48, 142, 180, 70 }
};
class Layout2P1: public Layout class Layout2P1: public Layout
{ {
public: public:
@ -39,43 +57,23 @@ class Layout2P1: public Layout
virtual unsigned int getZonesCount() const virtual unsigned int getZonesCount() const
{ {
return 3; return DIM(ZONES_LAYOUT_2P1);
} }
virtual Zone getZone(unsigned int index) const virtual Zone getZone(unsigned int index) const
{ {
return zones[index]; return ZONES_LAYOUT_2P1[index];
} }
virtual void refresh(bool setup=false); virtual void refresh();
static const ZoneOption options[];
protected:
static const Zone zones[3];
}; };
const Zone Layout2P1::zones[3] = { void Layout2P1::refresh()
{ 240, 60, 192, 145 },
{ 46, 60, 182, 66 },
{ 46, 139, 182, 66 }
};
const ZoneOption Layout2P1::options[] = {
{ "Top bar", ZoneOption::Bool },
{ "Flight mode", ZoneOption::Bool },
{ "Sliders", ZoneOption::Bool },
{ "Trims", ZoneOption::Bool },
{ NULL, ZoneOption::Bool }
};
void Layout2P1::refresh(bool setup)
{ {
theme->drawBackground(); theme->drawBackground();
if (persistentData->options[0].boolValue) { if (persistentData->options[0].boolValue) {
// Top Bar drawTopBar();
drawMainViewTopBar();
} }
if (persistentData->options[1].boolValue) { if (persistentData->options[1].boolValue) {
@ -98,11 +96,7 @@ void Layout2P1::refresh(bool setup)
drawTrims(mixerCurrentFlightMode); drawTrims(mixerCurrentFlightMode);
} }
Layout::refresh(setup); Layout::refresh();
} }
const uint8_t LBM_LAYOUT_2P1[] __DMA = { BaseLayoutFactory<Layout2P1> layout2P1("Layout2P1", LBM_LAYOUT_2P1, OPTIONS_LAYOUT_2P1);
#include "mask_layout2+1.lbm"
};
BaseLayoutFactory<Layout2P1> layout2P1("Layout2P1", LBM_LAYOUT_2P1, Layout2P1::options);

View file

@ -20,6 +20,15 @@
#include "opentx.h" #include "opentx.h"
const uint8_t LBM_LAYOUT_2x1[] = {
#include "mask_layout2x1.lbm"
};
const ZoneOption OPTIONS_LAYOUT_2x1[] = {
{ "Top bar", ZoneOption::Bool },
{ NULL, ZoneOption::Bool }
};
class Layout2x1: public Layout class Layout2x1: public Layout
{ {
public: public:
@ -55,31 +64,18 @@ class Layout2x1: public Layout
return zone; return zone;
} }
virtual void refresh(bool setup=false); virtual void refresh();
static const ZoneOption options[];
}; };
const ZoneOption Layout2x1::options[] = { void Layout2x1::refresh()
{ "Top bar", ZoneOption::Bool },
{ NULL, ZoneOption::Bool }
};
void Layout2x1::refresh(bool setup)
{ {
theme->drawBackground(); theme->drawBackground();
if (persistentData->options[0].boolValue) { if (persistentData->options[0].boolValue) {
// Top Bar drawTopBar();
drawMainViewTopBar();
} }
Layout::refresh(setup); Layout::refresh();
} }
const uint8_t LBM_LAYOUT_2x1[] __DMA = { BaseLayoutFactory<Layout2x1> Layout2x1("Layout2x1", LBM_LAYOUT_2x1, OPTIONS_LAYOUT_2x1);
#include "mask_layout2x1.lbm"
};
BaseLayoutFactory<Layout2x1> Layout2x1("Layout2x1", LBM_LAYOUT_2x1, Layout2x1::options);

View file

@ -20,6 +20,15 @@
#include "opentx.h" #include "opentx.h"
const uint8_t LBM_LAYOUT_2x2[] = {
#include "mask_layout2x2.lbm"
};
const ZoneOption OPTIONS_LAYOUT_2x2[] = {
{ "Top bar", ZoneOption::Bool },
{ NULL, ZoneOption::Bool }
};
class Layout2x2: public Layout class Layout2x2: public Layout
{ {
public: public:
@ -58,31 +67,18 @@ class Layout2x2: public Layout
return zone; return zone;
} }
virtual void refresh(bool setup=false); virtual void refresh();
static const ZoneOption options[];
}; };
const ZoneOption Layout2x2::options[] = { void Layout2x2::refresh()
{ "Top bar", ZoneOption::Bool },
{ NULL, ZoneOption::Bool }
};
void Layout2x2::refresh(bool setup)
{ {
theme->drawBackground(); theme->drawBackground();
if (persistentData->options[0].boolValue) { if (persistentData->options[0].boolValue) {
// Top Bar drawTopBar();
drawMainViewTopBar();
} }
Layout::refresh(setup); Layout::refresh();
} }
const uint8_t LBM_LAYOUT_2x2[] __DMA = { BaseLayoutFactory<Layout2x2> layout2x2("Layout2x2", LBM_LAYOUT_2x2, OPTIONS_LAYOUT_2x2);
#include "mask_layout2x2.lbm"
};
BaseLayoutFactory<Layout2x2> layout2x2("Layout2x2", LBM_LAYOUT_2x2, Layout2x2::options);

View file

@ -20,6 +20,22 @@
#include "opentx.h" #include "opentx.h"
const uint8_t LBM_LAYOUT_2x4[] = {
#include "mask_layout2x4.lbm"
};
const ZoneOption OPTIONS_LAYOUT_2x4[] = {
{ "Top bar", ZoneOption::Bool },
{ "Flight mode", ZoneOption::Bool },
{ "Sliders", ZoneOption::Bool },
{ "Trims", ZoneOption::Bool },
{ "Panel1 background", ZoneOption::Bool },
{ " Color", ZoneOption::Color },
{ "Panel2 background", ZoneOption::Bool },
{ " Color", ZoneOption::Color },
{ NULL, ZoneOption::Bool }
};
class Layout2x4: public Layout class Layout2x4: public Layout
{ {
public: public:
@ -56,31 +72,15 @@ class Layout2x4: public Layout
return zone; return zone;
} }
virtual void refresh(bool setup=false); virtual void refresh();
static const ZoneOption options[];
}; };
const ZoneOption Layout2x4::options[] = { void Layout2x4::refresh()
{ "Top bar", ZoneOption::Bool },
{ "Flight mode", ZoneOption::Bool },
{ "Sliders", ZoneOption::Bool },
{ "Trims", ZoneOption::Bool },
{ "Panel1 background", ZoneOption::Bool },
{ " Color", ZoneOption::Color },
{ "Panel2 background", ZoneOption::Bool },
{ " Color", ZoneOption::Color },
{ NULL, ZoneOption::Bool }
};
void Layout2x4::refresh(bool setup)
{ {
theme->drawBackground(); theme->drawBackground();
if (persistentData->options[0].boolValue) { if (persistentData->options[0].boolValue) {
// Top Bar drawTopBar();
drawMainViewTopBar();
} }
if (persistentData->options[1].boolValue) { if (persistentData->options[1].boolValue) {
@ -113,11 +113,7 @@ void Layout2x4::refresh(bool setup)
lcdDrawSolidFilledRect(250, 50, 180, 170, CUSTOM_COLOR); lcdDrawSolidFilledRect(250, 50, 180, 170, CUSTOM_COLOR);
} }
Layout::refresh(setup); Layout::refresh();
} }
const uint8_t LBM_LAYOUT_2x4[] __DMA = { BaseLayoutFactory<Layout2x4> layout2x4("Layout2x4", LBM_LAYOUT_2x4, OPTIONS_LAYOUT_2x4);
#include "mask_layout2x4.lbm"
};
BaseLayoutFactory<Layout2x4> layout2x4("Layout2x4", LBM_LAYOUT_2x4, Layout2x4::options);

View file

@ -109,24 +109,17 @@ int getFontHeight(LcdFlags flags)
return heightTable[FONTSIZE(flags) >> 8]; return heightTable[FONTSIZE(flags) >> 8];
} }
int getBitmapScale(const uint8_t * bmp, int dstWidth, int dstHeight) float getBitmapScale(const uint8_t * bmp, int dstWidth, int dstHeight)
{ {
int widthScale, heightScale;
int bmpWidth = getBitmapWidth(bmp); int bmpWidth = getBitmapWidth(bmp);
int bmpHeight = getBitmapHeight(bmp); int bmpHeight = getBitmapHeight(bmp);
if (bmpWidth == 0 || bmpHeight == 0) if (bmpWidth == 0 || bmpHeight == 0)
return 0; return 0;
if (bmpWidth > dstWidth) float widthScale = float(dstWidth) / bmpWidth;
widthScale = -((bmpWidth+dstWidth-1) / dstWidth); float heightScale = float(dstHeight) / bmpHeight;
else
widthScale = (dstWidth / bmpWidth);
if (bmpHeight > dstHeight)
heightScale = -((bmpHeight+dstHeight-1) / dstHeight);
else
heightScale = (dstHeight / bmpHeight);
return min(widthScale, heightScale); return min(widthScale, heightScale);
} }
@ -882,7 +875,7 @@ void lcdDrawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags
#if defined(SIMU) #if defined(SIMU)
inline void lcdDrawBitmapDMA(coord_t x, coord_t y, coord_t width, coord_t height, const uint8_t * img) inline void lcdDrawBitmapDMA(coord_t x, coord_t y, coord_t width, coord_t height, const uint8_t * img)
{ {
lcdDrawBitmap(x, y, img-4, 0, 0, -1); lcdDrawBitmap(x, y, img-4, 0, 0, 1.0);
} }
#endif #endif
@ -906,7 +899,7 @@ void lcdDrawAlphaBitmap(coord_t x, coord_t y, const uint8_t * bmp)
} }
} }
void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * bmp, coord_t offset, coord_t height, int scale) void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * bmp, coord_t offset, coord_t height, float scale)
{ {
int width = getBitmapWidth(bmp); int width = getBitmapWidth(bmp);
int h = getBitmapHeight(bmp); int h = getBitmapHeight(bmp);
@ -926,29 +919,17 @@ void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * bmp, coord_t offset, co
if (scale == 0) { if (scale == 0) {
lcdDrawBitmapDMA(x, y, width, height, bmp + 4 + offset * width * 2); lcdDrawBitmapDMA(x, y, width, height, bmp + 4 + offset * width * 2);
} }
else if (scale < 0) {
for (coord_t i=0, row=0; row<height; i+=1, row-=scale) {
display_t * p = &displayBuf[(y+i)*LCD_W + x];
const uint8_t * q = bmp + 4 + (offset+row)*width*2;
for (coord_t col=0; col<width; col-=scale) {
lcdDrawPixel(p, *((uint16_t *)q));
p++; q-=2*scale;
}
}
}
else { else {
for (coord_t row=0; row<height; row++) { int dstwidth = width * scale;
for (int i=0; i<scale; i++) { int dstheight = height * scale;
display_t * p = &displayBuf[(y+scale*row+i)*LCD_W + x]; for (coord_t i=0; i<dstheight; i++) {
const uint8_t * q = bmp + 4 + (offset+row)*width*2; display_t * p = &displayBuf[(y+i)*LCD_W + x];
for (coord_t col=0; col<width; col++) { const uint8_t * qs = bmp + 4 + (offset+int(i/scale))*width*2;
for (int j=0; j<scale; j++) { for (coord_t j=0; j<dstwidth; j++) {
const uint8_t * q = qs + int(j/scale) * 2;
lcdDrawPixel(p, *((uint16_t *)q)); lcdDrawPixel(p, *((uint16_t *)q));
p++; p++;
} }
q+=2;
}
}
} }
} }
} }
@ -956,7 +937,7 @@ void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * bmp, coord_t offset, co
void lcdDrawBlackOverlay() void lcdDrawBlackOverlay()
{ {
lcdDrawFilledRect(0, 0, LCD_W, LCD_H, SOLID, OVERLAY_COLOR | (8<<24)); lcdDrawFilledRect(0, 0, LCD_W, LCD_H, SOLID, OVERLAY_COLOR | OPACITY(8));
} }
void lcdDrawCircle(int x0, int y0, int radius) void lcdDrawCircle(int x0, int y0, int radius)

View file

@ -306,19 +306,17 @@ inline int getBitmapHeight(const uint8_t * bmp)
return *(((const uint16_t *)bmp)+1); return *(((const uint16_t *)bmp)+1);
} }
inline int getBitmapScaledSize(int size, int scale) inline int getBitmapScaledSize(int size, float scale)
{ {
if (scale >= -1 && scale <= 1) if (scale == 0.0)
return size; return size;
else if (scale < 0)
return -(size / scale);
else else
return size * scale; return size * scale;
} }
int getBitmapScale(const uint8_t * bmp, int dstWidth, int dstHeight); float getBitmapScale(const uint8_t * bmp, int dstWidth, int dstHeight);
int getTextWidth(const pm_char *s, int len=0, LcdFlags flags=0); int getTextWidth(const pm_char *s, int len=0, LcdFlags flags=0);
void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset=0, coord_t height=0, int scale=0); void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset=0, coord_t height=0, float scale=0);
void lcdDrawBitmapPattern(coord_t x, coord_t y, const uint8_t * img, LcdFlags flags=0, coord_t offset=0, coord_t width=0); void lcdDrawBitmapPattern(coord_t x, coord_t y, const uint8_t * img, LcdFlags flags=0, coord_t offset=0, coord_t width=0);
void lcdDrawAlphaBitmap(coord_t x, coord_t y, const uint8_t * bmp); void lcdDrawAlphaBitmap(coord_t x, coord_t y, const uint8_t * bmp);

View file

@ -544,9 +544,9 @@ bool menuModelSetup(evt_t event)
lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MODE); lcdDrawText(MENUS_MARGIN_LEFT, y, STR_MODE);
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_TARANIS_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].type, (menuHorizontalPosition==0 ? attr : 0)); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_TARANIS_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].type, (menuHorizontalPosition==0 ? attr : 0));
if (IS_MODULE_XJT(EXTERNAL_MODULE)) if (IS_MODULE_XJT(EXTERNAL_MODULE))
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN+40, y, STR_XJT_PROTOCOLS, 1+g_model.moduleData[EXTERNAL_MODULE].rfProtocol, (menuHorizontalPosition==1 ? attr : 0)); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN+70, y, STR_XJT_PROTOCOLS, 1+g_model.moduleData[EXTERNAL_MODULE].rfProtocol, (menuHorizontalPosition==1 ? attr : 0));
else if (IS_MODULE_DSM2(EXTERNAL_MODULE)) else if (IS_MODULE_DSM2(EXTERNAL_MODULE))
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN+40, y, STR_DSM_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, (menuHorizontalPosition==1 ? attr : 0)); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN+70, y, STR_DSM_PROTOCOLS, g_model.moduleData[EXTERNAL_MODULE].rfProtocol, (menuHorizontalPosition==1 ? attr : 0));
if (attr && s_editMode>0) { if (attr && s_editMode>0) {
switch (menuHorizontalPosition) { switch (menuHorizontalPosition) {
case 0: case 0:
@ -672,7 +672,9 @@ bool menuModelSetup(evt_t event)
lcdDrawText(MENUS_MARGIN_LEFT, y, TR_FAILSAFE); lcdDrawText(MENUS_MARGIN_LEFT, y, TR_FAILSAFE);
if (IS_MODULE_XJT(moduleIdx)) { if (IS_MODULE_XJT(moduleIdx)) {
lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VFAILSAFE, moduleData.failsafeMode, menuHorizontalPosition==0 ? attr : 0); lcdDrawTextAtIndex(MODEL_SETUP_2ND_COLUMN, y, STR_VFAILSAFE, moduleData.failsafeMode, menuHorizontalPosition==0 ? attr : 0);
if (moduleData.failsafeMode == FAILSAFE_CUSTOM) lcdDrawText(MODEL_SETUP_2ND_COLUMN + MODEL_SETUP_SET_FAILSAFE_OFS, y, STR_SET, menuHorizontalPosition==1 ? attr : 0); if (moduleData.failsafeMode == FAILSAFE_CUSTOM) {
drawButton(MODEL_SETUP_2ND_COLUMN + MODEL_SETUP_SET_FAILSAFE_OFS, y, STR_SET, menuHorizontalPosition==1 ? attr : 0);
}
if (attr) { if (attr) {
if (moduleData.failsafeMode != FAILSAFE_CUSTOM) if (moduleData.failsafeMode != FAILSAFE_CUSTOM)
menuHorizontalPosition = 0; menuHorizontalPosition = 0;
@ -700,7 +702,7 @@ bool menuModelSetup(evt_t event)
} }
if (IS_RANGECHECK_ENABLE()) { if (IS_RANGECHECK_ENABLE()) {
displayPopup("RSSI :"); theme->drawMessageBox("RSSI :", NULL, NULL, 0);
lcdDrawNumber(WARNING_LINE_X, WARNING_INFOLINE_Y, TELEMETRY_RSSI(), DBLSIZE|LEFT); lcdDrawNumber(WARNING_LINE_X, WARNING_INFOLINE_Y, TELEMETRY_RSSI(), DBLSIZE|LEFT);
} }

View file

@ -144,7 +144,7 @@ static const MenuHandlerFunc menuTabGeneral[] PROGMEM = {
menuGeneralVersion, menuGeneralVersion,
}; };
extern MenuHandlerFunc menuTabMainviews[1+MAX_CUSTOM_SCREENS]; extern const MenuHandlerFunc menuTabScreensSetup[1+MAX_CUSTOM_SCREENS] PROGMEM;
bool menuFirstCalib(evt_t event); bool menuFirstCalib(evt_t event);
bool menuMainView(evt_t event); bool menuMainView(evt_t event);
@ -274,10 +274,13 @@ bool check_submenu_simple(check_event_t event, uint8_t maxrow);
#define MENU(title, icons, tab, menu, lines_count, ...) \ #define MENU(title, icons, tab, menu, lines_count, ...) \
MENU_WITH_OPTIONS(title, icons, tab, DIM(tab), menu, lines_count, __VA_ARGS__) MENU_WITH_OPTIONS(title, icons, tab, DIM(tab), menu, lines_count, __VA_ARGS__)
#define SIMPLE_MENU(title, icons, tab, menu, lines_count) \ #define SIMPLE_MENU_WITH_OPTIONS(title, icons, tab, tabCount, menu, lines_count) \
if (event == EVT_ENTRY || event == EVT_ENTRY_UP) TRACE("Menu %s displayed ...", title); \ if (event == EVT_ENTRY || event == EVT_ENTRY_UP) TRACE("Menu %s displayed ...", title); \
if (!check_simple(event, menu, tab, DIM(tab), lines_count)) return false; \ if (!check_simple(event, menu, tab, tabCount, lines_count)) return false; \
drawMenuTemplate(title, icons); \ drawMenuTemplate(title, icons);
#define SIMPLE_MENU(title, icons, tab, menu, lines_count) \
SIMPLE_MENU_WITH_OPTIONS(title, icons, tab, DIM(tab), menu, lines_count)
#define SUBMENU(title, icon, lines_count, ...) \ #define SUBMENU(title, icon, lines_count, ...) \
MENU_TAB(__VA_ARGS__); \ MENU_TAB(__VA_ARGS__); \

View file

@ -53,7 +53,7 @@ void displayMessageBox()
void drawAlertBox(const char * title, const char * text, const char * action) void drawAlertBox(const char * title, const char * text, const char * action)
{ {
theme->drawAlertBox(title, text, action); theme->drawMessageBox(title, text, action, MESSAGEBOX_TYPE_ALERT);
} }
void message(const pm_char * title, const pm_char * text, const char * action, uint8_t sound) void message(const pm_char * title, const pm_char * text, const char * action, uint8_t sound)

View file

@ -20,66 +20,120 @@
#include "opentx.h" #include "opentx.h"
const uint8_t * LBM_SCREENS_SETUP_ICONS[] = {
LBM_MAINVIEWS_ICON,
LBM_MAINVIEWS_TOPBAR_ICON,
LBM_MAINVIEWS_ICONS[0],
LBM_MAINVIEWS_ICONS[1],
LBM_MAINVIEWS_ICONS[2],
LBM_MAINVIEWS_ICONS[3],
LBM_MAINVIEWS_ICONS[4]
};
Layout * currentScreen; Layout * currentScreen;
WidgetsContainerInterface * currentContainer;
Widget * currentWidget; Widget * currentWidget;
uint8_t currentZone; uint8_t currentZone;
#define SCREENS_SETUP_2ND_COLUMN 200 #define SCREENS_SETUP_2ND_COLUMN 200
ZoneOptionValue editZoneOption(coord_t y, const ZoneOption * option, ZoneOptionValue value, LcdFlags attr, evt_t event) char fileSelection[sizeof(ZoneOptionValue::stringValue)];
uint8_t fileSelectionDone;
int updateMainviewsMenu();
bool menuScreenAdd(evt_t event);
void onScreenSetupMenu(const char * result);
void onZoneOptionFileSelectionMenu(const char * result)
{
if (result == STR_UPDATE_LIST) {
if (!sdListFiles(BITMAPS_PATH, BITMAPS_EXT, sizeof(ZoneOptionValue::stringValue), NULL)) {
POPUP_WARNING(STR_NO_BITMAPS_ON_SD);
}
}
else {
fileSelectionDone = true;
memcpy(fileSelection, result, sizeof(fileSelection));
}
}
void editZoneOption(coord_t y, const ZoneOption * option, ZoneOptionValue * value, LcdFlags attr, uint32_t i_flags, evt_t event)
{ {
lcdDrawText(MENUS_MARGIN_LEFT, y, option->name); lcdDrawText(MENUS_MARGIN_LEFT, y, option->name);
if (option->type == ZoneOption::Bool) { if (option->type == ZoneOption::Bool) {
value.boolValue = editCheckBox(value.boolValue, SCREENS_SETUP_2ND_COLUMN, y, attr, event); value->boolValue = editCheckBox(value->boolValue, SCREENS_SETUP_2ND_COLUMN, y, attr, event); // TODO always does storageDirty(EE_MODEL)
} }
else if (option->type == ZoneOption::Integer) { else if (option->type == ZoneOption::Integer) {
lcdDrawNumber(SCREENS_SETUP_2ND_COLUMN, y, value.signedValue, attr | LEFT); lcdDrawNumber(SCREENS_SETUP_2ND_COLUMN, y, value->signedValue, attr | LEFT);
if (attr) { if (attr) {
CHECK_INCDEC_MODELVAR(event, value.signedValue, -30000, 30000); CHECK_INCDEC_MODELVAR(event, value->signedValue, -30000, 30000); // TODO i_flags
} }
} }
else if (option->type == ZoneOption::String) { else if (option->type == ZoneOption::String) {
editName(SCREENS_SETUP_2ND_COLUMN, y, value.stringValue, sizeof(value.stringValue), event, attr); editName(SCREENS_SETUP_2ND_COLUMN, y, value->stringValue, sizeof(value->stringValue), event, attr); // TODO i_flags?
}
else if (option->type == ZoneOption::File) {
if (ZEXIST(value->stringValue))
lcdDrawSizedText(SCREENS_SETUP_2ND_COLUMN, y, value->stringValue, sizeof(value->stringValue), attr);
else
lcdDrawTextAtIndex(SCREENS_SETUP_2ND_COLUMN, y, STR_VCSWFUNC, 0, attr); // TODO define
if (attr) {
if (event==EVT_KEY_BREAK(KEY_ENTER)) {
s_editMode = 0;
if (sdListFiles(BITMAPS_PATH, BITMAPS_EXT, sizeof(value->stringValue), value->stringValue, LIST_NONE_SD_FILE)) {
fileSelectionDone = false;
popupMenuHandler = onZoneOptionFileSelectionMenu;
}
else {
POPUP_WARNING(STR_NO_BITMAPS_ON_SD);
}
}
else if (fileSelectionDone) {
memcpy(value->stringValue, fileSelection, sizeof(fileSelection));
fileSelectionDone = false;
storageDirty(i_flags);
}
}
} }
else if (option->type == ZoneOption::TextSize) { else if (option->type == ZoneOption::TextSize) {
lcdDrawTextAtIndex(SCREENS_SETUP_2ND_COLUMN, y, "\010StandardTiny\0 Small\0 Mid\0 Double", value.unsignedValue, attr); lcdDrawTextAtIndex(SCREENS_SETUP_2ND_COLUMN, y, "\010StandardTiny\0 Small\0 Mid\0 Double", value->unsignedValue, attr);
if (attr) { if (attr) {
value.unsignedValue = checkIncDec(event, value.unsignedValue, 0, 4, EE_MODEL); value->unsignedValue = checkIncDec(event, value->unsignedValue, 0, 4, i_flags);
} }
} }
else if (option->type == ZoneOption::Timer) { else if (option->type == ZoneOption::Timer) {
drawStringWithIndex(SCREENS_SETUP_2ND_COLUMN, y, STR_TIMER, value.unsignedValue + 1, attr); drawStringWithIndex(SCREENS_SETUP_2ND_COLUMN, y, STR_TIMER, value->unsignedValue + 1, attr);
if (attr) { if (attr) {
value.unsignedValue = checkIncDec(event, value.unsignedValue, 0, MAX_TIMERS - 1, EE_MODEL); value->unsignedValue = checkIncDec(event, value->unsignedValue, 0, MAX_TIMERS - 1, i_flags);
} }
} }
else if (option->type == ZoneOption::Source) { else if (option->type == ZoneOption::Source) {
putsMixerSource(SCREENS_SETUP_2ND_COLUMN, y, value.unsignedValue, attr); putsMixerSource(SCREENS_SETUP_2ND_COLUMN, y, value->unsignedValue, attr);
if (attr) { if (attr) {
CHECK_INCDEC_MODELSOURCE(event, value.unsignedValue, 1, MIXSRC_LAST); CHECK_INCDEC_MODELSOURCE(event, value->unsignedValue, 1, MIXSRC_LAST);
} }
} }
else if (option->type == ZoneOption::Color) { else if (option->type == ZoneOption::Color) {
lcdSetColor(value.unsignedValue); lcdSetColor(value->unsignedValue);
lcdDrawSolidRect(SCREENS_SETUP_2ND_COLUMN, y, 40, 15, 1, attr ? TEXT_INVERTED_BGCOLOR : TEXT_COLOR); lcdDrawSolidRect(SCREENS_SETUP_2ND_COLUMN, y, 40, 15, 1, attr ? TEXT_INVERTED_BGCOLOR : TEXT_COLOR);
lcdDrawSolidFilledRect(SCREENS_SETUP_2ND_COLUMN + 1, y + 1, 38, 13, CUSTOM_COLOR); lcdDrawSolidFilledRect(SCREENS_SETUP_2ND_COLUMN + 1, y + 1, 38, 13, CUSTOM_COLOR);
if (attr) { if (attr) {
CHECK_INCDEC_MODELVAR(event, value.unsignedValue, 0, 65535); value->unsignedValue = checkIncDec(event, value->unsignedValue, i_flags, 65535, 0);
} }
} }
return value;
} }
bool menuWidgetSettings(evt_t event) template <class T>
bool menuSettings(const char * title, const T * object, uint32_t i_flags, evt_t event)
{ {
linesCount = 0; linesCount = 0;
const ZoneOption * options = currentWidget->getFactory()->getOptions(); const ZoneOption * options = object->getOptions();
for (const ZoneOption * option = options; option->name; option++) { for (const ZoneOption * option = options; option->name; option++) {
linesCount++; linesCount++;
} }
SUBMENU_WITH_OPTIONS("Widget settings", LBM_MAINVIEWS_ICON, linesCount, OPTION_MENU_TITLE_BAR, { 0, 0, 0 }); SUBMENU_WITH_OPTIONS(title, LBM_MAINVIEWS_ICON, linesCount, OPTION_MENU_TITLE_BAR, { 0, 0, 0 });
for (int i=0; i<NUM_BODY_LINES+1; i++) { for (int i=0; i<NUM_BODY_LINES+1; i++) {
coord_t y = MENU_CONTENT_TOP + i * FH; coord_t y = MENU_CONTENT_TOP + i * FH;
@ -88,17 +142,24 @@ bool menuWidgetSettings(evt_t event)
LcdFlags attr = (menuVerticalPosition == k ? blink : 0); LcdFlags attr = (menuVerticalPosition == k ? blink : 0);
if (k < linesCount) { if (k < linesCount) {
const ZoneOption * option = &options[k]; const ZoneOption * option = &options[k];
ZoneOptionValue value = currentWidget->getOptionValue(k); ZoneOptionValue * value = object->getOptionValue(k);
value = editZoneOption(y, option, value, attr, event); editZoneOption(y, option, value, attr, i_flags, event);
if (attr) {
currentWidget->setOptionValue(k, value);
}
} }
} }
return true; return true;
} }
bool menuWidgetSettings(evt_t event)
{
return menuSettings<Widget>("Widget settings", currentWidget, EE_MODEL, event);
}
bool menuThemeSettings(evt_t event)
{
return menuSettings<Theme>("Theme settings", theme, EE_GENERAL, event);
}
bool menuWidgetChoice(evt_t event) bool menuWidgetChoice(evt_t event)
{ {
static Widget * previousWidget; static Widget * previousWidget;
@ -108,8 +169,8 @@ bool menuWidgetChoice(evt_t event)
case EVT_ENTRY: case EVT_ENTRY:
{ {
const WidgetFactory * factory; const WidgetFactory * factory;
previousWidget = currentScreen->getWidget(currentZone); previousWidget = currentContainer->getWidget(currentZone);
currentScreen->setWidget(currentZone, NULL); currentContainer->setWidget(currentZone, NULL);
menuHorizontalPosition = 0; menuHorizontalPosition = 0;
if (previousWidget) { if (previousWidget) {
factory = previousWidget->getFactory(); factory = previousWidget->getFactory();
@ -123,19 +184,19 @@ bool menuWidgetChoice(evt_t event)
else { else {
factory = registeredWidgets[0]; factory = registeredWidgets[0];
} }
currentWidget = factory->create(currentScreen->getZone(currentZone), &tempData); currentWidget = factory->create(currentContainer->getZone(currentZone), &tempData);
break; break;
} }
case EVT_KEY_BREAK(KEY_EXIT): case EVT_KEY_BREAK(KEY_EXIT):
delete currentWidget; delete currentWidget;
currentScreen->setWidget(currentZone, previousWidget); currentContainer->setWidget(currentZone, previousWidget);
popMenu(); popMenu();
return false; return false;
case EVT_KEY_BREAK(KEY_ENTER): case EVT_KEY_BREAK(KEY_ENTER):
delete previousWidget; delete previousWidget;
currentScreen->createWidget(currentZone, registeredWidgets[menuHorizontalPosition]); currentContainer->createWidget(currentZone, registeredWidgets[menuHorizontalPosition]);
storageDirty(EE_MODEL); storageDirty(EE_MODEL);
popMenu(); popMenu();
return false; return false;
@ -143,21 +204,21 @@ bool menuWidgetChoice(evt_t event)
case EVT_ROTARY_RIGHT: case EVT_ROTARY_RIGHT:
if (menuHorizontalPosition < int(countRegisteredWidgets-1)) { if (menuHorizontalPosition < int(countRegisteredWidgets-1)) {
delete currentWidget; delete currentWidget;
currentWidget = registeredWidgets[++menuHorizontalPosition]->create(currentScreen->getZone(currentZone), &tempData); currentWidget = registeredWidgets[++menuHorizontalPosition]->create(currentContainer->getZone(currentZone), &tempData);
} }
break; break;
case EVT_ROTARY_LEFT: case EVT_ROTARY_LEFT:
if (menuHorizontalPosition > 0) { if (menuHorizontalPosition > 0) {
delete currentWidget; delete currentWidget;
currentWidget = registeredWidgets[--menuHorizontalPosition]->create(currentScreen->getZone(currentZone), &tempData); currentWidget = registeredWidgets[--menuHorizontalPosition]->create(currentContainer->getZone(currentZone), &tempData);
} }
break; break;
} }
currentScreen->refresh(); currentScreen->refresh();
Zone zone = currentScreen->getZone(currentZone); Zone zone = currentContainer->getZone(currentZone);
lcdDrawFilledRect(0, 0, zone.x-2, LCD_H, SOLID, OVERLAY_COLOR | (8<<24)); lcdDrawFilledRect(0, 0, zone.x-2, LCD_H, SOLID, OVERLAY_COLOR | (8<<24));
lcdDrawFilledRect(zone.x+zone.w+2, 0, LCD_W-zone.x-zone.w-2, LCD_H, SOLID, OVERLAY_COLOR | (8<<24)); lcdDrawFilledRect(zone.x+zone.w+2, 0, LCD_W-zone.x-zone.w-2, LCD_H, SOLID, OVERLAY_COLOR | (8<<24));
lcdDrawFilledRect(zone.x-2, 0, zone.w+4, zone.y-2, SOLID, OVERLAY_COLOR | (8<<24)); lcdDrawFilledRect(zone.x-2, 0, zone.w+4, zone.y-2, SOLID, OVERLAY_COLOR | (8<<24));
@ -176,20 +237,18 @@ bool menuWidgetChoice(evt_t event)
void onZoneMenu(const char * result) void onZoneMenu(const char * result)
{ {
if (result == STR_SELECT_WIDGET) { if (result == STR_SELECT_WIDGET) {
currentZone = menuVerticalPosition;
pushMenu(menuWidgetChoice); pushMenu(menuWidgetChoice);
} }
else if (result == STR_WIDGET_SETTINGS) { else if (result == STR_WIDGET_SETTINGS) {
currentWidget = currentScreen->getWidget(menuVerticalPosition);
pushMenu(menuWidgetSettings); pushMenu(menuWidgetSettings);
} }
else if (result == STR_REMOVE_WIDGET) { else if (result == STR_REMOVE_WIDGET) {
currentScreen->setWidget(menuVerticalPosition, NULL); currentContainer->setWidget(currentZone, NULL);
storageDirty(EE_MODEL); storageDirty(EE_MODEL);
} }
} }
bool menuSetupWidgets(evt_t event) bool menuWidgetsSetup(evt_t event)
{ {
switch (event) { switch (event) {
case EVT_ENTRY: case EVT_ENTRY:
@ -200,17 +259,30 @@ bool menuSetupWidgets(evt_t event)
return false; return false;
} }
currentScreen->refresh(true); currentScreen->refresh();
for (int i=currentScreen->getZonesCount()-1; i>=0; i--) { for (int i=currentContainer->getZonesCount()-1; i>=0; i--) {
Zone zone = currentScreen->getZone(i); Zone zone = currentContainer->getZone(i);
LcdFlags color;
int padding, thickness;
if (currentContainer == topbar) {
color = MENU_TITLE_COLOR;
padding = 2;
thickness = 1;
}
else {
color = TEXT_INVERTED_BGCOLOR;
padding = 4;
thickness = 2;
}
if (menuVerticalPosition == i) { if (menuVerticalPosition == i) {
lcdDrawSolidRect(zone.x-4, zone.y-4, zone.w+8, zone.h+8, 2, TEXT_INVERTED_BGCOLOR); lcdDrawSolidRect(zone.x-padding, zone.y-padding, zone.w+2*padding, zone.h+2*padding, thickness, color);
if (event == EVT_KEY_BREAK(KEY_ENTER)) { if (event == EVT_KEY_BREAK(KEY_ENTER)) {
Widget * widget = currentScreen->getWidget(i); currentZone = menuVerticalPosition;
if (widget) { currentWidget = currentContainer->getWidget(menuVerticalPosition);
if (currentWidget) {
POPUP_MENU_ADD_ITEM(STR_SELECT_WIDGET); POPUP_MENU_ADD_ITEM(STR_SELECT_WIDGET);
if (widget->getFactory()->getOptions()) if (currentWidget->getFactory()->getOptions())
POPUP_MENU_ADD_ITEM(STR_WIDGET_SETTINGS); POPUP_MENU_ADD_ITEM(STR_WIDGET_SETTINGS);
POPUP_MENU_ADD_ITEM(STR_REMOVE_WIDGET); POPUP_MENU_ADD_ITEM(STR_REMOVE_WIDGET);
popupMenuHandler = onZoneMenu; popupMenuHandler = onZoneMenu;
@ -221,15 +293,13 @@ bool menuSetupWidgets(evt_t event)
} }
} }
else { else {
lcdDrawRect(zone.x-4, zone.y-4, zone.w+8, zone.h+8, 2, 0x3F, TEXT_INVERTED_BGCOLOR); lcdDrawRect(zone.x-padding, zone.y-padding, zone.w+2*padding, zone.h+2*padding, thickness, 0x3F, color);
} }
} }
navigate(event, currentScreen->getZonesCount(), currentScreen->getZonesCount(), 1); navigate(event, currentContainer->getZonesCount(), currentContainer->getZonesCount(), 1);
return true; return true;
} }
extern int updateMainviewsMenu();
template <class T> template <class T>
T * editThemeChoice(coord_t x, coord_t y, T * array[], uint8_t count, T * current, bool needsOffsetCheck, LcdFlags attr, evt_t event) T * editThemeChoice(coord_t x, coord_t y, T * array[], uint8_t count, T * current, bool needsOffsetCheck, LcdFlags attr, evt_t event)
{ {
@ -291,12 +361,19 @@ T * editThemeChoice(coord_t x, coord_t y, T * array[], uint8_t count, T * curren
return NULL; return NULL;
} }
enum menuScreensThemeItems {
ITEM_SCREEN_SETUP_THEME,
ITEM_SCREEN_SETUP_THEME_SETTINGS = ITEM_SCREEN_SETUP_THEME+2,
ITEM_SCREEN_SETUP_TOPBAR,
ITEM_SCREEN_SETUP_MAX
};
bool menuScreensTheme(evt_t event) bool menuScreensTheme(evt_t event)
{ {
bool needsOffsetCheck = (menuVerticalPosition != 0 || menuHorizontalPosition < 0); bool needsOffsetCheck = (menuVerticalPosition != 0 || menuHorizontalPosition < 0);
menuPageCount = updateMainviewsMenu(); menuPageCount = updateMainviewsMenu();
MENU_WITH_OPTIONS("User interface", LBM_MAINVIEWS_ICONS, menuTabMainviews, menuPageCount, 0, 1, { uint8_t(NAVIGATION_LINE_BY_LINE|uint8_t(countRegisteredThemes-1)), ORPHAN_ROW, 0, 0, 0, 0 }); MENU_WITH_OPTIONS("User interface", LBM_SCREENS_SETUP_ICONS, menuTabScreensSetup, menuPageCount, 0, ITEM_SCREEN_SETUP_MAX, { uint8_t(NAVIGATION_LINE_BY_LINE|uint8_t(countRegisteredThemes-1)), ORPHAN_ROW, 0, 0, 0, 0 });
for (int i=0; i<NUM_BODY_LINES; i++) { for (int i=0; i<NUM_BODY_LINES; i++) {
coord_t y = MENU_CONTENT_TOP + i * FH; coord_t y = MENU_CONTENT_TOP + i * FH;
@ -304,10 +381,11 @@ bool menuScreensTheme(evt_t event)
LcdFlags blink = ((s_editMode > 0) ? BLINK | INVERS : INVERS); LcdFlags blink = ((s_editMode > 0) ? BLINK | INVERS : INVERS);
LcdFlags attr = (menuVerticalPosition == k ? blink : 0); LcdFlags attr = (menuVerticalPosition == k ? blink : 0);
switch (k) { switch (k) {
case 0: { case ITEM_SCREEN_SETUP_THEME: {
lcdDrawText(MENUS_MARGIN_LEFT, y + FH / 2, "Theme"); lcdDrawText(MENUS_MARGIN_LEFT, y + FH / 2, "Theme");
const Theme * new_theme = editThemeChoice<const Theme>(SCREENS_SETUP_2ND_COLUMN, y, registeredThemes, countRegisteredThemes, theme, needsOffsetCheck, attr, event); const Theme * new_theme = editThemeChoice<const Theme>(SCREENS_SETUP_2ND_COLUMN, y, registeredThemes, countRegisteredThemes, theme, needsOffsetCheck, attr, event);
if (new_theme) { if (new_theme) {
new_theme->init();
loadTheme(new_theme); loadTheme(new_theme);
strncpy(g_eeGeneral.themeName, new_theme->getName(), sizeof(g_eeGeneral.themeName)); strncpy(g_eeGeneral.themeName, new_theme->getName(), sizeof(g_eeGeneral.themeName));
storageDirty(EE_GENERAL); storageDirty(EE_GENERAL);
@ -315,34 +393,56 @@ bool menuScreensTheme(evt_t event)
break; break;
} }
case 1: case ITEM_SCREEN_SETUP_THEME_SETTINGS:
drawButton(SCREENS_SETUP_2ND_COLUMN, y, "Theme settings", attr);
if (attr && event == EVT_KEY_BREAK(KEY_ENTER) && theme->getOptions()) {
s_editMode = 0;
pushMenu(menuThemeSettings);
}
break; break;
case ITEM_SCREEN_SETUP_TOPBAR:
lcdDrawText(MENUS_MARGIN_LEFT, y, "Top bar");
drawButton(SCREENS_SETUP_2ND_COLUMN, y, "Setup", attr);
if (attr && event == EVT_KEY_BREAK(KEY_ENTER)) {
currentScreen = customScreens[0];
currentContainer = topbar;
pushMenu(menuWidgetsSetup);
}
break;
} }
} }
return true; return true;
} }
bool menuScreenAdd(evt_t event); enum menuScreenSetup {
void onScreenSetupMenu(const char * result); ITEM_SCREEN_SETUP_LAYOUT,
ITEM_SCREEN_SETUP_WIDGETS_SETUP = ITEM_SCREEN_SETUP_LAYOUT+2,
ITEM_SCREEN_SETUP_LAYOUT_OPTION1,
};
template <int T> bool menuScreenSetup(int index, evt_t event)
bool menuScreenSetup(evt_t event)
{ {
currentScreen = customScreens[T]; if (customScreens[index] == NULL) {
return menuScreenAdd(event);
}
currentScreen = customScreens[index];
currentContainer = currentScreen;
bool needsOffsetCheck = (menuVerticalPosition != 0 || menuHorizontalPosition < 0); bool needsOffsetCheck = (menuVerticalPosition != 0 || menuHorizontalPosition < 0);
linesCount = 3; linesCount = ITEM_SCREEN_SETUP_LAYOUT_OPTION1;
const ZoneOption * options = currentScreen->getFactory()->getOptions(); const ZoneOption * options = currentScreen->getFactory()->getOptions();
for (const ZoneOption * option = options; option->name; option++) { for (const ZoneOption * option = options; option->name; option++) {
linesCount++; linesCount++;
} }
char title[] = "Main view X"; char title[] = "Main view X";
title[sizeof(title)-2] = '1' + T; title[sizeof(title)-2] = '1' + index;
menuPageCount = updateMainviewsMenu(); menuPageCount = updateMainviewsMenu();
MENU_WITH_OPTIONS(title, LBM_MAINVIEWS_ICONS, menuTabMainviews, menuPageCount, T+1, linesCount, { uint8_t(NAVIGATION_LINE_BY_LINE|uint8_t(countRegisteredLayouts-1)), ORPHAN_ROW, 0, 0, 0, 0 }); MENU_WITH_OPTIONS(title, LBM_SCREENS_SETUP_ICONS, menuTabScreensSetup, menuPageCount, index+1, linesCount, { uint8_t(NAVIGATION_LINE_BY_LINE|uint8_t(countRegisteredLayouts-1)), ORPHAN_ROW, 0, 0, 0, 0 });
for (int i=0; i<NUM_BODY_LINES; i++) { for (int i=0; i<NUM_BODY_LINES; i++) {
coord_t y = MENU_CONTENT_TOP + i * FH; coord_t y = MENU_CONTENT_TOP + i * FH;
@ -350,46 +450,43 @@ bool menuScreenSetup(evt_t event)
LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS); LcdFlags blink = ((s_editMode>0) ? BLINK|INVERS : INVERS);
LcdFlags attr = (menuVerticalPosition == k ? blink : 0); LcdFlags attr = (menuVerticalPosition == k ? blink : 0);
switch(k) { switch(k) {
case 0: case ITEM_SCREEN_SETUP_LAYOUT:
{ {
lcdDrawText(MENUS_MARGIN_LEFT, y + FH / 2, "Layout"); lcdDrawText(MENUS_MARGIN_LEFT, y + FH / 2, "Layout");
const LayoutFactory * factory = editThemeChoice<const LayoutFactory>(SCREENS_SETUP_2ND_COLUMN, y, registeredLayouts, countRegisteredLayouts, currentScreen->getFactory(), needsOffsetCheck, attr, event); const LayoutFactory * factory = editThemeChoice<const LayoutFactory>(SCREENS_SETUP_2ND_COLUMN, y, registeredLayouts, countRegisteredLayouts, currentScreen->getFactory(), needsOffsetCheck, attr, event);
if (factory) { if (factory) {
delete customScreens[T]; delete customScreens[index];
customScreens[T] = factory->create(&g_model.screenData[T].layoutData); customScreens[index] = factory->create(&g_model.screenData[index].layoutData);
strncpy(g_model.screenData[T].layoutName, factory->getName(), sizeof(g_model.screenData[T].layoutName)); strncpy(g_model.screenData[index].layoutName, factory->getName(), sizeof(g_model.screenData[index].layoutName));
storageDirty(EE_MODEL); storageDirty(EE_MODEL);
} }
break; break;
} }
case 1: case ITEM_SCREEN_SETUP_LAYOUT+1:
break; break;
case 2: case ITEM_SCREEN_SETUP_WIDGETS_SETUP:
drawButton(SCREENS_SETUP_2ND_COLUMN, y, "Setup widgets", attr); drawButton(SCREENS_SETUP_2ND_COLUMN, y, "Setup widgets", attr);
if (attr && event == EVT_KEY_BREAK(KEY_ENTER)) { if (attr && event == EVT_KEY_BREAK(KEY_ENTER)) {
pushMenu(menuSetupWidgets); pushMenu(menuWidgetsSetup);
} }
break; break;
default: default:
if (k < linesCount) { if (k < linesCount) {
uint8_t index = k - 3; uint8_t index = k - ITEM_SCREEN_SETUP_LAYOUT_OPTION1;
const ZoneOption * option = &options[index]; const ZoneOption * option = &options[index];
ZoneOptionValue value = currentScreen->getOptionValue(index); ZoneOptionValue * value = currentScreen->getOptionValue(index);
value = editZoneOption(y, option, value, attr, event); editZoneOption(y, option, value, attr, EE_MODEL, event);
if (attr) {
currentScreen->setOptionValue(index, value);
}
} }
break; break;
} }
} }
if (menuVerticalPosition == -1 && T > 0 && event == EVT_KEY_LONG(KEY_ENTER)) { if (menuVerticalPosition == -1 && index > 0 && event == EVT_KEY_LONG(KEY_ENTER)) {
killEvents(KEY_ENTER); killEvents(KEY_ENTER);
menuHorizontalPosition = T; menuHorizontalPosition = index;
POPUP_MENU_ADD_ITEM(STR_REMOVE_SCREEN); POPUP_MENU_ADD_ITEM(STR_REMOVE_SCREEN);
popupMenuHandler = onScreenSetupMenu; popupMenuHandler = onScreenSetupMenu;
} }
@ -397,33 +494,29 @@ bool menuScreenSetup(evt_t event)
return true; return true;
} }
MenuHandlerFunc menuTabMainviews[1+MAX_CUSTOM_SCREENS] = { template<int N>
menuScreensTheme, bool menuCustomScreenSetup(evt_t event)
menuScreenSetup<0>, {
menuScreenSetup<1>, return menuScreenSetup(N, event);
menuScreenSetup<2>, }
menuScreenSetup<3>,
menuScreenSetup<4>
};
const MenuHandlerFunc menuMainviews[MAX_CUSTOM_SCREENS] = { const MenuHandlerFunc menuTabScreensSetup[1+MAX_CUSTOM_SCREENS] = {
menuScreenSetup<0>, menuScreensTheme,
menuScreenSetup<1>, menuCustomScreenSetup<0>,
menuScreenSetup<2>, menuCustomScreenSetup<1>,
menuScreenSetup<3>, menuCustomScreenSetup<2>,
menuScreenSetup<4> menuCustomScreenSetup<3>,
menuCustomScreenSetup<4>
}; };
int updateMainviewsMenu() int updateMainviewsMenu()
{ {
for (int index=1; index<MAX_CUSTOM_SCREENS; index++) { for (int index=1; index<MAX_CUSTOM_SCREENS; index++) {
if (customScreens[index]) { if (customScreens[index]) {
menuTabMainviews[1+index] = menuMainviews[index]; LBM_SCREENS_SETUP_ICONS[2+index] = LBM_MAINVIEWS_ICONS[index];
LBM_MAINVIEWS_ICONS[2+index] = LBM_MAINVIEWS_ITEM_OUT_ICON;
} }
else { else {
menuTabMainviews[1+index] = menuScreenAdd; LBM_SCREENS_SETUP_ICONS[2+index] = LBM_MAINVIEWS_ADD_ICON;
LBM_MAINVIEWS_ICONS[2+index] = LBM_MAINVIEWS_ADD_ICON;
return 2+index; return 2+index;
} }
} }
@ -436,12 +529,11 @@ bool menuScreenAdd(evt_t event)
if (event == EVT_KEY_BREAK(KEY_ENTER)) { if (event == EVT_KEY_BREAK(KEY_ENTER)) {
customScreens[menuPageCount-2] = registeredLayouts[0]->create(&g_model.screenData[menuPageCount-2].layoutData); customScreens[menuPageCount-2] = registeredLayouts[0]->create(&g_model.screenData[menuPageCount-2].layoutData);
chainMenu(menuMainviews[menuPageCount-2]); s_editMode = 0;
return false; return false;
} }
MENU_WITH_OPTIONS("Add main view", LBM_MAINVIEWS_ICONS, menuTabMainviews, menuPageCount, menuPageCount-1, 0, { uint8_t(NAVIGATION_LINE_BY_LINE|uint8_t(countRegisteredLayouts-1)), ORPHAN_ROW, 0, 0, 0, 0 }); SIMPLE_MENU_WITH_OPTIONS("Add main view", LBM_SCREENS_SETUP_ICONS, menuTabScreensSetup, menuPageCount, menuPageCount-1, 0);
return true; return true;
} }
@ -455,6 +547,6 @@ void onScreenSetupMenu(const char * result)
} }
memset(&g_model.screenData[MAX_CUSTOM_SCREENS-1], 0, sizeof(CustomScreenData)); memset(&g_model.screenData[MAX_CUSTOM_SCREENS-1], 0, sizeof(CustomScreenData));
customScreens[MAX_CUSTOM_SCREENS-1] = NULL; customScreens[MAX_CUSTOM_SCREENS-1] = NULL;
chainMenu(menuMainviews[menuHorizontalPosition > 0 ? menuHorizontalPosition-1 : 0]); // chainMenu(menuMainviews[menuHorizontalPosition > 0 ? menuHorizontalPosition-1 : 0]);
} }
} }

View file

@ -20,23 +20,54 @@
#include "opentx.h" #include "opentx.h"
void Theme::init() const
{
memset(&g_eeGeneral.themeData, 0, sizeof(Theme::PersistentData));
if (options) {
int i = 0;
for (const ZoneOption * option = options; option->name; option++, i++) {
// TODO compiler bug? The CPU freezes ... g_eeGeneral.themeData.options[i] = &option->deflt;
memcpy(&g_eeGeneral.themeData.options[i], &option->deflt, sizeof(ZoneOptionValue));
}
}
}
ZoneOptionValue * Theme::getOptionValue(unsigned int index) const
{
return &g_eeGeneral.themeData.options[index];
}
void Theme::drawThumb(uint16_t x, uint16_t y, uint32_t flags) const
{
lcdDrawBitmap(x, y, bitmap);
}
void Theme::drawBackground() const void Theme::drawBackground() const
{ {
lcdDrawSolidFilledRect(0, 0, LCD_W, LCD_H, TEXT_BGCOLOR); lcdDrawSolidFilledRect(0, 0, LCD_W, LCD_H, TEXT_BGCOLOR);
} }
void Theme::drawAlertBox(const char * title, const char * text, const char * action) const void Theme::drawMessageBox(const char * title, const char * text, const char * action, uint32_t flags) const
{ {
//if (flags & MESSAGEBOX_TYPE_ALERT) {
drawBackground(); drawBackground();
lcdDrawFilledRect(0, POPUP_Y, LCD_W, POPUP_H, SOLID, TEXT_INVERTED_COLOR | OPACITY(8)); lcdDrawFilledRect(0, POPUP_Y, LCD_W, POPUP_H, SOLID, TEXT_INVERTED_COLOR | OPACITY(8));
//}
if ((flags & MESSAGEBOX_TYPE_ALERT) || (flags & MESSAGEBOX_TYPE_WARNING)) {
lcdDrawAlphaBitmap(POPUP_X-80, POPUP_Y+12, LBM_ASTERISK); lcdDrawAlphaBitmap(POPUP_X-80, POPUP_Y+12, LBM_ASTERISK);
}
#if defined(TRANSLATIONS_FR) || defined(TRANSLATIONS_IT) || defined(TRANSLATIONS_CZ) #if defined(TRANSLATIONS_FR) || defined(TRANSLATIONS_IT) || defined(TRANSLATIONS_CZ)
if ((flags & MESSAGEBOX_TYPE_ALERT) || (flags & MESSAGEBOX_TYPE_WARNING)) {
lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y, STR_WARNING, ALARM_COLOR|DBLSIZE); lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y, STR_WARNING, ALARM_COLOR|DBLSIZE);
}
lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y+28, title, ALARM_COLOR|DBLSIZE); lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y+28, title, ALARM_COLOR|DBLSIZE);
#else #else
lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y, title, ALARM_COLOR|DBLSIZE); lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y, title, ALARM_COLOR|DBLSIZE);
if ((flags & MESSAGEBOX_TYPE_ALERT) || (flags & MESSAGEBOX_TYPE_WARNING)) {
lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y+28, STR_WARNING, ALARM_COLOR|DBLSIZE); lcdDrawText(WARNING_LINE_X, WARNING_LINE_Y+28, STR_WARNING, ALARM_COLOR|DBLSIZE);
}
#endif #endif
if (text) { if (text) {
@ -53,6 +84,7 @@ unsigned int countRegisteredThemes = 0;
void registerTheme(const Theme * theme) void registerTheme(const Theme * theme)
{ {
if (countRegisteredThemes < MAX_REGISTERED_THEMES) { if (countRegisteredThemes < MAX_REGISTERED_THEMES) {
TRACE("register theme %s", theme->getName());
registeredThemes[countRegisteredThemes++] = theme; registeredThemes[countRegisteredThemes++] = theme;
} }
} }
@ -70,6 +102,7 @@ const Theme * getTheme(const char * name)
void loadTheme(const Theme * new_theme) void loadTheme(const Theme * new_theme)
{ {
TRACE("load theme %s", new_theme->getName());
theme = new_theme; theme = new_theme;
theme->load(); theme->load();
} }
@ -80,5 +113,11 @@ void loadTheme()
memset(name, 0, sizeof(name)); memset(name, 0, sizeof(name));
strncpy(name, g_eeGeneral.themeName, sizeof(g_eeGeneral.themeName)); strncpy(name, g_eeGeneral.themeName, sizeof(g_eeGeneral.themeName));
const Theme * new_theme = getTheme(name); const Theme * new_theme = getTheme(name);
loadTheme(new_theme ? new_theme : theme); if (new_theme) {
loadTheme(new_theme);
}
else {
theme->init();
theme->load();
}
} }

View file

@ -21,42 +21,59 @@
#ifndef _THEME_H_ #ifndef _THEME_H_
#define _THEME_H_ #define _THEME_H_
class Theme; #define MAX_THEME_OPTIONS 5
class Theme;
void registerTheme(const Theme * theme); void registerTheme(const Theme * theme);
#define MESSAGEBOX_TYPE_INFO 0
#define MESSAGEBOX_TYPE_QUESTION 1
#define MESSAGEBOX_TYPE_WARNING 2
#define MESSAGEBOX_TYPE_ALERT 4
class Theme class Theme
{ {
public: public:
Theme(const char * name, const uint8_t * bitmap): struct PersistentData {
ZoneOptionValue options[MAX_THEME_OPTIONS];
};
Theme(const char * name, const uint8_t * bitmap, const ZoneOption * options=NULL):
name(name), name(name),
bitmap(bitmap) bitmap(bitmap),
options(options)
{ {
registerTheme(this); registerTheme(this);
} }
const char * getName() const inline const char * getName() const
{ {
return name; return name;
} }
virtual void drawThumb(uint16_t x, uint16_t y, uint32_t flags) const inline const ZoneOption * getOptions() const
{ {
extern void lcdDrawBitmap(int x, int y, const uint8_t * bitmap, int offset=0, int height=0, int scale=0); return options;
lcdDrawBitmap(x, y, bitmap);
} }
void init() const;
ZoneOptionValue * getOptionValue(unsigned int index) const;
virtual void drawThumb(uint16_t x, uint16_t y, uint32_t flags) const;
virtual void load() const = 0; virtual void load() const = 0;
virtual void drawBackground() const; virtual void drawBackground() const;
virtual void drawTopbarBackground(const uint8_t * icon) const = 0; virtual void drawTopbarBackground(const uint8_t * icon) const = 0;
virtual void drawAlertBox(const char * title, const char * text, const char * action) const; virtual void drawMessageBox(const char * title, const char * text, const char * action, uint32_t flags) const;
protected: protected:
const char * name; const char * name;
const uint8_t * bitmap; const uint8_t * bitmap;
const ZoneOption * options;
}; };
extern const Theme * theme; extern const Theme * theme;

View file

@ -20,15 +20,19 @@
#include "opentx.h" #include "opentx.h"
const uint8_t LBM_TOPMENU_BMP_OPENTX[] = { const uint8_t LBM_TOPMENU_BMP_OPENTX[] __DMA = {
#include "bmp_topmenu_opentx.lbm" #include "bmp_topmenu_opentx.lbm"
}; };
const uint8_t LBM_THEME_DARKBLUE[] __DMA = {
#include "bmp_darkblue.lbm"
};
class DarkblueTheme: public Theme class DarkblueTheme: public Theme
{ {
public: public:
DarkblueTheme(const char * name, const uint8_t * bitmap): DarkblueTheme():
Theme(name, bitmap) Theme("Darkblue", LBM_THEME_DARKBLUE)
{ {
} }
@ -77,8 +81,4 @@ class DarkblueTheme: public Theme
} }
}; };
const uint8_t LBM_THEME_DARKBLUE[] __DMA = { DarkblueTheme darkblueTheme;
#include "bmp_darkblue.lbm"
};
DarkblueTheme darkblueTheme("Darkblue", LBM_THEME_DARKBLUE);

View file

@ -0,0 +1,100 @@
/*
* 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 "opentx.h"
unsigned int Topbar::getZonesCount() const
{
return MAX_TOPBAR_ZONES;
}
Zone Topbar::getZone(unsigned int index) const
{
Zone zone;
zone.x = 50 + (TOPBAR_ZONE_WIDTH + 2*TOPBAR_ZONE_MARGIN) * index;
zone.y = TOPBAR_ZONE_MARGIN;
zone.w = TOPBAR_ZONE_WIDTH;
zone.h = MENU_HEADER_HEIGHT - 2*TOPBAR_ZONE_MARGIN;
return zone;
}
void drawTopBar()
{
theme->drawTopbarBackground(NULL);
// USB icon
if (usbPlugged()) {
lcdDrawBitmapPattern(378, 8, LBM_TOPMENU_USB, MENU_TITLE_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];
lcdDrawSolidFilledRect(390 + i * 6, 38 - height, 4, height, TELEMETRY_RSSI() >= rssiBarsValue[i] ? MENU_TITLE_COLOR : MENU_TITLE_DISABLE_COLOR);
}
topbar->refresh();
#if 0
// Radio battery - TODO
// putsValueWithUnit(370, 8, g_vbat100mV, UNIT_VOLTS, PREC1|SMLSIZE|MENU_TITLE_COLOR);
// lcdDrawSolidRect(300, 3, 20, 50, MENU_TITLE_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.frsky.voltsSource) { // TODO should not be in frsky struct
TelemetryItem & item = telemetryItems[g_model.frsky.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 : TEXT_COLOR);
lcdDrawSolidFilledRect(ALTITUDE_X, VOLTS_Y, ALTITUDE_W, ALTITUDE_H, TEXT_BGCOLOR);
lcdDrawText(ALTITUDE_X+PADDING, VOLTS_Y+2, "Voltage", att);
putsValueWithUnit(ALTITUDE_X+PADDING, VOLTS_Y+12, value, UNIT_VOLTS, DBLSIZE|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 : TEXT_COLOR);
lcdDrawSolidFilledRect(ALTITUDE_X, ALTITUDE_Y, ALTITUDE_W, ALTITUDE_H, TEXT_BGCOLOR);
lcdDrawText(ALTITUDE_X+PADDING, ALTITUDE_Y+2, "Alt", att);
putsValueWithUnit(ALTITUDE_X+PADDING, ALTITUDE_Y+12, value, UNIT_METERS, DBLSIZE|LEFT|att);
}
}
#endif
}

View file

@ -0,0 +1,44 @@
/*
* 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.
*/
#ifndef _TOPBAR_H_
#define _TOPBAR_H_
#include "widgets_container.h"
#define MAX_TOPBAR_ZONES 5
#define MAX_TOPBAR_OPTIONS 0
#define TOPBAR_ZONE_WIDTH 60
#define TOPBAR_ZONE_MARGIN 3
class Topbar: public WidgetsContainer<MAX_TOPBAR_ZONES, MAX_TOPBAR_OPTIONS>
{
public:
explicit Topbar(PersistentData * persistentData):
WidgetsContainer<MAX_TOPBAR_ZONES, MAX_TOPBAR_OPTIONS>(persistentData)
{
}
virtual unsigned int getZonesCount() const;
virtual Zone getZone(unsigned int index) const;
};
#endif // _TOPBAR_H_

View file

@ -30,6 +30,7 @@
#define POTS_LINE_Y 252 #define POTS_LINE_Y 252
Layout * customScreens[MAX_CUSTOM_SCREENS]; Layout * customScreens[MAX_CUSTOM_SCREENS];
Topbar * topbar;
void drawMainPots() void drawMainPots()
{ {
@ -79,72 +80,6 @@ void drawTrims(uint8_t flightMode)
} }
} }
void drawMainViewTopBar()
{
const int ALTITUDE_Y = 16;
const int VOLTS_Y = 16+16+30;
const int ALTITUDE_W = 56;
const int ALTITUDE_X = LCD_W-ALTITUDE_Y-ALTITUDE_W;
const int ALTITUDE_H = 30;
const int PADDING = 4;
theme->drawTopbarBackground(NULL);
// USB icon
if (usbPlugged()) {
lcdDrawBitmapPattern(378, 8, LBM_TOPMENU_USB, MENU_TITLE_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];
lcdDrawSolidFilledRect(390+i*6, 38-height, 4, height, TELEMETRY_RSSI() >= rssiBarsValue[i] ? MENU_TITLE_COLOR : MENU_TITLE_DISABLE_COLOR);
}
// Radio battery - TODO
// putsValueWithUnit(370, 8, g_vbat100mV, UNIT_VOLTS, PREC1|SMLSIZE|MENU_TITLE_COLOR);
// lcdDrawSolidRect(300, 3, 20, 50, MENU_TITLE_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.frsky.voltsSource) { // TODO should not be in frsky struct
TelemetryItem & item = telemetryItems[g_model.frsky.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 : TEXT_COLOR);
lcdDrawSolidFilledRect(ALTITUDE_X, VOLTS_Y, ALTITUDE_W, ALTITUDE_H, TEXT_BGCOLOR);
lcdDrawText(ALTITUDE_X+PADDING, VOLTS_Y+2, "Voltage", att);
putsValueWithUnit(ALTITUDE_X+PADDING, VOLTS_Y+12, value, UNIT_VOLTS, DBLSIZE|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 : TEXT_COLOR);
lcdDrawSolidFilledRect(ALTITUDE_X, ALTITUDE_Y, ALTITUDE_W, ALTITUDE_H, TEXT_BGCOLOR);
lcdDrawText(ALTITUDE_X+PADDING, ALTITUDE_Y+2, "Alt", att);
putsValueWithUnit(ALTITUDE_X+PADDING, ALTITUDE_Y+12, value, UNIT_METERS, DBLSIZE|LEFT|att);
}
}
}
bool isViewAvailable(int index) bool isViewAvailable(int index)
{ {
if (index <= VIEW_CHANNELS) if (index <= VIEW_CHANNELS)
@ -187,7 +122,7 @@ void onMainViewMenu(const char *result)
chainMenu(menuStatisticsView); chainMenu(menuStatisticsView);
} }
else if (result == STR_SETUP_SCREENS) { else if (result == STR_SETUP_SCREENS) {
pushMenu(menuTabMainviews[1]); pushMenu(menuTabScreensSetup[1]);
} }
else if (result == STR_ABOUT_US) { else if (result == STR_ABOUT_US) {
chainMenu(menuAboutView); chainMenu(menuAboutView);

View file

@ -25,6 +25,7 @@ unsigned int countRegisteredWidgets = 0;
void registerWidget(const WidgetFactory * factory) void registerWidget(const WidgetFactory * factory)
{ {
if (countRegisteredWidgets < MAX_REGISTERED_WIDGETS) { if (countRegisteredWidgets < MAX_REGISTERED_WIDGETS) {
TRACE("register widget %s", factory->getName());
registeredWidgets[countRegisteredWidgets++] = factory; registeredWidgets[countRegisteredWidgets++] = factory;
} }
} }

View file

@ -23,7 +23,7 @@
#include <inttypes.h> #include <inttypes.h>
#define MAX_WIDGET_OPTIONS 4 #define MAX_WIDGET_OPTIONS 5
struct Zone struct Zone
{ {
@ -45,6 +45,7 @@ struct ZoneOption
Source, Source,
Bool, Bool,
String, String,
File,
TextSize, TextSize,
Timer, Timer,
Switch, Switch,
@ -75,19 +76,16 @@ class Widget
{ {
} }
const WidgetFactory * getFactory() const inline const WidgetFactory * getFactory() const
{ {
return factory; return factory;
} }
virtual ZoneOptionValue getOptionValue(unsigned int index) const inline const ZoneOption * getOptions() const;
{
return persistentData->options[index];
}
virtual void setOptionValue(unsigned int index, ZoneOptionValue value) const inline ZoneOptionValue * getOptionValue(unsigned int index) const
{ {
persistentData->options[index] = value; return &persistentData->options[index];
} }
virtual void refresh() = 0; virtual void refresh() = 0;
@ -103,7 +101,7 @@ void registerWidget(const WidgetFactory * factory);
class WidgetFactory class WidgetFactory
{ {
public: public:
WidgetFactory(const char * name, const ZoneOption * options): WidgetFactory(const char * name, const ZoneOption * options=NULL):
name(name), name(name),
options(options) options(options)
{ {
@ -126,7 +124,8 @@ class WidgetFactory
if (options) { if (options) {
int i = 0; int i = 0;
for (const ZoneOption * option = options; option->name; option++) { for (const ZoneOption * option = options; option->name; option++) {
persistentData->options[i++] = option->deflt; // TODO compiler bug? The CPU freezes ... persistentData->options[i++] = option->deflt;
memcpy(&persistentData->options[i++], &option->deflt, sizeof(ZoneOptionValue));
} }
} }
} }
@ -157,6 +156,11 @@ class BaseWidgetFactory: public WidgetFactory
} }
}; };
inline const ZoneOption * Widget::getOptions() const
{
return getFactory()->getOptions();
}
#define MAX_REGISTERED_WIDGETS 10 #define MAX_REGISTERED_WIDGETS 10
extern unsigned int countRegisteredWidgets; extern unsigned int countRegisteredWidgets;
extern const WidgetFactory * registeredWidgets[MAX_REGISTERED_WIDGETS]; extern const WidgetFactory * registeredWidgets[MAX_REGISTERED_WIDGETS];

View file

@ -426,7 +426,7 @@ int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min, int
void drawSleepBitmap() void drawSleepBitmap()
{ {
lcdClear(); lcdClear();
lcdDrawAlphaBitmap((LCD_W-SLEEP_BITMAP_WIDTH)/2, (LCD_H-SLEEP_BITMAP_HEIGHT)/2, LBM_SLEEP); lcdDrawBitmap((LCD_W-SLEEP_BITMAP_WIDTH)/2, (LCD_H-SLEEP_BITMAP_HEIGHT)/2, LBM_SLEEP);
lcdRefresh(); lcdRefresh();
} }

View file

@ -78,7 +78,7 @@ void drawSleepBitmap();
void drawShutdownBitmap(uint32_t index); void drawShutdownBitmap(uint32_t index);
// Main view standard widgets // Main view standard widgets
void drawMainViewTopBar(); void drawTopBar();
void drawMainPots(); void drawMainPots();
void drawTrims(uint8_t flightMode); void drawTrims(uint8_t flightMode);

View file

@ -63,9 +63,9 @@ void GaugeWidget::refresh()
// Gauge // Gauge
lcdSetColor(color); lcdSetColor(color);
lcdDrawSolidFilledRect(zone.x, zone.y + 15, zone.w, 16, TEXT_INVERTED_COLOR); lcdDrawSolidFilledRect(zone.x, zone.y + 16, zone.w, 16, TEXT_INVERTED_COLOR);
lcdDrawNumber((percent >= 100 ? 20 : (percent >= 10 ? 10 : 0)) + zone.x+zone.w/2, zone.y + 16, percent, SMLSIZE | CUSTOM_COLOR, 0, NULL, "%"); lcdDrawNumber((percent >= 100 ? 20 : (percent >= 10 ? 10 : 0)) + zone.x+zone.w/2, zone.y + 17, percent, SMLSIZE | CUSTOM_COLOR, 0, NULL, "%");
lcdInvertRect(zone.x + w, zone.y + 15, zone.w - w, 16, CUSTOM_COLOR); lcdInvertRect(zone.x + w, zone.y + 16, zone.w - w, 16, CUSTOM_COLOR);
} }
BaseWidgetFactory<GaugeWidget> gaugeWidget("Gauge", GaugeWidget::options); BaseWidgetFactory<GaugeWidget> gaugeWidget("Gauge", GaugeWidget::options);

View file

@ -20,10 +20,10 @@
#include "opentx.h" #include "opentx.h"
class ModelPanelWidget: public Widget class ModelBitmapWidget: public Widget
{ {
public: public:
ModelPanelWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData): ModelBitmapWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData):
Widget(factory, zone, persistentData) Widget(factory, zone, persistentData)
{ {
} }
@ -31,26 +31,24 @@ class ModelPanelWidget: public Widget
virtual void refresh(); virtual void refresh();
}; };
void ModelPanelWidget::refresh() void ModelBitmapWidget::refresh()
{ {
if (zone.h >= MODEL_BITMAP_HEIGHT) { if (zone.h >= MODEL_BITMAP_HEIGHT) {
lcdDrawFilledRect(zone.x, zone.y, zone.w, zone.h, SOLID, MAINVIEW_PANES_COLOR | OPACITY(5)); lcdDrawFilledRect(zone.x, zone.y, zone.w, zone.h, SOLID, MAINVIEW_PANES_COLOR | OPACITY(5));
lcdDrawBitmapPattern(zone.x + 6, zone.y + 4, LBM_MODEL_ICON, MAINVIEW_GRAPHICS_COLOR); lcdDrawBitmapPattern(zone.x + 6, zone.y + 4, LBM_MODEL_ICON, MAINVIEW_GRAPHICS_COLOR);
lcdDrawSizedText(zone.x + 45, zone.y + 10, g_model.header.name, LEN_MODEL_NAME, ZCHAR | SMLSIZE); lcdDrawSizedText(zone.x + 45, zone.y + 10, g_model.header.name, LEN_MODEL_NAME, ZCHAR | SMLSIZE);
lcdDrawSolidFilledRect(zone.x + 39, zone.y + 27, zone.w - 48, 2, MAINVIEW_GRAPHICS_COLOR); lcdDrawSolidFilledRect(zone.x + 39, zone.y + 27, zone.w - 48, 2, MAINVIEW_GRAPHICS_COLOR);
int scale = getBitmapScale(modelBitmap, zone.w, zone.h - 25); float scale = getBitmapScale(modelBitmap, zone.w, zone.h - 25);
int width = getBitmapScaledSize(getBitmapWidth(modelBitmap), scale); int width = getBitmapScaledSize(getBitmapWidth(modelBitmap), scale);
int height = getBitmapScaledSize(getBitmapHeight(modelBitmap), scale); int height = getBitmapScaledSize(getBitmapHeight(modelBitmap), scale);
lcdDrawBitmap(zone.x + (zone.w - width) / 2, zone.y + zone.h - height / 2 - height / 2, modelBitmap, 0, 0, scale); lcdDrawBitmap(zone.x + (zone.w - width) / 2, zone.y + zone.h - height / 2 - height / 2, modelBitmap, 0, 0, scale);
} }
else { else {
int scale = getBitmapScale(modelBitmap, zone.w, zone.h); float scale = getBitmapScale(modelBitmap, 1000, zone.h);
int width = getBitmapScaledSize(getBitmapWidth(modelBitmap), scale); int width = getBitmapScaledSize(getBitmapWidth(modelBitmap), scale);
int height = getBitmapScaledSize(getBitmapHeight(modelBitmap), scale); int height = getBitmapScaledSize(getBitmapHeight(modelBitmap), scale);
lcdDrawFilledRect(zone.x, zone.y, zone.w, height, SOLID, MAINVIEW_PANES_COLOR | OPACITY(5)); lcdDrawBitmap(zone.x + (zone.w - width) / 2, zone.y + (zone.h - height) / 2, modelBitmap, 0, 0, scale);
lcdDrawSizedText(zone.x + 5, zone.y + 10, g_model.header.name, LEN_MODEL_NAME, ZCHAR | SMLSIZE);
lcdDrawBitmap(zone.x + zone.w - width, zone.y, modelBitmap, 0, 0, scale);
} }
} }
BaseWidgetFactory<ModelPanelWidget> modelPanelWidget("ModelPanel", NULL); BaseWidgetFactory<ModelBitmapWidget> modelBitmapWidget("ModelBmp", NULL);

View file

@ -41,12 +41,16 @@ const ZoneOption TimerWidget::options[] = {
void TimerWidget::refresh() void TimerWidget::refresh()
{ {
uint32_t index = persistentData->options[0].unsignedValue; uint32_t index = persistentData->options[0].unsignedValue;
TimerData & timerData = g_model.timers[index]; TimerData & timerData = g_model.timers[index];
TimerState & timerState = timersStates[index]; TimerState & timerState = timersStates[index];
if (zone.w >= 180 && zone.h >= 70) {
lcdDrawBitmapPattern(zone.x, zone.y, LBM_TIMER_BACKGROUND, MAINVIEW_PANES_COLOR); lcdDrawBitmapPattern(zone.x, zone.y, LBM_TIMER_BACKGROUND, MAINVIEW_PANES_COLOR);
if (timerData.start) { if (timerData.start) {
lcdDrawBitmapPatternPie(zone.x+2, zone.y+3, LBM_RSCALE, MAINVIEW_GRAPHICS_COLOR, 0, timerState.val <= 0 ? 360 : 360*(timerData.start-timerState.val)/timerData.start); lcdDrawBitmapPatternPie(
zone.x + 2,
zone.y + 3, LBM_RSCALE, MAINVIEW_GRAPHICS_COLOR, 0,
timerState.val <= 0 ? 360 : 360 * (timerData.start - timerState.val) / timerData.start);
} }
else { else {
lcdDrawBitmapPattern(zone.x + 3, zone.y + 4, LBM_TIMER, MAINVIEW_GRAPHICS_COLOR); lcdDrawBitmapPattern(zone.x + 3, zone.y + 4, LBM_TIMER, MAINVIEW_GRAPHICS_COLOR);
@ -57,5 +61,15 @@ void TimerWidget::refresh()
} }
drawStringWithIndex(zone.x + 137, zone.y + 17, "TMR", index + 1, SMLSIZE | TEXT_COLOR); drawStringWithIndex(zone.x + 137, zone.y + 17, "TMR", index + 1, SMLSIZE | TEXT_COLOR);
} }
else {
drawStringWithIndex(zone.x, zone.y, "TMR", index + 1, SMLSIZE | TEXT_INVERTED_COLOR);
if (zone.w > 100) {
putsTimer(zone.x, zone.y + 16, abs(timerState.val), TEXT_INVERTED_COLOR | LEFT | MIDSIZE);
}
else {
putsTimer(zone.x, zone.y + 14, abs(timerState.val), TEXT_INVERTED_COLOR | LEFT);
}
}
}
BaseWidgetFactory<TimerWidget> timerWidget("Timer", TimerWidget::options); BaseWidgetFactory<TimerWidget> timerWidget("Timer", TimerWidget::options);

View file

@ -44,23 +44,35 @@ void ValueWidget::refresh()
mixsrc_t field = persistentData->options[0].unsignedValue; mixsrc_t field = persistentData->options[0].unsignedValue;
LcdFlags color = TEXT_COLOR; LcdFlags color = TEXT_INVERTED_COLOR;
int x = zone.x; int x = zone.x;
int y = zone.y; int y = zone.y;
lcdDrawFilledRect(zone.x, zone.y, zone.w, zone.h, SOLID, MAINVIEW_PANES_COLOR | OPACITY(5)); // lcdDrawFilledRect(zone.x, zone.y, zone.w, zone.h, SOLID, MAINVIEW_PANES_COLOR | OPACITY(5));
int xValue, yValue; int xValue, yValue, xLabel, yLabel;
LcdFlags attr; LcdFlags attrValue, attrLabel=0;
if (zone.h < 50) { if (zone.w < 120 && zone.h < 50) {
xValue = x;
yValue = y+14;
xLabel = x;
yLabel = y;
attrValue = LEFT | NO_UNIT | MIDSIZE;
attrLabel = SMLSIZE;
}
else if (zone.h < 50) {
xValue = x+zone.w-NUMBERS_PADDING; xValue = x+zone.w-NUMBERS_PADDING;
yValue = y-2; yValue = y-2;
attr = NO_UNIT; xLabel = x+NUMBERS_PADDING;
yLabel = y+2;
attrValue = NO_UNIT | DBLSIZE;
} }
else { else {
xValue = x+NUMBERS_PADDING; xValue = x+NUMBERS_PADDING;
yValue = y+16; yValue = y+16;
attr = LEFT; xLabel = x+NUMBERS_PADDING;
yLabel = y+2;
attrValue = LEFT | DBLSIZE;
} }
if (field >= MIXSRC_FIRST_TIMER && field <= MIXSRC_LAST_TIMER) { if (field >= MIXSRC_FIRST_TIMER && field <= MIXSRC_LAST_TIMER) {
@ -69,7 +81,7 @@ void ValueWidget::refresh()
color = ALARM_COLOR; color = ALARM_COLOR;
} }
putsMixerSource(x+NUMBERS_PADDING, y+2, field, color); putsMixerSource(x+NUMBERS_PADDING, y+2, field, color);
putsTimer(xValue, yValue, abs(timerState.val), attr|DBLSIZE|color); putsTimer(xValue, yValue, abs(timerState.val), attrValue|DBLSIZE|color);
return; return;
} }
@ -83,8 +95,8 @@ void ValueWidget::refresh()
} }
} }
putsMixerSource(x+NUMBERS_PADDING, y+2, field, color); putsMixerSource(xLabel, yLabel, field, attrLabel|color);
putsChannel(xValue, yValue, field, attr|DBLSIZE|color); putsChannel(xValue, yValue, field, attrValue|color);
} }
BaseWidgetFactory<ValueWidget> ValueWidget("Value", ValueWidget::options); BaseWidgetFactory<ValueWidget> ValueWidget("Value", ValueWidget::options);

View file

@ -0,0 +1,133 @@
/*
* 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.
*/
#ifndef _WIDGETS_CONTAINER_H_
#define _WIDGETS_CONTAINER_H_
#include "widget.h"
class WidgetsContainerInterface
{
public:
virtual unsigned int getZonesCount() const = 0;
virtual Zone getZone(unsigned int index) const = 0;
inline Widget * getWidget(unsigned int index)
{
return widgets[index];
}
inline void setWidget(unsigned int index, Widget * widget)
{
widgets[index] = widget;
}
virtual void createWidget(unsigned int index, const WidgetFactory * factory) = 0;
protected:
Widget ** widgets;
};
template<int N, int O>
class WidgetsContainer: public WidgetsContainerInterface
{
public:
struct ZonePersistentData {
char widgetName[10];
Widget::PersistentData widgetData;
};
struct PersistentData {
ZonePersistentData zones[N];
ZoneOptionValue options[O];
};
public:
WidgetsContainer(PersistentData * persistentData):
persistentData(persistentData)
{
widgets = (Widget **)calloc(N, sizeof(Widget *));
}
virtual ~WidgetsContainer()
{
if (widgets) {
for (uint8_t i=0; i<N; i++) {
delete widgets[i];
}
free(widgets);
}
}
virtual void createWidget(unsigned int index, const WidgetFactory * factory)
{
if (widgets) {
memset(persistentData->zones[index].widgetName, 0, sizeof(persistentData->zones[index].widgetName));
strncpy(persistentData->zones[index].widgetName, factory->getName(), sizeof(persistentData->zones[index].widgetName));
widgets[index] = factory->create(getZone(index), &persistentData->zones[index].widgetData);
}
}
virtual void create()
{
memset(persistentData, 0, sizeof(PersistentData));
}
virtual void load()
{
if (widgets) {
unsigned int count = getZonesCount();
for (unsigned int i=0; i<count; i++) {
if (persistentData->zones[i].widgetName[0]) {
char name[sizeof(persistentData->zones[i].widgetName)+1];
memset(name, 0, sizeof(name));
strncpy(name, persistentData->zones[i].widgetName, sizeof(persistentData->zones[i].widgetName));
widgets[i] = loadWidget(name, getZone(i), &persistentData->zones[i].widgetData);
}
}
}
}
inline ZoneOptionValue * getOptionValue(unsigned int index) const
{
return &persistentData->options[index];
}
virtual unsigned int getZonesCount() const = 0;
virtual Zone getZone(unsigned int index) const = 0;
virtual void refresh()
{
if (widgets) {
for (int i=0; i<N; i++) {
if (widgets[i]) {
widgets[i]->refresh();
}
}
}
}
protected:
PersistentData * persistentData;
};
#endif // _WIDGETS_CONTAINER_H_

View file

@ -776,13 +776,61 @@ void exec(int function, int nresults=0)
} }
} }
ZoneOption * createOptionsArray(int reference)
{
if (reference == 0) {
return NULL;
}
int count = 0;
lua_rawgeti(L, LUA_REGISTRYINDEX, reference);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
count++;
}
ZoneOption * options = (ZoneOption *)malloc(sizeof(ZoneOption) * (count+1));
lua_rawgeti(L, LUA_REGISTRYINDEX, reference);
ZoneOption * option = options;
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TTABLE); // value is table
uint8_t field = 0;
for (lua_pushnil(L); lua_next(L, -2) && field<3; lua_pop(L, 1), field++) {
switch (field) {
case 0:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TSTRING); // value is string
option->name = lua_tostring(L, -1);
break;
case 1:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TNUMBER); // value is number
option->type = (ZoneOption::Type)lua_tointeger(L, -1);
break;
case 2:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TNUMBER); // value is number
option->deflt.signedValue = lua_tointeger(L, -1);
break;
}
}
TRACE("option %s %d %d", option->name, option->type, option->deflt.signedValue);
option++;
}
option->name = NULL; // sentinel
return options;
}
class LuaTheme: public Theme class LuaTheme: public Theme
{ {
friend void luaLoadThemeCallback(); friend void luaLoadThemeCallback();
public: public:
LuaTheme(const char * name, const uint8_t * bitmap): LuaTheme(const char * name, const uint8_t * bitmap, int options):
Theme(name, bitmap), Theme(name, bitmap, createOptionsArray(options)),
loadFunction(0), loadFunction(0),
drawBackgroundFunction(0), drawBackgroundFunction(0),
drawTopbarBackgroundFunction(0), drawTopbarBackgroundFunction(0),
@ -823,7 +871,7 @@ class LuaTheme: public Theme
void luaLoadThemeCallback() void luaLoadThemeCallback()
{ {
const char * name=NULL, * bitmap=NULL; const char * name=NULL, * bitmap=NULL;
int loadFunction=0, drawBackgroundFunction=0, drawTopbarBackgroundFunction=0; int themeOptions=0, loadFunction=0, drawBackgroundFunction=0, drawTopbarBackgroundFunction=0;
luaL_checktype(L, -1, LUA_TTABLE); luaL_checktype(L, -1, LUA_TTABLE);
@ -835,6 +883,10 @@ void luaLoadThemeCallback()
else if (!strcmp(key, "bitmap")) { else if (!strcmp(key, "bitmap")) {
bitmap = luaL_checkstring(L, -1); bitmap = luaL_checkstring(L, -1);
} }
else if (!strcmp(key, "options")) {
themeOptions = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L);
}
else if (!strcmp(key, "load")) { else if (!strcmp(key, "load")) {
loadFunction = luaL_ref(L, LUA_REGISTRYINDEX); loadFunction = luaL_ref(L, LUA_REGISTRYINDEX);
lua_pushnil(L); lua_pushnil(L);
@ -854,8 +906,9 @@ void luaLoadThemeCallback()
strcpy(path, THEMES_PATH "/"); strcpy(path, THEMES_PATH "/");
strcpy(path+sizeof(THEMES_PATH), bitmap); strcpy(path+sizeof(THEMES_PATH), bitmap);
uint8_t * bitmapData = (uint8_t *)malloc(BITMAP_BUFFER_SIZE(51, 31)); uint8_t * bitmapData = (uint8_t *)malloc(BITMAP_BUFFER_SIZE(51, 31));
TRACE("path=%s bitmapData=%p %d %p", path, bitmapData, BITMAP_BUFFER_SIZE(51, 31), path);
bmpLoad(bitmapData, path, 51, 31); bmpLoad(bitmapData, path, 51, 31);
LuaTheme * theme = new LuaTheme(name, bitmapData); LuaTheme * theme = new LuaTheme(name, bitmapData, themeOptions);
theme->loadFunction = loadFunction; theme->loadFunction = loadFunction;
theme->drawBackgroundFunction = drawBackgroundFunction; theme->drawBackgroundFunction = drawBackgroundFunction;
theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction;
@ -882,55 +935,6 @@ class LuaWidget: public Widget
int widgetData; int widgetData;
}; };
ZoneOption * createOptionsArray(int reference)
{
int count = 0;
lua_rawgeti(L, LUA_REGISTRYINDEX, reference);
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
count++;
}
ZoneOption * options = (ZoneOption *)malloc(sizeof(ZoneOption) * (count+1));
lua_rawgeti(L, LUA_REGISTRYINDEX, reference);
ZoneOption * option = options;
for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) {
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TTABLE); // value is table
// const char * key = NULL;
// ZoneOption::Type type = ZoneOption::Integer;
// int val = 0;
uint8_t field = 0;
for (lua_pushnil(L); lua_next(L, -2) && field<3; lua_pop(L, 1), field++) {
switch (field) {
case 0:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TSTRING); // value is string
option->name = lua_tostring(L, -1);
break;
case 1:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TNUMBER); // value is number
option->type = (ZoneOption::Type)lua_tointeger(L, -1);
break;
case 2:
luaL_checktype(L, -2, LUA_TNUMBER); // key is number
luaL_checktype(L, -1, LUA_TNUMBER); // value is number
option->deflt.signedValue = lua_tointeger(L, -1);
break;
}
}
// TRACE("option[%d] = %s %d %d", i, key, type, val);
option++;
// options[i++]. = (ZoneOption) { key, type, { .signedValue = val } };
}
option->name = NULL; // sentinel
return options;
}
void l_pushtableint(const char * key, int value) void l_pushtableint(const char * key, int value)
{ {
lua_pushstring(L, key); lua_pushstring(L, key);
@ -998,7 +1002,7 @@ void LuaWidget::refresh()
void luaLoadWidgetCallback() void luaLoadWidgetCallback()
{ {
const char * name=NULL, * options=NULL; const char * name=NULL;
int widgetOptions=0, createFunction=0, refreshFunction=0; int widgetOptions=0, createFunction=0, refreshFunction=0;
luaL_checktype(L, -1, LUA_TTABLE); luaL_checktype(L, -1, LUA_TTABLE);
@ -1071,6 +1075,7 @@ void luaLoadFiles(const char * directory, void (*callback)())
int pathlen = strlen(path); int pathlen = strlen(path);
FRESULT res = f_opendir(&dir, path); /* Open the directory */ FRESULT res = f_opendir(&dir, path); /* Open the directory */
if (res == FR_OK) { if (res == FR_OK) {
path[pathlen++] = '/'; path[pathlen++] = '/';
for (;;) { for (;;) {
@ -1078,12 +1083,15 @@ void luaLoadFiles(const char * directory, void (*callback)())
if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */
fn = * fno.lfname ? fno.lfname : fno.fname; fn = * fno.lfname ? fno.lfname : fno.fname;
uint8_t len = strlen(fn); uint8_t len = strlen(fn);
// Eliminates directories / non wav files // Eliminates directories / non scripts files
if (len < 5 || strcasecmp(fn+len-4, SCRIPTS_EXT) || (fno.fattrib & AM_DIR)) continue; if (len < 5 || strcasecmp(fn+len-4, SCRIPTS_EXT) || (fno.fattrib & AM_DIR)) continue;
strcpy(&path[pathlen], fn); strcpy(&path[pathlen], fn);
luaLoadFile(path, callback); luaLoadFile(path, callback);
} }
} }
else {
TRACE("f_opendir(%s) failed, code=%d", path, res);
}
} }
#endif #endif

View file

@ -440,8 +440,7 @@ enum UartModes {
char anaNames[NUM_STICKS+NUM_POTS][LEN_ANA_NAME]; \ char anaNames[NUM_STICKS+NUM_POTS][LEN_ANA_NAME]; \
char currModelFilename[LEN_MODEL_FILENAME+1]; \ char currModelFilename[LEN_MODEL_FILENAME+1]; \
uint8_t bluetoothEnable; \ uint8_t bluetoothEnable; \
char bluetoothName[LEN_BLUETOOTH_NAME]; \ char bluetoothName[LEN_BLUETOOTH_NAME];
char themeName[8];
#elif defined(PCBFLAMENCO) #elif defined(PCBFLAMENCO)
#define LEN_SWITCH_NAME 3 #define LEN_SWITCH_NAME 3
#define LEN_ANA_NAME 3 #define LEN_ANA_NAME 3
@ -840,6 +839,31 @@ PACK(typedef struct {
#endif #endif
#define ALTERNATE_VIEW 0x10 #define ALTERNATE_VIEW 0x10
#if defined(COLORLCD)
#include "layout.h"
#include "theme.h"
#include "topbar.h"
#define SWITCHES_WARNING_DATA \
swarnstate_t switchWarningState;
PACK(typedef struct {
char layoutName[10];
Layout::PersistentData layoutData;
}) CustomScreenData;
#define CUSTOM_SCREENS_DATA \
CustomScreenData screenData[MAX_CUSTOM_SCREENS]; \
Topbar::PersistentData topbarData;
#define THEME_DATA \
char themeName[8]; \
Theme::PersistentData themeData;
#else
#define SWITCHES_WARNING_DATA \
swarnstate_t switchWarningState; \
swarnenable_t switchWarningEnable;
#define CUSTOM_SCREENS_DATA
#define THEME_DATA
#endif
PACK(typedef struct { PACK(typedef struct {
uint8_t version; uint8_t version;
uint16_t variant; uint16_t variant;
@ -885,6 +909,8 @@ PACK(typedef struct {
EXTRA_GENERAL_FIELDS EXTRA_GENERAL_FIELDS
THEME_DATA
}) EEGeneral; }) EEGeneral;
#define SWITCHES_DELAY() uint8_t(15+g_eeGeneral.switchesDelay) #define SWITCHES_DELAY() uint8_t(15+g_eeGeneral.switchesDelay)
@ -2288,23 +2314,6 @@ enum DisplayTrims
DISPLAY_TRIMS_ALWAYS DISPLAY_TRIMS_ALWAYS
}; };
#if defined(COLORLCD)
#include "layout.h"
#define SWITCHES_WARNING_DATA \
swarnstate_t switchWarningState;
PACK(typedef struct {
char layoutName[10];
Layout::PersistentData layoutData;
}) CustomScreenData;
#define CUSTOM_SCREENS_DATA \
CustomScreenData screenData[MAX_CUSTOM_SCREENS];
#else
#define SWITCHES_WARNING_DATA \
swarnstate_t switchWarningState; \
swarnenable_t switchWarningEnable;
#define CUSTOM_SCREENS_DATA
#endif
PACK(typedef struct { PACK(typedef struct {
ModelHeader header; ModelHeader header;
TimerData timers[MAX_TIMERS]; TimerData timers[MAX_TIMERS];

View file

@ -2469,15 +2469,25 @@ uint16_t stackAvailable()
void opentxInit(OPENTX_INIT_ARGS) void opentxInit(OPENTX_INIT_ARGS)
{ {
#if defined(DEBUG) && defined(USB_SERIAL)
CoTickDelay(5000); // 10s
#endif
TRACE("opentxInit()"); TRACE("opentxInit()");
sdInit();
#if defined(COLORLCD) #if defined(COLORLCD)
topbar = new Topbar(&g_model.topbarData);
luaInit(); luaInit();
loadTheme();
#endif #endif
storageReadAll(); storageReadAll();
#if defined(COLORLCD)
loadTheme();
#endif
#if defined(CPUARM) #if defined(CPUARM)
if (UNEXPECTED_SHUTDOWN()) { if (UNEXPECTED_SHUTDOWN()) {
unexpectedShutdown = 1; unexpectedShutdown = 1;

View file

@ -352,7 +352,6 @@ long Open9xSim::onTimeout(FXObject*, FXSelector, void*)
updateKeysAndSwitches(); updateKeysAndSwitches();
#if defined(PCBHORUS) #if defined(PCBHORUS)
extern rotenc_t rotencValue;
#define ROTENC_VALUE rotencValue #define ROTENC_VALUE rotencValue
#else #else
#define ROTENC_VALUE g_rotenc[0] #define ROTENC_VALUE g_rotenc[0]

View file

@ -337,12 +337,17 @@ void * main_thread(void *)
menuHandlers[1] = menuModelSelect; menuHandlers[1] = menuModelSelect;
#if defined(COLORLCD) #if defined(COLORLCD)
topbar = new Topbar(&g_model.topbarData);
luaInit(); luaInit();
loadTheme(); // TODO the theme is not initialized, in case of sdcard error, we should have something strange
#endif #endif
storageReadAll(); // load general setup and selected model storageReadAll(); // load general setup and selected model
#if defined(COLORLCD)
loadTheme();
#endif
#if defined(SIMU_DISKIO) #if defined(SIMU_DISKIO)
f_mount(&g_FATFS_Obj, "", 1); f_mount(&g_FATFS_Obj, "", 1);
// call sdGetFreeSectors() now because f_getfree() takes a long time first time it's called // call sdGetFreeSectors() now because f_getfree() takes a long time first time it's called

View file

@ -222,6 +222,7 @@ uint32_t readTrims(void);
#if defined(REV9E) #if defined(REV9E)
// Rotary Encoder driver // Rotary Encoder driver
extern int32_t rotencValue;
void rotencInit(void); void rotencInit(void);
void rotencEnd(void); void rotencEnd(void);
void checkRotaryEncoder(void); void checkRotaryEncoder(void);

View file

@ -951,8 +951,8 @@
#define TR_BYTES "bytes" #define TR_BYTES "bytes"
#define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind")) #define TR_MODULE_BIND BUTTON(TR("Bnd", "Bind"))
#define TR_MODULE_RANGE BUTTON(TR("Rng", "Range")) #define TR_MODULE_RANGE BUTTON(TR("Rng", "Range"))
#define TR_RESET_BTN "[Reset]" #define TR_RESET_BTN BUTTON("Reset")
#define TR_SET "[Set]" #define TR_SET BUTTON("Set")
#define TR_TRAINER "Trainer Port" #define TR_TRAINER "Trainer Port"
#define TR_ANTENNAPROBLEM CENTER "TX Antenna problem!" #define TR_ANTENNAPROBLEM CENTER "TX Antenna problem!"
#define TR_MODELIDUSED TR("ID already used","Model ID already used") #define TR_MODELIDUSED TR("ID already used","Model ID already used")