diff --git a/radio/src/gui/colorlcd/channel_bar.h b/radio/src/gui/colorlcd/channel_bar.h index 5c1afb1ad..c9df34879 100644 --- a/radio/src/gui/colorlcd/channel_bar.h +++ b/radio/src/gui/colorlcd/channel_bar.h @@ -58,18 +58,30 @@ class MixerChannelBar : public ChannelBar chanVal = limit(-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(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT); + chanVal = limit(-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; -}; \ No newline at end of file +}; diff --git a/radio/src/gui/colorlcd/colors.h b/radio/src/gui/colorlcd/colors.h index 8d0991676..93c83152c 100644 --- a/radio/src/gui/colorlcd/colors.h +++ b/radio/src/gui/colorlcd/colors.h @@ -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) diff --git a/radio/src/gui/colorlcd/curve.cpp b/radio/src/gui/colorlcd/curve.cpp index ee62a79d0..ce796d63d 100644 --- a/radio/src/gui/colorlcd/curve.cpp +++ b/radio/src/gui/colorlcd/curve.cpp @@ -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) diff --git a/radio/src/gui/colorlcd/curveedit.cpp b/radio/src/gui/colorlcd/curveedit.cpp index 9eb248083..9de50061f 100644 --- a/radio/src/gui/colorlcd/curveedit.cpp +++ b/radio/src/gui/colorlcd/curveedit.cpp @@ -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() { diff --git a/radio/src/gui/colorlcd/curveedit.h b/radio/src/gui/colorlcd/curveedit.h index 11efa8f8a..d76de9553 100644 --- a/radio/src/gui/colorlcd/curveedit.h +++ b/radio/src/gui/colorlcd/curveedit.h @@ -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; diff --git a/radio/src/gui/colorlcd/layouts/topbar_impl.cpp b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp index 68d9e7378..7ba5bfb02 100644 --- a/radio/src/gui/colorlcd/layouts/topbar_impl.cpp +++ b/radio/src/gui/colorlcd/layouts/topbar_impl.cpp @@ -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 diff --git a/radio/src/gui/colorlcd/layouts/trims.cpp b/radio/src/gui/colorlcd/layouts/trims.cpp index 013ba9bc6..82dc4f9e3 100644 --- a/radio/src/gui/colorlcd/layouts/trims.cpp +++ b/radio/src/gui/colorlcd/layouts/trims.cpp @@ -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); } diff --git a/radio/src/gui/colorlcd/model_curves.cpp b/radio/src/gui/colorlcd/model_curves.cpp index fdf2295c0..8d463fe67 100644 --- a/radio/src/gui/colorlcd/model_curves.cpp +++ b/radio/src/gui/colorlcd/model_curves.cpp @@ -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, [=]() { diff --git a/radio/src/gui/colorlcd/model_curves.h b/radio/src/gui/colorlcd/model_curves.h index a747b50e6..52fe9b1f4 100644 --- a/radio/src/gui/colorlcd/model_curves.h +++ b/radio/src/gui/colorlcd/model_curves.h @@ -30,7 +30,7 @@ class ModelCurvesPage: public PageTab { virtual void build(FormWindow * window) override { - build(window, -1); + build(window, 0); } protected: diff --git a/radio/src/gui/colorlcd/model_flightmodes.cpp b/radio/src/gui/colorlcd/model_flightmodes.cpp index 1298828d4..26bcfc789 100644 --- a/radio/src/gui/colorlcd/model_flightmodes.cpp +++ b/radio/src/gui/colorlcd/model_flightmodes.cpp @@ -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); } diff --git a/radio/src/gui/colorlcd/model_gvars.cpp b/radio/src/gui/colorlcd/model_gvars.cpp index e810d85ed..9b3cf42fa 100644 --- a/radio/src/gui/colorlcd/model_gvars.cpp +++ b/radio/src/gui/colorlcd/model_gvars.cpp @@ -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()); -} \ No newline at end of file +} diff --git a/radio/src/gui/colorlcd/model_inputs.cpp b/radio/src/gui/colorlcd/model_inputs.cpp index 143b3cf30..815d709e6 100644 --- a/radio/src/gui/colorlcd/model_inputs.cpp +++ b/radio/src/gui/colorlcd/model_inputs.cpp @@ -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(); } diff --git a/radio/src/gui/colorlcd/model_inputs.h b/radio/src/gui/colorlcd/model_inputs.h index 0f6afbd93..9677c4916 100644 --- a/radio/src/gui/colorlcd/model_inputs.h +++ b/radio/src/gui/colorlcd/model_inputs.h @@ -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; diff --git a/radio/src/gui/colorlcd/model_logical_switches.cpp b/radio/src/gui/colorlcd/model_logical_switches.cpp index 4d3e6aa5e..90b900562 100644 --- a/radio/src/gui/colorlcd/model_logical_switches.cpp +++ b/radio/src/gui/colorlcd/model_logical_switches.cpp @@ -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); } } diff --git a/radio/src/gui/colorlcd/model_logical_switches.h b/radio/src/gui/colorlcd/model_logical_switches.h index fc3a505bf..d211ead04 100644 --- a/radio/src/gui/colorlcd/model_logical_switches.h +++ b/radio/src/gui/colorlcd/model_logical_switches.h @@ -29,7 +29,7 @@ public: virtual void build(FormWindow * window) override { - build(window, -1); + build(window, 0); } protected: diff --git a/radio/src/gui/colorlcd/model_mixes.cpp b/radio/src/gui/colorlcd/model_mixes.cpp index eb409397b..09804edf1 100644 --- a/radio/src/gui/colorlcd/model_mixes.cpp +++ b/radio/src/gui/colorlcd/model_mixes.cpp @@ -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(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(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(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 { diff --git a/radio/src/gui/colorlcd/model_outputs.cpp b/radio/src/gui/colorlcd/model_outputs.cpp index aa381ad59..bbc42f58c 100644 --- a/radio/src/gui/colorlcd/model_outputs.cpp +++ b/radio/src/gui/colorlcd/model_outputs.cpp @@ -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); } diff --git a/radio/src/gui/colorlcd/model_outputs.h b/radio/src/gui/colorlcd/model_outputs.h index 2a5c61734..25671a4d7 100644 --- a/radio/src/gui/colorlcd/model_outputs.h +++ b/radio/src/gui/colorlcd/model_outputs.h @@ -29,7 +29,7 @@ class ModelOutputsPage: public PageTab { virtual void build(FormWindow * window) override { - build(window, -1); + build(window, 0); } protected: diff --git a/radio/src/gui/colorlcd/model_select.cpp b/radio/src/gui/colorlcd/model_select.cpp index b0478ce90..da6209d0e 100644 --- a/radio/src/gui/colorlcd/model_select.cpp +++ b/radio/src/gui/colorlcd/model_select.cpp @@ -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 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 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) { diff --git a/radio/src/gui/colorlcd/model_setup.cpp b/radio/src/gui/colorlcd/model_setup.cpp index 208633f2c..b7817d2c7 100644 --- a/radio/src/gui/colorlcd/model_setup.cpp +++ b/radio/src/gui/colorlcd/model_setup.cpp @@ -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: diff --git a/radio/src/gui/colorlcd/model_telemetry.cpp b/radio/src/gui/colorlcd/model_telemetry.cpp index ca24c6c99..0803eb61b 100644 --- a/radio/src/gui/colorlcd/model_telemetry.cpp +++ b/radio/src/gui/colorlcd/model_telemetry.cpp @@ -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 { diff --git a/radio/src/gui/colorlcd/page.cpp b/radio/src/gui/colorlcd/page.cpp index a042e9d80..91d7e3704 100644 --- a/radio/src/gui/colorlcd/page.cpp +++ b/radio/src/gui/colorlcd/page.cpp @@ -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): diff --git a/radio/src/gui/colorlcd/page.h b/radio/src/gui/colorlcd/page.h index 212993575..6d1717a91 100644 --- a/radio/src/gui/colorlcd/page.h +++ b/radio/src/gui/colorlcd/page.h @@ -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 diff --git a/radio/src/gui/colorlcd/radio_calibration.cpp b/radio/src/gui/colorlcd/radio_calibration.cpp index f34f09ec8..fcf41f723 100644 --- a/radio/src/gui/colorlcd/radio_calibration.cpp +++ b/radio/src/gui/colorlcd/radio_calibration.cpp @@ -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); diff --git a/radio/src/gui/colorlcd/radio_sdmanager.cpp b/radio/src/gui/colorlcd/radio_sdmanager.cpp index 5079e5269..de720ed17 100644 --- a/radio/src/gui/colorlcd/radio_sdmanager.cpp +++ b/radio/src/gui/colorlcd/radio_sdmanager.cpp @@ -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(); } diff --git a/radio/src/gui/colorlcd/radio_tools.cpp b/radio/src/gui/colorlcd/radio_tools.cpp index d3be72812..3484f2495 100644 --- a/radio/src/gui/colorlcd/radio_tools.cpp +++ b/radio/src/gui/colorlcd/radio_tools.cpp @@ -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 diff --git a/radio/src/gui/colorlcd/sourcechoice.cpp b/radio/src/gui/colorlcd/sourcechoice.cpp index 53a4c23c1..68efe32d8 100644 --- a/radio/src/gui/colorlcd/sourcechoice.cpp +++ b/radio/src/gui/colorlcd/sourcechoice.cpp @@ -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 diff --git a/radio/src/gui/colorlcd/special_functions.cpp b/radio/src/gui/colorlcd/special_functions.cpp index a7092095a..72814bcd7 100644 --- a/radio/src/gui/colorlcd/special_functions.cpp +++ b/radio/src/gui/colorlcd/special_functions.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()); } diff --git a/radio/src/gui/colorlcd/special_functions.h b/radio/src/gui/colorlcd/special_functions.h index 0fa96341c..eaf85ec9b 100644 --- a/radio/src/gui/colorlcd/special_functions.h +++ b/radio/src/gui/colorlcd/special_functions.h @@ -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: diff --git a/radio/src/gui/colorlcd/switchchoice.cpp b/radio/src/gui/colorlcd/switchchoice.cpp index 6f90e8878..9db366569 100644 --- a/radio/src/gui/colorlcd/switchchoice.cpp +++ b/radio/src/gui/colorlcd/switchchoice.cpp @@ -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 filter) diff --git a/radio/src/gui/colorlcd/tabsgroup.cpp b/radio/src/gui/colorlcd/tabsgroup.cpp index 3484d1187..a0b7c32a8 100644 --- a/radio/src/gui/colorlcd/tabsgroup.cpp +++ b/radio/src/gui/colorlcd/tabsgroup.cpp @@ -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) diff --git a/radio/src/gui/colorlcd/tabsgroup.h b/radio/src/gui/colorlcd/tabsgroup.h index a985c111d..d3af8c15d 100644 --- a/radio/src/gui/colorlcd/tabsgroup.h +++ b/radio/src/gui/colorlcd/tabsgroup.h @@ -155,7 +155,7 @@ class TabsGroupHeader: public FormGroup { protected: #if defined(HARDWARE_TOUCH) - IconButton back; + Button back; #endif uint8_t icon; TabsCarousel carousel; diff --git a/radio/src/gui/colorlcd/theme.cpp b/radio/src/gui/colorlcd/theme.cpp index b9561fab9..e3626dd6b 100644 --- a/radio/src/gui/colorlcd/theme.cpp +++ b/radio/src/gui/colorlcd/theme.cpp @@ -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); } } diff --git a/radio/src/gui/colorlcd/theme.h b/radio/src/gui/colorlcd/theme.h index fdd5149c9..9645a3084 100644 --- a/radio/src/gui/colorlcd/theme.h +++ b/radio/src/gui/colorlcd/theme.h @@ -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 & tabs, uint8_t currentIndex) const = 0; + virtual void drawPageHeader(BitmapBuffer *dc, std::vector &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 & getRegisteredThemes(); +extern const uint8_t LBM_DROPDOWN[]; + #endif // _COLORLCD_THEME_H_ diff --git a/radio/src/gui/colorlcd/themes/480_default.cpp b/radio/src/gui/colorlcd/themes/480_default.cpp index e0c5714b0..5d5907536 100644 --- a/radio/src/gui/colorlcd/themes/480_default.cpp +++ b/radio/src/gui/colorlcd/themes/480_default.cpp @@ -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 & tabs, uint8_t currentIndex) const override + void drawPageHeader(BitmapBuffer *dc, std::vector &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); diff --git a/radio/src/gui/colorlcd/themes/flysky.cpp b/radio/src/gui/colorlcd/themes/flysky.cpp index a395287d3..a8c519d41 100644 --- a/radio/src/gui/colorlcd/themes/flysky.cpp +++ b/radio/src/gui/colorlcd/themes/flysky.cpp @@ -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 & tabs, uint8_t currentIndex) const override + void drawPageHeader(BitmapBuffer *dc, std::vector &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 diff --git a/radio/src/gui/colorlcd/timeedit.cpp b/radio/src/gui/colorlcd/timeedit.cpp index 72245d17d..804eb4b9c 100644 --- a/radio/src/gui/colorlcd/timeedit.cpp +++ b/radio/src/gui/colorlcd/timeedit.cpp @@ -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) diff --git a/radio/src/gui/colorlcd/view_channels.cpp b/radio/src/gui/colorlcd/view_channels.cpp index 84d6238bd..8bfd1905a 100644 --- a/radio/src/gui/colorlcd/view_channels.cpp +++ b/radio/src/gui/colorlcd/view_channels.cpp @@ -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); } }; diff --git a/radio/src/gui/colorlcd/view_logical_switches.cpp b/radio/src/gui/colorlcd/view_logical_switches.cpp index d8c5afc3e..3b4810338 100644 --- a/radio/src/gui/colorlcd/view_logical_switches.cpp +++ b/radio/src/gui/colorlcd/view_logical_switches.cpp @@ -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}); } diff --git a/radio/src/gui/colorlcd/view_logical_switches.h b/radio/src/gui/colorlcd/view_logical_switches.h index f7aab6ecf..eb7785ffb 100644 --- a/radio/src/gui/colorlcd/view_logical_switches.h +++ b/radio/src/gui/colorlcd/view_logical_switches.h @@ -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: diff --git a/radio/src/gui/colorlcd/widgets/text.cpp b/radio/src/gui/colorlcd/widgets/text.cpp index cbc1f3db3..857fede08 100644 --- a/radio/src/gui/colorlcd/widgets/text.cpp +++ b/radio/src/gui/colorlcd/widgets/text.cpp @@ -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 } diff --git a/radio/src/storage/modelslist.h b/radio/src/storage/modelslist.h index 07d1f7af6..f9bde8302 100644 --- a/radio/src/storage/modelslist.h +++ b/radio/src/storage/modelslist.h @@ -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) diff --git a/radio/src/targets/horus/libopenui_config.h b/radio/src/targets/horus/libopenui_config.h index 87c7e8f23..2e89621f3 100644 --- a/radio/src/targets/horus/libopenui_config.h +++ b/radio/src/targets/horus/libopenui_config.h @@ -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; diff --git a/radio/src/tests/transparency_CN_480x272.png b/radio/src/tests/transparency_CN_480x272.png index 3f0252491..92083a206 100644 Binary files a/radio/src/tests/transparency_CN_480x272.png and b/radio/src/tests/transparency_CN_480x272.png differ diff --git a/radio/src/tests/transparency_EN_480x272.png b/radio/src/tests/transparency_EN_480x272.png index d6a71c799..a1cc5987b 100644 Binary files a/radio/src/tests/transparency_EN_480x272.png and b/radio/src/tests/transparency_EN_480x272.png differ diff --git a/radio/src/thirdparty/libopenui b/radio/src/thirdparty/libopenui index 09e855345..6b661c490 160000 --- a/radio/src/thirdparty/libopenui +++ b/radio/src/thirdparty/libopenui @@ -1 +1 @@ -Subproject commit 09e855345973329eb66e319b2921ad3235331d66 +Subproject commit 6b661c4907bcafc08436e5c96fc5a38e9eb6e499