Merge pull request #193 from EdgeTX/theme-facelift
Default Theme facelift
This commit is contained in:
@@ -58,18 +58,30 @@ class MixerChannelBar : public ChannelBar
|
||||
chanVal = limit<int>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
|
||||
|
||||
// Draw Background
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), BARGRAPH_BGCOLOR);
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), FIELD_BGCOLOR);
|
||||
|
||||
// Draw mixer bar
|
||||
if (chanVal > 0) {
|
||||
dc->drawSolidFilledRect(0 + width() / 2, 0, divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2), height(), BARGRAPH2_COLOR);
|
||||
dc->drawNumber(width() / 2 - 10, 0, displayVal, FONT(XS) | DEFAULT_COLOR | RIGHT, 0, nullptr, "%");
|
||||
}
|
||||
else if (chanVal < 0) {
|
||||
|
||||
dc->drawSolidFilledRect(
|
||||
0 + width() / 2, 0,
|
||||
divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2),
|
||||
height(), FOCUS_BGCOLOR);
|
||||
|
||||
dc->drawNumber(width() / 2 - 10, 0, displayVal,
|
||||
FONT(XS) | DEFAULT_COLOR | RIGHT, 0, nullptr, "%");
|
||||
|
||||
} else if (chanVal < 0) {
|
||||
|
||||
const unsigned endpoint = width() / 2;
|
||||
const unsigned size = divRoundClosest(-chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2);
|
||||
dc->drawSolidFilledRect(endpoint - size, 0, size, height(), BARGRAPH2_COLOR);
|
||||
dc->drawNumber(10 + width() / 2, 0, displayVal, FONT(XS) | DEFAULT_COLOR, 0, nullptr, "%");
|
||||
const unsigned size =
|
||||
divRoundClosest(-chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2);
|
||||
|
||||
dc->drawSolidFilledRect(endpoint - size, 0, size, height(),
|
||||
FOCUS_BGCOLOR);
|
||||
|
||||
dc->drawNumber(10 + width() / 2, 0, displayVal,
|
||||
FONT(XS) | DEFAULT_COLOR, 0, nullptr, "%");
|
||||
}
|
||||
|
||||
// Draw middle bar
|
||||
@@ -100,36 +112,47 @@ class OutputChannelBar : public ChannelBar
|
||||
int chanVal = calcRESXto100(channelOutputs[channel]);
|
||||
int displayVal = chanVal;
|
||||
|
||||
chanVal = limit<int>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
|
||||
chanVal = limit<int>(-VIEW_CHANNELS_LIMIT_PCT, chanVal,
|
||||
VIEW_CHANNELS_LIMIT_PCT);
|
||||
|
||||
// Draw Background
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), BARGRAPH_BGCOLOR);
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), FIELD_BGCOLOR);
|
||||
|
||||
// Draw output bar
|
||||
if (chanVal > 0) {
|
||||
dc->drawSolidFilledRect(width() / 2, 0, divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2), height(), BARGRAPH1_COLOR);
|
||||
dc->drawNumber(width() / 2 - 10, 0, displayVal, FONT(XS) | DEFAULT_COLOR | RIGHT, 0, nullptr, "%");
|
||||
}
|
||||
else if (chanVal < 0) {
|
||||
|
||||
dc->drawSolidFilledRect(
|
||||
width() / 2, 0,
|
||||
divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2),
|
||||
height(), HIGHLIGHT_COLOR);
|
||||
|
||||
dc->drawNumber(width() / 2 - 10, 0, displayVal,
|
||||
FONT(XS) | DEFAULT_COLOR | RIGHT, 0, nullptr, "%");
|
||||
|
||||
} else if (chanVal < 0) {
|
||||
unsigned endpoint = width() / 2;
|
||||
unsigned size = divRoundClosest(-chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2);
|
||||
dc->drawSolidFilledRect(endpoint - size, 0, size, height(), BARGRAPH1_COLOR);
|
||||
dc->drawNumber(width() / 2 + 10, 0, displayVal, FONT(XS) | DEFAULT_COLOR, 0, nullptr, "%");
|
||||
unsigned size =
|
||||
divRoundClosest(-chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2);
|
||||
|
||||
dc->drawSolidFilledRect(endpoint - size, 0, size, height(),
|
||||
HIGHLIGHT_COLOR);
|
||||
|
||||
dc->drawNumber(width() / 2 + 10, 0, displayVal,
|
||||
FONT(XS) | DEFAULT_COLOR, 0, nullptr, "%");
|
||||
}
|
||||
|
||||
// Draw middle bar
|
||||
dc->drawSolidVerticalLine(width() / 2, 0, height(), DEFAULT_COLOR);
|
||||
|
||||
// Draw output limits bars
|
||||
LimitData * ld = limitAddress(channel);
|
||||
LimitData* ld = limitAddress(channel);
|
||||
if (ld && ld->revert) {
|
||||
drawOutputBarLimits(dc, posOnBar(-100 - ld->max / 10), posOnBar(100 - ld->min / 10));
|
||||
//lcd->drawBitmap(x - X_OFFSET + 7, y + 25, chanMonInvertedBitmap);
|
||||
drawOutputBarLimits(dc, posOnBar(-100 - ld->max / 10),
|
||||
posOnBar(100 - ld->min / 10));
|
||||
} else if (ld) {
|
||||
drawOutputBarLimits(dc, posOnBar(-100 + ld->min / 10),
|
||||
posOnBar(100 + ld->max / 10));
|
||||
}
|
||||
else if (ld) {
|
||||
drawOutputBarLimits(dc, posOnBar(-100 + ld->min / 10), posOnBar(100 + ld->max / 10));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inline unsigned posOnBar(int value_to100)
|
||||
@@ -193,13 +216,13 @@ class ComboChannelBar : public ChannelBar
|
||||
// Override icon
|
||||
#if defined(OVERRIDE_CHANNEL_FUNCTION)
|
||||
if (safetyCh[channel] != OVERRIDE_CHANNEL_UNDEFINED)
|
||||
dc->drawBitmap(0, 1, chanMonLockedBitmap);
|
||||
dc->drawMask(0, 1, chanMonLockedBitmap, DEFAULT_COLOR);
|
||||
#endif
|
||||
|
||||
// Channel reverted icon
|
||||
LimitData * ld = limitAddress(channel);
|
||||
if (ld && ld->revert) {
|
||||
lcd->drawBitmap(0, 20, chanMonInvertedBitmap);
|
||||
lcd->drawMask(0, 20, chanMonInvertedBitmap, DEFAULT_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,4 +238,4 @@ class ComboChannelBar : public ChannelBar
|
||||
|
||||
protected:
|
||||
int value = 0;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -27,50 +27,58 @@
|
||||
// TODO common code, not in target
|
||||
enum LcdColorIndex
|
||||
{
|
||||
DEFAULT_COLOR_INDEX,
|
||||
DEFAULT_BGCOLOR_INDEX,
|
||||
FOCUS_COLOR_INDEX,
|
||||
FOCUS_BGCOLOR_INDEX,
|
||||
TEXT_STATUSBAR_COLOR_INDEX,
|
||||
LINE_COLOR_INDEX,
|
||||
MENU_LINE_COLOR_INDEX = LINE_COLOR_INDEX,
|
||||
CHECKBOX_COLOR_INDEX,
|
||||
SCROLLBAR_COLOR_INDEX,
|
||||
MENU_BGCOLOR_INDEX,
|
||||
MENU_HIGHLIGHT_BGCOLOR_INDEX /*= MENU_BGCOLOR_INDEX*/,
|
||||
MENU_COLOR_INDEX,
|
||||
MENU_TITLE_DISABLE_COLOR_INDEX,
|
||||
HEADER_COLOR_INDEX,
|
||||
ALARM_COLOR_INDEX,
|
||||
HIGHLIGHT_COLOR_INDEX,
|
||||
MENU_HIGHLIGHT_COLOR_INDEX = HIGHLIGHT_COLOR_INDEX,
|
||||
TEXT_DISABLE_COLOR_INDEX,
|
||||
DISABLE_COLOR_INDEX,
|
||||
CURVE_COLOR_INDEX,
|
||||
CURVE_AXIS_COLOR_INDEX,
|
||||
CURVE_CURSOR_COLOR_INDEX,
|
||||
HEADER_BGCOLOR_INDEX,
|
||||
HEADER_ICON_BGCOLOR_INDEX,
|
||||
HEADER_CURRENT_BGCOLOR_INDEX,
|
||||
TITLE_BGCOLOR_INDEX,
|
||||
TRIM_BGCOLOR_INDEX,
|
||||
TRIM_SHADOW_COLOR_INDEX,
|
||||
MAINVIEW_PANES_COLOR_INDEX,
|
||||
MAINVIEW_GRAPHICS_COLOR_INDEX,
|
||||
OVERLAY_COLOR_INDEX,
|
||||
CUSTOM_COLOR_INDEX,
|
||||
BARGRAPH1_COLOR_INDEX,
|
||||
BARGRAPH2_COLOR_INDEX,
|
||||
BARGRAPH_BGCOLOR_INDEX,
|
||||
SCROLLBOX_COLOR_INDEX,
|
||||
TABLE_HEADER_BGCOLOR_INDEX,
|
||||
TABLE_BGCOLOR_INDEX,
|
||||
BATTERY_CHARGE_COLOR_INDEX,
|
||||
CHECKBOX_COLOR_INDEX,
|
||||
CURVE_AXIS_COLOR_INDEX,
|
||||
CURVE_COLOR_INDEX,
|
||||
CURVE_CURSOR_COLOR_INDEX,
|
||||
CUSTOM_COLOR_INDEX,
|
||||
DEFAULT_BGCOLOR_INDEX,
|
||||
DEFAULT_COLOR_INDEX,
|
||||
DISABLE_COLOR_INDEX,
|
||||
EDIT_MARKER_COLOR_INDEX,
|
||||
FIELD_BGCOLOR_INDEX,
|
||||
FIELD_FRAME_COLOR_INDEX,
|
||||
FOCUS_BGCOLOR_INDEX,
|
||||
FOCUS_COLOR_INDEX,
|
||||
HEADER_BGCOLOR_INDEX,
|
||||
HEADER_COLOR_INDEX,
|
||||
HEADER_CURRENT_BGCOLOR_INDEX,
|
||||
HEADER_ICON_BGCOLOR_INDEX,
|
||||
HIGHLIGHT_COLOR_INDEX,
|
||||
LINE_COLOR_INDEX,
|
||||
MENU_HIGHLIGHT_BGCOLOR_INDEX,
|
||||
MAINVIEW_GRAPHICS_COLOR_INDEX,
|
||||
MAINVIEW_PANES_COLOR_INDEX,
|
||||
MENU_BGCOLOR_INDEX,
|
||||
MENU_COLOR_INDEX,
|
||||
MENU_HIGHLIGHT_COLOR_INDEX,
|
||||
MENU_LINE_COLOR_INDEX,
|
||||
MENU_TITLE_DISABLE_COLOR_INDEX,
|
||||
OVERLAY_COLOR_INDEX,
|
||||
SCROLLBAR_COLOR_INDEX,
|
||||
SCROLLBOX_COLOR_INDEX,
|
||||
TABLE_BGCOLOR_INDEX,
|
||||
TABLE_HEADER_BGCOLOR_INDEX,
|
||||
TEXT_DISABLE_COLOR_INDEX,
|
||||
TEXT_STATUSBAR_COLOR_INDEX,
|
||||
TITLE_BGCOLOR_INDEX,
|
||||
TRIM_BGCOLOR_INDEX,
|
||||
TRIM_SHADOW_COLOR_INDEX,
|
||||
|
||||
// this one MUST be last
|
||||
LCD_COLOR_COUNT,
|
||||
};
|
||||
|
||||
|
||||
//#define MENU_HIGHLIGHT_COLOR_INDEX HIGHLIGHT_COLOR_INDEX
|
||||
//#define MENU_LINE_COLOR_INDEX LINE_COLOR_INDEX
|
||||
|
||||
|
||||
//
|
||||
// Basic color definitions
|
||||
//
|
||||
@@ -116,6 +124,9 @@ inline void lcdSetColor(uint16_t color)
|
||||
#define DEFAULT_BGCOLOR COLOR(DEFAULT_BGCOLOR_INDEX)
|
||||
#define DEFAULT_COLOR COLOR(DEFAULT_COLOR_INDEX)
|
||||
#define DISABLE_COLOR COLOR(DISABLE_COLOR_INDEX)
|
||||
#define EDIT_MARKER_COLOR COLOR(EDIT_MARKER_COLOR_INDEX)
|
||||
#define FIELD_BGCOLOR COLOR(FIELD_BGCOLOR_INDEX)
|
||||
#define FIELD_FRAME_COLOR COLOR(FIELD_FRAME_COLOR_INDEX)
|
||||
#define FOCUS_BGCOLOR COLOR(FOCUS_BGCOLOR_INDEX)
|
||||
#define FOCUS_COLOR COLOR(FOCUS_COLOR_INDEX)
|
||||
#define HEADER_BGCOLOR COLOR(HEADER_BGCOLOR_INDEX)
|
||||
|
||||
@@ -27,21 +27,20 @@
|
||||
|
||||
void Curve::drawBackground(BitmapBuffer * dc)
|
||||
{
|
||||
lcdSetColor(RGB(0xE0, 0xE0, 0xE0));
|
||||
dc->clear(CUSTOM_COLOR);
|
||||
dc->clear(FIELD_BGCOLOR);
|
||||
|
||||
// Axis
|
||||
dc->drawSolidHorizontalLine(0, height()/2, width(), DISABLE_COLOR);
|
||||
dc->drawSolidVerticalLine(width()/2, 0, height(), DISABLE_COLOR);
|
||||
dc->drawSolidHorizontalLine(0, height()/2, width(), FIELD_FRAME_COLOR);
|
||||
dc->drawSolidVerticalLine(width()/2, 0, height(), FIELD_FRAME_COLOR);
|
||||
|
||||
// Extra lines
|
||||
dc->drawVerticalLine(width()/4, 0, height(), STASHED, DISABLE_COLOR);
|
||||
dc->drawVerticalLine(width()*3/4, 0, height(), STASHED, DISABLE_COLOR);
|
||||
dc->drawHorizontalLine(0, height()/4, width(), STASHED, DISABLE_COLOR);
|
||||
dc->drawHorizontalLine(0, height()*3/4, width(), STASHED, DISABLE_COLOR);
|
||||
dc->drawVerticalLine(width()/4, 0, height(), STASHED, FIELD_FRAME_COLOR);
|
||||
dc->drawVerticalLine(width()*3/4, 0, height(), STASHED, FIELD_FRAME_COLOR);
|
||||
dc->drawHorizontalLine(0, height()/4, width(), STASHED, FIELD_FRAME_COLOR);
|
||||
dc->drawHorizontalLine(0, height()*3/4, width(), STASHED, FIELD_FRAME_COLOR);
|
||||
|
||||
// Outside border
|
||||
// dc->drawSolidRect(0, 0, width(), height(), 1, DEFAULT_COLOR);
|
||||
dc->drawSolidRect(0, 0, width(), height(), 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
coord_t Curve::getPointX(int x) const
|
||||
@@ -89,17 +88,17 @@ void Curve::drawPosition(BitmapBuffer * dc)
|
||||
coord_t y = getPointY(valueY);
|
||||
|
||||
// the 2 lines
|
||||
dc->drawSolidHorizontalLine(0, y, width(), CURVE_CURSOR_COLOR);
|
||||
dc->drawSolidVerticalLine(x, 0, height(), CURVE_CURSOR_COLOR);
|
||||
dc->drawSolidHorizontalLine(0, y, width(), HIGHLIGHT_COLOR);
|
||||
dc->drawSolidVerticalLine(x, 0, height(), HIGHLIGHT_COLOR);
|
||||
|
||||
// the point (white inside)
|
||||
dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT, CURVE_CURSOR_COLOR);
|
||||
dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT_CENTER, DEFAULT_BGCOLOR);
|
||||
dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT, HIGHLIGHT_COLOR);
|
||||
dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT_CENTER, FOCUS_COLOR);
|
||||
|
||||
char coords[16];
|
||||
strAppendSigned(strAppend(strAppendSigned(coords, calcRESXto100(valueX)), ","), calcRESXto100(valueY));
|
||||
dc->drawSolidFilledRect(10, 11, 1 + getTextWidth(coords, 0, FONT(XS)), 17, CURVE_CURSOR_COLOR);
|
||||
dc->drawText(11, 10, coords, FONT(XS)|DEFAULT_BGCOLOR);
|
||||
dc->drawSolidFilledRect(10, 11, 1 + getTextWidth(coords, 0, FONT(XS)), 17, HIGHLIGHT_COLOR);
|
||||
dc->drawText(11, 10, coords, FONT(XS) | FOCUS_COLOR);
|
||||
}
|
||||
|
||||
void Curve::drawPoint(BitmapBuffer * dc, const CurvePoint & point)
|
||||
|
||||
@@ -42,48 +42,73 @@ void CurveDataEdit::update()
|
||||
grid.setMarginRight(parent->width() - rect.w + 5);
|
||||
|
||||
coord_t boxWidth = rect.w / 5;
|
||||
coord_t boxHeight = (rect.h - 6) / 3;
|
||||
coord_t boxHeight = PAGE_LINE_HEIGHT;
|
||||
|
||||
CurveHeader & curve = g_model.curves[index];
|
||||
uint8_t curvePointsCount = 5 + curve.points;
|
||||
|
||||
// Point number
|
||||
for (uint8_t i = 0; i < curvePointsCount; i++) {
|
||||
new StaticText(this, {i * boxWidth, 10, boxWidth, boxHeight}, std::to_string(i + 1), 0, RIGHT | TEXT_DISABLE_COLOR);
|
||||
auto txt = new StaticText(
|
||||
this,
|
||||
{i * boxWidth + PAGE_PADDING, 10, boxWidth - PAGE_PADDING, boxHeight},
|
||||
std::to_string(i + 1) + " ", 0, RIGHT | DEFAULT_COLOR);
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
}
|
||||
grid.spacer(rect.h / 3);
|
||||
grid.spacer(boxHeight + 10 + PAGE_PADDING);
|
||||
|
||||
// x value
|
||||
if (curve.type == CURVE_TYPE_CUSTOM) {
|
||||
// Adjustable points for custom curves
|
||||
for (uint8_t i = 0; i < curvePointsCount; i++) {
|
||||
int8_t * points = curveAddress(index);
|
||||
auto pointEdit = new NumberEdit(this, {coord_t(PAGE_LINE_SPACING + 1 + i * boxWidth), 10 + boxHeight, coord_t(boxWidth - PAGE_LINE_SPACING), boxHeight - 12},
|
||||
i <= 1 ? -100 : points[curvePointsCount + i - 2],
|
||||
i >= curvePointsCount - 2 ? 100 : points[curvePointsCount + i],
|
||||
GET_VALUE(i == 0 ? -100 : i == curvePointsCount - 1 ? 100 : points[curvePointsCount + i - 1]),
|
||||
[=](int32_t newValue) {
|
||||
points[curvePointsCount + i - 1] = newValue;
|
||||
SET_DIRTY();
|
||||
curveEdit->updatePreview();
|
||||
}, 0, RIGHT);
|
||||
int8_t* points = curveAddress(index);
|
||||
auto pointEdit = new NumberEdit(
|
||||
this,
|
||||
{coord_t(PAGE_LINE_SPACING + 1 + i * boxWidth),
|
||||
grid.getWindowHeight(), coord_t(boxWidth - PAGE_LINE_SPACING),
|
||||
boxHeight},
|
||||
i <= 1 ? -100 : points[curvePointsCount + i - 2],
|
||||
i >= curvePointsCount - 2 ? 100 : points[curvePointsCount + i],
|
||||
GET_VALUE(i == 0 ? -100
|
||||
: i == curvePointsCount - 1
|
||||
? 100
|
||||
: points[curvePointsCount + i - 1]),
|
||||
[=](int32_t newValue) {
|
||||
points[curvePointsCount + i - 1] = newValue;
|
||||
SET_DIRTY();
|
||||
curveEdit->updatePreview();
|
||||
},
|
||||
0, RIGHT);
|
||||
|
||||
if (i == 0 || i == curvePointsCount - 1) {
|
||||
pointEdit->disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (uint8_t i = 0; i < curvePointsCount; i++) {
|
||||
new StaticText(this, {i * boxWidth, 10 + boxHeight, boxWidth, boxHeight}, std::to_string(-100 + 200 * i / (5 + curve.points - 1)), 0, RIGHT | TEXT_DISABLE_COLOR);
|
||||
new StaticText(this, {i * boxWidth, grid.getWindowHeight(), boxWidth, boxHeight},
|
||||
std::to_string(-100 + 200 * i / (5 + curve.points - 1)), 0,
|
||||
RIGHT | DEFAULT_COLOR);
|
||||
}
|
||||
}
|
||||
grid.spacer(boxHeight + PAGE_PADDING);
|
||||
|
||||
// y value
|
||||
for (uint8_t i = 0; i < curvePointsCount; i++) {
|
||||
int8_t * points = curveAddress(index);
|
||||
new NumberEdit(this, {coord_t(PAGE_LINE_SPACING + 1 + i * boxWidth), 10 + 2 * boxHeight, coord_t(boxWidth - PAGE_LINE_SPACING), boxHeight - 12}, -100, 100,
|
||||
GET_VALUE(points[i]), [=](int32_t newValue) { points[i] = newValue; SET_DIRTY(); curveEdit->updatePreview(); }, 0, RIGHT);
|
||||
int8_t* points = curveAddress(index);
|
||||
new NumberEdit(
|
||||
this,
|
||||
{coord_t(PAGE_LINE_SPACING + 1 + i * boxWidth),
|
||||
grid.getWindowHeight(),
|
||||
coord_t(boxWidth - PAGE_LINE_SPACING),
|
||||
boxHeight},
|
||||
-100, 100, GET_VALUE(points[i]),
|
||||
[=](int32_t newValue) {
|
||||
points[i] = newValue;
|
||||
SET_DIRTY();
|
||||
curveEdit->updatePreview();
|
||||
},
|
||||
0, RIGHT);
|
||||
}
|
||||
|
||||
setInnerWidth(curvePointsCount * boxWidth);
|
||||
@@ -92,8 +117,8 @@ void CurveDataEdit::update()
|
||||
void CurveDataEdit::paint(BitmapBuffer * dc)
|
||||
{
|
||||
dc->clear(DEFAULT_BGCOLOR);
|
||||
dc->drawSolidHorizontalLine(0, rect.h / 3, getInnerWidth(), 0);
|
||||
dc->drawSolidHorizontalLine(0, 2 * rect.h / 3, getInnerWidth(), 0);
|
||||
// dc->drawSolidHorizontalLine(0, rect.h / 3, getInnerWidth(), 0);
|
||||
// dc->drawSolidHorizontalLine(0, 2 * rect.h / 3, getInnerWidth(), 0);
|
||||
drawHorizontalScrollbar(dc);
|
||||
}
|
||||
|
||||
@@ -125,35 +150,35 @@ void CurveEdit::updatePreview()
|
||||
invalidate();
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool CurveEdit::onTouchEnd(coord_t x, coord_t y)
|
||||
{
|
||||
if (!hasFocus()) {
|
||||
setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
// #if defined(HARDWARE_TOUCH)
|
||||
// bool CurveEdit::onTouchEnd(coord_t x, coord_t y)
|
||||
// {
|
||||
// if (!hasFocus()) {
|
||||
// setFocus(SET_FOCUS_DEFAULT);
|
||||
// }
|
||||
|
||||
CurveKeyboard::show(this, isCustomCurve());
|
||||
// CurveKeyboard::show(this, isCustomCurve());
|
||||
|
||||
CurveHeader & curve = g_model.curves[index];
|
||||
for (int i=0; i<5 + curve.points; i++) {
|
||||
if (i != current) {
|
||||
point_t point = getPoint(index, i);
|
||||
if (abs(preview.getPointX(point.x) - x) <= 10 && abs(preview.getPointY(point.y) - y) <= 10) {
|
||||
current = i;
|
||||
updatePreview();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// CurveHeader & curve = g_model.curves[index];
|
||||
// for (int i=0; i<5 + curve.points; i++) {
|
||||
// if (i != current) {
|
||||
// point_t point = getPoint(index, i);
|
||||
// if (abs(preview.getPointX(point.x) - x) <= 10 && abs(preview.getPointY(point.y) - y) <= 10) {
|
||||
// current = i;
|
||||
// updatePreview();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
// return true;
|
||||
// }
|
||||
|
||||
void CurveEdit::onFocusLost()
|
||||
{
|
||||
CurveKeyboard::hide();
|
||||
}
|
||||
#endif
|
||||
// void CurveEdit::onFocusLost()
|
||||
// {
|
||||
// CurveKeyboard::hide();
|
||||
// }
|
||||
// #endif
|
||||
|
||||
void CurveEdit::next()
|
||||
{
|
||||
|
||||
@@ -62,11 +62,10 @@ class CurveEdit: public FormField
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
|
||||
void onFocusLost() override;
|
||||
#endif
|
||||
// #if defined(HARDWARE_TOUCH)
|
||||
// bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
// void onFocusLost() override;
|
||||
// #endif
|
||||
|
||||
protected:
|
||||
Curve preview;
|
||||
|
||||
@@ -85,25 +85,26 @@ void TopbarImpl::paint(BitmapBuffer * dc)
|
||||
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);
|
||||
//dc->drawSolidVerticalLine(DATETIME_SEPARATOR_X, 7, 31, MENU_COLOR);
|
||||
dc->drawText(DATETIME_MIDDLE, DATETIME_LINE1, str, FONT(XS) | CENTERED| FOCUS_COLOR);
|
||||
|
||||
getTimerString(str, getValue(MIXSRC_TX_TIME));
|
||||
dc->drawText(DATETIME_MIDDLE, DATETIME_LINE2, str, FONT(XS) | CENTERED | MENU_COLOR);
|
||||
dc->drawText(DATETIME_MIDDLE, DATETIME_LINE2, str, FONT(XS) | CENTERED | FOCUS_COLOR);
|
||||
|
||||
#if defined(INTERNAL_GPS)
|
||||
if (gpsData.fix) {
|
||||
char s[10];
|
||||
sprintf(s, "%d", gpsData.numSat);
|
||||
dc->drawText(LCD_W-148, 4, s, FONT(XS) | CENTERED | MENU_COLOR);
|
||||
dc->drawText(LCD_W-148, 4, s, FONT(XS) | CENTERED | FOCUS_COLOR);
|
||||
}
|
||||
dc->drawBitmapPattern(LCD_W-158, 22, LBM_TOPMENU_GPS, (gpsData.fix) ? MENU_COLOR : MENU_TITLE_DISABLE_COLOR);
|
||||
dc->drawBitmapPattern(LCD_W - 158, 22, LBM_TOPMENU_GPS,
|
||||
(gpsData.fix) ? FOCUS_COLOR : MENU_TITLE_DISABLE_COLOR);
|
||||
#endif
|
||||
|
||||
// USB icon
|
||||
if (usbPlugged()) {
|
||||
|
||||
LcdFlags flags = MENU_COLOR;
|
||||
LcdFlags flags = FOCUS_COLOR;
|
||||
if (getSelectedUsbMode() == USB_UNSELECTED_MODE) {
|
||||
flags = MENU_TITLE_DISABLE_COLOR;
|
||||
}
|
||||
@@ -112,7 +113,7 @@ void TopbarImpl::paint(BitmapBuffer * dc)
|
||||
}
|
||||
// Logs
|
||||
else if (isFunctionActive(FUNCTION_LOGS) && BLINK_ON_PHASE) {
|
||||
dc->drawBitmapPattern(LCD_W - 98, 6, LBM_DOT, MENU_COLOR);
|
||||
dc->drawBitmapPattern(LCD_W - 98, 6, LBM_DOT, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
// RSSI
|
||||
@@ -120,42 +121,45 @@ void TopbarImpl::paint(BitmapBuffer * dc)
|
||||
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);
|
||||
dc->drawSolidFilledRect(LCD_W - 90 + i * 6, 38 - height, 4, height,
|
||||
TELEMETRY_RSSI() >= rssiBarsValue[i]
|
||||
? FOCUS_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);
|
||||
dc->drawBitmapPattern(LCD_W-94, 4, LBM_TOPMENU_ANTENNA, FOCUS_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);
|
||||
dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_0, FOCUS_COLOR);
|
||||
else if (requiredSpeakerVolume < 7)
|
||||
dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_1, MENU_COLOR);
|
||||
dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_1, FOCUS_COLOR);
|
||||
else if (requiredSpeakerVolume < 13)
|
||||
dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_2, MENU_COLOR);
|
||||
dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_2, FOCUS_COLOR);
|
||||
else if (requiredSpeakerVolume < 19)
|
||||
dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_3, MENU_COLOR);
|
||||
dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_3, FOCUS_COLOR);
|
||||
else
|
||||
dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_4, MENU_COLOR);
|
||||
dc->drawBitmapPattern(LCD_W - 130, 4, LBM_TOPMENU_VOLUME_4, FOCUS_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);
|
||||
dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT_CHARGING, FOCUS_COLOR);
|
||||
}
|
||||
else {
|
||||
dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, MENU_COLOR);
|
||||
dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, FOCUS_COLOR);
|
||||
}
|
||||
#else
|
||||
dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, MENU_COLOR);
|
||||
dc->drawBitmapPattern(LCD_W - 130, 25, LBM_TOPMENU_TXBATT, FOCUS_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);
|
||||
dc->drawSolidFilledRect(LCD_W - 128 + 4 * i, 30, 2, 8, i >= bars ? MENU_TITLE_DISABLE_COLOR : FOCUS_COLOR);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
@@ -44,19 +44,25 @@ void MainViewHorizontalTrim::paint(BitmapBuffer * dc)
|
||||
}
|
||||
|
||||
// Trim line
|
||||
lcdSetColor(GREY); // TODO add a color
|
||||
dc->drawSolidFilledRect(TRIM_SQUARE_SIZE / 2, (height() - TRIM_LINE_WIDTH - 1) / 2, width() - TRIM_SQUARE_SIZE + 1, TRIM_LINE_WIDTH, CUSTOM_COLOR);
|
||||
dc->drawSolidFilledRect(
|
||||
TRIM_SQUARE_SIZE / 2, (height() - TRIM_LINE_WIDTH - 1) / 2,
|
||||
width() - TRIM_SQUARE_SIZE + 1, TRIM_LINE_WIDTH, DEFAULT_COLOR);
|
||||
|
||||
// Trim square
|
||||
coord_t x = divRoundClosest((width() - TRIM_SQUARE_SIZE) * (value - trimMin), trimMax - trimMin);
|
||||
drawTrimSquare(dc, x, 0, (value < TRIM_MIN || value > TRIM_MAX) ? HIGHLIGHT_COLOR /* TODO add a color */ : TRIM_BGCOLOR);
|
||||
coord_t x = divRoundClosest((width() - TRIM_SQUARE_SIZE) * (value - trimMin),
|
||||
trimMax - trimMin);
|
||||
drawTrimSquare(dc, x, 0,
|
||||
(value < TRIM_MIN || value > TRIM_MAX)
|
||||
? HIGHLIGHT_COLOR /* TODO add a color */
|
||||
: TRIM_BGCOLOR);
|
||||
|
||||
// Trim value / small lines on the square
|
||||
if (g_model.displayTrims == DISPLAY_TRIMS_ALWAYS) {
|
||||
// TODO DISPLAY_TRIMS_CHANGE
|
||||
dc->drawNumber(x + (TRIM_SQUARE_SIZE + 1) / 2, 3, divRoundClosest(value * 100, trimMax), FONT(XXS) | FOCUS_COLOR | CENTERED);
|
||||
}
|
||||
else {
|
||||
dc->drawNumber(x + (TRIM_SQUARE_SIZE + 1) / 2, 3,
|
||||
divRoundClosest(value * 100, trimMax),
|
||||
FONT(XXS) | FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
if (value >= 0) {
|
||||
dc->drawSolidVerticalLine(x + 4, 3, 9, FOCUS_COLOR);
|
||||
}
|
||||
@@ -79,19 +85,26 @@ void MainViewVerticalTrim::paint(BitmapBuffer * dc)
|
||||
}
|
||||
|
||||
// Trim line
|
||||
lcdSetColor(GREY); // TODO add a color
|
||||
dc->drawSolidFilledRect((width() - TRIM_LINE_WIDTH) / 2, TRIM_SQUARE_SIZE / 2, TRIM_LINE_WIDTH, height() - TRIM_SQUARE_SIZE + 1, CUSTOM_COLOR);
|
||||
dc->drawSolidFilledRect((width() - TRIM_LINE_WIDTH) / 2, TRIM_SQUARE_SIZE / 2,
|
||||
TRIM_LINE_WIDTH, height() - TRIM_SQUARE_SIZE + 1,
|
||||
DEFAULT_COLOR);
|
||||
|
||||
// Trim square
|
||||
coord_t y = height() - TRIM_SQUARE_SIZE - divRoundClosest((height() - TRIM_SQUARE_SIZE) * (value - trimMin), trimMax - trimMin);
|
||||
drawTrimSquare(dc, 0, y, (value < TRIM_MIN || value > TRIM_MAX) ? HIGHLIGHT_COLOR /* TODO add a color */ : TRIM_BGCOLOR);
|
||||
coord_t y = height() - TRIM_SQUARE_SIZE -
|
||||
divRoundClosest((height() - TRIM_SQUARE_SIZE) * (value - trimMin),
|
||||
trimMax - trimMin);
|
||||
drawTrimSquare(dc, 0, y,
|
||||
(value < TRIM_MIN || value > TRIM_MAX)
|
||||
? HIGHLIGHT_COLOR /* TODO add a color */
|
||||
: TRIM_BGCOLOR);
|
||||
|
||||
// Trim value / small lines on the square
|
||||
if (g_model.displayTrims == DISPLAY_TRIMS_ALWAYS) {
|
||||
// TODO DISPLAY_TRIMS_CHANGE
|
||||
dc->drawNumber((TRIM_SQUARE_SIZE + 1) / 2, y + 3, divRoundClosest(value * 100, trimMax), FONT(XXS) | FOCUS_COLOR | CENTERED);
|
||||
}
|
||||
else {
|
||||
dc->drawNumber((TRIM_SQUARE_SIZE + 1) / 2, y + 3,
|
||||
divRoundClosest(value * 100, trimMax),
|
||||
FONT(XXS) | FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
if (value >= 0) {
|
||||
dc->drawSolidHorizontalLine(3, y + 4, 9, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
@@ -42,10 +42,16 @@ class CurveEditWindow : public Page
|
||||
|
||||
void buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MENUCURVE, 0, MENU_COLOR);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_MENUCURVE, 0, FOCUS_COLOR);
|
||||
char s[16];
|
||||
strAppendStringWithIndex(s, STR_CV, index + 1);
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, s, 0, MENU_COLOR);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
s, 0, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
@@ -226,8 +232,14 @@ class CurveButton : public Button {
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, FIELD_BGCOLOR);
|
||||
|
||||
// bounding rect
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? CHECKBOX_COLOR : DISABLE_COLOR);
|
||||
if (hasFocus()) {
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
} else {
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
// curve characteristics
|
||||
if (isCurveUsed(index)) {
|
||||
@@ -297,7 +309,9 @@ void ModelCurvesPage::build(FormWindow * window, int8_t focusIndex)
|
||||
|
||||
if (isCurveUsed(index)) {
|
||||
// Curve label
|
||||
new StaticText(window, grid.getLabelSlot(), getCurveString(1 + index), BUTTON_BACKGROUND, CENTERED);
|
||||
auto txt =
|
||||
new StaticText(window, grid.getLabelSlot(), getCurveString(1 + index),
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
// Curve drawing
|
||||
Button * button = new CurveButton(window, grid.getFieldSlot(), index);
|
||||
@@ -319,16 +333,30 @@ void ModelCurvesPage::build(FormWindow * window, int8_t focusIndex)
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
if (focusIndex == index) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
txt->setHeight(button->height());
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
auto button = new TextButton(window, grid.getLabelSlot(),
|
||||
getCurveString(1 + index));
|
||||
|
||||
button->setPressHandler([=]() {
|
||||
Menu *menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
|
||||
@@ -30,7 +30,7 @@ class ModelCurvesPage: public PageTab {
|
||||
|
||||
virtual void build(FormWindow * window) override
|
||||
{
|
||||
build(window, -1);
|
||||
build(window, 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -58,6 +58,9 @@ class FlightModeGroup: public FormGroup
|
||||
if (index == getFlightMode()) {
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), HIGHLIGHT_COLOR);
|
||||
}
|
||||
else {
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), FIELD_BGCOLOR);
|
||||
}
|
||||
FormGroup::paint(dc);
|
||||
}
|
||||
|
||||
|
||||
@@ -64,9 +64,18 @@ void GVarButton::paint(BitmapBuffer * dc)
|
||||
currentFlightMode = getFlightMode();
|
||||
gvarSum = 0;
|
||||
|
||||
dc->drawSolidFilledRect(0, 0, nameRectW, rect.h, CURVE_AXIS_COLOR);
|
||||
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, getGVarString(gvarIdx), 0);
|
||||
dc->drawSizedText(x, y, gvar->name, LEN_GVAR_NAME, 0);
|
||||
LcdFlags bgColor = FIELD_BGCOLOR;
|
||||
LcdFlags textColor = 0;
|
||||
if (hasFocus()) {
|
||||
bgColor = FOCUS_BGCOLOR;
|
||||
textColor = FOCUS_COLOR;
|
||||
}
|
||||
|
||||
dc->drawSolidFilledRect(0, 0, nameRectW, rect.h, bgColor);
|
||||
dc->drawSolidFilledRect(nameRectW, 0, rect.w - nameRectW, rect.h, FIELD_BGCOLOR);
|
||||
|
||||
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, getGVarString(gvarIdx), textColor);
|
||||
dc->drawSizedText(x, y, gvar->name, LEN_GVAR_NAME, textColor);
|
||||
|
||||
// values are right aligned
|
||||
x += GVAR_NAME_SIZE;
|
||||
@@ -91,7 +100,8 @@ void GVarButton::paint(BitmapBuffer * dc)
|
||||
}
|
||||
|
||||
if (!bgFilled) {
|
||||
dc->drawSolidFilledRect(startX, y, width() - startX, PAGE_LINE_HEIGHT, CURVE_AXIS_COLOR);
|
||||
dc->drawSolidFilledRect(startX, y, width() - startX, PAGE_LINE_HEIGHT,
|
||||
FIELD_FRAME_COLOR);
|
||||
bgFilled = true;
|
||||
}
|
||||
|
||||
@@ -116,7 +126,10 @@ void GVarButton::paint(BitmapBuffer * dc)
|
||||
}
|
||||
}
|
||||
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? FOCUS_BGCOLOR : DISABLE_COLOR);
|
||||
if (hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
void GVarButton::drawFlightMode(BitmapBuffer * dc, coord_t x, coord_t y, int fm, LcdFlags attr)
|
||||
@@ -131,17 +144,17 @@ void GVarRenderer::paint(BitmapBuffer * dc)
|
||||
lastFlightMode = getFlightMode();
|
||||
FlightModeData * fmData = &g_model.flightModeData[lastFlightMode];
|
||||
lastGVar = fmData->gvars[index];
|
||||
coord_t x = drawStringWithIndex(dc, 0, FIELD_PADDING_TOP, STR_GV, index + 1, MENU_COLOR, nullptr, "=");
|
||||
coord_t x = drawStringWithIndex(dc, 0, FIELD_PADDING_TOP, STR_GV, index + 1,
|
||||
FOCUS_COLOR, nullptr, "=");
|
||||
if (lastGVar > GVAR_MAX) {
|
||||
uint8_t fm = lastGVar - GVAR_MAX - 1;
|
||||
if (fm >= lastFlightMode)
|
||||
fm++;
|
||||
char label[16];
|
||||
getFlightModeString(label, fm + 1);
|
||||
dc->drawSizedText(x, FIELD_PADDING_TOP, label, strlen(label), MENU_COLOR);
|
||||
}
|
||||
else {
|
||||
drawGVarValue(dc, x, FIELD_PADDING_TOP, index, lastGVar, MENU_COLOR);
|
||||
dc->drawSizedText(x, FIELD_PADDING_TOP, label, strlen(label), FOCUS_COLOR);
|
||||
} else {
|
||||
drawGVarValue(dc, x, FIELD_PADDING_TOP, index, lastGVar, FOCUS_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,8 +180,15 @@ bool GVarRenderer::isUpdated()
|
||||
|
||||
void GVarEditWindow::buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_GLOBAL_VAR, 0, MENU_COLOR);
|
||||
gVarInHeader = new GVarRenderer(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, index);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_GLOBAL_VAR, 0, FOCUS_COLOR);
|
||||
gVarInHeader =
|
||||
new GVarRenderer(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
index);
|
||||
}
|
||||
|
||||
void GVarEditWindow::checkEvents()
|
||||
@@ -357,4 +377,4 @@ void ModelGVarsPage::build(FormWindow * window)
|
||||
grid.nextLine(button->height());
|
||||
}
|
||||
window->setInnerHeight(grid.getWindowHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,94 +91,104 @@ void deleteExpo(uint8_t idx)
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
|
||||
class InputEditWindow: public Page
|
||||
class InputEditWindow : public Page
|
||||
{
|
||||
public:
|
||||
InputEditWindow(int8_t input, uint8_t index):
|
||||
public:
|
||||
InputEditWindow(int8_t input, uint8_t index) :
|
||||
Page(ICON_MODEL_INPUTS),
|
||||
input(input),
|
||||
index(index),
|
||||
preview(this, {INPUT_EDIT_CURVE_LEFT, INPUT_EDIT_CURVE_TOP, INPUT_EDIT_CURVE_WIDTH, INPUT_EDIT_CURVE_HEIGHT},
|
||||
[=](int x) -> int {
|
||||
ExpoData * line = expoAddress(index);
|
||||
int16_t anas[MAX_INPUTS] = {0};
|
||||
applyExpos(anas, e_perout_mode_inactive_flight_mode, line->srcRaw, x);
|
||||
return anas[line->chn];
|
||||
},
|
||||
[=]() -> int {
|
||||
return getValue(expoAddress(index)->srcRaw);
|
||||
})
|
||||
{
|
||||
preview(
|
||||
this,
|
||||
{INPUT_EDIT_CURVE_LEFT, INPUT_EDIT_CURVE_TOP, INPUT_EDIT_CURVE_WIDTH,
|
||||
INPUT_EDIT_CURVE_HEIGHT},
|
||||
[=](int x) -> int {
|
||||
ExpoData *line = expoAddress(index);
|
||||
int16_t anas[MAX_INPUTS] = {0};
|
||||
applyExpos(anas, e_perout_mode_inactive_flight_mode, line->srcRaw,
|
||||
x);
|
||||
return anas[line->chn];
|
||||
},
|
||||
[=]() -> int { return getValue(expoAddress(index)->srcRaw); })
|
||||
{
|
||||
#if LCD_W > LCD_H
|
||||
body.setWidth(LCD_W - 170);
|
||||
body.setWidth(LCD_W - preview.width() - PAGE_PADDING);
|
||||
body.setLeft(preview.width() + PAGE_PADDING);
|
||||
#else
|
||||
body.setRect({0, INPUT_EDIT_CURVE_TOP + INPUT_EDIT_CURVE_HEIGHT, LCD_W, LCD_H - INPUT_EDIT_CURVE_TOP - INPUT_EDIT_CURVE_HEIGHT});
|
||||
body.setRect({0, INPUT_EDIT_CURVE_TOP + INPUT_EDIT_CURVE_HEIGHT, LCD_W,
|
||||
LCD_H - INPUT_EDIT_CURVE_TOP - INPUT_EDIT_CURVE_HEIGHT});
|
||||
#endif
|
||||
buildBody(&body);
|
||||
buildHeader(&header);
|
||||
}
|
||||
buildBody(&body);
|
||||
buildHeader(&header);
|
||||
}
|
||||
|
||||
void deleteLater(bool detach = true, bool trash = true) override
|
||||
{
|
||||
if (_deleted)
|
||||
return;
|
||||
void deleteLater(bool detach = true, bool trash = true) override
|
||||
{
|
||||
if (_deleted) return;
|
||||
|
||||
preview.deleteLater(true, false);
|
||||
preview.deleteLater(true, false);
|
||||
|
||||
Page::deleteLater(detach, trash);
|
||||
}
|
||||
Page::deleteLater(detach, trash);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t input;
|
||||
uint8_t index;
|
||||
Curve preview;
|
||||
Choice * trimChoice = nullptr;
|
||||
FormGroup * curveParamField = nullptr;
|
||||
protected:
|
||||
uint8_t input;
|
||||
uint8_t index;
|
||||
Curve preview;
|
||||
Choice *trimChoice = nullptr;
|
||||
FormGroup *curveParamField = nullptr;
|
||||
|
||||
void buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MENUINPUTS, 0, MENU_COLOR);
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, getSourceString(MIXSRC_FIRST_INPUT + input), 0, MENU_COLOR);
|
||||
}
|
||||
void buildHeader(Window *window)
|
||||
{
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_MENUINPUTS, 0, FOCUS_COLOR);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
getSourceString(MIXSRC_FIRST_INPUT + input), 0, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
// TODO share this code with MIXER
|
||||
void updateCurveParamField(ExpoData * line)
|
||||
{
|
||||
curveParamField->clear();
|
||||
// TODO share this code with MIXER
|
||||
void updateCurveParamField(ExpoData *line)
|
||||
{
|
||||
curveParamField->clear();
|
||||
|
||||
const rect_t rect = {0, 0, curveParamField->width(), curveParamField->height()};
|
||||
const rect_t rect = {0, 0, curveParamField->width(),
|
||||
curveParamField->height()};
|
||||
|
||||
switch (line->curve.type) {
|
||||
case CURVE_REF_DIFF:
|
||||
case CURVE_REF_EXPO:
|
||||
{
|
||||
GVarNumberEdit * edit = new GVarNumberEdit(curveParamField, rect, -100, 100, GET_SET_DEFAULT(line->curve.value));
|
||||
edit->setSuffix("%");
|
||||
break;
|
||||
}
|
||||
switch (line->curve.type) {
|
||||
case CURVE_REF_DIFF:
|
||||
case CURVE_REF_EXPO: {
|
||||
GVarNumberEdit *edit =
|
||||
new GVarNumberEdit(curveParamField, rect, -100, 100,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
edit->setSuffix("%");
|
||||
break;
|
||||
}
|
||||
|
||||
case CURVE_REF_FUNC:
|
||||
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1, GET_SET_DEFAULT(line->curve.value));
|
||||
break;
|
||||
case CURVE_REF_FUNC:
|
||||
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
break;
|
||||
|
||||
case CURVE_REF_CUSTOM:
|
||||
{
|
||||
auto choice = new Choice(curveParamField, rect, -MAX_CURVES, MAX_CURVES, GET_SET_DEFAULT(line->curve.value));
|
||||
choice->setTextHandler([](int value) {
|
||||
return getCurveString(value);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case CURVE_REF_CUSTOM: {
|
||||
auto choice = new Choice(curveParamField, rect, -MAX_CURVES, MAX_CURVES,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
choice->setTextHandler([](int value) { return getCurveString(value); });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void buildBody(FormWindow * window)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.setLabelWidth(INPUT_EDIT_LABELS_WIDTH);
|
||||
grid.spacer(PAGE_PADDING);
|
||||
void buildBody(FormWindow *window)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.setLabelWidth(INPUT_EDIT_LABELS_WIDTH);
|
||||
grid.spacer(PAGE_PADDING);
|
||||
|
||||
ExpoData * line = expoAddress(index) ;
|
||||
ExpoData *line = expoAddress(index);
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
grid.setMarginRight(180);
|
||||
@@ -302,19 +312,23 @@ void CommonInputOrMixButton::checkEvents()
|
||||
Button::checkEvents();
|
||||
}
|
||||
|
||||
void CommonInputOrMixButton::drawFlightModes(BitmapBuffer *dc, FlightModesType value)
|
||||
void CommonInputOrMixButton::drawFlightModes(BitmapBuffer *dc,
|
||||
FlightModesType value,
|
||||
LcdFlags textColor)
|
||||
{
|
||||
dc->drawMask(146, 2 + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, mixerSetupFlightmodeIcon, DEFAULT_COLOR);
|
||||
dc->drawMask(146, 2 + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupFlightmodeIcon, textColor);
|
||||
coord_t x = 166;
|
||||
for (int i = 0; i < MAX_FLIGHT_MODES; i++) {
|
||||
char s[] = " ";
|
||||
s[0] = '0' + i;
|
||||
if (value & (1 << i)) {
|
||||
dc->drawText(x, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP + 2, s, FONT(XS) | TEXT_DISABLE_COLOR);
|
||||
}
|
||||
else {
|
||||
dc->drawSolidFilledRect(x, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP + 2, 8, 3, CHECKBOX_COLOR);
|
||||
dc->drawText(x, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP + 2, s, FONT(XS));
|
||||
dc->drawText(x, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP + 2, s,
|
||||
FONT(XS) | TEXT_DISABLE_COLOR);
|
||||
} else {
|
||||
dc->drawSolidFilledRect(x, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP + 2, 8, 3,
|
||||
FOCUS_BGCOLOR);
|
||||
dc->drawText(x, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP + 2, s, FONT(XS) | textColor);
|
||||
}
|
||||
x += 8;
|
||||
}
|
||||
@@ -322,56 +336,68 @@ void CommonInputOrMixButton::drawFlightModes(BitmapBuffer *dc, FlightModesType v
|
||||
|
||||
void CommonInputOrMixButton::paint(BitmapBuffer * dc)
|
||||
{
|
||||
if (active)
|
||||
dc->drawSolidFilledRect(2, 2, rect.w - 4, rect.h - 4, HIGHLIGHT_COLOR);
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(),
|
||||
/*hasFocus() ? FOCUS_BGCOLOR :*/ FIELD_BGCOLOR);
|
||||
paintBody(dc);
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? CHECKBOX_COLOR : DISABLE_COLOR);
|
||||
|
||||
if (!hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
}
|
||||
|
||||
class InputLineButton : public CommonInputOrMixButton {
|
||||
public:
|
||||
InputLineButton(FormGroup * parent, const rect_t & rect, uint8_t index):
|
||||
class InputLineButton : public CommonInputOrMixButton
|
||||
{
|
||||
public:
|
||||
InputLineButton(FormGroup *parent, const rect_t &rect, uint8_t index) :
|
||||
CommonInputOrMixButton(parent, rect, index)
|
||||
{
|
||||
const ExpoData & line = g_model.expoData[index];
|
||||
if (line.swtch || line.curve.value != 0 || line.flightModes) {
|
||||
setHeight(height() + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP);
|
||||
}
|
||||
{
|
||||
const ExpoData &line = g_model.expoData[index];
|
||||
if (line.swtch || line.curve.value != 0 || line.flightModes) {
|
||||
setHeight(height() + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP);
|
||||
}
|
||||
}
|
||||
|
||||
bool isActive() const override { return isExpoActive(index); }
|
||||
|
||||
void paintBody(BitmapBuffer *dc) override
|
||||
{
|
||||
const ExpoData &line = g_model.expoData[index];
|
||||
|
||||
LcdFlags textColor = DEFAULT_COLOR;
|
||||
// if (hasFocus())
|
||||
// textColor = FOCUS_COLOR;
|
||||
|
||||
// first line ...
|
||||
drawValueOrGVar(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, line.weight,
|
||||
-100, 100, textColor);
|
||||
drawSource(dc, 60, FIELD_PADDING_TOP, line.srcRaw, textColor);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, FIELD_PADDING_TOP, mixerSetupLabelIcon, textColor);
|
||||
dc->drawSizedText(166, FIELD_PADDING_TOP, line.name, sizeof(line.name),
|
||||
textColor);
|
||||
}
|
||||
|
||||
bool isActive() const override
|
||||
{
|
||||
return isExpoActive(index);
|
||||
// second line ...
|
||||
if (line.swtch) {
|
||||
dc->drawMask(3, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupSwitchIcon, textColor);
|
||||
drawSwitch(dc, 21, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.swtch,
|
||||
textColor);
|
||||
}
|
||||
|
||||
void paintBody(BitmapBuffer * dc) override
|
||||
{
|
||||
const ExpoData & line = g_model.expoData[index];
|
||||
|
||||
// first line ...
|
||||
drawValueOrGVar(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, line.weight, -100, 100);
|
||||
drawSource(dc, 60, FIELD_PADDING_TOP, line.srcRaw);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, FIELD_PADDING_TOP, mixerSetupLabelIcon, DEFAULT_COLOR);
|
||||
dc->drawSizedText(166, FIELD_PADDING_TOP, line.name, sizeof(line.name));
|
||||
}
|
||||
|
||||
// second line ...
|
||||
if (line.swtch) {
|
||||
dc->drawMask(3, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, mixerSetupSwitchIcon, DEFAULT_COLOR);
|
||||
drawSwitch(dc, 21, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.swtch);
|
||||
}
|
||||
|
||||
if (line.curve.value != 0 ) {
|
||||
dc->drawMask(60, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, mixerSetupCurveIcon, DEFAULT_COLOR);
|
||||
drawCurveRef(dc, 80, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.curve);
|
||||
}
|
||||
|
||||
if (line.flightModes) {
|
||||
drawFlightModes(dc, line.flightModes);
|
||||
}
|
||||
if (line.curve.value != 0) {
|
||||
dc->drawMask(60, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupCurveIcon, textColor);
|
||||
drawCurveRef(dc, 80, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.curve,
|
||||
textColor);
|
||||
}
|
||||
|
||||
if (line.flightModes) {
|
||||
drawFlightModes(dc, line.flightModes, textColor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ModelInputsPage::ModelInputsPage():
|
||||
@@ -396,27 +422,29 @@ void ModelInputsPage::editInput(FormWindow * window, uint8_t input, uint8_t inde
|
||||
});
|
||||
}
|
||||
|
||||
void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
void ModelInputsPage::build(FormWindow *window, int8_t focusIndex)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
grid.setLabelWidth(66);
|
||||
|
||||
int inputIndex = 0;
|
||||
ExpoData * line = g_model.expoData;
|
||||
ExpoData *line = g_model.expoData;
|
||||
for (uint8_t input = 0; input < MAX_INPUTS; input++) {
|
||||
if (inputIndex < MAX_EXPOS && line->chn == input && EXPO_VALID(line)) {
|
||||
new StaticText(window, grid.getLabelSlot(), getSourceString(MIXSRC_FIRST_INPUT + input), BUTTON_BACKGROUND, CENTERED);
|
||||
coord_t h = grid.getWindowHeight();
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_FIRST_INPUT + input),
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
while (inputIndex < MAX_EXPOS && line->chn == input && EXPO_VALID(line)) {
|
||||
Button * button = new InputLineButton(window, grid.getFieldSlot(), inputIndex);
|
||||
if (focusIndex == inputIndex)
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
Button *button =
|
||||
new InputLineButton(window, grid.getFieldSlot(), inputIndex);
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
button->bringToTop();
|
||||
Menu * menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
editInput(window, input, inputIndex);
|
||||
});
|
||||
Menu *menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT,
|
||||
[=]() { editInput(window, input, inputIndex); });
|
||||
if (!reachExposLimit()) {
|
||||
menu->addLine(STR_INSERT_BEFORE, [=]() {
|
||||
insertExpo(inputIndex, input);
|
||||
@@ -434,7 +462,8 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
menu->addLine(STR_PASTE_BEFORE, [=]() {
|
||||
copyExpo(s_copySrcIdx, inputIndex, PASTE_BEFORE);
|
||||
if (s_copyMode == MOVE_MODE) {
|
||||
deleteExpo((s_copySrcIdx > inputIndex) ? s_copySrcIdx+1 : s_copySrcIdx);
|
||||
deleteExpo((s_copySrcIdx > inputIndex) ? s_copySrcIdx + 1
|
||||
: s_copySrcIdx);
|
||||
s_copyMode = 0;
|
||||
}
|
||||
rebuild(window, inputIndex);
|
||||
@@ -442,10 +471,11 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
menu->addLine(STR_PASTE_AFTER, [=]() {
|
||||
copyExpo(s_copySrcIdx, inputIndex, PASTE_AFTER);
|
||||
if (s_copyMode == MOVE_MODE) {
|
||||
deleteExpo((s_copySrcIdx > inputIndex) ? s_copySrcIdx+1 : s_copySrcIdx);
|
||||
deleteExpo((s_copySrcIdx > inputIndex) ? s_copySrcIdx + 1
|
||||
: s_copySrcIdx);
|
||||
s_copyMode = 0;
|
||||
}
|
||||
rebuild(window, inputIndex+1);
|
||||
rebuild(window, inputIndex + 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -459,22 +489,40 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
if (focus) button->bringToTop();
|
||||
});
|
||||
|
||||
grid.spacer(button->height() - 2);
|
||||
|
||||
if (focusIndex == inputIndex) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
grid.spacer(button->height() - 1);
|
||||
++inputIndex;
|
||||
++line;
|
||||
}
|
||||
|
||||
h = grid.getWindowHeight() - h + 1;
|
||||
txt->setHeight(h);
|
||||
|
||||
grid.spacer(7);
|
||||
}
|
||||
else {
|
||||
auto button = new TextButton(window, grid.getLabelSlot(), getSourceString(MIXSRC_FIRST_INPUT + input));
|
||||
if (focusIndex == inputIndex)
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
} else {
|
||||
auto button = new TextButton(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_FIRST_INPUT + input));
|
||||
if (focusIndex == inputIndex) button->setFocus(SET_FOCUS_DEFAULT);
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
button->bringToTop();
|
||||
Menu * menu = new Menu(window);
|
||||
Menu *menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
insertExpo(inputIndex, input);
|
||||
editInput(window, input, inputIndex);
|
||||
@@ -484,8 +532,9 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
if (s_copyMode != 0) {
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
copyExpo(s_copySrcIdx, inputIndex, input);
|
||||
if(s_copyMode == MOVE_MODE) {
|
||||
deleteExpo((s_copySrcIdx >= inputIndex) ? s_copySrcIdx+1 : s_copySrcIdx);
|
||||
if (s_copyMode == MOVE_MODE) {
|
||||
deleteExpo((s_copySrcIdx >= inputIndex) ? s_copySrcIdx + 1
|
||||
: s_copySrcIdx);
|
||||
s_copyMode = 0;
|
||||
}
|
||||
rebuild(window, -1);
|
||||
@@ -500,7 +549,7 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
}
|
||||
}
|
||||
|
||||
Window * focus = Window::getFocus();
|
||||
Window *focus = Window::getFocus();
|
||||
if (focus) {
|
||||
focus->bringToTop();
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ class CommonInputOrMixButton : public Button {
|
||||
|
||||
void checkEvents() override;
|
||||
|
||||
void drawFlightModes(BitmapBuffer *dc, FlightModesType value);
|
||||
void drawFlightModes(BitmapBuffer *dc, FlightModesType value, LcdFlags textColor);
|
||||
|
||||
void paint(BitmapBuffer * dc) override;
|
||||
|
||||
|
||||
@@ -73,8 +73,15 @@ class LogicalSwitchEditPage: public Page
|
||||
|
||||
void buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, { PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT }, STR_MENULOGICALSWITCHES, 0, MENU_COLOR);
|
||||
headerSwitchName = new StaticText(window, { PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT }, getSwitchPositionName(SWSRC_SW1 + index), 0, MENU_COLOR);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_MENULOGICALSWITCHES, 0, FOCUS_COLOR);
|
||||
headerSwitchName = new StaticText(
|
||||
window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
getSwitchPositionName(SWSRC_SW1 + index), 0, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
void updateLogicalSwitchOneWindow()
|
||||
@@ -234,93 +241,97 @@ static constexpr coord_t col1 = 20;
|
||||
static constexpr coord_t col2 = (LCD_W - 100) / 3 + col1;
|
||||
static constexpr coord_t col3 = ((LCD_W - 100) / 3) * 2 + col1;
|
||||
|
||||
class LogicalSwitchButton : public Button {
|
||||
public:
|
||||
LogicalSwitchButton(FormGroup * parent, const rect_t & rect, int lsIndex):
|
||||
Button(parent, rect),
|
||||
lsIndex(lsIndex),
|
||||
active(isActive())
|
||||
{
|
||||
LogicalSwitchData * ls = lswAddress(lsIndex);
|
||||
if (ls->andsw != SWSRC_NONE || ls->duration != 0 || ls->delay != 0)
|
||||
setHeight(height() + 20);
|
||||
if (lswFamily(ls->func) == LS_FAMILY_EDGE)
|
||||
setHeight(height() + 20);
|
||||
class LogicalSwitchButton : public Button
|
||||
{
|
||||
public:
|
||||
LogicalSwitchButton(FormGroup* parent, const rect_t& rect, int lsIndex) :
|
||||
Button(parent, rect), lsIndex(lsIndex), active(isActive())
|
||||
{
|
||||
LogicalSwitchData* ls = lswAddress(lsIndex);
|
||||
if (ls->andsw != SWSRC_NONE || ls->duration != 0 || ls->delay != 0)
|
||||
setHeight(height() + 20);
|
||||
if (lswFamily(ls->func) == LS_FAMILY_EDGE) setHeight(height() + 20);
|
||||
}
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + lsIndex);
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
active = !active;
|
||||
}
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + lsIndex);
|
||||
Button::checkEvents();
|
||||
}
|
||||
|
||||
void paintLogicalSwitchLine(BitmapBuffer* dc)
|
||||
{
|
||||
LogicalSwitchData* ls = lswAddress(lsIndex);
|
||||
uint8_t lsFamily = lswFamily(ls->func);
|
||||
|
||||
// CSW func
|
||||
dc->drawTextAtIndex(col1, line1, STR_VCSWFUNC, ls->func);
|
||||
|
||||
// CSW params
|
||||
if (lsFamily == LS_FAMILY_BOOL || lsFamily == LS_FAMILY_STICKY) {
|
||||
drawSwitch(dc, col2, line1, ls->v1);
|
||||
drawSwitch(dc, col3, line1, ls->v2);
|
||||
} else if (lsFamily == LS_FAMILY_EDGE) {
|
||||
drawSwitch(dc, col1, line2, ls->v1);
|
||||
putsEdgeDelayParam(dc, col2, line2, ls);
|
||||
} else if (lsFamily == LS_FAMILY_COMP) {
|
||||
drawSource(dc, col2, line1, ls->v1, 0);
|
||||
drawSource(dc, col3, line1, ls->v2, 0);
|
||||
} else if (lsFamily == LS_FAMILY_TIMER) {
|
||||
dc->drawNumber(col2, line1, lswTimerValue(ls->v1), LEFT | PREC1);
|
||||
dc->drawNumber(col3, line1, lswTimerValue(ls->v2), LEFT | PREC1);
|
||||
} else {
|
||||
drawSource(dc, col2, line1, ls->v1, 0);
|
||||
drawSourceCustomValue(
|
||||
dc, col3, line1, ls->v1,
|
||||
(ls->v1 <= MIXSRC_LAST_CH ? calc100toRESX(ls->v2) : ls->v2), 0);
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
active = !active;
|
||||
}
|
||||
// AND switch
|
||||
drawSwitch(dc, col1, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2,
|
||||
ls->andsw, 0);
|
||||
|
||||
Button::checkEvents();
|
||||
// CSW duration
|
||||
if (ls->duration > 0) {
|
||||
dc->drawNumber(col2, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2,
|
||||
ls->duration, PREC1 | LEFT);
|
||||
}
|
||||
|
||||
void paintLogicalSwitchLine(BitmapBuffer * dc)
|
||||
{
|
||||
LogicalSwitchData * ls = lswAddress(lsIndex);
|
||||
uint8_t lsFamily = lswFamily(ls->func);
|
||||
|
||||
// CSW func
|
||||
dc->drawTextAtIndex(col1, line1, STR_VCSWFUNC, ls->func);
|
||||
|
||||
// CSW params
|
||||
if (lsFamily == LS_FAMILY_BOOL || lsFamily == LS_FAMILY_STICKY) {
|
||||
drawSwitch(dc, col2, line1, ls->v1);
|
||||
drawSwitch(dc, col3, line1, ls->v2);
|
||||
}
|
||||
else if (lsFamily == LS_FAMILY_EDGE) {
|
||||
drawSwitch(dc, col1, line2, ls->v1);
|
||||
putsEdgeDelayParam(dc, col2, line2, ls);
|
||||
}
|
||||
else if (lsFamily == LS_FAMILY_COMP) {
|
||||
drawSource(dc, col2, line1, ls->v1, 0);
|
||||
drawSource(dc, col3, line1, ls->v2, 0);
|
||||
}
|
||||
else if (lsFamily == LS_FAMILY_TIMER) {
|
||||
dc->drawNumber(col2, line1, lswTimerValue(ls->v1), LEFT|PREC1);
|
||||
dc->drawNumber(col3, line1, lswTimerValue(ls->v2), LEFT|PREC1);
|
||||
}
|
||||
else {
|
||||
drawSource(dc, col2, line1, ls->v1, 0);
|
||||
drawSourceCustomValue(dc, col3, line1, ls->v1, (ls->v1 <= MIXSRC_LAST_CH ? calc100toRESX(ls->v2) : ls->v2), 0);
|
||||
}
|
||||
|
||||
// AND switch
|
||||
drawSwitch(dc, col1, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2, ls->andsw, 0);
|
||||
|
||||
// CSW duration
|
||||
if (ls->duration > 0) {
|
||||
dc->drawNumber(col2, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2, ls->duration, PREC1 | LEFT);
|
||||
}
|
||||
|
||||
// CSW delay
|
||||
if (lsFamily != LS_FAMILY_EDGE && ls->delay > 0) {
|
||||
dc->drawNumber(col3, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2, ls->delay, PREC1 | LEFT);
|
||||
}
|
||||
// CSW delay
|
||||
if (lsFamily != LS_FAMILY_EDGE && ls->delay > 0) {
|
||||
dc->drawNumber(col3, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2,
|
||||
ls->delay, PREC1 | LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
if (active)
|
||||
dc->drawSolidFilledRect(2, 2, rect.w-4, rect.h-4, HIGHLIGHT_COLOR);
|
||||
void paint(BitmapBuffer* dc) override
|
||||
{
|
||||
if (active)
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, HIGHLIGHT_COLOR);
|
||||
else
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, FIELD_BGCOLOR);
|
||||
|
||||
paintLogicalSwitchLine(dc);
|
||||
paintLogicalSwitchLine(dc);
|
||||
|
||||
// The bounding rect
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? CHECKBOX_COLOR : DISABLE_COLOR);
|
||||
}
|
||||
// The bounding rect
|
||||
if (hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t lsIndex;
|
||||
bool active;
|
||||
protected:
|
||||
uint8_t lsIndex;
|
||||
bool active;
|
||||
};
|
||||
|
||||
ModelLogicalSwitchesPage::ModelLogicalSwitchesPage():
|
||||
@@ -344,17 +355,18 @@ void ModelLogicalSwitchesPage::editLogicalSwitch(FormWindow * window, uint8_t ls
|
||||
});
|
||||
}
|
||||
|
||||
void ModelLogicalSwitchesPage::build(FormWindow * window, int8_t focusIndex)
|
||||
void ModelLogicalSwitchesPage::build(FormWindow* window, int8_t focusIndex)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
grid.setLabelWidth(66);
|
||||
|
||||
for (uint8_t i = 0; i < MAX_LOGICAL_SWITCHES; i++) {
|
||||
LogicalSwitchData * ls = lswAddress(i);
|
||||
LogicalSwitchData* ls = lswAddress(i);
|
||||
|
||||
if (ls->func == LS_FUNC_NONE) {
|
||||
auto button = new TextButton(window, grid.getLabelSlot(), getSwitchPositionName(SWSRC_SW1+i));
|
||||
auto button = new TextButton(window, grid.getLabelSlot(),
|
||||
getSwitchPositionName(SWSRC_SW1 + i));
|
||||
button->setPressHandler([=]() {
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH) {
|
||||
Menu* menu = new Menu(window);
|
||||
@@ -370,40 +382,54 @@ void ModelLogicalSwitchesPage::build(FormWindow * window, int8_t focusIndex)
|
||||
return 0;
|
||||
});
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
else {
|
||||
new StaticText(window, grid.getLabelSlot(), getSwitchPositionName(SWSRC_SW1 + i), BUTTON_BACKGROUND, CENTERED);
|
||||
} else {
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(),
|
||||
getSwitchPositionName(SWSRC_SW1 + i),
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
auto button = new LogicalSwitchButton(window, grid.getFieldSlot(), i);
|
||||
button->setPressHandler([=]() {
|
||||
Menu * menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
editLogicalSwitch(window, i);
|
||||
Menu* menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() { editLogicalSwitch(window, i); });
|
||||
if (ls->func)
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
clipboard.type = CLIPBOARD_TYPE_CUSTOM_SWITCH;
|
||||
clipboard.data.csw = *ls;
|
||||
});
|
||||
if (ls->func)
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
clipboard.type = CLIPBOARD_TYPE_CUSTOM_SWITCH;
|
||||
clipboard.data.csw = *ls;
|
||||
});
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH)
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
*ls = clipboard.data.csw;
|
||||
storageDirty(EE_MODEL);
|
||||
rebuild(window, i);
|
||||
});
|
||||
if (ls->func || ls->v1 || ls->v2 || ls->delay || ls->duration || ls->andsw)
|
||||
menu->addLine(STR_CLEAR, [=]() {
|
||||
memset(ls, 0, sizeof(LogicalSwitchData));
|
||||
storageDirty(EE_MODEL);
|
||||
rebuild(window, i);
|
||||
});
|
||||
return 0;
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH)
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
*ls = clipboard.data.csw;
|
||||
storageDirty(EE_MODEL);
|
||||
rebuild(window, i);
|
||||
});
|
||||
if (ls->func || ls->v1 || ls->v2 || ls->delay || ls->duration ||
|
||||
ls->andsw)
|
||||
menu->addLine(STR_CLEAR, [=]() {
|
||||
memset(ls, 0, sizeof(LogicalSwitchData));
|
||||
storageDirty(EE_MODEL);
|
||||
rebuild(window, i);
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
if (focusIndex == i) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
txt->setHeight(button->height());
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
|
||||
virtual void build(FormWindow * window) override
|
||||
{
|
||||
build(window, -1);
|
||||
build(window, 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -53,235 +53,253 @@ bool reachMixesLimit()
|
||||
return false;
|
||||
}
|
||||
|
||||
class MixEditWindow : public Page {
|
||||
public:
|
||||
MixEditWindow(int8_t channel, uint8_t mixIndex) :
|
||||
Page(ICON_MODEL_MIXER),
|
||||
channel(channel),
|
||||
mixIndex(mixIndex)
|
||||
{
|
||||
buildBody(&body);
|
||||
buildHeader(&header);
|
||||
class MixEditWindow : public Page
|
||||
{
|
||||
public:
|
||||
MixEditWindow(int8_t channel, uint8_t mixIndex) :
|
||||
Page(ICON_MODEL_MIXER), channel(channel), mixIndex(mixIndex)
|
||||
{
|
||||
buildBody(&body);
|
||||
buildHeader(&header);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t channel;
|
||||
uint8_t mixIndex;
|
||||
FormGroup *curveParamField = nullptr;
|
||||
|
||||
void buildHeader(Window *window)
|
||||
{
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_MIXES, 0, FOCUS_COLOR);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
getSourceString(MIXSRC_CH1 + channel), 0, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
void buildBody(FormWindow *window)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(8);
|
||||
|
||||
MixData *mix = mixAddress(mixIndex);
|
||||
|
||||
// Mix name
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXNAME);
|
||||
new RadioTextEdit(window, grid.getFieldSlot(), mix->name,
|
||||
sizeof(mix->name));
|
||||
grid.nextLine();
|
||||
|
||||
// Source
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SOURCE);
|
||||
new SourceChoice(window, grid.getFieldSlot(), 0, MIXSRC_LAST,
|
||||
GET_SET_DEFAULT(mix->srcRaw));
|
||||
grid.nextLine();
|
||||
|
||||
// Weight
|
||||
new StaticText(window, grid.getLabelSlot(), STR_WEIGHT);
|
||||
auto gvar =
|
||||
new GVarNumberEdit(window, grid.getFieldSlot(), MIX_WEIGHT_MIN,
|
||||
MIX_WEIGHT_MAX, GET_SET_DEFAULT(mix->weight));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
|
||||
// Offset
|
||||
new StaticText(window, grid.getLabelSlot(), STR_OFFSET);
|
||||
gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_OFFSET_MIN,
|
||||
MIX_OFFSET_MAX, GET_SET_DEFAULT(mix->offset));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
|
||||
// Trim
|
||||
new StaticText(window, grid.getLabelSlot(), STR_TRIM);
|
||||
new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(mix->carryTrim));
|
||||
grid.nextLine();
|
||||
|
||||
// Curve
|
||||
new StaticText(&body, grid.getLabelSlot(), STR_CURVE);
|
||||
new Choice(&body, grid.getFieldSlot(2, 0), "\004DiffExpoFuncCstm", 0,
|
||||
CURVE_REF_CUSTOM, GET_DEFAULT(mix->curve.type),
|
||||
[=](int32_t newValue) {
|
||||
mix->curve.type = newValue;
|
||||
mix->curve.value = 0;
|
||||
SET_DIRTY();
|
||||
updateCurveParamField(mix);
|
||||
});
|
||||
curveParamField =
|
||||
new FormGroup(&body, grid.getFieldSlot(2, 1), FORM_FORWARD_FOCUS);
|
||||
updateCurveParamField(mix);
|
||||
grid.nextLine();
|
||||
|
||||
// Flight modes
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FLMODE);
|
||||
for (uint8_t i = 0; i < MAX_FLIGHT_MODES; i++) {
|
||||
char fm[2] = {char('0' + i), '\0'};
|
||||
if (i > 0 && (i % 4) == 0) grid.nextLine();
|
||||
new TextButton(
|
||||
window, grid.getFieldSlot(4, i % 4), fm,
|
||||
[=]() -> uint8_t {
|
||||
BFBIT_FLIP(mix->flightModes, bfBit<uint8_t>(i));
|
||||
SET_DIRTY();
|
||||
return !(bfSingleBitGet(mix->flightModes, i));
|
||||
},
|
||||
OPAQUE | (bfSingleBitGet(mix->flightModes, i) ? 0 : BUTTON_CHECKED));
|
||||
}
|
||||
grid.nextLine();
|
||||
|
||||
protected:
|
||||
uint8_t channel;
|
||||
uint8_t mixIndex;
|
||||
FormGroup * curveParamField = nullptr;
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH);
|
||||
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST_IN_MIXES,
|
||||
SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(mix->swtch));
|
||||
grid.nextLine();
|
||||
|
||||
void buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MIXES, 0, MENU_COLOR);
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, getSourceString(MIXSRC_CH1 + channel), 0, MENU_COLOR);
|
||||
}
|
||||
// Warning
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXWARNING);
|
||||
auto edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, 3,
|
||||
GET_SET_DEFAULT(mix->mixWarn));
|
||||
edit->setZeroText(STR_OFF);
|
||||
grid.nextLine();
|
||||
|
||||
void buildBody(FormWindow * window)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(8);
|
||||
// Multiplex
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MULTPX);
|
||||
new Choice(window, grid.getFieldSlot(), STR_VMLTPX, 0, 2,
|
||||
GET_SET_DEFAULT(mix->mltpx));
|
||||
grid.nextLine();
|
||||
|
||||
MixData * mix = mixAddress(mixIndex);
|
||||
// Delay up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYUP);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayUp),
|
||||
SET_VALUE(mix->delayUp, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Mix name
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXNAME);
|
||||
new RadioTextEdit(window, grid.getFieldSlot(), mix->name, sizeof(mix->name));
|
||||
grid.nextLine();
|
||||
// Delay down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYDOWN);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayDown),
|
||||
SET_VALUE(mix->delayDown, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Source
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SOURCE);
|
||||
new SourceChoice(window, grid.getFieldSlot(), 0, MIXSRC_LAST, GET_SET_DEFAULT(mix->srcRaw));
|
||||
grid.nextLine();
|
||||
// Slow up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWUP);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedUp),
|
||||
SET_VALUE(mix->speedUp, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Weight
|
||||
new StaticText(window, grid.getLabelSlot(), STR_WEIGHT);
|
||||
auto gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, GET_SET_DEFAULT(mix->weight));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
// Slow down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWDOWN);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedDown),
|
||||
SET_VALUE(mix->speedDown, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Offset
|
||||
new StaticText(window, grid.getLabelSlot(), STR_OFFSET);
|
||||
gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_OFFSET_MIN, MIX_OFFSET_MAX, GET_SET_DEFAULT(mix->offset));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
window->setInnerHeight(grid.getWindowHeight());
|
||||
}
|
||||
|
||||
// Trim
|
||||
new StaticText(window, grid.getLabelSlot(), STR_TRIM);
|
||||
new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(mix->carryTrim));
|
||||
grid.nextLine();
|
||||
// TODO share this code with INPUT
|
||||
void updateCurveParamField(MixData *line)
|
||||
{
|
||||
curveParamField->clear();
|
||||
|
||||
// Curve
|
||||
new StaticText(&body, grid.getLabelSlot(), STR_CURVE);
|
||||
new Choice(&body, grid.getFieldSlot(2, 0), "\004DiffExpoFuncCstm", 0, CURVE_REF_CUSTOM,
|
||||
GET_DEFAULT(mix->curve.type),
|
||||
[=](int32_t newValue) {
|
||||
mix->curve.type = newValue;
|
||||
mix->curve.value = 0;
|
||||
SET_DIRTY();
|
||||
updateCurveParamField(mix);
|
||||
});
|
||||
curveParamField = new FormGroup(&body, grid.getFieldSlot(2, 1), FORM_FORWARD_FOCUS);
|
||||
updateCurveParamField(mix);
|
||||
grid.nextLine();
|
||||
const rect_t rect = {0, 0, curveParamField->width(),
|
||||
curveParamField->height()};
|
||||
|
||||
// Flight modes
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FLMODE);
|
||||
for (uint8_t i = 0; i < MAX_FLIGHT_MODES; i++) {
|
||||
char fm[2] = {char('0' + i), '\0'};
|
||||
if (i > 0 && (i % 4) == 0)
|
||||
grid.nextLine();
|
||||
new TextButton(window, grid.getFieldSlot(4, i % 4), fm,
|
||||
[=]() -> uint8_t {
|
||||
BFBIT_FLIP(mix->flightModes, bfBit<uint8_t>(i));
|
||||
SET_DIRTY();
|
||||
return !(bfSingleBitGet(mix->flightModes, i));
|
||||
},
|
||||
OPAQUE | (bfSingleBitGet(mix->flightModes, i) ? 0 : BUTTON_CHECKED));
|
||||
switch (line->curve.type) {
|
||||
case CURVE_REF_DIFF:
|
||||
case CURVE_REF_EXPO: {
|
||||
GVarNumberEdit *edit =
|
||||
new GVarNumberEdit(curveParamField, rect, -100, 100,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
edit->setSuffix("%");
|
||||
break;
|
||||
}
|
||||
grid.nextLine();
|
||||
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH);
|
||||
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(mix->swtch));
|
||||
grid.nextLine();
|
||||
case CURVE_REF_FUNC:
|
||||
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
break;
|
||||
|
||||
// Warning
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXWARNING);
|
||||
auto edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, 3, GET_SET_DEFAULT(mix->mixWarn));
|
||||
edit->setZeroText(STR_OFF);
|
||||
grid.nextLine();
|
||||
|
||||
// Multiplex
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MULTPX);
|
||||
new Choice(window, grid.getFieldSlot(), STR_VMLTPX, 0, 2, GET_SET_DEFAULT(mix->mltpx));
|
||||
grid.nextLine();
|
||||
|
||||
// Delay up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYUP);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayUp),
|
||||
SET_VALUE(mix->delayUp, newValue),
|
||||
0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Delay down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYDOWN);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayDown),
|
||||
SET_VALUE(mix->delayDown, newValue),
|
||||
0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Slow up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWUP);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedUp),
|
||||
SET_VALUE(mix->speedUp, newValue),
|
||||
0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Slow down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWDOWN);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedDown),
|
||||
SET_VALUE(mix->speedDown, newValue),
|
||||
0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
window->setInnerHeight(grid.getWindowHeight());
|
||||
}
|
||||
|
||||
// TODO share this code with INPUT
|
||||
void updateCurveParamField(MixData * line)
|
||||
{
|
||||
curveParamField->clear();
|
||||
|
||||
const rect_t rect = {0, 0, curveParamField->width(), curveParamField->height()};
|
||||
|
||||
switch (line->curve.type) {
|
||||
case CURVE_REF_DIFF:
|
||||
case CURVE_REF_EXPO:
|
||||
{
|
||||
GVarNumberEdit * edit = new GVarNumberEdit(curveParamField, rect, -100, 100, GET_SET_DEFAULT(line->curve.value));
|
||||
edit->setSuffix("%");
|
||||
break;
|
||||
}
|
||||
|
||||
case CURVE_REF_FUNC:
|
||||
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1, GET_SET_DEFAULT(line->curve.value));
|
||||
break;
|
||||
|
||||
case CURVE_REF_CUSTOM:
|
||||
{
|
||||
auto choice = new Choice(curveParamField, rect, -MAX_CURVES, MAX_CURVES, GET_SET_DEFAULT(line->curve.value));
|
||||
choice->setTextHandler([](int value) {
|
||||
return getCurveString(value);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case CURVE_REF_CUSTOM: {
|
||||
auto choice = new Choice(curveParamField, rect, -MAX_CURVES, MAX_CURVES,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
choice->setTextHandler([](int value) { return getCurveString(value); });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MixLineButton : public CommonInputOrMixButton {
|
||||
public:
|
||||
MixLineButton(FormGroup * parent, const rect_t & rect, uint8_t index) :
|
||||
class MixLineButton : public CommonInputOrMixButton
|
||||
{
|
||||
public:
|
||||
MixLineButton(FormGroup *parent, const rect_t &rect, uint8_t index) :
|
||||
CommonInputOrMixButton(parent, rect, index)
|
||||
{
|
||||
const MixData & mix = g_model.mixData[index];
|
||||
if (mix.swtch || mix.curve.value != 0 || mix.flightModes) {
|
||||
setHeight(height() + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP);
|
||||
}
|
||||
{
|
||||
const MixData &mix = g_model.mixData[index];
|
||||
if (mix.swtch || mix.curve.value != 0 || mix.flightModes) {
|
||||
setHeight(height() + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP);
|
||||
}
|
||||
}
|
||||
|
||||
bool isActive() const override { return isMixActive(index); }
|
||||
|
||||
void paintBody(BitmapBuffer *dc) override
|
||||
{
|
||||
const MixData &line = g_model.mixData[index];
|
||||
|
||||
LcdFlags textColor = DEFAULT_COLOR;
|
||||
|
||||
// first line ...
|
||||
drawValueOrGVar(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, line.weight,
|
||||
MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, textColor);
|
||||
drawSource(dc, 60, FIELD_PADDING_TOP, line.srcRaw, textColor);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, FIELD_PADDING_TOP, mixerSetupLabelIcon, textColor);
|
||||
dc->drawSizedText(166, FIELD_PADDING_TOP, line.name, sizeof(line.name),
|
||||
textColor);
|
||||
}
|
||||
|
||||
bool isActive() const override
|
||||
{
|
||||
return isMixActive(index);
|
||||
// second line ...
|
||||
if (line.swtch) {
|
||||
dc->drawMask(3, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupSwitchIcon, textColor);
|
||||
drawSwitch(dc, 21, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.swtch,
|
||||
textColor);
|
||||
}
|
||||
|
||||
void paintBody(BitmapBuffer * dc) override
|
||||
{
|
||||
const MixData & line = g_model.mixData[index];
|
||||
|
||||
// first line ...
|
||||
drawValueOrGVar(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, line.weight, MIX_WEIGHT_MIN, MIX_WEIGHT_MAX);
|
||||
drawSource(dc, 60, FIELD_PADDING_TOP, line.srcRaw);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, FIELD_PADDING_TOP, mixerSetupLabelIcon, DEFAULT_COLOR);
|
||||
dc->drawSizedText(166, FIELD_PADDING_TOP, line.name, sizeof(line.name));
|
||||
}
|
||||
|
||||
// second line ...
|
||||
if (line.swtch) {
|
||||
dc->drawMask(3, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, mixerSetupSwitchIcon, DEFAULT_COLOR);
|
||||
drawSwitch(dc, 21, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.swtch);
|
||||
}
|
||||
|
||||
if (line.curve.value) {
|
||||
dc->drawMask(60, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, mixerSetupCurveIcon, DEFAULT_COLOR);
|
||||
drawCurveRef(dc, 80, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.curve, 0);
|
||||
}
|
||||
|
||||
if (line.flightModes) {
|
||||
drawFlightModes(dc, line.flightModes);
|
||||
}
|
||||
if (line.curve.value) {
|
||||
dc->drawMask(60, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupCurveIcon, textColor);
|
||||
drawCurveRef(dc, 80, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.curve,
|
||||
textColor);
|
||||
}
|
||||
|
||||
if (line.flightModes) {
|
||||
drawFlightModes(dc, line.flightModes, textColor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void insertMix(uint8_t idx, uint8_t channel)
|
||||
{
|
||||
pauseMixerCalculations();
|
||||
MixData * mix = mixAddress(idx);
|
||||
MixData *mix = mixAddress(idx);
|
||||
memmove(mix + 1, mix, (MAX_MIXERS - (idx + 1)) * sizeof(MixData));
|
||||
memclear(mix, sizeof(MixData));
|
||||
mix->destCh = channel;
|
||||
mix->srcRaw = channel + 1;
|
||||
if (!isSourceAvailable(mix->srcRaw)) {
|
||||
mix->srcRaw = (channel > 3 ? MIXSRC_Rud - 1 + channel : MIXSRC_Rud - 1 + channelOrder(channel));
|
||||
mix->srcRaw = (channel > 3 ? MIXSRC_Rud - 1 + channel
|
||||
: MIXSRC_Rud - 1 + channelOrder(channel));
|
||||
while (!isSourceAvailable(mix->srcRaw)) {
|
||||
mix->srcRaw += 1;
|
||||
}
|
||||
@@ -313,6 +331,21 @@ void ModelMixesPage::editMix(FormWindow * window, uint8_t channel, uint8_t mixIn
|
||||
});
|
||||
}
|
||||
|
||||
class MixLineTitle : public StaticText
|
||||
{
|
||||
public:
|
||||
using StaticText::StaticText;
|
||||
|
||||
void setTextFlags(LcdFlags flags)
|
||||
{
|
||||
textFlags = flags;
|
||||
for (auto child : children) {
|
||||
auto bitmap = dynamic_cast<StaticBitmap*>(child);
|
||||
if (bitmap) bitmap->setMaskColor(flags & 0xFFFF0000);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void ModelMixesPage::build(FormWindow * window, int8_t focusMixIndex)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
@@ -329,12 +362,15 @@ void ModelMixesPage::build(FormWindow * window, int8_t focusMixIndex)
|
||||
MixData * mix = g_model.mixData;
|
||||
for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) {
|
||||
if (mixIndex < MAX_MIXERS && mix->srcRaw > 0 && mix->destCh == ch) {
|
||||
new StaticText(window, grid.getLabelSlot(), getSourceString(MIXSRC_CH1 + ch), BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
coord_t h = grid.getWindowHeight();
|
||||
auto txt = new MixLineTitle(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_CH1 + ch),
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
uint8_t count = 0;
|
||||
while (mixIndex < MAX_MIXERS && mix->srcRaw > 0 && mix->destCh == ch) {
|
||||
Button * button = new MixLineButton(window, grid.getFieldSlot(), mixIndex);
|
||||
if (focusMixIndex == mixIndex)
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
button->bringToTop();
|
||||
Menu * menu = new Menu(window);
|
||||
@@ -385,14 +421,42 @@ void ModelMixesPage::build(FormWindow * window, int8_t focusMixIndex)
|
||||
});
|
||||
|
||||
if (count++ > 0) {
|
||||
new StaticBitmap(window, {35, button->top() + (button->height() - 18) / 2, 25, 17}, mixerMultiplexBitmap[mix->mltpx]);
|
||||
new StaticBitmap(
|
||||
txt,
|
||||
{35 - txt->left(),
|
||||
button->top() - txt->top() + (button->height() - 18) / 2, 25,
|
||||
17},
|
||||
mixerMultiplexBitmap[mix->mltpx], DEFAULT_COLOR);
|
||||
}
|
||||
|
||||
grid.spacer(button->height() - 2);
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
if (focus) button->bringToTop();
|
||||
});
|
||||
|
||||
if (focusMixIndex == mixIndex) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
|
||||
grid.spacer(button->height() - 1);
|
||||
++mixIndex;
|
||||
++mix;
|
||||
}
|
||||
|
||||
h = grid.getWindowHeight() - h + 1;
|
||||
txt->setHeight(h);
|
||||
|
||||
grid.spacer(7);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -39,8 +39,14 @@ class OutputEditWindow : public Page {
|
||||
|
||||
void buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MENULIMITS, 0, MENU_COLOR);
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, getSourceString(MIXSRC_CH1 + channel), 0, MENU_COLOR);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_MENULIMITS, 0, FOCUS_COLOR);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
getSourceString(MIXSRC_CH1 + channel), 0, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
void buildBody(FormWindow * window)
|
||||
@@ -120,28 +126,44 @@ class OutputLineButton : public Button {
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
LcdFlags textColor = DEFAULT_COLOR;
|
||||
LcdFlags bgColor = FIELD_BGCOLOR;
|
||||
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), bgColor);
|
||||
|
||||
// first line
|
||||
dc->drawNumber(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, output->min - 1000, PREC1);
|
||||
dc->drawNumber(68, FIELD_PADDING_TOP, output->max + 1000, PREC1);
|
||||
dc->drawNumber(132, FIELD_PADDING_TOP, output->offset, PREC1);
|
||||
dc->drawNumber(226, FIELD_PADDING_TOP, PPM_CENTER + output->ppmCenter, RIGHT);
|
||||
dc->drawText(228, FIELD_PADDING_TOP, output->symetrical ? "=" : "\210");
|
||||
dc->drawNumber(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, output->min - 1000,
|
||||
PREC1 | textColor);
|
||||
dc->drawNumber(68, FIELD_PADDING_TOP, output->max + 1000, PREC1 | textColor);
|
||||
dc->drawNumber(132, FIELD_PADDING_TOP, output->offset, PREC1 | textColor);
|
||||
dc->drawNumber(226, FIELD_PADDING_TOP, PPM_CENTER + output->ppmCenter,
|
||||
RIGHT | textColor);
|
||||
dc->drawText(228, FIELD_PADDING_TOP, output->symetrical ? "=" : "\210",
|
||||
textColor);
|
||||
|
||||
// second line
|
||||
if (output->revert) {
|
||||
dc->drawTextAtIndex(4, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, STR_MMMINV, output->revert);
|
||||
dc->drawTextAtIndex(4, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, STR_MMMINV,
|
||||
output->revert, textColor);
|
||||
}
|
||||
if (output->curve) {
|
||||
dc->drawMask(68, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, mixerSetupCurveIcon, DEFAULT_COLOR);
|
||||
dc->drawText(88, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, getCurveString(output->curve));
|
||||
dc->drawMask(68, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupCurveIcon, textColor);
|
||||
dc->drawText(88, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
getCurveString(output->curve), textColor);
|
||||
}
|
||||
if (output->name[0]) {
|
||||
dc->drawMask(146, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, mixerSetupLabelIcon, DEFAULT_COLOR);
|
||||
dc->drawSizedText(166, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, output->name, sizeof(output->name));
|
||||
dc->drawMask(146, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupLabelIcon, textColor);
|
||||
dc->drawSizedText(166, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
output->name, sizeof(output->name), textColor);
|
||||
}
|
||||
|
||||
// bounding rect
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? CHECKBOX_COLOR : DISABLE_COLOR);
|
||||
if (hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -171,7 +193,9 @@ void ModelOutputsPage::build(FormWindow * window, int8_t focusChannel)
|
||||
LimitData * output = limitAddress(ch);
|
||||
|
||||
// Channel label
|
||||
new StaticText(window, grid.getLabelSlot(), getSourceString(MIXSRC_CH1 + ch), BUTTON_BACKGROUND, CENTERED);
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_CH1 + ch),
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
// Channel settings
|
||||
Button * button = new OutputLineButton(window, grid.getFieldSlot(), output);
|
||||
@@ -203,11 +227,25 @@ void ModelOutputsPage::build(FormWindow * window, int8_t focusChannel)
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
if (focusChannel == ch) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
txt->setHeight(button->height());
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class ModelOutputsPage: public PageTab {
|
||||
|
||||
virtual void build(FormWindow * window) override
|
||||
{
|
||||
build(window, -1);
|
||||
build(window, 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -24,9 +24,23 @@
|
||||
#include "storage/modelslist.h"
|
||||
#include "libopenui.h"
|
||||
|
||||
#define CATEGORIES_WIDTH 120
|
||||
#define MODELS_LEFT 123
|
||||
#define MODELS_COLUMN_WIDTH 174
|
||||
#if LCD_W > LCD_H
|
||||
constexpr int MODEL_CELLS_PER_LINE = 3;
|
||||
#else
|
||||
constexpr int MODEL_CELLS_PER_LINE = 2;
|
||||
#endif
|
||||
|
||||
constexpr coord_t MODEL_CELL_PADDING = 6;
|
||||
|
||||
constexpr coord_t MODEL_SELECT_CELL_WIDTH =
|
||||
(LCD_W - (MODEL_CELLS_PER_LINE + 1) * MODEL_CELL_PADDING) /
|
||||
MODEL_CELLS_PER_LINE;
|
||||
|
||||
constexpr coord_t MODEL_SELECT_CELL_HEIGHT = 92;
|
||||
|
||||
constexpr coord_t MODEL_IMAGE_WIDTH = MODEL_SELECT_CELL_WIDTH;
|
||||
constexpr coord_t MODEL_IMAGE_HEIGHT = 72;
|
||||
|
||||
|
||||
enum ModelSelectMode {
|
||||
MODE_SELECT_MODEL,
|
||||
@@ -66,310 +80,268 @@ void setCurrentCategory(unsigned int index)
|
||||
}
|
||||
#endif
|
||||
|
||||
class ModelButton: public Button {
|
||||
public:
|
||||
ModelButton(FormGroup * parent, const rect_t & rect, ModelCell * modelCell, Window * footer) :
|
||||
Button(parent, rect),
|
||||
modelCell(modelCell)
|
||||
{
|
||||
load();
|
||||
}
|
||||
class ModelButton : public Button
|
||||
{
|
||||
public:
|
||||
ModelButton(FormGroup *parent, const rect_t &rect, ModelCell *modelCell) :
|
||||
Button(parent, rect), modelCell(modelCell)
|
||||
{
|
||||
load();
|
||||
}
|
||||
|
||||
void load()
|
||||
{
|
||||
uint8_t version;
|
||||
~ModelButton()
|
||||
{
|
||||
if (buffer) { delete buffer; }
|
||||
}
|
||||
|
||||
void load()
|
||||
{
|
||||
uint8_t version;
|
||||
|
||||
PACK(struct {
|
||||
ModelHeader header;
|
||||
TimerData timers[MAX_TIMERS];
|
||||
}) partialModel;
|
||||
const char * error = nullptr;
|
||||
PACK(struct {
|
||||
ModelHeader header;
|
||||
TimerData timers[MAX_TIMERS];
|
||||
})
|
||||
partialModel;
|
||||
const char *error = nullptr;
|
||||
|
||||
if (strncmp(modelCell->modelFilename, g_eeGeneral.currModelFilename, LEN_MODEL_FILENAME) == 0) {
|
||||
memcpy(&partialModel.header, &g_model.header, sizeof(partialModel));
|
||||
}
|
||||
else {
|
||||
error = readModel(modelCell->modelFilename, (uint8_t *)&partialModel.header, sizeof(partialModel), &version);
|
||||
if (!error) {
|
||||
if (modelCell->modelName[0] == '\0'
|
||||
&& partialModel.header.name[0] != '\0') {
|
||||
modelCell->setModelName(partialModel.header.name);
|
||||
}
|
||||
if (strncmp(modelCell->modelFilename, g_eeGeneral.currModelFilename,
|
||||
LEN_MODEL_FILENAME) == 0) {
|
||||
memcpy(&partialModel.header, &g_model.header, sizeof(partialModel));
|
||||
} else {
|
||||
error =
|
||||
readModel(modelCell->modelFilename, (uint8_t *)&partialModel.header,
|
||||
sizeof(partialModel), &version);
|
||||
if (!error) {
|
||||
if (modelCell->modelName[0] == '\0' &&
|
||||
partialModel.header.name[0] != '\0') {
|
||||
modelCell->setModelName(partialModel.header.name);
|
||||
}
|
||||
}
|
||||
|
||||
buffer = new BitmapBuffer(BMP_RGB565, MODELCELL_WIDTH, MODELCELL_HEIGHT);
|
||||
if (buffer == nullptr) {
|
||||
return;
|
||||
}
|
||||
buffer->clear(DEFAULT_BGCOLOR);
|
||||
|
||||
if (error) {
|
||||
buffer->drawText(5, 2, "(Invalid Model)", DEFAULT_COLOR);
|
||||
buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, DEFAULT_COLOR);
|
||||
}
|
||||
else {
|
||||
char timerName[LEN_TIMER_STRING];
|
||||
buffer->drawSizedText(5, 2, modelCell->modelName, LEN_MODEL_NAME, FONT(XS) | DEFAULT_COLOR);
|
||||
getTimerString(timerName, 0);
|
||||
for (auto & timer : partialModel.timers) {
|
||||
if (timer.mode > 0 && timer.persistent) {
|
||||
getTimerString(timerName, timer.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
buffer->drawText(101, 40, timerName, DEFAULT_COLOR);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
buffer->drawBitmapPattern(104+i*11, 25, LBM_SCORE0, TITLE_BGCOLOR);
|
||||
}
|
||||
GET_FILENAME(filename, BITMAPS_PATH, partialModel.header.bitmap, "");
|
||||
const BitmapBuffer * bitmap = BitmapBuffer::loadBitmap(filename);
|
||||
if (bitmap) {
|
||||
buffer->drawScaledBitmap(bitmap, 5, 24, 56, 32);
|
||||
delete bitmap;
|
||||
}
|
||||
else {
|
||||
buffer->drawBitmapPattern(5, 23, LBM_LIBRARY_SLOT, DEFAULT_COLOR);
|
||||
}
|
||||
}
|
||||
buffer->drawSolidHorizontalLine(5, 19, 143, LINE_COLOR);
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
FormField::paint(dc);
|
||||
dc->drawBitmap(10, 2, buffer);
|
||||
if (modelCell == modelslist.getCurrentModel()) {
|
||||
dc->drawBitmapPattern(112, 71, LBM_ACTIVE_MODEL, TITLE_BGCOLOR);
|
||||
}
|
||||
}
|
||||
|
||||
const char * modelFilename()
|
||||
{
|
||||
return modelCell->modelFilename;
|
||||
delete buffer;
|
||||
buffer = new BitmapBuffer(BMP_RGB565, width(), height());
|
||||
if (buffer == nullptr) {
|
||||
return;
|
||||
}
|
||||
buffer->clear(FIELD_BGCOLOR);
|
||||
|
||||
if (error) {
|
||||
buffer->drawText(width() / 2, 2, "(Invalid Model)",
|
||||
DEFAULT_COLOR | CENTERED);
|
||||
} else {
|
||||
GET_FILENAME(filename, BITMAPS_PATH, partialModel.header.bitmap, "");
|
||||
const BitmapBuffer *bitmap = BitmapBuffer::loadBitmap(filename);
|
||||
if (bitmap) {
|
||||
buffer->drawScaledBitmap(bitmap, 0, 0, width(), height());
|
||||
delete bitmap;
|
||||
} else {
|
||||
buffer->drawText(width() / 2, 56, "(No Picture)",
|
||||
FONT(XXS) | DEFAULT_COLOR | CENTERED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer *dc) override
|
||||
{
|
||||
FormField::paint(dc);
|
||||
|
||||
if (buffer)
|
||||
dc->drawBitmap(0, 0, buffer);
|
||||
|
||||
if (modelCell == modelslist.getCurrentModel()) {
|
||||
dc->drawSolidFilledRect(0, 0, width(), 20, HIGHLIGHT_COLOR);
|
||||
dc->drawSizedText(width() / 2, 2, modelCell->modelName,
|
||||
LEN_MODEL_NAME,
|
||||
DEFAULT_COLOR | CENTERED);
|
||||
} else {
|
||||
LcdFlags textColor;
|
||||
// if (hasFocus()) {
|
||||
// dc->drawFilledRect(0, 0, width(), 20, SOLID, FOCUS_BGCOLOR, 5);
|
||||
// textColor = FOCUS_COLOR;
|
||||
// }
|
||||
// else {
|
||||
dc->drawFilledRect(0, 0, width(), 20, SOLID, FIELD_BGCOLOR, 5);
|
||||
textColor = DEFAULT_COLOR;
|
||||
// }
|
||||
|
||||
dc->drawSizedText(width() / 2, 2, modelCell->modelName,
|
||||
LEN_MODEL_NAME,
|
||||
textColor | CENTERED);
|
||||
}
|
||||
|
||||
protected:
|
||||
ModelCell * modelCell;
|
||||
BitmapBuffer * buffer = nullptr;
|
||||
if (!hasFocus()) {
|
||||
dc->drawSolidRect(0, 0, width(), height(), 1, FIELD_FRAME_COLOR);
|
||||
} else {
|
||||
dc->drawSolidRect(0, 0, width(), height(), 2, FOCUS_BGCOLOR);
|
||||
}
|
||||
}
|
||||
|
||||
const char *modelFilename() { return modelCell->modelFilename; }
|
||||
|
||||
protected:
|
||||
ModelCell *modelCell;
|
||||
BitmapBuffer *buffer = nullptr;
|
||||
};
|
||||
|
||||
class ModelSelectFooter: public Window {
|
||||
public:
|
||||
explicit ModelSelectFooter(Window * parent):
|
||||
Window(parent, {0, parent->height() - MODEL_SELECT_FOOTER_HEIGHT, LCD_W, MODEL_SELECT_FOOTER_HEIGHT}, OPAQUE)
|
||||
{
|
||||
}
|
||||
class ModelCategoryPageBody : public FormWindow
|
||||
{
|
||||
public:
|
||||
ModelCategoryPageBody(FormWindow *parent, const rect_t &rect,
|
||||
ModelsCategory *category) :
|
||||
FormWindow(parent, rect, FORM_FORWARD_FOCUS), category(category)
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void setCurrentModel(ModelCell * model)
|
||||
{
|
||||
currentModel = model;
|
||||
invalidate();
|
||||
}
|
||||
void update(int selected = 0)
|
||||
{
|
||||
clear();
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), DISABLE_COLOR);
|
||||
uint32_t size = sdGetSize() / 100;
|
||||
coord_t x = 7;
|
||||
if (modelselSdFreeBitmap) {
|
||||
dc->drawMask(7, 4, modelselSdFreeBitmap, DEFAULT_COLOR);
|
||||
x += modelselSdFreeBitmap->width() + 3;
|
||||
}
|
||||
x = dc->drawNumber(x, 3, size, PREC1|FONT(XS), 0, nullptr, "GB");
|
||||
x += 20;
|
||||
if (modelselModelQtyBitmap) {
|
||||
dc->drawMask(x, 4, modelselModelQtyBitmap, DEFAULT_COLOR);
|
||||
x += modelselModelQtyBitmap->width() + 3;
|
||||
}
|
||||
x = dc->drawNumber(x, 3, modelslist.getModelsCount(), FONT(XS));
|
||||
if (currentModel) {
|
||||
x += 20;
|
||||
if (modelselModelNameBitmap) {
|
||||
dc->drawMask(x, 4, modelselModelNameBitmap, DEFAULT_COLOR);
|
||||
x += modelselModelNameBitmap->width() + 3;
|
||||
}
|
||||
dc->drawText(x, 3, currentModel->modelFilename, FONT(XS) | DEFAULT_COLOR);
|
||||
}
|
||||
}
|
||||
int index = 0;
|
||||
coord_t y = MODEL_CELL_PADDING;
|
||||
coord_t x = MODEL_CELL_PADDING;
|
||||
|
||||
protected:
|
||||
ModelCell * currentModel = nullptr;
|
||||
};
|
||||
for (auto &model : *category) {
|
||||
auto button = new ModelButton(
|
||||
this, {x, y, MODEL_SELECT_CELL_WIDTH, MODEL_SELECT_CELL_HEIGHT},
|
||||
model);
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
if (button->hasFocus()) {
|
||||
Menu *menu = new Menu(parent);
|
||||
if (model != modelslist.getCurrentModel()) {
|
||||
menu->addLine(STR_SELECT_MODEL, [=]() {
|
||||
// we store the latest changes if any
|
||||
storageFlushCurrentModel();
|
||||
storageCheck(true);
|
||||
memcpy(g_eeGeneral.currModelFilename, model->modelFilename,
|
||||
LEN_MODEL_FILENAME);
|
||||
loadModel(g_eeGeneral.currModelFilename, false);
|
||||
storageDirty(EE_GENERAL);
|
||||
storageCheck(true);
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
constexpr coord_t MODEL_SELECT_CELL_WIDTH = (LCD_W - 3 * PAGE_PADDING) / 2;
|
||||
#else
|
||||
constexpr coord_t MODEL_SELECT_CELL_WIDTH = LCD_W - 2 * PAGE_PADDING;
|
||||
#endif
|
||||
constexpr coord_t MODEL_SELECT_CELL_HEIGHT = 94;
|
||||
|
||||
class ModelCategoryPageBody: public FormWindow {
|
||||
public:
|
||||
ModelCategoryPageBody(FormWindow * parent, const rect_t & rect, ModelsCategory * category, ModelSelectFooter * footer):
|
||||
FormWindow(parent, rect, FORM_FORWARD_FOCUS),
|
||||
category(category),
|
||||
footer(footer)
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void update(int selected = 0)
|
||||
{
|
||||
clear();
|
||||
|
||||
int index = 0;
|
||||
coord_t y = PAGE_PADDING;
|
||||
coord_t x = PAGE_PADDING;
|
||||
coord_t h = PAGE_PADDING;
|
||||
for (auto & model: * category) {
|
||||
auto button = new ModelButton(this, {x, y, MODEL_SELECT_CELL_WIDTH, MODEL_SELECT_CELL_HEIGHT}, model, nullptr);
|
||||
|
||||
button->setFocusHandler([=](bool active) {
|
||||
if (active) {
|
||||
footer->setCurrentModel(model);
|
||||
modelslist.setCurrentModel(model);
|
||||
update(); // modelslist.getModelIndex(modelCell));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
if (button->hasFocus()) {
|
||||
Menu * menu = new Menu(parent);
|
||||
if (model != modelslist.getCurrentModel()) {
|
||||
menu->addLine(STR_SELECT_MODEL, [=]() {
|
||||
// we store the latest changes if any
|
||||
storageFlushCurrentModel();
|
||||
storageCheck(true);
|
||||
memcpy(g_eeGeneral.currModelFilename, model->modelFilename, LEN_MODEL_FILENAME);
|
||||
loadModel(g_eeGeneral.currModelFilename, false);
|
||||
storageDirty(EE_GENERAL);
|
||||
storageCheck(true);
|
||||
|
||||
modelslist.setCurrentModel(model);
|
||||
update(); // modelslist.getModelIndex(modelCell));
|
||||
});
|
||||
}
|
||||
menu->addLine(STR_CREATE_MODEL, getCreateModelAction());
|
||||
menu->addLine(STR_DUPLICATE_MODEL, [=]() {
|
||||
char duplicatedFilename[LEN_MODEL_FILENAME + 1];
|
||||
memcpy(duplicatedFilename, model->modelFilename, sizeof(duplicatedFilename));
|
||||
if (findNextFileIndex(duplicatedFilename, LEN_MODEL_FILENAME, MODELS_PATH)) {
|
||||
sdCopyFile(model->modelFilename, MODELS_PATH, duplicatedFilename, MODELS_PATH);
|
||||
modelslist.addModel(category, duplicatedFilename);
|
||||
update(index);
|
||||
}
|
||||
else {
|
||||
POPUP_WARNING("Invalid File");
|
||||
}
|
||||
});
|
||||
// menu->addLine(STR_MOVE_MODEL);
|
||||
if (model != modelslist.getCurrentModel()) {
|
||||
menu->addLine(STR_DELETE_MODEL, [=]() {
|
||||
new ConfirmDialog(parent, STR_DELETE_MODEL, std::string(model->modelName, sizeof(model->modelName)).c_str(), [=] {
|
||||
modelslist.removeModel(category, model);
|
||||
update(index > 0 ? index - 1 : 0);
|
||||
menu->addLine(STR_CREATE_MODEL, getCreateModelAction());
|
||||
menu->addLine(STR_DUPLICATE_MODEL, [=]() {
|
||||
char duplicatedFilename[LEN_MODEL_FILENAME + 1];
|
||||
memcpy(duplicatedFilename, model->modelFilename,
|
||||
sizeof(duplicatedFilename));
|
||||
if (findNextFileIndex(duplicatedFilename, LEN_MODEL_FILENAME,
|
||||
MODELS_PATH)) {
|
||||
sdCopyFile(model->modelFilename, MODELS_PATH, duplicatedFilename,
|
||||
MODELS_PATH);
|
||||
modelslist.addModel(category, duplicatedFilename);
|
||||
update(index);
|
||||
} else {
|
||||
POPUP_WARNING("Invalid File");
|
||||
}
|
||||
});
|
||||
// menu->addLine(STR_MOVE_MODEL);
|
||||
if (model != modelslist.getCurrentModel()) {
|
||||
menu->addLine(STR_DELETE_MODEL, [=]() {
|
||||
new ConfirmDialog(
|
||||
parent, STR_DELETE_MODEL,
|
||||
std::string(model->modelName, sizeof(model->modelName))
|
||||
.c_str(),
|
||||
[=] {
|
||||
modelslist.removeModel(category, model);
|
||||
update(index > 0 ? index - 1 : 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
|
||||
if (selected == index) {
|
||||
});
|
||||
}
|
||||
} else {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
footer->setCurrentModel(model);
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
|
||||
if (selected == index) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
if (index % 2 == 0) {
|
||||
x = PAGE_PADDING + MODEL_SELECT_CELL_WIDTH + PAGE_PADDING;
|
||||
h += MODEL_SELECT_CELL_HEIGHT + PAGE_PADDING;
|
||||
}
|
||||
else {
|
||||
x = PAGE_PADDING;
|
||||
y += MODEL_SELECT_CELL_HEIGHT + PAGE_PADDING;
|
||||
}
|
||||
if (index % MODEL_CELLS_PER_LINE == 0) {
|
||||
x = MODEL_CELL_PADDING;
|
||||
y += MODEL_SELECT_CELL_HEIGHT + MODEL_CELL_PADDING;
|
||||
} else {
|
||||
x += MODEL_CELL_PADDING + MODEL_SELECT_CELL_WIDTH;
|
||||
}
|
||||
#else
|
||||
h += MODEL_SELECT_CELL_HEIGHT + PAGE_PADDING;
|
||||
y += MODEL_SELECT_CELL_HEIGHT + PAGE_PADDING;
|
||||
y += MODEL_SELECT_CELL_HEIGHT + MODEL_CELL_PADDING;
|
||||
#endif
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
setInnerHeight(h);
|
||||
|
||||
if (category->empty()) {
|
||||
setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
y += MODEL_SELECT_CELL_HEIGHT + MODEL_CELL_PADDING;
|
||||
setInnerHeight(y);
|
||||
|
||||
if (category->empty()) {
|
||||
setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
void onEvent(event_t event) override
|
||||
{
|
||||
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
Menu * menu = new Menu(this);
|
||||
menu->addLine(STR_CREATE_MODEL, getCreateModelAction());
|
||||
//TODO: create category?
|
||||
}
|
||||
else {
|
||||
FormWindow::onEvent(event);
|
||||
}
|
||||
void onEvent(event_t event) override
|
||||
{
|
||||
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
|
||||
Menu *menu = new Menu(this);
|
||||
menu->addLine(STR_CREATE_MODEL, getCreateModelAction());
|
||||
// TODO: create category?
|
||||
} else {
|
||||
FormWindow::onEvent(event);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void setFocus(uint8_t flag = SET_FOCUS_DEFAULT, Window * from = nullptr) override
|
||||
{
|
||||
if (category->empty()) {
|
||||
// use Window::setFocus() to avoid forwarding focus to nowhere
|
||||
// this crashes currently in libopenui
|
||||
Window::setFocus(flag, from);
|
||||
}
|
||||
else {
|
||||
FormWindow::setFocus(flag, from);
|
||||
}
|
||||
void setFocus(uint8_t flag = SET_FOCUS_DEFAULT,
|
||||
Window *from = nullptr) override
|
||||
{
|
||||
if (category->empty()) {
|
||||
// use Window::setFocus() to avoid forwarding focus to nowhere
|
||||
// this crashes currently in libopenui
|
||||
Window::setFocus(flag, from);
|
||||
} else {
|
||||
FormWindow::setFocus(flag, from);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
ModelsCategory * category;
|
||||
ModelSelectFooter * footer;
|
||||
|
||||
std::function<void(void)> getCreateModelAction()
|
||||
{
|
||||
return [=]() {
|
||||
storageCheck(true);
|
||||
modelslist.setCurrentModel(modelslist.addModel(category, createModel()));
|
||||
#if defined(LUA)
|
||||
// chainMenu(menuModelWizard);
|
||||
#endif
|
||||
update(category->size() - 1);
|
||||
};
|
||||
}
|
||||
protected:
|
||||
ModelsCategory *category;
|
||||
|
||||
std::function<void(void)> getCreateModelAction()
|
||||
{
|
||||
return [=]() {
|
||||
storageCheck(true);
|
||||
modelslist.setCurrentModel(modelslist.addModel(category, createModel()));
|
||||
update(category->size() - 1);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class ModelCategoryPage: public PageTab {
|
||||
public:
|
||||
explicit ModelCategoryPage(ModelsCategory * category) :
|
||||
PageTab(category->name, ICON_MODEL),
|
||||
category(category)
|
||||
{
|
||||
}
|
||||
class ModelCategoryPage : public PageTab
|
||||
{
|
||||
public:
|
||||
explicit ModelCategoryPage(ModelsCategory *category) :
|
||||
PageTab(category->name, ICON_MODEL), category(category)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
ModelsCategory * category;
|
||||
protected:
|
||||
ModelsCategory *category;
|
||||
|
||||
void build(FormWindow * window) override
|
||||
{
|
||||
auto footer = new ModelSelectFooter(window);
|
||||
new ModelCategoryPageBody(window, {0, 0, LCD_W, window->height() - MODEL_SELECT_FOOTER_HEIGHT}, category, footer);
|
||||
}
|
||||
void build(FormWindow *window) override
|
||||
{
|
||||
new ModelCategoryPageBody(
|
||||
window, {0, 0, LCD_W, window->height()},
|
||||
category);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ModelSelectMenu::ModelSelectMenu():
|
||||
TabsGroup(ICON_MODEL)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,11 @@ std::string switchWarninglabel(swsrc_t index)
|
||||
CHAR_DOWN
|
||||
};
|
||||
|
||||
return TEXT_AT_INDEX(STR_VSRCRAW, (index + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1)) + std::string(&switchPositions[g_model.switchWarningState >> (3*index) & 0x07], 1);
|
||||
return TEXT_AT_INDEX(STR_VSRCRAW,
|
||||
(index + MIXSRC_FIRST_SWITCH - MIXSRC_Rud + 1)) +
|
||||
std::string(
|
||||
&switchPositions[g_model.switchWarningState >> (3 * index) & 0x07],
|
||||
1);
|
||||
}
|
||||
|
||||
class ChannelFailsafeBargraph: public Window {
|
||||
@@ -80,7 +84,7 @@ class ChannelFailsafeBargraph: public Window {
|
||||
class FailSafeBody : public FormGroup {
|
||||
public:
|
||||
FailSafeBody(FormGroup * parent, const rect_t & rect, uint8_t moduleIdx) :
|
||||
FormGroup(parent, rect),
|
||||
FormGroup(parent, rect, FORM_FORWARD_FOCUS),
|
||||
moduleIdx(moduleIdx)
|
||||
{
|
||||
build();
|
||||
@@ -106,16 +110,17 @@ class FailSafeBody : public FormGroup {
|
||||
new StaticText(this, grid.getLabelSlot(), getSourceString(MIXSRC_CH1 + ch));
|
||||
|
||||
// Channel numeric value
|
||||
new NumberEdit(this, grid.getFieldSlot(3, 0), -lim, lim,
|
||||
GET_DEFAULT(calcRESXto1000(g_model.failsafeChannels[ch])),
|
||||
new NumberEdit(this, grid.getFieldSlot(8, 0), -lim, lim,
|
||||
GET_DEFAULT(g_model.failsafeChannels[ch]),
|
||||
SET_VALUE(g_model.failsafeChannels[ch], newValue),
|
||||
0, PREC1);
|
||||
0, PREC1 | RIGHT);
|
||||
|
||||
// Channel bargraph
|
||||
new ChannelFailsafeBargraph(this, {150, grid.getWindowHeight(), 150, PAGE_LINE_HEIGHT}, moduleIdx, ch);
|
||||
new ChannelFailsafeBargraph(this, {180, grid.getWindowHeight(), 150, PAGE_LINE_HEIGHT}, moduleIdx, ch);
|
||||
grid.nextLine();
|
||||
}
|
||||
|
||||
grid.spacer();
|
||||
auto out2fail = new TextButton(this, grid.getLineSlot(), STR_CHANNELS2FAILSAFE);
|
||||
out2fail->setPressHandler([=]() {
|
||||
setCustomFailsafe(moduleIdx);
|
||||
@@ -124,33 +129,24 @@ class FailSafeBody : public FormGroup {
|
||||
});
|
||||
|
||||
grid.nextLine();
|
||||
setInnerHeight(grid.getWindowHeight());
|
||||
setInnerHeight(grid.getWindowHeight() + PAGE_PADDING);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t moduleIdx;
|
||||
};
|
||||
|
||||
class FailSafeFooter : public Window {
|
||||
public:
|
||||
FailSafeFooter(Window * parent, const rect_t & rect) :
|
||||
Window(parent, rect)
|
||||
{
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class FailSafePage : public Page {
|
||||
public:
|
||||
explicit FailSafePage(uint8_t moduleIdx) :
|
||||
Page(ICON_STATS_ANALOGS),
|
||||
moduleIdx(moduleIdx)
|
||||
{
|
||||
new FailSafeBody(&body, {0, 0, LCD_W, height() - footerHeight}, moduleIdx);
|
||||
new FailSafeFooter(&body, {0, height() - footerHeight, LCD_W, footerHeight});
|
||||
new FailSafeBody(&body, {0, 0, LCD_W, body.height()}, moduleIdx);
|
||||
new StaticText(&header,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_FAILSAFESET, 0, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -61,6 +61,12 @@ class SensorButton : public Button {
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
uint32_t now = RTOS_GET_MS();
|
||||
if (now - lastRefresh >= 200) {
|
||||
// update at least every 200ms
|
||||
invalidate();
|
||||
}
|
||||
|
||||
TelemetryItem & telemetryItem = telemetryItems[index];
|
||||
if (telemetryItem.isFresh()) {
|
||||
invalidate();
|
||||
@@ -73,9 +79,10 @@ class SensorButton : public Button {
|
||||
{
|
||||
TelemetryItem &telemetryItem = telemetryItems[index];
|
||||
|
||||
if (telemetryItem.isFresh()) {
|
||||
if (telemetryItem.isFresh())
|
||||
dc->drawSolidFilledRect(2, 2, rect.w - 4, rect.h - 4, HIGHLIGHT_COLOR);
|
||||
}
|
||||
else
|
||||
dc->drawSolidFilledRect(2, 2, rect.w - 4, rect.h - 4, FIELD_BGCOLOR);
|
||||
|
||||
dc->drawNumber(2, 1, number, LEFT, 0, nullptr, ":");
|
||||
|
||||
@@ -86,7 +93,7 @@ class SensorButton : public Button {
|
||||
drawSensorCustomValue(dc, SENSOR_COL2, line1, index, getValue(MIXSRC_FIRST_TELEM + 3 * index), LEFT | color);
|
||||
}
|
||||
else {
|
||||
dc->drawText(SENSOR_COL2, line1, "---", CURVE_COLOR);
|
||||
dc->drawText(SENSOR_COL2, line1, "---", DEFAULT_COLOR);
|
||||
}
|
||||
|
||||
TelemetrySensor * sensor = & g_model.telemetrySensors[index];
|
||||
@@ -96,12 +103,17 @@ class SensorButton : public Button {
|
||||
else if (sensor->type == TELEM_TYPE_CUSTOM && !g_model.ignoreSensorIds) {
|
||||
dc->drawNumber(SENSOR_COL3, line1, sensor->instance, LEFT);
|
||||
}
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? CHECKBOX_COLOR : DISABLE_COLOR);
|
||||
|
||||
if (hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t index;
|
||||
uint8_t number;
|
||||
uint32_t lastRefresh = 0;
|
||||
};
|
||||
|
||||
class SensorEditWindow : public Page {
|
||||
|
||||
@@ -26,19 +26,20 @@ PageHeader::PageHeader(Page * parent, uint8_t icon):
|
||||
FormGroup(parent, { 0, 0, LCD_W, MENU_HEADER_HEIGHT }, OPAQUE),
|
||||
icon(icon)
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
, back(this, { 0, 0, MENU_HEADER_BUTTON_WIDTH, MENU_HEADER_BUTTON_WIDTH }, ICON_BACK,
|
||||
, back(this, { 0, 0, MENU_HEADER_BUTTON_WIDTH, MENU_HEADER_BUTTON_WIDTH },
|
||||
[=]() -> uint8_t {
|
||||
parent->deleteLater();
|
||||
return 0;
|
||||
}, NO_FOCUS)
|
||||
}, NO_FOCUS | FORM_NO_BORDER)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
void PageHeader::paint(BitmapBuffer * dc)
|
||||
{
|
||||
OpenTxTheme::instance()->drawMenuBackground(dc, getIcon(), "");
|
||||
dc->drawSolidFilledRect(MENU_HEADER_HEIGHT, 0, LCD_W - MENU_HEADER_HEIGHT, MENU_HEADER_HEIGHT, MENU_BGCOLOR);
|
||||
OpenTxTheme::instance()->drawPageHeaderBackground(dc, getIcon(), "");
|
||||
dc->drawSolidFilledRect(MENU_HEADER_HEIGHT, 0, LCD_W - MENU_HEADER_HEIGHT,
|
||||
MENU_HEADER_HEIGHT, HEADER_COLOR);
|
||||
}
|
||||
|
||||
Page::Page(unsigned icon):
|
||||
|
||||
@@ -51,7 +51,7 @@ class PageHeader: public FormGroup
|
||||
protected:
|
||||
uint8_t icon;
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
IconButton back;
|
||||
Button back;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -84,7 +84,7 @@ class Page: public Window
|
||||
|
||||
bool onTouchSlide(coord_t x, coord_t y, coord_t startX, coord_t startY, coord_t slideX, coord_t slideY) override
|
||||
{
|
||||
Window::onTouchSlide(x, y, startX, startY, slideX, slideY);
|
||||
Window::onTouchSlide(x, y, startX, startY, 0/*slideX*/, slideY);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -30,11 +30,14 @@ uint8_t menuCalibrationState;
|
||||
|
||||
class StickCalibrationWindow: public Window {
|
||||
public:
|
||||
StickCalibrationWindow(Window * parent, const rect_t & rect, uint8_t stickX, uint8_t stickY):
|
||||
Window(parent, rect, REFRESH_ALWAYS),
|
||||
stickX(stickX),
|
||||
stickY(stickY)
|
||||
{
|
||||
StickCalibrationWindow(Window *parent, const rect_t &rect, uint8_t stickX,
|
||||
uint8_t stickY) :
|
||||
Window(parent, rect, REFRESH_ALWAYS), stickX(stickX), stickY(stickY)
|
||||
{
|
||||
setLeft(rect.x - calibStickBackground->width() / 2);
|
||||
setTop(rect.y - calibStickBackground->height() / 2);
|
||||
setWidth(calibStickBackground->width());
|
||||
setHeight(calibStickBackground->height());
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
@@ -42,7 +45,9 @@ class StickCalibrationWindow: public Window {
|
||||
dc->drawBitmap(0, 0, calibStickBackground);
|
||||
int16_t x = calibratedAnalogs[CONVERT_MODE(stickX)];
|
||||
int16_t y = calibratedAnalogs[CONVERT_MODE(stickY)];
|
||||
dc->drawBitmap(width() / 2 - 9 + (bitmapSize / 2 * x) / RESX, height() / 2 - 9 - (bitmapSize / 2 * y) / RESX, calibStick);
|
||||
dc->drawBitmap(width() / 2 - 9 + (bitmapSize / 2 * x) / RESX,
|
||||
height() / 2 - 9 - (bitmapSize / 2 * y) / RESX,
|
||||
calibStick);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -61,8 +66,15 @@ RadioCalibrationPage::RadioCalibrationPage(bool initial):
|
||||
|
||||
void RadioCalibrationPage::buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MENUCALIBRATION, 0, MENU_COLOR);
|
||||
text = new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MENUTOSTART, 0,MENU_COLOR);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_MENUCALIBRATION, 0, FOCUS_COLOR);
|
||||
|
||||
text = new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
STR_MENUTOSTART, 0, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
void RadioCalibrationPage::buildBody(FormWindow * window)
|
||||
@@ -72,8 +84,13 @@ void RadioCalibrationPage::buildBody(FormWindow * window)
|
||||
// The two sticks
|
||||
|
||||
//TODO: dynamic placing
|
||||
new StickCalibrationWindow(window, {40, 20, 90, 90}, STICK1, STICK2);
|
||||
new StickCalibrationWindow(window, {LCD_W - 130, 20, 90, 90}, STICK4, STICK3);
|
||||
new StickCalibrationWindow(window,
|
||||
{window->width() / 3, window->height() / 2, 0, 0},
|
||||
STICK1, STICK2);
|
||||
|
||||
new StickCalibrationWindow(window,
|
||||
{(2 * window->width()) / 3, window->height() / 2, 0, 0},
|
||||
STICK4, STICK3);
|
||||
|
||||
rect_t r = { 0, 0, window->width(), window->height() };
|
||||
auto deco = new ViewMainDecoration(window, r);
|
||||
|
||||
@@ -235,14 +235,15 @@ void RadioSdManagerPage::build(FormWindow * window)
|
||||
// sort directories and files
|
||||
directories.sort(compare_nocase);
|
||||
files.sort(compare_nocase);
|
||||
|
||||
|
||||
for (auto name: directories) {
|
||||
new TextButton(window, grid.getLabelSlot(), name, [=]() -> uint8_t {
|
||||
auto b = new TextButton(window, grid.getLabelSlot(), name, [=]() -> uint8_t {
|
||||
f_chdir(name.data());
|
||||
window->clear();
|
||||
build(window);
|
||||
return 0;
|
||||
}, 0);
|
||||
}, OPAQUE);
|
||||
b->setBgColorHandler([=]() -> LcdFlags { return FIELD_BGCOLOR; });
|
||||
grid.nextLine();
|
||||
}
|
||||
|
||||
|
||||
@@ -112,10 +112,11 @@ void RadioToolsPage::rebuild(FormWindow * window)
|
||||
*ext = '\0';
|
||||
label = getBasename(path);
|
||||
}
|
||||
new StaticText(window, grid.getLabelSlot(), "lua", BUTTON_BACKGROUND, CENTERED);
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(), "lua",
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
std::string path_str(path);
|
||||
new TextButton(
|
||||
auto b = new TextButton(
|
||||
window, grid.getFieldSlot(1), label,
|
||||
[window, path_str]() -> uint8_t {
|
||||
f_chdir("/SCRIPTS/TOOLS/");
|
||||
@@ -124,7 +125,18 @@ void RadioToolsPage::rebuild(FormWindow * window)
|
||||
StandaloneLuaWindow::instance()->attach(window);
|
||||
return 0;
|
||||
},
|
||||
0);
|
||||
OPAQUE);
|
||||
b->setBgColorHandler([=]() -> LcdFlags { return FIELD_BGCOLOR; });
|
||||
b->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
}
|
||||
@@ -133,61 +145,166 @@ void RadioToolsPage::rebuild(FormWindow * window)
|
||||
|
||||
#if defined(INTERNAL_MODULE_PXX2)
|
||||
// PXX2 modules tools
|
||||
if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER)) {
|
||||
new StaticText(window, grid.getLabelSlot(), "access", BUTTON_BACKGROUND, CENTERED);
|
||||
new TextButton(window, grid.getFieldSlot(1), STR_SPECTRUM_ANALYSER_INT, [=]() -> uint8_t {
|
||||
new RadioSpectrumAnalyser(INTERNAL_MODULE);
|
||||
return 0;
|
||||
}, 0);
|
||||
if (isPXX2ModuleOptionAvailable(
|
||||
reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE]
|
||||
.information.modelID,
|
||||
MODULE_OPTION_SPECTRUM_ANALYSER)) {
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(), "access", BUTTON_BACKGROUND,
|
||||
CENTERED);
|
||||
auto b = new TextButton(
|
||||
window, grid.getFieldSlot(1), STR_SPECTRUM_ANALYSER_INT,
|
||||
[=]() -> uint8_t {
|
||||
new RadioSpectrumAnalyser(INTERNAL_MODULE);
|
||||
return 0;
|
||||
},
|
||||
OPAQUE);
|
||||
b->setBgColorHandler([=]() -> LcdFlags { return FIELD_BGCOLOR; });
|
||||
b->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
|
||||
if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) {
|
||||
new StaticText(window, grid.getLabelSlot(), "access", BUTTON_BACKGROUND, CENTERED);
|
||||
new TextButton(window, grid.getFieldSlot(1), STR_POWER_METER_INT, [=]() -> uint8_t {
|
||||
// new RadioPowerMeter(INTERNAL_MODULE);
|
||||
return 0;
|
||||
}, 0);
|
||||
if (isPXX2ModuleOptionAvailable(
|
||||
reusableBuffer.hardwareAndSettings.modules[INTERNAL_MODULE]
|
||||
.information.modelID,
|
||||
MODULE_OPTION_POWER_METER)) {
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(), "access",
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
auto b = new TextButton(
|
||||
window, grid.getFieldSlot(1), STR_POWER_METER_INT,
|
||||
[=]() -> uint8_t {
|
||||
// new RadioPowerMeter(INTERNAL_MODULE);
|
||||
return 0;
|
||||
},
|
||||
OPAQUE);
|
||||
b->setBgColorHandler([=]() -> LcdFlags { return FIELD_BGCOLOR; });
|
||||
b->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
#endif
|
||||
#if defined(INTERNAL_MODULE_MULTI)
|
||||
new StaticText(window, grid.getLabelSlot(), "multi", BUTTON_BACKGROUND, CENTERED);
|
||||
new TextButton(window, grid.getFieldSlot(1), STR_SPECTRUM_ANALYSER_INT, [=]() -> uint8_t {
|
||||
new RadioSpectrumAnalyser(INTERNAL_MODULE);
|
||||
return 0;
|
||||
}, 0);
|
||||
grid.nextLine();
|
||||
{
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(), "multi",
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
auto b = new TextButton(
|
||||
window, grid.getFieldSlot(1), STR_SPECTRUM_ANALYSER_INT,
|
||||
[=]() -> uint8_t {
|
||||
new RadioSpectrumAnalyser(INTERNAL_MODULE);
|
||||
return 0;
|
||||
},
|
||||
OPAQUE);
|
||||
b->setBgColorHandler([=]() -> LcdFlags { return FIELD_BGCOLOR; });
|
||||
b->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
#endif
|
||||
#if defined(PXX2)|| defined(MULTIMODULE)
|
||||
if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_SPECTRUM_ANALYSER) || isModuleMultimodule(EXTERNAL_MODULE)) {
|
||||
new StaticText(window, grid.getLabelSlot(), isModuleMultimodule(EXTERNAL_MODULE) ? "multi" : "access", BUTTON_BACKGROUND, CENTERED);
|
||||
new TextButton(window, grid.getFieldSlot(1), STR_SPECTRUM_ANALYSER_EXT, [=]() -> uint8_t {
|
||||
new RadioSpectrumAnalyser(EXTERNAL_MODULE);
|
||||
return 0;
|
||||
}, 0);
|
||||
if (isPXX2ModuleOptionAvailable(
|
||||
reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE]
|
||||
.information.modelID,
|
||||
MODULE_OPTION_SPECTRUM_ANALYSER) ||
|
||||
isModuleMultimodule(EXTERNAL_MODULE)) {
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(),
|
||||
isModuleMultimodule(EXTERNAL_MODULE) ? "multi" : "access",
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
auto b = new TextButton(
|
||||
window, grid.getFieldSlot(1), STR_SPECTRUM_ANALYSER_EXT,
|
||||
[=]() -> uint8_t {
|
||||
new RadioSpectrumAnalyser(EXTERNAL_MODULE);
|
||||
return 0;
|
||||
},
|
||||
OPAQUE);
|
||||
b->setBgColorHandler([=]() -> LcdFlags { return FIELD_BGCOLOR; });
|
||||
b->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
#endif
|
||||
#if defined(PXX2)
|
||||
if (isPXX2ModuleOptionAvailable(reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE].information.modelID, MODULE_OPTION_POWER_METER)) {
|
||||
new StaticText(window, grid.getLabelSlot(), "access", BUTTON_BACKGROUND, CENTERED);
|
||||
new TextButton(window, grid.getFieldSlot(1), STR_POWER_METER_EXT, [=]() -> uint8_t {
|
||||
// new RadioPowerMeter(EXTERNAL_MODULE);
|
||||
return 0;
|
||||
}, 0);
|
||||
|
||||
if (isPXX2ModuleOptionAvailable(
|
||||
reusableBuffer.hardwareAndSettings.modules[EXTERNAL_MODULE]
|
||||
.information.modelID,
|
||||
MODULE_OPTION_POWER_METER)) {
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(), "access",
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
auto b = new TextButton(
|
||||
window, grid.getFieldSlot(1), STR_POWER_METER_EXT,
|
||||
[=]() -> uint8_t {
|
||||
// new RadioPowerMeter(EXTERNAL_MODULE);
|
||||
return 0;
|
||||
},
|
||||
OPAQUE);
|
||||
b->setBgColorHandler([=]() -> LcdFlags { return FIELD_BGCOLOR; });
|
||||
b->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(GHOST)
|
||||
if (isModuleGhost(EXTERNAL_MODULE)) {
|
||||
new StaticText(window, grid.getLabelSlot(), "ghost", BUTTON_BACKGROUND, CENTERED);
|
||||
new TextButton(window, grid.getFieldSlot(1), "Ghost module config", [=]() -> uint8_t {
|
||||
new RadioGhostModuleConfig(EXTERNAL_MODULE);
|
||||
return 0;
|
||||
}, 0);
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(), "ghost",
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
auto b = new TextButton(
|
||||
window, grid.getFieldSlot(1), "Ghost module config",
|
||||
[=]() -> uint8_t {
|
||||
new RadioGhostModuleConfig(EXTERNAL_MODULE);
|
||||
return 0;
|
||||
},
|
||||
OPAQUE);
|
||||
b->setBgColorHandler([=]() -> LcdFlags { return FIELD_BGCOLOR; });
|
||||
b->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -64,12 +64,15 @@ void SourceChoice::paint(BitmapBuffer * dc)
|
||||
if (editMode)
|
||||
textColor = FOCUS_COLOR;
|
||||
else if (hasFocus())
|
||||
textColor = FOCUS_BGCOLOR;
|
||||
else if (value == 0)
|
||||
textColor = DISABLE_COLOR;
|
||||
textColor = FOCUS_COLOR;
|
||||
// else if (value == 0)
|
||||
// textColor = DISABLE_COLOR;
|
||||
else
|
||||
textColor = 0;
|
||||
|
||||
drawSource(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, value, textColor);
|
||||
dc->drawBitmapPattern(rect.w - 20, (rect.h - 11) / 2, LBM_DROPDOWN,
|
||||
textColor);
|
||||
}
|
||||
|
||||
// defined in gui/gui_common.cpp
|
||||
|
||||
@@ -24,235 +24,301 @@
|
||||
|
||||
#define SET_DIRTY() storageDirty(functions == g_model.customFn ? EE_MODEL : EE_GENERAL)
|
||||
|
||||
class SpecialFunctionEditPage : public Page {
|
||||
public:
|
||||
SpecialFunctionEditPage(CustomFunctionData * functions, uint8_t index) :
|
||||
Page(functions == g_model.customFn ? ICON_MODEL_SPECIAL_FUNCTIONS : ICON_RADIO_GLOBAL_FUNCTIONS),
|
||||
class SpecialFunctionEditPage : public Page
|
||||
{
|
||||
public:
|
||||
SpecialFunctionEditPage(CustomFunctionData *functions, uint8_t index) :
|
||||
Page(functions == g_model.customFn ? ICON_MODEL_SPECIAL_FUNCTIONS
|
||||
: ICON_RADIO_GLOBAL_FUNCTIONS),
|
||||
functions(functions),
|
||||
index(index)
|
||||
{
|
||||
buildHeader(&header);
|
||||
buildBody(&body);
|
||||
{
|
||||
buildHeader(&header);
|
||||
buildBody(&body);
|
||||
}
|
||||
|
||||
protected:
|
||||
CustomFunctionData *functions;
|
||||
uint8_t index;
|
||||
FormGroup *specialFunctionOneWindow = nullptr;
|
||||
StaticText *headerSF = nullptr;
|
||||
bool active = false;
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return ((functions == g_model.customFn
|
||||
? modelFunctionsContext.activeSwitches
|
||||
: globalFunctionsContext.activeSwitches) &
|
||||
((MASK_CFN_TYPE)1 << index)
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Page::checkEvents();
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
headerSF->setTextFlags(isActive() ? FONT(BOLD) | HIGHLIGHT_COLOR
|
||||
: MENU_COLOR);
|
||||
active = !active;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
CustomFunctionData * functions;
|
||||
uint8_t index;
|
||||
FormGroup * specialFunctionOneWindow = nullptr;
|
||||
StaticText * headerSF = nullptr;
|
||||
bool active = false;
|
||||
void buildHeader(Window *window)
|
||||
{
|
||||
new StaticText(
|
||||
window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, 20},
|
||||
functions == g_model.customFn ? STR_MENUCUSTOMFUNC
|
||||
: STR_MENUSPECIALFUNCS,
|
||||
0, FOCUS_COLOR);
|
||||
headerSF = new StaticText(
|
||||
window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, 20},
|
||||
(functions == g_model.customFn ? "SF" : "GF") + std::to_string(index),
|
||||
0, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return ((functions == g_model.customFn ? modelFunctionsContext.activeSwitches : globalFunctionsContext.activeSwitches) & ((MASK_CFN_TYPE)1 << index) ? 1 : 0);
|
||||
}
|
||||
void updateSpecialFunctionOneWindow()
|
||||
{
|
||||
FormGridLayout grid;
|
||||
specialFunctionOneWindow->clear();
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Page::checkEvents();
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
headerSF->setTextFlags(isActive() ? FONT(BOLD) |HIGHLIGHT_COLOR : MENU_COLOR);
|
||||
active = !active;
|
||||
}
|
||||
}
|
||||
CustomFunctionData *cfn = &functions[index];
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
|
||||
void buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, { PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, 20 }, functions == g_model.customFn ? STR_MENUCUSTOMFUNC : STR_MENUSPECIALFUNCS, 0, MENU_COLOR);
|
||||
headerSF = new StaticText(window, { PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, 20 }, (functions == g_model.customFn ? "SF" : "GF" ) + std::to_string(index), 0, MENU_COLOR);
|
||||
}
|
||||
|
||||
void updateSpecialFunctionOneWindow()
|
||||
{
|
||||
FormGridLayout grid;
|
||||
specialFunctionOneWindow->clear();
|
||||
|
||||
CustomFunctionData * cfn = &functions[index];
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
|
||||
// Func param
|
||||
switch (func) {
|
||||
case FUNC_OVERRIDE_CHANNEL:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_CH);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 1, MAX_OUTPUT_CHANNELS, GET_SET_VALUE_WITH_OFFSET(CFN_CH_INDEX(cfn), 1));
|
||||
grid.nextLine();
|
||||
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), -100, 100, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_TRAINER: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
auto choice = new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0,NUM_STICKS + 1,GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
choice->setTextHandler([=](int32_t value) {
|
||||
if (value == 0)
|
||||
return std::string(STR_STICKS);
|
||||
else if (value == NUM_STICKS + 1)
|
||||
return std::string(STR_CHANS);
|
||||
else
|
||||
return TEXT_AT_INDEX(STR_VSRCRAW, value);;
|
||||
});
|
||||
grid.nextLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case FUNC_RESET:
|
||||
if (CFN_PARAM(cfn) < FUNC_RESET_PARAM_FIRST_TELEM) {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_RESET);
|
||||
auto choice = new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
FUNC_RESET_PARAM_FIRST_TELEM + lastUsedTelemetryIndex(),
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
choice->setAvailableHandler(isSourceAvailableInResetSpecialFunction);
|
||||
choice->setTextHandler([=](int32_t value) {
|
||||
if (value < FUNC_RESET_PARAM_FIRST_TELEM)
|
||||
return TEXT_AT_INDEX(STR_VFSWRESET, value);
|
||||
else
|
||||
return std::string(g_model.telemetrySensors[value - FUNC_RESET_PARAM_FIRST_TELEM].label, TELEM_LABEL_LEN);
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
break;
|
||||
|
||||
case FUNC_VOLUME:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VOLUME);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0, MIXSRC_LAST_CH, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_BACKLIGHT:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0, MIXSRC_LAST_CH, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_SOUND:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(), STR_FUNCSOUNDS, 0,
|
||||
AU_SPECIAL_SOUND_LAST - AU_SPECIAL_SOUND_FIRST - 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_TRACK:
|
||||
case FUNC_BACKGND_MUSIC:
|
||||
case FUNC_PLAY_SCRIPT:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new FileChoice(specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
func == FUNC_PLAY_SCRIPT ? SCRIPTS_FUNCS_PATH : std::string(SOUNDS_PATH, SOUNDS_PATH_LNG_OFS) +
|
||||
std::string(currentLanguagePack->id, 2),
|
||||
func == FUNC_PLAY_SCRIPT ? SCRIPTS_EXT : SOUNDS_EXT,
|
||||
sizeof(cfn->play.name),
|
||||
[=]() {
|
||||
return std::string(cfn->play.name, ZLEN(cfn->play.name));
|
||||
},
|
||||
[=](std::string newValue) {
|
||||
strncpy(cfn->play.name, newValue.c_str(), sizeof(cfn->play.name));
|
||||
SET_DIRTY();
|
||||
}, true); // strip extension
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_SET_TIMER: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_TIMER);
|
||||
auto timerchoice = new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0, TIMERS - 1, GET_SET_DEFAULT(CFN_TIMER_INDEX(cfn)));
|
||||
timerchoice->setTextHandler([](int32_t value) {
|
||||
return std::string(STR_TIMER) + std::to_string(value + 1);
|
||||
});
|
||||
grid.nextLine();
|
||||
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new TimeEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0, 9 * 60 * 60 - 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case FUNC_SET_FAILSAFE:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_MODULE);
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(), "\004Int.Ext.", 0, NUM_MODULES - 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_VALUE:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0, MIXSRC_LAST_TELEM, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_HAPTIC:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0, 3, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_LOGS: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
auto edit = new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0, 255, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
edit->setDisplayHandler([=](BitmapBuffer * dc, LcdFlags flags, int32_t value) {
|
||||
dc->drawNumber(2, 2, CFN_PARAM(cfn), PREC1, sizeof(CFN_PARAM(cfn)), nullptr, "s");
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_ENABLE_PARAM(func)) {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_ENABLE);
|
||||
new CheckBox(specialFunctionOneWindow, grid.getFieldSlot(), GET_SET_DEFAULT(CFN_ACTIVE(cfn)));
|
||||
// Func param
|
||||
switch (func) {
|
||||
case FUNC_OVERRIDE_CHANNEL:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_CH);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 1,
|
||||
MAX_OUTPUT_CHANNELS,
|
||||
GET_SET_VALUE_WITH_OFFSET(CFN_CH_INDEX(cfn), 1));
|
||||
grid.nextLine();
|
||||
}
|
||||
else if (HAS_REPEAT_PARAM(func)) { // !1x 1x 1s 2s 3s ...
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_REPEAT);
|
||||
auto repeat = new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(2, 1), -1, 60/CFN_PLAY_REPEAT_MUL, GET_SET_DEFAULT(CFN_PLAY_REPEAT(cfn)));
|
||||
repeat->setDisplayHandler([](BitmapBuffer * dc, LcdFlags flags, int32_t value) {
|
||||
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), -100, 100,
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_TRAINER: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
auto choice =
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
NUM_STICKS + 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
choice->setTextHandler([=](int32_t value) {
|
||||
if (value == 0)
|
||||
dc->drawText(3, 0, "1x", flags);
|
||||
else if (value == CFN_PLAY_REPEAT_NOSTART)
|
||||
dc->drawText(3, 0, "!1x", flags);
|
||||
return std::string(STR_STICKS);
|
||||
else if (value == NUM_STICKS + 1)
|
||||
return std::string(STR_CHANS);
|
||||
else
|
||||
dc->drawNumber(3, 0, value * CFN_PLAY_REPEAT_MUL, flags, 0, nullptr, "s");
|
||||
return TEXT_AT_INDEX(STR_VSRCRAW, value);
|
||||
;
|
||||
});
|
||||
grid.nextLine();
|
||||
break;
|
||||
}
|
||||
|
||||
specialFunctionOneWindow->adjustHeight();
|
||||
case FUNC_RESET:
|
||||
if (CFN_PARAM(cfn) < FUNC_RESET_PARAM_FIRST_TELEM) {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_RESET);
|
||||
auto choice = new Choice(
|
||||
specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
FUNC_RESET_PARAM_FIRST_TELEM + lastUsedTelemetryIndex(),
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
choice->setAvailableHandler(isSourceAvailableInResetSpecialFunction);
|
||||
choice->setTextHandler([=](int32_t value) {
|
||||
if (value < FUNC_RESET_PARAM_FIRST_TELEM)
|
||||
return TEXT_AT_INDEX(STR_VFSWRESET, value);
|
||||
else
|
||||
return std::string(
|
||||
g_model.telemetrySensors[value - FUNC_RESET_PARAM_FIRST_TELEM]
|
||||
.label,
|
||||
TELEM_LABEL_LEN);
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
break;
|
||||
|
||||
case FUNC_VOLUME:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VOLUME);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
MIXSRC_LAST_CH, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_BACKLIGHT:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
MIXSRC_LAST_CH, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_SOUND:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
STR_FUNCSOUNDS, 0,
|
||||
AU_SPECIAL_SOUND_LAST - AU_SPECIAL_SOUND_FIRST - 1,
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_TRACK:
|
||||
case FUNC_BACKGND_MUSIC:
|
||||
case FUNC_PLAY_SCRIPT:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new FileChoice(
|
||||
specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
func == FUNC_PLAY_SCRIPT
|
||||
? SCRIPTS_FUNCS_PATH
|
||||
: std::string(SOUNDS_PATH, SOUNDS_PATH_LNG_OFS) +
|
||||
std::string(currentLanguagePack->id, 2),
|
||||
func == FUNC_PLAY_SCRIPT ? SCRIPTS_EXT : SOUNDS_EXT,
|
||||
sizeof(cfn->play.name),
|
||||
[=]() { return std::string(cfn->play.name, ZLEN(cfn->play.name)); },
|
||||
[=](std::string newValue) {
|
||||
strncpy(cfn->play.name, newValue.c_str(), sizeof(cfn->play.name));
|
||||
SET_DIRTY();
|
||||
},
|
||||
true); // strip extension
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_SET_TIMER: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_TIMER);
|
||||
auto timerchoice =
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
TIMERS - 1, GET_SET_DEFAULT(CFN_TIMER_INDEX(cfn)));
|
||||
timerchoice->setTextHandler([](int32_t value) {
|
||||
return std::string(STR_TIMER) + std::to_string(value + 1);
|
||||
});
|
||||
grid.nextLine();
|
||||
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new TimeEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
9 * 60 * 60 - 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case FUNC_SET_FAILSAFE:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_MODULE);
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
"\004Int.Ext.", 0, NUM_MODULES - 1,
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_VALUE:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
MIXSRC_LAST_TELEM, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_HAPTIC:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0, 3,
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_LOGS: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
auto edit =
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
255, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
edit->setDisplayHandler(
|
||||
[=](BitmapBuffer *dc, LcdFlags flags, int32_t value) {
|
||||
dc->drawNumber(2, 2, CFN_PARAM(cfn), PREC1,
|
||||
sizeof(CFN_PARAM(cfn)), nullptr, "s");
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void buildBody(FormWindow * window)
|
||||
{
|
||||
// SF.one
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
|
||||
CustomFunctionData * cfn = &functions[index];
|
||||
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH);
|
||||
auto switchChoice = new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST, SWSRC_LAST, GET_SET_DEFAULT(CFN_SWITCH(cfn)));
|
||||
switchChoice->setAvailableHandler([=](int value) {
|
||||
return (functions == g_model.customFn ? isSwitchAvailable(value, ModelCustomFunctionsContext)
|
||||
: isSwitchAvailable(value,
|
||||
GeneralCustomFunctionsContext));
|
||||
});
|
||||
if (HAS_ENABLE_PARAM(func)) {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_ENABLE);
|
||||
new CheckBox(specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
GET_SET_DEFAULT(CFN_ACTIVE(cfn)));
|
||||
grid.nextLine();
|
||||
|
||||
// Function
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FUNC);
|
||||
auto functionChoice = new Choice(window, grid.getFieldSlot(), STR_VFSWFUNC, 0, FUNC_MAX - 1, GET_DEFAULT(CFN_FUNC(cfn)));
|
||||
functionChoice->setSetValueHandler([=](int32_t newValue) {
|
||||
CFN_FUNC(cfn) = newValue;
|
||||
CFN_RESET(cfn);
|
||||
SET_DIRTY();
|
||||
updateSpecialFunctionOneWindow();
|
||||
});
|
||||
functionChoice->setAvailableHandler([=](int value) {
|
||||
return isAssignableFunctionAvailable(value, functions);
|
||||
});
|
||||
} else if (HAS_REPEAT_PARAM(func)) { // !1x 1x 1s 2s 3s ...
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_REPEAT);
|
||||
auto repeat = new NumberEdit(
|
||||
specialFunctionOneWindow, grid.getFieldSlot(2, 1), -1,
|
||||
60 / CFN_PLAY_REPEAT_MUL, GET_SET_DEFAULT(CFN_PLAY_REPEAT(cfn)));
|
||||
repeat->setDisplayHandler(
|
||||
[](BitmapBuffer *dc, LcdFlags flags, int32_t value) {
|
||||
if (value == 0)
|
||||
dc->drawText(3, 0, "1x", flags);
|
||||
else if (value == CFN_PLAY_REPEAT_NOSTART)
|
||||
dc->drawText(3, 0, "!1x", flags);
|
||||
else
|
||||
dc->drawNumber(3, 0, value * CFN_PLAY_REPEAT_MUL, flags, 0,
|
||||
nullptr, "s");
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
|
||||
specialFunctionOneWindow = new FormGroup(window, {0, grid.getWindowHeight(), LCD_W, 0}, FORM_FORWARD_FOCUS);
|
||||
specialFunctionOneWindow->adjustHeight();
|
||||
}
|
||||
|
||||
void buildBody(FormWindow *window)
|
||||
{
|
||||
// SF.one
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
|
||||
CustomFunctionData *cfn = &functions[index];
|
||||
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH);
|
||||
auto switchChoice =
|
||||
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST, SWSRC_LAST,
|
||||
GET_SET_DEFAULT(CFN_SWITCH(cfn)));
|
||||
switchChoice->setAvailableHandler([=](int value) {
|
||||
return (functions == g_model.customFn
|
||||
? isSwitchAvailable(value, ModelCustomFunctionsContext)
|
||||
: isSwitchAvailable(value, GeneralCustomFunctionsContext));
|
||||
});
|
||||
grid.nextLine();
|
||||
|
||||
// Function
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FUNC);
|
||||
auto functionChoice =
|
||||
new Choice(window, grid.getFieldSlot(), STR_VFSWFUNC, 0, FUNC_MAX - 1,
|
||||
GET_DEFAULT(CFN_FUNC(cfn)));
|
||||
functionChoice->setSetValueHandler([=](int32_t newValue) {
|
||||
CFN_FUNC(cfn) = newValue;
|
||||
CFN_RESET(cfn);
|
||||
SET_DIRTY();
|
||||
updateSpecialFunctionOneWindow();
|
||||
grid.addWindow(specialFunctionOneWindow);
|
||||
}
|
||||
});
|
||||
functionChoice->setAvailableHandler([=](int value) {
|
||||
return isAssignableFunctionAvailable(value, functions);
|
||||
});
|
||||
grid.nextLine();
|
||||
|
||||
specialFunctionOneWindow = new FormGroup(
|
||||
window, {0, grid.getWindowHeight(), LCD_W, 0}, FORM_FORWARD_FOCUS);
|
||||
updateSpecialFunctionOneWindow();
|
||||
grid.addWindow(specialFunctionOneWindow);
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr coord_t line1 = FIELD_PADDING_TOP;
|
||||
@@ -261,161 +327,178 @@ static constexpr coord_t col1 = 20;
|
||||
static constexpr coord_t col2 = (LCD_W - 100) / 3 + col1;
|
||||
static constexpr coord_t col3 = ((LCD_W - 100) / 3) * 2 + col1 + 20;
|
||||
|
||||
class SpecialFunctionButton : public Button {
|
||||
public:
|
||||
SpecialFunctionButton(FormWindow * parent, const rect_t &rect, CustomFunctionData * functions, uint8_t index) :
|
||||
Button(parent, rect),
|
||||
functions(functions),
|
||||
index(index)
|
||||
{
|
||||
const CustomFunctionData * cfn = &functions[index];
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
if (!cfn->isEmpty() &&
|
||||
(HAS_ENABLE_PARAM(func) || HAS_REPEAT_PARAM(func) || (func == FUNC_PLAY_TRACK || func == FUNC_BACKGND_MUSIC || func == FUNC_PLAY_SCRIPT))) {
|
||||
setHeight(line2 + PAGE_LINE_HEIGHT);
|
||||
}
|
||||
class SpecialFunctionButton : public Button
|
||||
{
|
||||
public:
|
||||
SpecialFunctionButton(FormWindow *parent, const rect_t &rect,
|
||||
CustomFunctionData *functions, uint8_t index) :
|
||||
Button(parent, rect), functions(functions), index(index)
|
||||
{
|
||||
const CustomFunctionData *cfn = &functions[index];
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
if (!cfn->isEmpty() &&
|
||||
(HAS_ENABLE_PARAM(func) || HAS_REPEAT_PARAM(func) ||
|
||||
(func == FUNC_PLAY_TRACK || func == FUNC_BACKGND_MUSIC ||
|
||||
func == FUNC_PLAY_SCRIPT))) {
|
||||
setHeight(line2 + PAGE_LINE_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "SpecialFunctionButton";
|
||||
}
|
||||
std::string getName() const override { return "SpecialFunctionButton"; }
|
||||
#endif
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return ((functions == g_model.customFn ? modelFunctionsContext.activeSwitches : globalFunctionsContext.activeSwitches) & ((MASK_CFN_TYPE)1 << index) ? 1 : 0);
|
||||
bool isActive() const
|
||||
{
|
||||
return ((functions == g_model.customFn
|
||||
? modelFunctionsContext.activeSwitches
|
||||
: globalFunctionsContext.activeSwitches) &
|
||||
((MASK_CFN_TYPE)1 << index)
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Button::checkEvents();
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
active = !active;
|
||||
}
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Button::checkEvents();
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
active = !active;
|
||||
}
|
||||
void paintSpecialFunctionLine(BitmapBuffer *dc)
|
||||
{
|
||||
const CustomFunctionData *cfn = &functions[index];
|
||||
if (functions[index].func == FUNC_OVERRIDE_CHANNEL &&
|
||||
functions != g_model.customFn) {
|
||||
functions[index].func = FUNC_OVERRIDE_CHANNEL + 1;
|
||||
}
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
|
||||
void paintSpecialFunctionLine(BitmapBuffer * dc)
|
||||
{
|
||||
const CustomFunctionData * cfn = &functions[index];
|
||||
if (functions[index].func == FUNC_OVERRIDE_CHANNEL && functions != g_model.customFn) {
|
||||
functions[index].func = FUNC_OVERRIDE_CHANNEL + 1;
|
||||
}
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
drawSwitch(dc, col1, line1, CFN_SWITCH(cfn), 0);
|
||||
if (cfn->isEmpty()) return;
|
||||
|
||||
drawSwitch(dc, col1, line1, CFN_SWITCH(cfn), 0);
|
||||
if (cfn->isEmpty())
|
||||
return;
|
||||
dc->drawTextAtIndex(col2, line1, STR_VFSWFUNC, func, 0);
|
||||
int16_t val_min = 0;
|
||||
int16_t val_max = 255;
|
||||
|
||||
dc->drawTextAtIndex(col2, line1, STR_VFSWFUNC, func, 0);
|
||||
int16_t val_min = 0;
|
||||
int16_t val_max = 255;
|
||||
switch (func) {
|
||||
case FUNC_OVERRIDE_CHANNEL:
|
||||
drawChn(dc, col1, line2, CFN_CH_INDEX(cfn) + 1, 0);
|
||||
getMixSrcRange(MIXSRC_FIRST_CH, val_min, val_max);
|
||||
dc->drawNumber(col2, line2, CFN_PARAM(cfn));
|
||||
break;
|
||||
|
||||
switch (func) {
|
||||
case FUNC_OVERRIDE_CHANNEL:
|
||||
drawChn(dc, col1, line2, CFN_CH_INDEX(cfn) + 1, 0);
|
||||
getMixSrcRange(MIXSRC_FIRST_CH, val_min, val_max);
|
||||
dc->drawNumber(col2, line2, CFN_PARAM(cfn));
|
||||
break;
|
||||
case FUNC_TRAINER:
|
||||
drawSource(
|
||||
dc, col1, line2,
|
||||
CFN_CH_INDEX(cfn) == 0 ? 0 : MIXSRC_Rud + CFN_CH_INDEX(cfn) - 1);
|
||||
break;
|
||||
|
||||
case FUNC_TRAINER:
|
||||
drawSource(dc, col1, line2, CFN_CH_INDEX(cfn) == 0 ? 0 : MIXSRC_Rud + CFN_CH_INDEX(cfn) - 1);
|
||||
break;
|
||||
|
||||
case FUNC_RESET:
|
||||
if (CFN_PARAM(cfn) < FUNC_RESET_PARAM_FIRST_TELEM) {
|
||||
dc->drawTextAtIndex(col1, line2, STR_VFSWRESET, CFN_PARAM(cfn));
|
||||
}
|
||||
else {
|
||||
TelemetrySensor * sensor = &g_model.telemetrySensors[CFN_PARAM(cfn) - FUNC_RESET_PARAM_FIRST_TELEM];
|
||||
dc->drawSizedText(col1, line2, sensor->label, TELEM_LABEL_LEN);
|
||||
}
|
||||
break;
|
||||
|
||||
case FUNC_VOLUME:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_BACKLIGHT:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_SOUND:
|
||||
dc->drawTextAtIndex(col1, line2, STR_FUNCSOUNDS, CFN_PARAM(cfn));
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_TRACK:
|
||||
case FUNC_BACKGND_MUSIC:
|
||||
case FUNC_PLAY_SCRIPT:
|
||||
if (ZEXIST(cfn->play.name))
|
||||
dc->drawSizedText(col1, line2, cfn->play.name, sizeof(cfn->play.name), 0);
|
||||
else
|
||||
dc->drawTextAtIndex(col1, line2, STR_VCSWFUNC, 0, 0);
|
||||
break;
|
||||
|
||||
case FUNC_SET_TIMER:
|
||||
drawStringWithIndex(dc, col1, line2, STR_TIMER, CFN_TIMER_INDEX(cfn) + 1, 0);
|
||||
break;
|
||||
|
||||
case FUNC_SET_FAILSAFE:
|
||||
dc->drawTextAtIndex(col1, line2, "\004Int.Ext.", CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_VALUE:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_HAPTIC:
|
||||
dc->drawNumber(col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_LOGS:
|
||||
dc->drawNumber(col3, line1, CFN_PARAM(cfn), PREC1, sizeof(CFN_PARAM(cfn)), nullptr, "s");
|
||||
break;
|
||||
}
|
||||
if (HAS_ENABLE_PARAM(func)) {
|
||||
theme->drawCheckBox(dc, CFN_ACTIVE(cfn), col3, line2);
|
||||
}
|
||||
else if (HAS_REPEAT_PARAM(func)) {
|
||||
if (CFN_PLAY_REPEAT(cfn) == 0) {
|
||||
dc->drawText(col3, line2, "1x", 0);
|
||||
}
|
||||
else if (CFN_PLAY_REPEAT(cfn) == CFN_PLAY_REPEAT_NOSTART) {
|
||||
dc->drawText(col3, line2, "!1x", 0);
|
||||
}
|
||||
else {
|
||||
dc->drawNumber(col3 + 12, line2, CFN_PLAY_REPEAT(cfn) * CFN_PLAY_REPEAT_MUL, 0 | RIGHT, 0, nullptr, "s");
|
||||
case FUNC_RESET:
|
||||
if (CFN_PARAM(cfn) < FUNC_RESET_PARAM_FIRST_TELEM) {
|
||||
dc->drawTextAtIndex(col1, line2, STR_VFSWRESET, CFN_PARAM(cfn));
|
||||
} else {
|
||||
TelemetrySensor *sensor =
|
||||
&g_model.telemetrySensors[CFN_PARAM(cfn) -
|
||||
FUNC_RESET_PARAM_FIRST_TELEM];
|
||||
dc->drawSizedText(col1, line2, sensor->label, TELEM_LABEL_LEN);
|
||||
}
|
||||
break;
|
||||
|
||||
case FUNC_VOLUME:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_BACKLIGHT:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_SOUND:
|
||||
dc->drawTextAtIndex(col1, line2, STR_FUNCSOUNDS, CFN_PARAM(cfn));
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_TRACK:
|
||||
case FUNC_BACKGND_MUSIC:
|
||||
case FUNC_PLAY_SCRIPT:
|
||||
if (ZEXIST(cfn->play.name))
|
||||
dc->drawSizedText(col1, line2, cfn->play.name, sizeof(cfn->play.name),
|
||||
0);
|
||||
else
|
||||
dc->drawTextAtIndex(col1, line2, STR_VCSWFUNC, 0, 0);
|
||||
break;
|
||||
|
||||
case FUNC_SET_TIMER:
|
||||
drawStringWithIndex(dc, col1, line2, STR_TIMER,
|
||||
CFN_TIMER_INDEX(cfn) + 1, 0);
|
||||
break;
|
||||
|
||||
case FUNC_SET_FAILSAFE:
|
||||
dc->drawTextAtIndex(col1, line2, "\004Int.Ext.", CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_VALUE:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_HAPTIC:
|
||||
dc->drawNumber(col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_LOGS:
|
||||
dc->drawNumber(col3, line1, CFN_PARAM(cfn), PREC1,
|
||||
sizeof(CFN_PARAM(cfn)), nullptr, "s");
|
||||
break;
|
||||
}
|
||||
if (HAS_ENABLE_PARAM(func)) {
|
||||
theme->drawCheckBox(dc, CFN_ACTIVE(cfn), col3, line2);
|
||||
} else if (HAS_REPEAT_PARAM(func)) {
|
||||
if (CFN_PLAY_REPEAT(cfn) == 0) {
|
||||
dc->drawText(col3, line2, "1x", 0);
|
||||
} else if (CFN_PLAY_REPEAT(cfn) == CFN_PLAY_REPEAT_NOSTART) {
|
||||
dc->drawText(col3, line2, "!1x", 0);
|
||||
} else {
|
||||
dc->drawNumber(col3 + 12, line2,
|
||||
CFN_PLAY_REPEAT(cfn) * CFN_PLAY_REPEAT_MUL, 0 | RIGHT, 0,
|
||||
nullptr, "s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
if (active)
|
||||
dc->drawSolidFilledRect(2, 2, rect.w - 4, rect.h - 4, HIGHLIGHT_COLOR);
|
||||
void paint(BitmapBuffer *dc) override
|
||||
{
|
||||
if (active)
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, HIGHLIGHT_COLOR);
|
||||
else
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, FIELD_BGCOLOR);
|
||||
|
||||
paintSpecialFunctionLine(dc);
|
||||
paintSpecialFunctionLine(dc);
|
||||
|
||||
// The bounding rect
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? CHECKBOX_COLOR : DISABLE_COLOR);
|
||||
}
|
||||
// The bounding rect
|
||||
if (hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
protected:
|
||||
CustomFunctionData * functions;
|
||||
uint8_t index;
|
||||
bool active = false;
|
||||
protected:
|
||||
CustomFunctionData *functions;
|
||||
uint8_t index;
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
SpecialFunctionsPage::SpecialFunctionsPage(CustomFunctionData * functions) :
|
||||
PageTab(functions == g_model.customFn ? STR_MENUCUSTOMFUNC : STR_MENUSPECIALFUNCS,
|
||||
functions == g_model.customFn ? ICON_MODEL_SPECIAL_FUNCTIONS : ICON_RADIO_GLOBAL_FUNCTIONS),
|
||||
functions(functions)
|
||||
SpecialFunctionsPage::SpecialFunctionsPage(CustomFunctionData *functions) :
|
||||
PageTab(functions == g_model.customFn ? STR_MENUCUSTOMFUNC
|
||||
: STR_MENUSPECIALFUNCS,
|
||||
functions == g_model.customFn ? ICON_MODEL_SPECIAL_FUNCTIONS
|
||||
: ICON_RADIO_GLOBAL_FUNCTIONS),
|
||||
functions(functions)
|
||||
{
|
||||
}
|
||||
|
||||
void SpecialFunctionsPage::rebuild(FormWindow * window, int8_t focusSpecialFunctionIndex)
|
||||
void SpecialFunctionsPage::rebuild(FormWindow *window,
|
||||
int8_t focusSpecialFunctionIndex)
|
||||
{
|
||||
coord_t scrollPosition = window->getScrollPositionY();
|
||||
window->clear();
|
||||
@@ -423,15 +506,14 @@ void SpecialFunctionsPage::rebuild(FormWindow * window, int8_t focusSpecialFunct
|
||||
window->setScrollPositionY(scrollPosition);
|
||||
}
|
||||
|
||||
void SpecialFunctionsPage::editSpecialFunction(FormWindow * window, uint8_t index)
|
||||
void SpecialFunctionsPage::editSpecialFunction(FormWindow *window,
|
||||
uint8_t index)
|
||||
{
|
||||
auto editPage = new SpecialFunctionEditPage(functions, index);
|
||||
editPage->setCloseHandler([=]() {
|
||||
rebuild(window, index);
|
||||
});
|
||||
editPage->setCloseHandler([=]() { rebuild(window, index); });
|
||||
}
|
||||
|
||||
void SpecialFunctionsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
void SpecialFunctionsPage::build(FormWindow *window, int8_t focusIndex)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
@@ -440,11 +522,10 @@ void SpecialFunctionsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
Window::clearFocus();
|
||||
|
||||
char s[] = "SFxx";
|
||||
if (functions == g_eeGeneral.customFn)
|
||||
s[0] = 'G';
|
||||
if (functions == g_eeGeneral.customFn) s[0] = 'G';
|
||||
|
||||
for (uint8_t i = 0; i < MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
CustomFunctionData * cfn = &functions[i];
|
||||
CustomFunctionData *cfn = &functions[i];
|
||||
strAppendUnsigned(&s[2], i);
|
||||
|
||||
if (cfn->swtch == 0) {
|
||||
@@ -464,64 +545,82 @@ void SpecialFunctionsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
return 0;
|
||||
});
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
else {
|
||||
new StaticText(window, grid.getLabelSlot(), s, BUTTON_BACKGROUND, CENTERED);
|
||||
} else {
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(), s,
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
auto button = new SpecialFunctionButton(window, grid.getFieldSlot(), functions, i);
|
||||
auto button =
|
||||
new SpecialFunctionButton(window, grid.getFieldSlot(), functions, i);
|
||||
button->setPressHandler([=]() {
|
||||
button->bringToTop();
|
||||
Menu * menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
editSpecialFunction(window, i);
|
||||
button->bringToTop();
|
||||
Menu *menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() { editSpecialFunction(window, i); });
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
clipboard.type = CLIPBOARD_TYPE_CUSTOM_FUNCTION;
|
||||
clipboard.data.cfn = *cfn;
|
||||
});
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_FUNCTION) {
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
*cfn = clipboard.data.cfn;
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
clipboard.type = CLIPBOARD_TYPE_CUSTOM_FUNCTION;
|
||||
clipboard.data.cfn = *cfn;
|
||||
}
|
||||
if (functions[MAX_SPECIAL_FUNCTIONS - 1].isEmpty()) {
|
||||
menu->addLine(STR_INSERT, [=]() {
|
||||
memmove(
|
||||
cfn + 1, cfn,
|
||||
(MAX_SPECIAL_FUNCTIONS - i - 1) * sizeof(CustomFunctionData));
|
||||
memset(cfn, 0, sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_FUNCTION) {
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
*cfn = clipboard.data.cfn;
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
}
|
||||
if (functions[MAX_SPECIAL_FUNCTIONS - 1].isEmpty()) {
|
||||
menu->addLine(STR_INSERT, [=]() {
|
||||
memmove(cfn + 1, cfn, (MAX_SPECIAL_FUNCTIONS - i - 1) * sizeof(CustomFunctionData));
|
||||
memset(cfn, 0, sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
}
|
||||
menu->addLine(STR_CLEAR, [=]() {
|
||||
memset(cfn, 0, sizeof(CustomFunctionData));
|
||||
}
|
||||
menu->addLine(STR_CLEAR, [=]() {
|
||||
memset(cfn, 0, sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
});
|
||||
for (int j = i; j < MAX_SPECIAL_FUNCTIONS; j++) {
|
||||
if (!functions[j].isEmpty()) {
|
||||
menu->addLine(STR_DELETE, [=]() {
|
||||
memmove(
|
||||
cfn, cfn + 1,
|
||||
(MAX_SPECIAL_FUNCTIONS - i - 1) * sizeof(CustomFunctionData));
|
||||
memset(&functions[MAX_SPECIAL_FUNCTIONS - 1], 0,
|
||||
sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
});
|
||||
for (int j = i; j < MAX_SPECIAL_FUNCTIONS; j++) {
|
||||
if (!functions[j].isEmpty()) {
|
||||
menu->addLine(STR_DELETE, [=]() {
|
||||
memmove(cfn, cfn + 1, (MAX_SPECIAL_FUNCTIONS - i - 1) * sizeof(CustomFunctionData));
|
||||
memset(&functions[MAX_SPECIAL_FUNCTIONS - 1], 0, sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
break;
|
||||
}
|
||||
rebuild(window, i);
|
||||
});
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
if (focusIndex == i) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
txt->setHeight(button->height());
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
}
|
||||
|
||||
grid.nextLine();
|
||||
|
||||
// window->setLastField();
|
||||
// window->setLastField();
|
||||
window->setInnerHeight(grid.getWindowHeight());
|
||||
}
|
||||
|
||||
@@ -31,11 +31,7 @@ class SpecialFunctionsPage: public PageTab {
|
||||
|
||||
void build(FormWindow * window) override
|
||||
{
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
build(window, -1);
|
||||
#else
|
||||
build(window, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -48,12 +48,15 @@ void SwitchChoice::paint(BitmapBuffer * dc)
|
||||
if (editMode)
|
||||
textColor = FOCUS_COLOR;
|
||||
else if (hasFocus())
|
||||
textColor = FOCUS_BGCOLOR;
|
||||
else if (value == 0)
|
||||
textColor = DISABLE_COLOR;
|
||||
textColor = FOCUS_COLOR;
|
||||
// else if (value == 0)
|
||||
// textColor = DISABLE_COLOR;
|
||||
else
|
||||
textColor = 0;
|
||||
textColor = DEFAULT_COLOR;
|
||||
|
||||
drawSwitch(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, value, textColor);
|
||||
dc->drawBitmapPattern(rect.w - 20, (rect.h - 11) / 2, LBM_DROPDOWN,
|
||||
textColor);
|
||||
}
|
||||
|
||||
void SwitchChoice::fillMenu(Menu * menu, std::function<bool(int16_t)> filter)
|
||||
|
||||
@@ -32,12 +32,12 @@
|
||||
TabsGroupHeader::TabsGroupHeader(TabsGroup * parent, uint8_t icon):
|
||||
FormGroup(parent, { 0, 0, LCD_W, MENU_BODY_TOP }, OPAQUE),
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
back(this, { 0, 0, MENU_HEADER_BUTTON_WIDTH, MENU_HEADER_BUTTON_WIDTH }, ICON_BACK,
|
||||
back(this, { 0, 0, MENU_HEADER_BUTTON_WIDTH, MENU_HEADER_BUTTON_WIDTH },
|
||||
[=]() -> uint8_t {
|
||||
parent->deleteLater();
|
||||
ViewMain::instance()->setFocus((SET_FOCUS_DEFAULT));
|
||||
return 1;
|
||||
}, NO_FOCUS),
|
||||
}, NO_FOCUS | FORM_NO_BORDER),
|
||||
#endif
|
||||
icon(icon),
|
||||
carousel(this, parent)
|
||||
@@ -46,12 +46,15 @@ TabsGroupHeader::TabsGroupHeader(TabsGroup * parent, uint8_t icon):
|
||||
|
||||
void TabsGroupHeader::paint(BitmapBuffer * dc)
|
||||
{
|
||||
OpenTxTheme::instance()->drawMenuBackground(dc, icon, title);
|
||||
OpenTxTheme::instance()->drawPageHeaderBackground(dc, icon, title);
|
||||
}
|
||||
|
||||
TabsCarousel::TabsCarousel(Window * parent, TabsGroup * menu):
|
||||
Window(parent, { MENU_HEADER_BUTTONS_LEFT, 0, LCD_W - MENU_HEADER_BUTTONS_LEFT, MENU_HEADER_HEIGHT + 10 }, TRANSPARENT),
|
||||
menu(menu)
|
||||
TabsCarousel::TabsCarousel(Window* parent, TabsGroup* menu) :
|
||||
Window(parent,
|
||||
{MENU_HEADER_BUTTONS_LEFT, 0, LCD_W - MENU_HEADER_BUTTONS_LEFT,
|
||||
MENU_HEADER_HEIGHT + 10},
|
||||
TRANSPARENT),
|
||||
menu(menu)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -62,7 +65,7 @@ void TabsCarousel::updateInnerWidth()
|
||||
|
||||
void TabsCarousel::paint(BitmapBuffer * dc)
|
||||
{
|
||||
OpenTxTheme::instance()->drawMenuHeader(dc, menu->tabs, currentIndex);
|
||||
OpenTxTheme::instance()->drawPageHeader(dc, menu->tabs, currentIndex);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
|
||||
@@ -155,7 +155,7 @@ class TabsGroupHeader: public FormGroup {
|
||||
|
||||
protected:
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
IconButton back;
|
||||
Button back;
|
||||
#endif
|
||||
uint8_t icon;
|
||||
TabsCarousel carousel;
|
||||
|
||||
@@ -166,23 +166,18 @@ void OpenTxTheme::drawBackground(BitmapBuffer * dc) const
|
||||
// }
|
||||
//}
|
||||
|
||||
void OpenTxTheme::drawCheckBox(BitmapBuffer * dc, bool checked, coord_t x, coord_t y, bool focus) const
|
||||
void OpenTxTheme::drawCheckBox(BitmapBuffer *dc, bool checked, coord_t x,
|
||||
coord_t y, bool focus) const
|
||||
{
|
||||
dc->drawSolidFilledRect(x, y, 16, 16, FIELD_BGCOLOR);
|
||||
if (focus) {
|
||||
dc->drawSolidFilledRect(x + 0, y + 2, 16, 16, FOCUS_BGCOLOR);
|
||||
if (checked) {
|
||||
dc->drawSolidFilledRect(x + 2, y + 4, 12, 12, DEFAULT_BGCOLOR);
|
||||
dc->drawSolidFilledRect(x + 3, y + 5, 10, 10, CHECKBOX_COLOR);
|
||||
}
|
||||
else {
|
||||
dc->drawSolidFilledRect(x + 2, y + 4, 12, 12, DEFAULT_BGCOLOR);
|
||||
}
|
||||
dc->drawSolidRect(x, y, 16, 16, 2, FOCUS_BGCOLOR);
|
||||
}
|
||||
else {
|
||||
dc->drawSolidRect(x + 0, y + 2, 16, 16, 1, DISABLE_COLOR);
|
||||
if (checked) {
|
||||
dc->drawSolidFilledRect(x + 2, y + 4, 12, 12, CHECKBOX_COLOR);
|
||||
}
|
||||
dc->drawSolidRect(x, y, 16, 16, 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
if (checked) {
|
||||
dc->drawSolidFilledRect(x + 3, y + 3, 10, 10, CHECKBOX_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,37 +187,43 @@ void OpenTxTheme::drawChoice(BitmapBuffer * dc, ChoiceBase * choice, const char
|
||||
if (choice->isEditMode())
|
||||
textColor = FOCUS_COLOR;
|
||||
else if (choice->hasFocus())
|
||||
textColor = FOCUS_BGCOLOR;
|
||||
else if (!str || str[0] == '\0')
|
||||
textColor = DISABLE_COLOR;
|
||||
textColor = FOCUS_COLOR;
|
||||
// else if (!str || str[0] == '\0')
|
||||
// textColor = FOCUS_COLOR;
|
||||
else
|
||||
textColor = DEFAULT_COLOR;
|
||||
|
||||
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, str[0] == '\0' ? "---" : str, textColor);
|
||||
dc->drawBitmapPattern(choice->getRect().w - 20, (choice->getRect().h - 11) / 2, choice->getType() == CHOICE_TYPE_FOLDER ? LBM_FOLDER : LBM_DROPDOWN, textColor);
|
||||
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP,
|
||||
str[0] == '\0' ? "---" : str, textColor);
|
||||
|
||||
dc->drawBitmapPattern(
|
||||
choice->getRect().w - 20, (choice->getRect().h - 11) / 2,
|
||||
choice->getType() == CHOICE_TYPE_FOLDER ? LBM_FOLDER : LBM_DROPDOWN,
|
||||
textColor);
|
||||
}
|
||||
|
||||
void OpenTxTheme::drawSlider(BitmapBuffer * dc, int vmin, int vmax, int value, const rect_t & rect, bool edit, bool focus) const
|
||||
void OpenTxTheme::drawSlider(BitmapBuffer *dc, int vmin, int vmax, int value,
|
||||
const rect_t &rect, bool edit, bool focus) const
|
||||
{
|
||||
int val = limit(vmin, value, vmax);
|
||||
int w = divRoundClosest((rect.w - 16) * (val - vmin), vmax - vmin);
|
||||
|
||||
if (edit) {
|
||||
dc->drawBitmapPattern(0, 11, LBM_SLIDER_BAR_LEFT, FOCUS_BGCOLOR);
|
||||
dc->drawSolidFilledRect(4, 11, rect.w - 8, 4, FOCUS_BGCOLOR);
|
||||
dc->drawBitmapPattern(rect.w - 4, 11, LBM_SLIDER_BAR_RIGHT, FOCUS_BGCOLOR);
|
||||
}
|
||||
else {
|
||||
dc->drawBitmapPattern(0, 11, LBM_SLIDER_BAR_LEFT, LINE_COLOR);
|
||||
dc->drawSolidFilledRect(4, 11, rect.w - 8, 4, LINE_COLOR);
|
||||
dc->drawBitmapPattern(rect.w - 4, 11, LBM_SLIDER_BAR_RIGHT, LINE_COLOR);
|
||||
LcdFlags color = DEFAULT_COLOR;
|
||||
if (focus) {
|
||||
color = FOCUS_BGCOLOR;
|
||||
}
|
||||
|
||||
dc->drawBitmapPattern(w, 5, LBM_SLIDER_POINT_OUT, DEFAULT_COLOR);
|
||||
dc->drawBitmapPattern(w, 5, LBM_SLIDER_POINT_MID, DEFAULT_BGCOLOR);
|
||||
// if ((options & INVERS) && (!(options & BLINK) || !BLINK_ON_PHASE))
|
||||
if (focus) {
|
||||
dc->drawBitmapPattern(w, 5, LBM_SLIDER_POINT_IN, FOCUS_BGCOLOR);
|
||||
dc->drawBitmapPattern(0, 11, LBM_SLIDER_BAR_LEFT, color);
|
||||
dc->drawSolidFilledRect(4, 11, rect.w - 8, 4, color);
|
||||
dc->drawBitmapPattern(rect.w - 4, 11, LBM_SLIDER_BAR_RIGHT, color);
|
||||
|
||||
dc->drawBitmapPattern(w, 5, LBM_SLIDER_POINT_OUT, color);
|
||||
dc->drawBitmapPattern(w, 5, LBM_SLIDER_POINT_MID, FIELD_BGCOLOR);
|
||||
|
||||
if (edit) {
|
||||
dc->drawBitmapPattern(w, 5, LBM_SLIDER_POINT_IN, EDIT_MARKER_COLOR);
|
||||
} else {
|
||||
dc->drawBitmapPattern(w, 5, LBM_SLIDER_POINT_IN, FIELD_BGCOLOR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,9 +85,11 @@ class OpenTxTheme: public Theme
|
||||
|
||||
virtual void drawBackground(BitmapBuffer * dc) const;
|
||||
|
||||
virtual void drawMenuBackground(BitmapBuffer * dc, uint8_t icon, const char *title) const = 0;
|
||||
virtual void drawPageHeaderBackground(BitmapBuffer *dc, uint8_t icon,
|
||||
const char *title) const = 0;
|
||||
|
||||
virtual void drawMenuHeader(BitmapBuffer * dc, std::vector<PageTab *> & tabs, uint8_t currentIndex) const = 0;
|
||||
virtual void drawPageHeader(BitmapBuffer *dc, std::vector<PageTab *> &tabs,
|
||||
uint8_t currentIndex) const = 0;
|
||||
|
||||
// virtual void drawMessageBox(const char * title, const char * text, const
|
||||
// char * action, uint32_t flags) const override;
|
||||
@@ -122,4 +124,6 @@ void loadTheme();
|
||||
|
||||
std::list<OpenTxTheme *> & getRegisteredThemes();
|
||||
|
||||
extern const uint8_t LBM_DROPDOWN[];
|
||||
|
||||
#endif // _COLORLCD_THEME_H_
|
||||
|
||||
@@ -28,6 +28,16 @@ const ZoneOption OPTIONS_THEME_DEFAULT[] = {
|
||||
{ nullptr, ZoneOption::Bool }
|
||||
};
|
||||
|
||||
constexpr uint16_t __TEXT_COLOR = RGB(0x0C, 0x3F, 0x66);
|
||||
constexpr uint16_t __BACKGROUND_COLOR = RGB(0x12, 0x5E, 0x99);
|
||||
constexpr uint16_t __FOCUS_COLOR = RGB(0x14, 0xA1, 0xE5);
|
||||
constexpr uint16_t __DATAFIELD_FRAME_COLOR = RGB(0xB6, 0xE0, 0xF2);
|
||||
constexpr uint16_t __TAB_BACKGROUND_COLOR = RGB(0xE4, 0xEE, 0xF2);
|
||||
constexpr uint16_t __PARAM_BACKGROUND_COLOR = WHITE;
|
||||
|
||||
constexpr uint16_t __EDIT_MARKER_COLOR = RGB(0x00, 0x99, 0x09);
|
||||
constexpr uint16_t __ACTIVE_MARKER_COLOR = RGB(0xFF, 0xDE, 0x00);
|
||||
|
||||
class Theme480: public OpenTxTheme
|
||||
{
|
||||
public:
|
||||
@@ -45,43 +55,45 @@ class Theme480: public OpenTxTheme
|
||||
lcdColorTable[BARGRAPH2_COLOR_INDEX] = RGB(167, 167, 167);
|
||||
lcdColorTable[BARGRAPH_BGCOLOR_INDEX] = RGB(222, 222, 222);
|
||||
lcdColorTable[BATTERY_CHARGE_COLOR_INDEX] = GREEN;
|
||||
lcdColorTable[CHECKBOX_COLOR_INDEX] = RED;
|
||||
lcdColorTable[CHECKBOX_COLOR_INDEX] = __FOCUS_COLOR;
|
||||
lcdColorTable[CURVE_COLOR_INDEX] = RED;
|
||||
lcdColorTable[CURVE_CURSOR_COLOR_INDEX] = RED;
|
||||
lcdColorTable[DEFAULT_BGCOLOR_INDEX] = WHITE;
|
||||
lcdColorTable[DEFAULT_COLOR_INDEX] = BLACK;
|
||||
lcdColorTable[DEFAULT_BGCOLOR_INDEX] = __TAB_BACKGROUND_COLOR;
|
||||
lcdColorTable[DEFAULT_COLOR_INDEX] = __TEXT_COLOR;
|
||||
lcdColorTable[DISABLE_COLOR_INDEX] = LIGHTGREY;
|
||||
lcdColorTable[FOCUS_BGCOLOR_INDEX] = RED;
|
||||
lcdColorTable[EDIT_MARKER_COLOR_INDEX] = __EDIT_MARKER_COLOR;
|
||||
lcdColorTable[FIELD_BGCOLOR_INDEX] = WHITE;
|
||||
lcdColorTable[FIELD_FRAME_COLOR_INDEX] = __DATAFIELD_FRAME_COLOR;
|
||||
lcdColorTable[FOCUS_BGCOLOR_INDEX] = __FOCUS_COLOR;
|
||||
lcdColorTable[FOCUS_COLOR_INDEX] = WHITE;
|
||||
lcdColorTable[HEADER_COLOR_INDEX] = DARKRED;
|
||||
lcdColorTable[HEADER_CURRENT_BGCOLOR_INDEX] = RED;
|
||||
lcdColorTable[HEADER_ICON_BGCOLOR_INDEX] = RED;
|
||||
lcdColorTable[HIGHLIGHT_COLOR_INDEX] = YELLOW;
|
||||
lcdColorTable[HEADER_COLOR_INDEX] = __BACKGROUND_COLOR;
|
||||
lcdColorTable[HEADER_CURRENT_BGCOLOR_INDEX] = __FOCUS_COLOR;
|
||||
lcdColorTable[HEADER_ICON_BGCOLOR_INDEX] = __BACKGROUND_COLOR;
|
||||
lcdColorTable[HIGHLIGHT_COLOR_INDEX] = __ACTIVE_MARKER_COLOR;
|
||||
lcdColorTable[LINE_COLOR_INDEX] = GREY;
|
||||
lcdColorTable[MAINVIEW_GRAPHICS_COLOR_INDEX] = RED;
|
||||
lcdColorTable[MAINVIEW_PANES_COLOR_INDEX] = WHITE;
|
||||
|
||||
// this is what the status bar uses...
|
||||
//lcdColorTable[MENU_BGCOLOR_INDEX] = DARKRED;
|
||||
lcdColorTable[MENU_BGCOLOR_INDEX] = WHITE;
|
||||
lcdColorTable[MENU_COLOR_INDEX] = __BACKGROUND_COLOR; // Menu font color
|
||||
|
||||
// Menu font color
|
||||
lcdColorTable[MENU_BGCOLOR_INDEX] = DARKRED;//DARKGREY;
|
||||
lcdColorTable[MENU_COLOR_INDEX] = WHITE;
|
||||
// Selected item in menu
|
||||
lcdColorTable[MENU_HIGHLIGHT_BGCOLOR_INDEX] = BLACK;
|
||||
lcdColorTable[MENU_HIGHLIGHT_BGCOLOR_INDEX] = __FOCUS_COLOR;
|
||||
lcdColorTable[MENU_HIGHLIGHT_COLOR_INDEX] = WHITE;
|
||||
lcdColorTable[MENU_LINE_COLOR_INDEX] = __DATAFIELD_FRAME_COLOR;
|
||||
|
||||
lcdColorTable[MENU_TITLE_DISABLE_COLOR_INDEX] = RGB(GET_RED(RED)>>1, GET_GREEN(RED)>>1, GET_BLUE(RED)>>1);
|
||||
lcdColorTable[MENU_TITLE_DISABLE_COLOR_INDEX] = __TEXT_COLOR;
|
||||
lcdColorTable[OVERLAY_COLOR_INDEX] = BLACK;
|
||||
lcdColorTable[SCROLLBAR_COLOR_INDEX] = RED;
|
||||
lcdColorTable[SCROLLBAR_COLOR_INDEX] = __TEXT_COLOR;
|
||||
lcdColorTable[TEXT_DISABLE_COLOR_INDEX] = GREY;
|
||||
lcdColorTable[TEXT_STATUSBAR_COLOR_INDEX] = WHITE;
|
||||
lcdColorTable[TITLE_BGCOLOR_INDEX] = RED;
|
||||
lcdColorTable[TRIM_BGCOLOR_INDEX] = RED;
|
||||
lcdColorTable[TITLE_BGCOLOR_INDEX] = __BACKGROUND_COLOR;
|
||||
|
||||
lcdColorTable[TRIM_BGCOLOR_INDEX] = __FOCUS_COLOR;
|
||||
lcdColorTable[TRIM_SHADOW_COLOR_INDEX] = BLACK;
|
||||
}
|
||||
|
||||
void loadMenuIcon(uint8_t index, const uint8_t * lbm, uint32_t color=MENU_COLOR) const
|
||||
void loadMenuIcon(uint8_t index, const uint8_t * lbm) const
|
||||
{
|
||||
BitmapBuffer * mask = BitmapBuffer::load8bitMask(lbm);
|
||||
if (mask) {
|
||||
@@ -91,15 +103,15 @@ class Theme480: public OpenTxTheme
|
||||
delete menuIconNormal[index];
|
||||
menuIconNormal[index] = new BitmapBuffer(BMP_RGB565, mask->width(), mask->height());
|
||||
if (menuIconNormal[index]) {
|
||||
menuIconNormal[index]->clear(MENU_BGCOLOR);
|
||||
menuIconNormal[index]->drawMask(0, 0, mask, color);
|
||||
menuIconNormal[index]->clear(HEADER_ICON_BGCOLOR);
|
||||
menuIconNormal[index]->drawMask(0, 0, mask, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
delete menuIconSelected[index];
|
||||
menuIconSelected[index] = new BitmapBuffer(BMP_RGB565, mask->width(), mask->height());
|
||||
if (menuIconSelected[index]) {
|
||||
menuIconSelected[index]->clear(HEADER_CURRENT_BGCOLOR);
|
||||
menuIconSelected[index]->drawMask(0, 0, mask, color);
|
||||
menuIconSelected[index]->drawMask(0, 0, mask, FOCUS_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,7 +119,7 @@ class Theme480: public OpenTxTheme
|
||||
void loadIcons() const
|
||||
{
|
||||
#if defined(LOG_TELEMETRY) || !defined(WATCHDOG)
|
||||
loadMenuIcon(ICON_OPENTX, mask_opentx_testmode, DEFAULT_COLOR);
|
||||
loadMenuIcon(ICON_OPENTX, mask_opentx_testmode);
|
||||
#else
|
||||
loadMenuIcon(ICON_OPENTX, mask_edgetx);
|
||||
#endif
|
||||
@@ -170,7 +182,7 @@ class Theme480: public OpenTxTheme
|
||||
|
||||
currentMenuBackground->drawSolidFilledRect(
|
||||
0, 0, currentMenuBackground->width(), MENU_HEADER_HEIGHT,
|
||||
MENU_BGCOLOR);
|
||||
HEADER_COLOR);
|
||||
|
||||
currentMenuBackground->drawSolidFilledRect(
|
||||
0, MENU_HEADER_HEIGHT, currentMenuBackground->width(),
|
||||
@@ -185,12 +197,12 @@ class Theme480: public OpenTxTheme
|
||||
|
||||
currentMenuBackground->drawMask(0, 0, shadow, TRIM_SHADOW_COLOR);
|
||||
|
||||
currentMenuBackground->drawMask(10, 39, dot, MENU_COLOR);
|
||||
currentMenuBackground->drawMask(10, 39, dot, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
delete topleftBitmap;
|
||||
topleftBitmap = BitmapBuffer::load8bitMaskOnBackground(
|
||||
mask_topleft, TITLE_BGCOLOR, HEADER_COLOR);
|
||||
mask_topleft, HEADER_CURRENT_BGCOLOR, HEADER_COLOR);
|
||||
|
||||
delete background;
|
||||
delete shadow;
|
||||
@@ -245,41 +257,41 @@ class Theme480: public OpenTxTheme
|
||||
|
||||
// Channels monitor screen
|
||||
delete chanMonLockedBitmap;
|
||||
chanMonLockedBitmap = BitmapBuffer::loadMaskOnBackground(getFilePath("mask_monitor_lockch.png"), DEFAULT_COLOR, DEFAULT_BGCOLOR);
|
||||
chanMonLockedBitmap = BitmapBuffer::load8bitMask(mask_monitor_lockch);
|
||||
|
||||
delete chanMonInvertedBitmap;
|
||||
chanMonInvertedBitmap = BitmapBuffer::loadMaskOnBackground(getFilePath("mask_monitor_inver.png"), DEFAULT_COLOR, DEFAULT_BGCOLOR);
|
||||
chanMonInvertedBitmap = BitmapBuffer::load8bitMask(mask_monitor_inver);
|
||||
|
||||
// Mixer setup screen
|
||||
delete mixerSetupMixerBitmap;
|
||||
mixerSetupMixerBitmap = BitmapBuffer::loadMaskOnBackground("mask_sbar_mixer.png", MENU_COLOR, MENU_BGCOLOR);
|
||||
mixerSetupMixerBitmap = BitmapBuffer::load8bitMask(mask_sbar_mixer);
|
||||
|
||||
delete mixerSetupToBitmap;
|
||||
mixerSetupToBitmap = BitmapBuffer::loadMaskOnBackground("mask_sbar_to.png", MENU_COLOR, MENU_BGCOLOR);
|
||||
mixerSetupToBitmap = BitmapBuffer::load8bitMask(mask_sbar_to);
|
||||
|
||||
delete mixerSetupOutputBitmap;
|
||||
mixerSetupOutputBitmap = BitmapBuffer::loadMaskOnBackground("mask_sbar_output.png", MENU_COLOR, MENU_BGCOLOR);
|
||||
mixerSetupOutputBitmap = BitmapBuffer::load8bitMask(mask_sbar_output);
|
||||
|
||||
delete mixerSetupAddBitmap;
|
||||
mixerSetupAddBitmap = BitmapBuffer::loadMaskOnBackground(getFilePath("mask_mplex_add.png"), DEFAULT_COLOR, DEFAULT_BGCOLOR);
|
||||
mixerSetupAddBitmap = BitmapBuffer::load8bitMask(mask_mplex_add);
|
||||
|
||||
delete mixerSetupMultiBitmap;
|
||||
mixerSetupMultiBitmap = BitmapBuffer::loadMaskOnBackground(getFilePath("mask_mplex_multi.png"), DEFAULT_COLOR, DEFAULT_BGCOLOR);
|
||||
mixerSetupMultiBitmap = BitmapBuffer::load8bitMask(mask_mplex_multi);
|
||||
|
||||
delete mixerSetupReplaceBitmap;
|
||||
mixerSetupReplaceBitmap = BitmapBuffer::loadMaskOnBackground(getFilePath("mask_mplex_replace.png"), DEFAULT_COLOR, DEFAULT_BGCOLOR);
|
||||
mixerSetupReplaceBitmap = BitmapBuffer::load8bitMask(mask_mplex_replace);
|
||||
|
||||
delete mixerSetupLabelIcon;
|
||||
mixerSetupLabelIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_label.png"));
|
||||
mixerSetupLabelIcon = BitmapBuffer::load8bitMask(mask_textline_label);
|
||||
|
||||
delete mixerSetupCurveIcon;
|
||||
mixerSetupCurveIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_curve.png"));
|
||||
mixerSetupCurveIcon = BitmapBuffer::load8bitMask(mask_textline_curve);
|
||||
|
||||
delete mixerSetupSwitchIcon;
|
||||
mixerSetupSwitchIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_switch.png"));
|
||||
mixerSetupSwitchIcon = BitmapBuffer::load8bitMask(mask_textline_switch);
|
||||
|
||||
delete mixerSetupFlightmodeIcon;
|
||||
mixerSetupFlightmodeIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_fm.png"));
|
||||
mixerSetupFlightmodeIcon = BitmapBuffer::load8bitMask(mask_textline_fm);
|
||||
|
||||
// delete mixerSetupSlowIcon;
|
||||
// mixerSetupSlowIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_slow.png"));
|
||||
@@ -347,7 +359,8 @@ class Theme480: public OpenTxTheme
|
||||
}
|
||||
}
|
||||
|
||||
void drawMenuBackground(BitmapBuffer * dc, uint8_t icon, const char * title) const override
|
||||
void drawPageHeaderBackground(BitmapBuffer *dc, uint8_t icon,
|
||||
const char *title) const override
|
||||
{
|
||||
if (topleftBitmap) {
|
||||
dc->drawBitmap(0, 0, topleftBitmap);
|
||||
@@ -363,10 +376,14 @@ class Theme480: public OpenTxTheme
|
||||
else
|
||||
dc->drawBitmap(5, 7, menuIconSelected[icon]);
|
||||
|
||||
dc->drawSolidFilledRect(0, MENU_HEADER_HEIGHT, LCD_W, MENU_TITLE_TOP - MENU_HEADER_HEIGHT, DEFAULT_BGCOLOR); // the white separation line
|
||||
dc->drawSolidFilledRect(0, MENU_TITLE_TOP, LCD_W, MENU_TITLE_HEIGHT, TITLE_BGCOLOR); // the title line background
|
||||
dc->drawSolidFilledRect(0, MENU_HEADER_HEIGHT, LCD_W,
|
||||
MENU_TITLE_TOP - MENU_HEADER_HEIGHT,
|
||||
DEFAULT_BGCOLOR); // the white separation line
|
||||
|
||||
dc->drawSolidFilledRect(0, MENU_TITLE_TOP, LCD_W, MENU_TITLE_HEIGHT,
|
||||
TITLE_BGCOLOR); // the title line background
|
||||
if (title) {
|
||||
dc->drawText(MENUS_MARGIN_LEFT, MENU_TITLE_TOP + 3, title, MENU_COLOR);
|
||||
dc->drawText(MENUS_MARGIN_LEFT, MENU_TITLE_TOP + 3, title, FOCUS_COLOR);
|
||||
}
|
||||
|
||||
drawMenuDatetime(dc);
|
||||
@@ -382,20 +399,24 @@ class Theme480: public OpenTxTheme
|
||||
return state == STATE_DEFAULT ? menuIconNormal[index] : menuIconSelected[index];
|
||||
}
|
||||
|
||||
void drawMenuHeader(BitmapBuffer * dc, std::vector<PageTab *> & tabs, uint8_t currentIndex) const override
|
||||
void drawPageHeader(BitmapBuffer *dc, std::vector<PageTab *> &tabs,
|
||||
uint8_t currentIndex) const override
|
||||
{
|
||||
for (unsigned index = 0; index < tabs.size(); index++) {
|
||||
if (index != currentIndex) {
|
||||
dc->drawBitmap(index*MENU_HEADER_BUTTON_WIDTH + 2, 7, menuIconNormal[tabs[index]->getIcon()]);
|
||||
dc->drawBitmap(index * MENU_HEADER_BUTTON_WIDTH + 2, 7,
|
||||
menuIconNormal[tabs[index]->getIcon()]);
|
||||
}
|
||||
}
|
||||
dc->drawBitmap(currentIndex*MENU_HEADER_BUTTON_WIDTH, 0, currentMenuBackground);
|
||||
dc->drawBitmap(currentIndex*MENU_HEADER_BUTTON_WIDTH + 2, 7, menuIconSelected[tabs[currentIndex]->getIcon()]);
|
||||
dc->drawBitmap(currentIndex * MENU_HEADER_BUTTON_WIDTH, 0,
|
||||
currentMenuBackground);
|
||||
dc->drawBitmap(currentIndex * MENU_HEADER_BUTTON_WIDTH + 2, 7,
|
||||
menuIconSelected[tabs[currentIndex]->getIcon()]);
|
||||
}
|
||||
|
||||
void drawMenuDatetime(BitmapBuffer * dc) const
|
||||
{
|
||||
dc->drawSolidVerticalLine(DATETIME_SEPARATOR_X, 7, 31, FOCUS_COLOR);
|
||||
//dc->drawSolidVerticalLine(DATETIME_SEPARATOR_X, 7, 31, FOCUS_COLOR);
|
||||
|
||||
struct gtm t;
|
||||
gettime(&t);
|
||||
|
||||
@@ -348,25 +348,30 @@ class FlyskyTheme: public OpenTxTheme
|
||||
}
|
||||
}
|
||||
|
||||
void drawMenuBackground(BitmapBuffer * dc, uint8_t icon, const char * title) const override
|
||||
void drawPageHeaderBackground(BitmapBuffer *dc, uint8_t icon,
|
||||
const char *title) const override
|
||||
{
|
||||
// if (topleftBitmap) {
|
||||
// dc->drawBitmap(0, 0, topleftBitmap);
|
||||
// uint16_t width = topleftBitmap->width();
|
||||
// dc->drawSolidFilledRect(width, 0, LCD_W-width, MENU_HEADER_HEIGHT, HEADER_BGCOLOR);
|
||||
// }
|
||||
// else {
|
||||
dc->drawSolidFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, HEADER_BGCOLOR);
|
||||
// }
|
||||
//
|
||||
// if (icon == ICON_OPENTX)
|
||||
// dc->drawBitmap(4, 10, menuIconSelected[ICON_OPENTX]);
|
||||
// else
|
||||
// dc->drawBitmap(5, 7, menuIconSelected[icon]);
|
||||
//
|
||||
dc->drawSolidFilledRect(0, MENU_HEADER_HEIGHT, LCD_W, MENU_TITLE_TOP - MENU_HEADER_HEIGHT, DEFAULT_BGCOLOR); // the white separation line
|
||||
dc->drawSolidFilledRect(0, MENU_TITLE_TOP, LCD_W, MENU_TITLE_HEIGHT, TITLE_BGCOLOR); // the title line background
|
||||
//
|
||||
// if (topleftBitmap) {
|
||||
// dc->drawBitmap(0, 0, topleftBitmap);
|
||||
// uint16_t width = topleftBitmap->width();
|
||||
// dc->drawSolidFilledRect(width, 0, LCD_W-width,
|
||||
// MENU_HEADER_HEIGHT, HEADER_BGCOLOR);
|
||||
// }
|
||||
// else {
|
||||
dc->drawSolidFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, HEADER_BGCOLOR);
|
||||
// }
|
||||
//
|
||||
// if (icon == ICON_OPENTX)
|
||||
// dc->drawBitmap(4, 10, menuIconSelected[ICON_OPENTX]);
|
||||
// else
|
||||
// dc->drawBitmap(5, 7, menuIconSelected[icon]);
|
||||
//
|
||||
dc->drawSolidFilledRect(0, MENU_HEADER_HEIGHT, LCD_W,
|
||||
MENU_TITLE_TOP - MENU_HEADER_HEIGHT,
|
||||
DEFAULT_BGCOLOR); // the white separation line
|
||||
dc->drawSolidFilledRect(0, MENU_TITLE_TOP, LCD_W, MENU_TITLE_HEIGHT,
|
||||
TITLE_BGCOLOR); // the title line background
|
||||
//
|
||||
if (title) {
|
||||
dc->drawText(MENUS_MARGIN_LEFT, MENU_TITLE_TOP + 2, title, MENU_COLOR);
|
||||
}
|
||||
@@ -382,19 +387,25 @@ class FlyskyTheme: public OpenTxTheme
|
||||
return state == STATE_DEFAULT ? menuIconNormal[index] : menuIconSelected[index];
|
||||
}
|
||||
|
||||
void drawMenuHeader(BitmapBuffer * dc, std::vector<PageTab *> & tabs, uint8_t currentIndex) const override
|
||||
void drawPageHeader(BitmapBuffer *dc, std::vector<PageTab *> &tabs,
|
||||
uint8_t currentIndex) const override
|
||||
{
|
||||
uint8_t padding_left = 4;
|
||||
|
||||
dc->drawSolidFilledRect(0, 0, 4, MENU_HEADER_BUTTON_WIDTH, HEADER_BGCOLOR);
|
||||
dc->drawSolidFilledRect(0, 0, 4, MENU_HEADER_BUTTON_WIDTH,
|
||||
HEADER_BGCOLOR);
|
||||
for (unsigned i = 0; i < tabs.size(); i++) {
|
||||
dc->drawBitmap(padding_left + i*MENU_HEADER_BUTTON_WIDTH, 0, theme->getIcon(tabs[i]->getIcon(), currentIndex == i ? STATE_PRESSED : STATE_DEFAULT));
|
||||
dc->drawBitmap(
|
||||
padding_left + i * MENU_HEADER_BUTTON_WIDTH, 0,
|
||||
theme->getIcon(tabs[i]->getIcon(),
|
||||
currentIndex == i ? STATE_PRESSED : STATE_DEFAULT));
|
||||
}
|
||||
// coord_t x = padding_left + MENU_HEADER_BUTTON_WIDTH * tabs.size();
|
||||
// coord_t w = width() - x;
|
||||
// if (w > 0) {
|
||||
// dc->drawSolidFilledRect(x, 0, w, MENU_HEADER_BUTTON_WIDTH, HEADER_BGCOLOR);
|
||||
// }
|
||||
// coord_t x = padding_left + MENU_HEADER_BUTTON_WIDTH * tabs.size();
|
||||
// coord_t w = width() - x;
|
||||
// if (w > 0) {
|
||||
// dc->drawSolidFilledRect(x, 0, w, MENU_HEADER_BUTTON_WIDTH,
|
||||
// HEADER_BGCOLOR);
|
||||
// }
|
||||
}
|
||||
|
||||
void drawMenuDatetime(BitmapBuffer * dc) const
|
||||
|
||||
@@ -36,11 +36,13 @@ void TimeEdit::paint(BitmapBuffer * dc)
|
||||
if (editMode)
|
||||
textColor = FOCUS_COLOR;
|
||||
else if (hasFocus())
|
||||
textColor = FOCUS_BGCOLOR;
|
||||
textColor = FOCUS_COLOR;
|
||||
else
|
||||
textColor = DEFAULT_COLOR;
|
||||
|
||||
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, getTimerString(getValue(), (textFlags & TIMEHOUR) != 0), textColor);
|
||||
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP,
|
||||
getTimerString(getValue(), (textFlags & TIMEHOUR) != 0),
|
||||
textColor);
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_KEYS)
|
||||
|
||||
@@ -46,9 +46,9 @@ class ChannelsViewFooter: public Window {
|
||||
// Draw single legend
|
||||
coord_t drawChannelsMonitorLegend(BitmapBuffer * dc, coord_t x, const char * s, int color)
|
||||
{
|
||||
dc->drawSolidFilledRect(x, 2, LEG_COLORBOX + 2, LEG_COLORBOX + 2, BARGRAPH_BGCOLOR);
|
||||
dc->drawSolidFilledRect(x + 1, 3, LEG_COLORBOX, LEG_COLORBOX, color);
|
||||
dc->drawText(x + 20, 2, s, TEXT_STATUSBAR_COLOR);
|
||||
dc->drawSolidFilledRect(x, 4, LEG_COLORBOX + 2, LEG_COLORBOX + 2, BARGRAPH_BGCOLOR);
|
||||
dc->drawSolidFilledRect(x + 1, 5, LEG_COLORBOX, LEG_COLORBOX, color);
|
||||
dc->drawText(x + 20, 4, s, TEXT_STATUSBAR_COLOR);
|
||||
return x + 25 + getTextWidth(s);
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ class ChannelsViewFooter: public Window {
|
||||
// Draw legend bar
|
||||
coord_t x = 10;
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), TITLE_BGCOLOR);
|
||||
x = drawChannelsMonitorLegend(dc, MENUS_MARGIN_LEFT, STR_MONITOR_OUTPUT_DESC, BARGRAPH1_COLOR);
|
||||
drawChannelsMonitorLegend(dc, x, STR_MONITOR_MIXER_DESC, BARGRAPH2_COLOR);
|
||||
x = drawChannelsMonitorLegend(dc, MENUS_MARGIN_LEFT, STR_MONITOR_OUTPUT_DESC, HIGHLIGHT_COLOR);
|
||||
drawChannelsMonitorLegend(dc, x, STR_MONITOR_MIXER_DESC, FOCUS_BGCOLOR);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,27 +27,30 @@
|
||||
class LogicalSwitchDisplayButton : public TextButton
|
||||
{
|
||||
public:
|
||||
LogicalSwitchDisplayButton(FormGroup * parent, const rect_t & rect, std::string text, unsigned index):
|
||||
TextButton(parent, rect, std::move(text)),
|
||||
index(index)
|
||||
{
|
||||
}
|
||||
LogicalSwitchDisplayButton(FormGroup* parent, const rect_t& rect,
|
||||
std::string text, unsigned index) :
|
||||
TextButton(parent, rect, std::move(text), nullptr, OPAQUE), index(index)
|
||||
{
|
||||
setBgColorHandler([=]() -> LcdFlags {
|
||||
if (getSwitch(SWSRC_SW1 + index)) return HIGHLIGHT_COLOR;
|
||||
return FIELD_BGCOLOR;
|
||||
});
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
bool newvalue = getSwitch(SWSRC_SW1 + index);
|
||||
if (value != newvalue) {
|
||||
if (newvalue) {
|
||||
setTextFlags(FONT(BOLD) | HIGHLIGHT_COLOR);
|
||||
}
|
||||
else {
|
||||
setTextFlags(FONT(STD) | DEFAULT_COLOR);
|
||||
}
|
||||
value = newvalue;
|
||||
invalidate();
|
||||
}
|
||||
Button::checkEvents();
|
||||
}
|
||||
void checkEvents() override
|
||||
{
|
||||
bool newvalue = getSwitch(SWSRC_SW1 + index);
|
||||
if (value != newvalue) {
|
||||
if (newvalue) {
|
||||
setTextFlags(FONT(BOLD) | DEFAULT_COLOR);
|
||||
} else {
|
||||
setTextFlags(FONT(STD) | DEFAULT_COLOR);
|
||||
}
|
||||
value = newvalue;
|
||||
invalidate();
|
||||
}
|
||||
Button::checkEvents();
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned index = 0;
|
||||
@@ -61,21 +64,28 @@ void LogicalSwitchesViewPage::build(FormWindow * window)
|
||||
grid.spacer(PAGE_PADDING);
|
||||
grid.setLabelWidth(8);
|
||||
|
||||
// Footer
|
||||
footer = new LogicalSwitchDisplayFooter(
|
||||
window, {0, window->height() - LSW_VIEW_FOOTER_HEIGHT, window->width(),
|
||||
LSW_VIEW_FOOTER_HEIGHT});
|
||||
|
||||
// LSW table
|
||||
std::string lsString ("LS64");
|
||||
std::string lsString("LS64");
|
||||
lcdColorTable[CUSTOM_COLOR_INDEX] = RGB(160, 160, 160);
|
||||
for (uint8_t i = 0; i < MAX_LOGICAL_SWITCHES; i++) {
|
||||
|
||||
strAppendSigned(&lsString[1], i + 1, 2);
|
||||
auto button = new LogicalSwitchDisplayButton(window, grid.getFieldSlot(8, i % 8), lsString, i);
|
||||
button->setPressHandler([=]() {
|
||||
footer->setIndex(i);
|
||||
footer->invalidate();
|
||||
|
||||
auto button = new LogicalSwitchDisplayButton(
|
||||
window, grid.getFieldSlot(8, i % 8), lsString, i);
|
||||
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
footer->setIndex(i);
|
||||
footer->invalidate();
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
if ((i + 1) % 8 == 0)
|
||||
grid.nextLine();
|
||||
if ((i + 1) % 8 == 0) grid.nextLine();
|
||||
}
|
||||
|
||||
// Footer
|
||||
footer = new LogicalSwitchDisplayFooter(window, {0,window->height() - LSW_VIEW_FOOTER_HEIGHT, window->width(), LSW_VIEW_FOOTER_HEIGHT});
|
||||
}
|
||||
|
||||
@@ -30,77 +30,76 @@ constexpr coord_t CSW_4TH_COLUMN = 280;
|
||||
constexpr coord_t CSW_5TH_COLUMN = 340;
|
||||
constexpr coord_t CSW_6TH_COLUMN = 390;
|
||||
|
||||
void putsEdgeDelayParam(BitmapBuffer * dc, coord_t x, coord_t y, LogicalSwitchData * ls, LcdFlags flags);
|
||||
void putsEdgeDelayParam(BitmapBuffer* dc, coord_t x, coord_t y,
|
||||
LogicalSwitchData* ls, LcdFlags flags);
|
||||
|
||||
class LogicalSwitchDisplayFooter: public Window {
|
||||
public:
|
||||
explicit LogicalSwitchDisplayFooter(Window * parent, rect_t rect):
|
||||
Window(parent, rect, OPAQUE),
|
||||
rect(rect)
|
||||
{
|
||||
class LogicalSwitchDisplayFooter : public Window
|
||||
{
|
||||
public:
|
||||
explicit LogicalSwitchDisplayFooter(Window* parent, rect_t rect) :
|
||||
Window(parent, rect, OPAQUE), rect(rect)
|
||||
{
|
||||
}
|
||||
|
||||
void setIndex(unsigned value) { index = value; }
|
||||
|
||||
void paint(BitmapBuffer* dc) override
|
||||
{
|
||||
dc->clear(TITLE_BGCOLOR);
|
||||
LogicalSwitchData* cs = lswAddress(index);
|
||||
|
||||
LcdFlags textColor = FOCUS_COLOR;
|
||||
dc->drawTextAtIndex(10, 1, STR_VCSWFUNC, cs->func, textColor);
|
||||
// CSW params
|
||||
unsigned int cstate = lswFamily(cs->func);
|
||||
|
||||
if (cstate == LS_FAMILY_BOOL || cstate == LS_FAMILY_STICKY) {
|
||||
drawSwitch(dc, CSW_2ND_COLUMN, 1, cs->v1, textColor);
|
||||
drawSwitch(dc, CSW_3RD_COLUMN, 1, cs->v2, textColor);
|
||||
} else if (cstate == LS_FAMILY_EDGE) {
|
||||
drawSwitch(dc, CSW_2ND_COLUMN, 1, cs->v1, textColor);
|
||||
putsEdgeDelayParam(dc, CSW_3RD_COLUMN, 1, cs, textColor);
|
||||
} else if (cstate == LS_FAMILY_COMP) {
|
||||
drawSource(dc, CSW_2ND_COLUMN, 1, cs->v1, textColor);
|
||||
drawSource(dc, CSW_3RD_COLUMN, 1, cs->v2, textColor);
|
||||
} else if (cstate == LS_FAMILY_TIMER) {
|
||||
dc->drawNumber(CSW_2ND_COLUMN, 1, lswTimerValue(cs->v1),
|
||||
LEFT | PREC1 | textColor);
|
||||
dc->drawNumber(CSW_3RD_COLUMN, 1, lswTimerValue(cs->v2),
|
||||
LEFT | PREC1 | textColor);
|
||||
} else {
|
||||
drawSource(dc, CSW_2ND_COLUMN, 1, cs->v1, textColor);
|
||||
drawSourceCustomValue(
|
||||
dc, CSW_3RD_COLUMN, 1, cs->v1,
|
||||
cs->v1 <= MIXSRC_LAST_CH ? calc100toRESX(cs->v2) : cs->v2,
|
||||
LEFT | textColor);
|
||||
}
|
||||
|
||||
void setIndex(unsigned value)
|
||||
{
|
||||
index = value;
|
||||
// CSW AND switch
|
||||
drawSwitch(dc, CSW_4TH_COLUMN, 1, cs->andsw, textColor);
|
||||
|
||||
// CSW duration
|
||||
if (cs->duration > 0)
|
||||
dc->drawNumber(CSW_5TH_COLUMN, 1, cs->duration,
|
||||
PREC1 | LEFT | textColor);
|
||||
else
|
||||
dc->drawTextAtIndex(CSW_5TH_COLUMN, 1, STR_MMMINV, 0, textColor);
|
||||
|
||||
// CSW delay
|
||||
if (cstate == LS_FAMILY_EDGE) {
|
||||
dc->drawText(CSW_6TH_COLUMN, 1, STR_NA, textColor);
|
||||
} else if (cs->delay > 0) {
|
||||
dc->drawNumber(CSW_6TH_COLUMN, 1, cs->delay, PREC1 | LEFT | textColor);
|
||||
} else {
|
||||
dc->drawTextAtIndex(CSW_6TH_COLUMN, 1, STR_MMMINV, 0, textColor);
|
||||
}
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
dc->clear(TITLE_BGCOLOR);
|
||||
LogicalSwitchData * cs = lswAddress(index);
|
||||
dc->drawTextAtIndex(10, 1, STR_VCSWFUNC, cs->func, MENU_COLOR);
|
||||
// CSW params
|
||||
unsigned int cstate = lswFamily(cs->func);
|
||||
|
||||
if (cstate == LS_FAMILY_BOOL || cstate == LS_FAMILY_STICKY) {
|
||||
drawSwitch(dc, CSW_2ND_COLUMN, 1, cs->v1, MENU_COLOR);
|
||||
drawSwitch(dc, CSW_3RD_COLUMN, 1, cs->v2, MENU_COLOR);
|
||||
}
|
||||
else if (cstate == LS_FAMILY_EDGE) {
|
||||
drawSwitch(dc, CSW_2ND_COLUMN, 1, cs->v1, MENU_COLOR);
|
||||
putsEdgeDelayParam(dc, CSW_3RD_COLUMN, 1, cs, MENU_COLOR);
|
||||
}
|
||||
else if (cstate == LS_FAMILY_COMP) {
|
||||
drawSource(dc, CSW_2ND_COLUMN, 1, cs->v1, MENU_COLOR);
|
||||
drawSource(dc, CSW_3RD_COLUMN, 1, cs->v2, MENU_COLOR);
|
||||
}
|
||||
else if (cstate == LS_FAMILY_TIMER) {
|
||||
dc->drawNumber(CSW_2ND_COLUMN, 1, lswTimerValue(cs->v1), LEFT | PREC1 | MENU_COLOR);
|
||||
dc->drawNumber(CSW_3RD_COLUMN, 1, lswTimerValue(cs->v2), LEFT | PREC1 | MENU_COLOR);
|
||||
}
|
||||
else {
|
||||
drawSource(dc, CSW_2ND_COLUMN, 1, cs->v1, MENU_COLOR);
|
||||
drawSourceCustomValue(dc, CSW_3RD_COLUMN, 1, cs->v1, cs->v1 <= MIXSRC_LAST_CH ? calc100toRESX(cs->v2) : cs->v2, LEFT | MENU_COLOR);
|
||||
}
|
||||
|
||||
// CSW AND switch
|
||||
drawSwitch(dc, CSW_4TH_COLUMN, 1, cs->andsw, MENU_COLOR);
|
||||
|
||||
// CSW duration
|
||||
if (cs->duration > 0)
|
||||
dc->drawNumber(CSW_5TH_COLUMN, 1, cs->duration, PREC1 | LEFT | MENU_COLOR);
|
||||
else
|
||||
dc->drawTextAtIndex(CSW_5TH_COLUMN, 1, STR_MMMINV, 0, MENU_COLOR);
|
||||
|
||||
// CSW delay
|
||||
if (cstate == LS_FAMILY_EDGE) {
|
||||
dc->drawText(CSW_6TH_COLUMN, 1, STR_NA, MENU_COLOR);
|
||||
}
|
||||
else if (cs->delay > 0) {
|
||||
dc->drawNumber(CSW_6TH_COLUMN, 1, cs->delay, PREC1 | LEFT | MENU_COLOR);
|
||||
}
|
||||
else {
|
||||
dc->drawTextAtIndex(CSW_6TH_COLUMN, 1, STR_MMMINV, 0, MENU_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
rect_t rect;
|
||||
unsigned index = 0;
|
||||
protected:
|
||||
rect_t rect;
|
||||
unsigned index = 0;
|
||||
};
|
||||
|
||||
|
||||
class LogicalSwitchesViewPage : public PageTab
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -53,7 +53,7 @@ class TextWidget: public Widget
|
||||
|
||||
const ZoneOption TextWidget::options[] = {
|
||||
{ STR_TEXT, ZoneOption::String, OPTION_VALUE_STRING(TEXT_WIDGET_DEFAULT_LABEL) },
|
||||
{ STR_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(RED) },
|
||||
{ STR_COLOR, ZoneOption::Color, OPTION_VALUE_UNSIGNED(DEFAULT_COLOR>>16) },
|
||||
{ STR_SIZE, ZoneOption::TextSize, OPTION_VALUE_UNSIGNED(0) },
|
||||
{ STR_SHADOW, ZoneOption::Bool, OPTION_VALUE_BOOL(false) },
|
||||
{ nullptr, ZoneOption::Bool }
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#include "sdcard_raw.h"
|
||||
#endif
|
||||
|
||||
#define MODELCELL_WIDTH 172
|
||||
#define MODELCELL_HEIGHT 59
|
||||
// #define MODELCELL_WIDTH 172
|
||||
// #define MODELCELL_HEIGHT 59
|
||||
|
||||
// modelXXXXXXX.bin F,FF F,3F,FF\r\n
|
||||
#define LEN_MODELS_IDX_LINE (LEN_MODEL_FILENAME + sizeof(" F,FF F,3F,FF\r\n")-1)
|
||||
|
||||
@@ -106,9 +106,9 @@ constexpr uint32_t PAGE_TITLE_LEFT = 50;
|
||||
|
||||
constexpr uint32_t INPUT_EDIT_LABELS_WIDTH = 120;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 158;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = LCD_H - MENU_HEADER_HEIGHT;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_LEFT = LCD_W - 158;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_TOP = MENU_HEADER_HEIGHT;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = INPUT_EDIT_CURVE_WIDTH;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_LEFT = PAGE_PADDING;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_TOP = MENU_HEADER_HEIGHT + PAGE_PADDING;
|
||||
constexpr coord_t MENUS_LINE_HEIGHT = 30;
|
||||
constexpr coord_t MENUS_WIDTH = 200;
|
||||
constexpr coord_t MENUS_OFFSET_TOP = 20;
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Vendored
+1
-1
Submodule radio/src/thirdparty/libopenui updated: 09e8553459...6b661c4907
Reference in New Issue
Block a user