diff --git a/radio/src/curves.cpp b/radio/src/curves.cpp index 849a6a15d..ad8715ec2 100644 --- a/radio/src/curves.cpp +++ b/radio/src/curves.cpp @@ -416,3 +416,34 @@ int applyCurrentCurve(int x) return applyCustomCurve(x, s_currIdxSubMenu); } #endif + +#if defined(COLORLCD) +char *getCurveRefString(char *dest, size_t len, const CurveRef& curve) +{ + if (!len) return dest; + char *s = dest; + + if (curve.value != 0) { + switch (curve.type) { + case CURVE_REF_DIFF: + *(s++) = 'D'; if (--len == 0) return dest; + getValueOrGVarString(s, len, curve.value, -100, 100, 0, "%"); + return dest; + + case CURVE_REF_EXPO: + *(s++) = 'E'; if (--len == 0) return dest; + getValueOrGVarString(s, len, curve.value, -100, 100, 0, "%"); + return dest; + + case CURVE_REF_FUNC: + strAppend(dest, STR_VCURVEFUNC[curve.value], len); + return dest; + + case CURVE_REF_CUSTOM: + return getCurveString(dest, curve.value); + } + } + + return dest; +} +#endif diff --git a/radio/src/curves.h b/radio/src/curves.h index 4e209e4f5..9ca039851 100644 --- a/radio/src/curves.h +++ b/radio/src/curves.h @@ -47,4 +47,6 @@ int applyCustomCurve(int x, uint8_t idx); int applyCurve(int x, CurveRef & curve); int applyCurrentCurve(int x); +char *getCurveRefString(char *dest, size_t len, const CurveRef& curve); + #endif diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt index 65b105914..3a66af71b 100644 --- a/radio/src/gui/colorlcd/CMakeLists.txt +++ b/radio/src/gui/colorlcd/CMakeLists.txt @@ -207,6 +207,7 @@ add_gui_src(input_mix_group.cpp) add_gui_src(input_mix_button.cpp) add_gui_src(channel_bar.cpp) +add_gui_src(list_line_button.cpp) add_gui_src(lvgl_widgets/input_mix_line.c) add_gui_src(lvgl_widgets/input_mix_group.c) diff --git a/radio/src/gui/colorlcd/bitmaps.cpp b/radio/src/gui/colorlcd/bitmaps.cpp index d0e7e9410..5c279b55f 100644 --- a/radio/src/gui/colorlcd/bitmaps.cpp +++ b/radio/src/gui/colorlcd/bitmaps.cpp @@ -161,18 +161,12 @@ static const uint8_t mask_stats_throttle_graph[] = { static const uint8_t mask_stats_timers[] = { #include "mask_stats_timers.lbm" }; -static const uint8_t mask_textline_curve[] = { -#include "mask_textline_curve.lbm" -}; static const uint8_t mask_textline_delay[] = { #include "mask_textline_delay.lbm" }; static const uint8_t mask_textline_delayslow[] = { #include "mask_textline_delayslow.lbm" }; -static const uint8_t mask_textline_fm[] = { -#include "mask_textline_fm.lbm" -}; static const uint8_t mask_textline_label[] = { #include "mask_textline_label.lbm" }; @@ -241,13 +235,12 @@ BitmapBuffer * chanMonInvertedBitmap = nullptr; BitmapBuffer * mixerSetupMixerBitmap = nullptr; BitmapBuffer * mixerSetupToBitmap = nullptr; BitmapBuffer * mixerSetupOutputBitmap = nullptr; -BitmapBuffer * mixerSetupCurveIcon = nullptr; +// BitmapBuffer * mixerSetupCurveIcon = nullptr; BitmapBuffer * mixerSetupSwitchIcon = nullptr; BitmapBuffer * mixerSetupLabelIcon = nullptr; BitmapBuffer * mixerSetupDelayIcon = nullptr; BitmapBuffer * mixerSetupSlowIcon = nullptr; BitmapBuffer * mixerSetupDelaySlowIcon = nullptr; -BitmapBuffer * mixerSetupFlightmodeIcon = nullptr; struct _BuiltinBitmap { @@ -277,9 +270,8 @@ static const _BuiltinBitmap _builtinBitmaps[] = { {BMP_8BIT, mask_sbar_output, &mixerSetupOutputBitmap}, {BMP_8BIT, mask_textline_label, &mixerSetupLabelIcon}, - {BMP_8BIT, mask_textline_curve, &mixerSetupCurveIcon}, + // {BMP_8BIT, mask_textline_curve, &mixerSetupCurveIcon}, {BMP_8BIT, mask_textline_switch, &mixerSetupSwitchIcon}, - {BMP_8BIT, mask_textline_fm, &mixerSetupFlightmodeIcon}, {BMP_8BIT, mask_textline_slow, &mixerSetupSlowIcon}, {BMP_8BIT, mask_textline_delay, &mixerSetupDelayIcon}, {BMP_8BIT, mask_textline_delayslow, &mixerSetupDelaySlowIcon}, diff --git a/radio/src/gui/colorlcd/bitmaps.h b/radio/src/gui/colorlcd/bitmaps.h index 0fa5b6ac2..5dd5156b5 100644 --- a/radio/src/gui/colorlcd/bitmaps.h +++ b/radio/src/gui/colorlcd/bitmaps.h @@ -51,7 +51,6 @@ extern BitmapBuffer * mixerSetupAddBitmap; extern BitmapBuffer * mixerSetupMultiBitmap; extern BitmapBuffer * mixerSetupReplaceBitmap; extern BitmapBuffer * mixerSetupLabelIcon; -extern BitmapBuffer * mixerSetupFlightmodeIcon; extern BitmapBuffer * mixerSetupCurveIcon; extern BitmapBuffer * mixerSetupSwitchIcon; extern BitmapBuffer * mixerSetupDelayIcon; diff --git a/radio/src/gui/colorlcd/draw_functions.cpp b/radio/src/gui/colorlcd/draw_functions.cpp index 1e3d948e3..97f8d8f99 100644 --- a/radio/src/gui/colorlcd/draw_functions.cpp +++ b/radio/src/gui/colorlcd/draw_functions.cpp @@ -259,12 +259,12 @@ void drawCurveRef(BitmapBuffer * dc, coord_t x, coord_t y, const CurveRef & curv switch (curve.type) { case CURVE_REF_DIFF: x = dc->drawText(x, y, "D", flags); - drawValueOrGVar(dc, x, y + 2, curve.value, -100, 100, LEFT | FONT(XS) | flags); + drawValueOrGVar(dc, x, y, curve.value, -100, 100, LEFT | flags); break; case CURVE_REF_EXPO: x = dc->drawText(x, y, "E", flags); - drawValueOrGVar(dc, x, y + 2, curve.value, -100, 100, LEFT | FONT(XS) | flags); + drawValueOrGVar(dc, x, y, curve.value, -100, 100, LEFT | flags); break; case CURVE_REF_FUNC: diff --git a/radio/src/gui/colorlcd/input_mix_button.cpp b/radio/src/gui/colorlcd/input_mix_button.cpp index 2f8476c1e..700380e80 100644 --- a/radio/src/gui/colorlcd/input_mix_button.cpp +++ b/radio/src/gui/colorlcd/input_mix_button.cpp @@ -22,72 +22,143 @@ #include "input_mix_button.h" #include "opentx.h" -#include "lvgl_widgets/input_mix_line.h" +// icon: 17 x 17 +static const uint8_t _mask_textline_fm[] = { +#include "mask_textline_fm.lbm" +}; +STATIC_LZ4_BITMAP(mask_textline_fm); -void InputMixButton::self_size(lv_event_t* e) -{ - auto obj = lv_event_get_target(e); - auto p = (lv_point_t*)lv_event_get_param(e); +// total: 92 x 17 +#define FM_CANVAS_HEIGHT 17 +#define FM_CANVAS_WIDTH 92 - auto btn = (InputMixButton*)lv_obj_get_user_data(obj); - if (!btn) return; +#if LCD_W > LCD_H // Landscape +static const lv_coord_t col_dsc[] = { + LV_GRID_FR(1), // weigth + LV_GRID_FR(1), // source + LV_GRID_FR(4), // opts + FM_CANVAS_WIDTH, // flight modes + LV_GRID_TEMPLATE_LAST +}; - p->y = btn->calcHeight(); -} +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; +#else // Portrait +static const lv_coord_t col_dsc[] = { + LV_GRID_FR(1), // weigth + LV_GRID_FR(1), // source + LV_GRID_FR(2), // opts + LV_GRID_TEMPLATE_LAST +}; -void InputMixButton::value_changed(lv_event_t* e) -{ - auto obj = lv_event_get_target(e); - lv_obj_refresh_self_size(obj); -} +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; +#endif + +static const char _empty_txt[] = ""; InputMixButton::InputMixButton(Window* parent, uint8_t index) : - Button(parent, rect_t{}, nullptr, 0, 0/*COLOR_THEME_PRIMARY1*/, - input_mix_line_create), - index(index) + ListLineButton(parent, index) { - lv_obj_add_event_cb(lvobj, InputMixButton::self_size, LV_EVENT_GET_SELF_SIZE, nullptr); - lv_obj_add_event_cb(lvobj, InputMixButton::value_changed, LV_EVENT_VALUE_CHANGED, nullptr); + lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); + lv_obj_set_grid_dsc_array(lvobj, col_dsc, row_dsc); + + weight = lv_label_create(lvobj); + lv_obj_set_grid_cell(weight, LV_GRID_ALIGN_END, 0, 1, LV_GRID_ALIGN_START, 0, 1); + + source = lv_label_create(lvobj); + lv_obj_set_grid_cell(source, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_START, 0, 1); + + opts = lv_label_create(lvobj); +#if LCD_W > LCD_H // Landscape + lv_obj_set_grid_cell(opts, LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_START, 0, 1); +#else + lv_obj_set_grid_cell(opts, LV_GRID_ALIGN_STRETCH, 2, 1, LV_GRID_ALIGN_START, 0, 2); +#endif } -void InputMixButton::checkEvents() +InputMixButton::~InputMixButton() { - check(isActive()); - Button::checkEvents(); + if (fm_buffer) free(fm_buffer); } -void InputMixButton::drawFlightModes(BitmapBuffer *dc, FlightModesType value, - LcdFlags textColor, coord_t x, coord_t y) +void InputMixButton::setWeight(gvar_t value, gvar_t min, gvar_t max) { - dc->drawMask(x, y + 2, mixerSetupFlightmodeIcon, textColor); + char s[32]; + getValueOrGVarString(s, sizeof(s), value, min, max, 0, "%"); + lv_label_set_text(weight, s); +} + +void InputMixButton::setSource(mixsrc_t idx) +{ + char* s = getSourceString(idx); + lv_label_set_text(source, s); +} + +void InputMixButton::setFlightModes(uint16_t modes) +{ + if (modes == fm_modes) return; + fm_modes = modes; + + if (!fm_modes) { + if (!fm_canvas) return; + lv_obj_del(fm_canvas); + free(fm_buffer); + fm_canvas = nullptr; + fm_buffer = nullptr; + return; + } + + if (!fm_canvas) { + fm_canvas = lv_canvas_create(lvobj); + fm_buffer = malloc(FM_CANVAS_WIDTH * FM_CANVAS_HEIGHT); + lv_canvas_set_buffer(fm_canvas, fm_buffer, FM_CANVAS_WIDTH, + FM_CANVAS_HEIGHT, LV_IMG_CF_ALPHA_8BIT); + +#if LCD_W > LCD_H // Landscape + lv_obj_set_grid_cell(fm_canvas, LV_GRID_ALIGN_START, 3, 1, + LV_GRID_ALIGN_CENTER, 0, 1); +#else + lv_obj_set_grid_cell(fm_canvas, LV_GRID_ALIGN_CENTER, 0, 2, + LV_GRID_ALIGN_CENTER, 1, 1); +#endif + + lv_obj_set_style_img_recolor(fm_canvas, makeLvColor(COLOR_THEME_SECONDARY1), 0); + lv_obj_set_style_img_recolor_opa(fm_canvas, LV_OPA_COVER, 0); + } + + lv_canvas_fill_bg(fm_canvas, lv_color_black(), LV_OPA_TRANSP); + + auto mask = (const uint8_t*)mask_textline_fm; + auto mask_hdr = (const uint16_t*)mask; + lv_coord_t w = mask_hdr[0]; + lv_coord_t h = mask_hdr[1]; + + coord_t x = 0; + lv_canvas_copy_buf(fm_canvas, mask + 4, x, 0, w, h); x += 20; + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + + lv_draw_rect_dsc_t rect_dsc; + lv_draw_rect_dsc_init(&rect_dsc); + rect_dsc.bg_opa = LV_OPA_COVER; + + const lv_font_t* font = getFont(FONT(XS)); + label_dsc.font = font; + for (int i = 0; i < MAX_FLIGHT_MODES; i++) { char s[] = " "; s[0] = '0' + i; - if (value & (1 << i)) { - dc->drawText(x, y + 2, s, FONT(XS) | COLOR_THEME_DISABLED); + if (fm_modes & (1 << i)) { + label_dsc.color = lv_color_make(0x7f, 0x7f, 0x7f); } else { - dc->drawSolidFilledRect(x, y + 2, 8, 3, COLOR_THEME_FOCUS); - dc->drawText(x, y + 2, s, FONT(XS) | textColor); + lv_canvas_draw_rect(fm_canvas, x, 0, 8, 3, &rect_dsc); + label_dsc.color = lv_color_white(); } + lv_canvas_draw_text(fm_canvas, x, 0, 8, &label_dsc, s); x += 8; } } - -lv_coord_t InputMixButton::calcHeight() const -{ - auto h = getFontHeight(FONT(STD)); - // h += 2 * lv_obj_get_style_border_width(lvobj, LV_PART_MAIN); - // h += lv_obj_get_style_pad_top(lvobj, LV_PART_MAIN); - // h += lv_obj_get_style_pad_bottom(lvobj, LV_PART_MAIN); - - size_t lines = getLines(); - if (lines > 1) { - lines -= 1; - h += lines * lv_obj_get_style_text_line_space(lvobj, LV_PART_MAIN); - h += lines * getFontHeight(FONT(STD)); - } - - return h; -} diff --git a/radio/src/gui/colorlcd/input_mix_button.h b/radio/src/gui/colorlcd/input_mix_button.h index 96fe4fd11..9af19de21 100644 --- a/radio/src/gui/colorlcd/input_mix_button.h +++ b/radio/src/gui/colorlcd/input_mix_button.h @@ -21,28 +21,25 @@ #pragma once -#include "button.h" +#include "list_line_button.h" +#include "opentx_types.h" -class InputMixButton : public Button +class InputMixButton : public ListLineButton { + lv_obj_t* fm_canvas = nullptr; + void* fm_buffer = nullptr; + uint16_t fm_modes = 0; + public: InputMixButton(Window* parent, uint8_t index); - - uint8_t getIndex() const { return index; } - void setIndex(uint8_t i) { index = i; } - - void checkEvents() override; - - void drawFlightModes(BitmapBuffer *dc, FlightModesType value, - LcdFlags textColor, coord_t x, coord_t y); + ~InputMixButton(); protected: - uint8_t index; + lv_obj_t* weight; + lv_obj_t* source; + lv_obj_t* opts; - static void self_size(lv_event_t* e); - static void value_changed(lv_event_t* e); - - lv_coord_t calcHeight() const; - virtual size_t getLines() const = 0; - virtual bool isActive() const = 0; + void setWeight(gvar_t value, gvar_t min, gvar_t max); + void setSource(mixsrc_t idx); + void setFlightModes(uint16_t modes); }; diff --git a/radio/src/gui/colorlcd/input_mix_group.cpp b/radio/src/gui/colorlcd/input_mix_group.cpp index c6f63c958..8a2e79752 100644 --- a/radio/src/gui/colorlcd/input_mix_group.cpp +++ b/radio/src/gui/colorlcd/input_mix_group.cpp @@ -69,20 +69,30 @@ InputMixGroup::InputMixGroup(Window* parent, mixsrc_t idx) : lv_obj_set_size(line_container, lv_pct(100), LV_SIZE_CONTENT); lv_obj_set_flex_flow(line_container, LV_FLEX_FLOW_COLUMN); lv_obj_set_style_flex_cross_place(line_container, LV_FLEX_ALIGN_END, 0); - lv_obj_set_style_pad_row(line_container, lv_dpx(8), LV_PART_MAIN); + lv_obj_set_style_pad_row(line_container, lv_dpx(4), LV_PART_MAIN); } -void InputMixGroup::addMixerMonitor(uint8_t channel) +void InputMixGroup::enableMixerMonitor(uint8_t channel) { - rect_t r{ 0, 0, 100, 14 }; - auto mon = new MixerChannelBar(this, r, channel); - mon->setDrawMiddleBar(false); + if (monitor != nullptr) return; - lv_obj_t* mon_obj = mon->getLvObj(); + rect_t r{ 0, 0, 100, 14 }; + monitor = new MixerChannelBar(this, r, channel); + monitor->setDrawMiddleBar(false); + + lv_obj_t* mon_obj = monitor->getLvObj(); lv_obj_set_parent(mon_obj, line_container); + lv_obj_move_to_index(mon_obj, 0); lv_obj_set_style_translate_x(mon_obj, -lv_dpx(8), 0); } +void InputMixGroup::disableMixerMonitor() +{ + if (!monitor) return; + monitor->deleteLater(); + monitor = nullptr; +} + void InputMixGroup::addLine(Window* line, const uint8_t* symbol) { lines.emplace_back(line, symbol); diff --git a/radio/src/gui/colorlcd/input_mix_group.h b/radio/src/gui/colorlcd/input_mix_group.h index 4eddd12d2..be5dda55b 100644 --- a/radio/src/gui/colorlcd/input_mix_group.h +++ b/radio/src/gui/colorlcd/input_mix_group.h @@ -26,6 +26,8 @@ #include +class MixerChannelBar; + class InputMixGroup : public Window { struct Line { @@ -43,12 +45,17 @@ class InputMixGroup : public Window lv_obj_t* label; lv_obj_t* line_container; + MixerChannelBar* monitor = nullptr; + static void value_changed(lv_event_t* e); public: InputMixGroup(Window* parent, mixsrc_t idx); - void addMixerMonitor(uint8_t channel); + void enableMixerMonitor(uint8_t channel); + void disableMixerMonitor(); + + bool mixerMonitorEnabled() { return monitor != nullptr; } mixsrc_t getMixSrc() { return idx; } size_t getLineCount() { return lines.size(); } diff --git a/radio/src/gui/colorlcd/list_line_button.cpp b/radio/src/gui/colorlcd/list_line_button.cpp new file mode 100644 index 000000000..7a449286c --- /dev/null +++ b/radio/src/gui/colorlcd/list_line_button.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "list_line_button.h" +#include "opentx.h" + +#include "lvgl_widgets/input_mix_line.h" + +void ListLineButton::value_changed(lv_event_t* e) +{ + auto obj = lv_event_get_target(e); + auto btn = (ListLineButton*)lv_obj_get_user_data(obj); + if (btn) btn->refresh(); +} + +ListLineButton::ListLineButton(Window* parent, uint8_t index) : + Button(parent, rect_t{}, nullptr, 0, 0, input_mix_line_create), + index(index) +{ + lv_obj_add_event_cb(lvobj, ListLineButton::value_changed, LV_EVENT_VALUE_CHANGED, nullptr); +} + +void ListLineButton::checkEvents() +{ + check(isActive()); + Button::checkEvents(); +} diff --git a/radio/src/gui/colorlcd/list_line_button.h b/radio/src/gui/colorlcd/list_line_button.h new file mode 100644 index 000000000..df81e3a62 --- /dev/null +++ b/radio/src/gui/colorlcd/list_line_button.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include "button.h" +#include "opentx_types.h" + +class ListLineButton : public Button +{ + public: + ListLineButton(Window* parent, uint8_t index); + + uint8_t getIndex() const { return index; } + void setIndex(uint8_t i) { index = i; } + + void checkEvents() override; + + protected: + uint8_t index; + + static void value_changed(lv_event_t* e); + + virtual bool isActive() const = 0; + virtual void refresh() = 0; +}; diff --git a/radio/src/gui/colorlcd/model_inputs.cpp b/radio/src/gui/colorlcd/model_inputs.cpp index 8c29f2685..5bfe283bf 100644 --- a/radio/src/gui/colorlcd/model_inputs.cpp +++ b/radio/src/gui/colorlcd/model_inputs.cpp @@ -131,76 +131,45 @@ class InputLineButton : public InputMixButton public: using InputMixButton::InputMixButton; - void paint(BitmapBuffer *dc) override + void refresh() override { const ExpoData &line = g_model.expoData[index]; - LcdFlags textColor = COLOR_THEME_SECONDARY1; + setWeight(line.weight, -100, 100); + setSource(line.srcRaw); - coord_t border = lv_obj_get_style_border_width(lvobj, LV_PART_MAIN); - coord_t pad_left = lv_obj_get_style_pad_left(lvobj, LV_PART_MAIN); + char tmp_str[64]; + size_t maxlen = sizeof(tmp_str); - coord_t left = pad_left + border; - coord_t line_h = lv_obj_get_style_text_line_space(lvobj, LV_PART_MAIN) - + getFontHeight(FONT(STD)); - - // first line ... - coord_t y = 0; - y += border; - y += lv_obj_get_style_pad_top(lvobj, LV_PART_MAIN); - - coord_t x = left; - drawValueOrGVar(dc, x, y, line.weight, -100, 100, textColor); - drawSource(dc, x + 65, y, line.srcRaw, textColor); + char *s = tmp_str; + *s = '\0'; if (line.name[0]) { - dc->drawMask(146, y, mixerSetupLabelIcon, textColor); - dc->drawSizedText(166, y, line.name, sizeof(line.name), textColor); + int cnt = lv_snprintf(s, maxlen, "%.*s ", (int)sizeof(line.name), line.name); + if (cnt >= maxlen) maxlen = 0; + else { maxlen -= cnt; s += cnt; } } - // second line ... - y += line_h; if (line.swtch || line.curve.value) { - if (line.swtch) { - dc->drawMask(x, y, mixerSetupSwitchIcon, textColor); - drawSwitch(dc, x + 21, y, line.swtch, textColor); - } - if (line.curve.value != 0) { - dc->drawMask(x + 65, y, mixerSetupCurveIcon, textColor); - drawCurveRef(dc, x + 85, y, line.curve, textColor); - } + if (line.swtch) { + char* sw_pos = getSwitchPositionName(line.swtch); + int cnt = lv_snprintf(s, maxlen, "%s ", sw_pos); + if (cnt >= maxlen) maxlen = 0; + else { maxlen -= cnt; s += cnt; } + } + if (line.curve.value != 0) { + getCurveRefString(s, maxlen, line.curve); + int cnt = strnlen(s, maxlen); + if (cnt >= maxlen) maxlen = 0; + else { maxlen -= cnt; s += cnt; } + } } + lv_label_set_text_fmt(opts, "%.*s", (int)sizeof(tmp_str), tmp_str); - if (line.flightModes) { -#if LCD_H > LCD_W - // third line ... - y += line_h; - x = left; -#else - x = 146; -#endif - drawFlightModes(dc, line.flightModes, textColor, x, y); - } + setFlightModes(line.flightModes); } protected: bool isActive() const override { return isExpoActive(index); } - size_t getLines() const override { - const ExpoData* line = expoAddress(index); - size_t lines = 1; -#if LCD_W > LCD_H - if (line->swtch || line->curve.value != 0 || line->flightModes) { - lines += 1; - } -#else - if (line->swtch || line->curve.value != 0) { - lines += 1; - } - if (line->flightModes) { - lines += 1; - } -#endif - return lines; - } }; ModelInputsPage::ModelInputsPage(): @@ -273,6 +242,8 @@ InputMixButton* ModelInputsPage::createLineButton(InputMixGroup *group, uint8_t index) { auto button = new InputLineButton(group, index); + button->refresh(); + lines.emplace_back(button); group->addLine(button); @@ -467,7 +438,7 @@ void ModelInputsPage::build(FormWindow *window) form = new FormGroup(window, rect_t{}); form->setFlexLayout(); - form->padRow(lv_dpx(8)); + form->padRow(lv_dpx(4)); auto form_obj = form->getLvObj(); lv_obj_set_width(form_obj, lv_pct(100)); diff --git a/radio/src/gui/colorlcd/model_mixes.cpp b/radio/src/gui/colorlcd/model_mixes.cpp index 7d9ba780f..e0e59e391 100644 --- a/radio/src/gui/colorlcd/model_mixes.cpp +++ b/radio/src/gui/colorlcd/model_mixes.cpp @@ -174,18 +174,22 @@ class MixLineButton : public InputMixButton { public: MixLineButton(Window* parent, uint8_t index); - void paint(BitmapBuffer* dc) override; + void deleteLater(bool detach = true, bool trash = true) override; + void refresh() override; protected: - size_t getLines() const override; bool isActive() const override { return isMixActive(index); } }; static void mix_draw_mplex(lv_event_t* e) { + auto target = (lv_obj_t*)lv_event_get_target(e); + auto group = (InputMixGroup*)lv_obj_get_user_data(target); + uint32_t offset = group->mixerMonitorEnabled() ? 1 : 0; + auto obj = (lv_obj_t*)lv_event_get_user_data(e); - if (!obj || (lv_obj_get_index(obj) <= 1)) return; + if (!obj || (lv_obj_get_index(obj) <= offset)) return; auto btn = (MixLineButton*)lv_obj_get_user_data(obj); if (!btn) return; @@ -249,94 +253,56 @@ void MixLineButton::deleteLater(bool detach, bool trash) InputMixButton::deleteLater(detach, trash); } -size_t MixLineButton::getLines() const -{ - size_t lines = 1; - const MixData* mix = mixAddress(index); - - uint8_t delayslow = 0; - if (mix->speedDown || mix->speedUp) delayslow = 1; - if (mix->delayUp || mix->delayDown) delayslow += 2; - - if (mix->flightModes || mix->name[0] || delayslow) { - lines += 1; - } - - return lines; -} - -void MixLineButton::paint(BitmapBuffer* dc) +void MixLineButton::refresh() { const MixData& line = g_model.mixData[index]; - LcdFlags textColor = COLOR_THEME_SECONDARY1; + setWeight(line.weight, MIX_WEIGHT_MIN, MIX_WEIGHT_MAX); + setSource(line.srcRaw); - coord_t border = lv_obj_get_style_border_width(lvobj, LV_PART_MAIN); - coord_t pad_left = lv_obj_get_style_pad_left(lvobj, LV_PART_MAIN); - coord_t pad_right = lv_obj_get_style_pad_right(lvobj, LV_PART_MAIN); + char tmp_str[64]; + size_t maxlen = sizeof(tmp_str); - coord_t left = pad_left + border; - coord_t line_h = lv_obj_get_style_text_line_space(lvobj, LV_PART_MAIN) - + getFontHeight(FONT(STD)); + char *s = tmp_str; + *s = '\0'; -#if LCD_W > LCD_H - const coord_t pad = 42; -#else - const coord_t pad = 0; -#endif - - // first line ... - coord_t y = 0; - y += border; - y += lv_obj_get_style_pad_top(lvobj, LV_PART_MAIN); + if (line.name[0]) { + int cnt = lv_snprintf(s, maxlen, "%.*s ", (int)sizeof(line.name), line.name); + if (cnt >= maxlen) maxlen = 0; + else { maxlen -= cnt; s += cnt; } + } - coord_t x = left; - drawValueOrGVar(dc, x, y, line.weight, MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, textColor); - x += 46 + pad; - - drawSource(dc, x, y, line.srcRaw, textColor); - x += 60 + pad; - - // second line ... if (line.swtch || line.curve.value) { if (line.swtch) { - if (pad) dc->drawMask(x - 20, y, mixerSetupSwitchIcon, textColor); - drawSwitch(dc, x, y, line.swtch, textColor); + char* sw_pos = getSwitchPositionName(line.swtch); + int cnt = lv_snprintf(s, maxlen, "%s ", sw_pos); + if (cnt >= maxlen) maxlen = 0; + else { maxlen -= cnt; s += cnt; } } - x += 44 + pad; - if (line.curve.value) { - if (pad) dc->drawMask(x - 20, y, mixerSetupCurveIcon, textColor); - drawCurveRef(dc, x, y, line.curve, textColor); - } - // x += 48 + pad; - } - - uint8_t delayslow = 0; - if (line.speedDown || line.speedUp) delayslow = 1; - if (line.delayUp || line.delayDown) delayslow += 2; - - if (line.flightModes || line.name[0] || delayslow) { - y += line_h; - x = left; - - if (line.flightModes) { - drawFlightModes(dc, line.flightModes, textColor, x, y); - } - x += 104 + 3*pad/2; - - if (line.name[0]) { - dc->drawMask(x, y, mixerSetupLabelIcon, textColor); - dc->drawSizedText(x + 20, y, line.name, sizeof(line.name), textColor); - } - - if (delayslow) { - BitmapBuffer* delayslowbmp[] = {mixerSetupSlowIcon, mixerSetupDelayIcon, - mixerSetupDelaySlowIcon}; - const BitmapBuffer* mask = delayslowbmp[delayslow - 1]; - coord_t w = lv_obj_get_width(lvobj); - w -= mask->width(); - dc->drawMask(w - border - pad_right, y, mask, textColor); + if (line.curve.value != 0) { + getCurveRefString(s, maxlen, line.curve); + int cnt = strnlen(s, maxlen); + if (cnt >= maxlen) maxlen = 0; + else { maxlen -= cnt; s += cnt; } } } + lv_label_set_text_fmt(opts, "%.*s", (int)sizeof(tmp_str), tmp_str); + + setFlightModes(line.flightModes); + + // TODO: should we add these? then it would be best to have them in the font... + // + // uint8_t delayslow = 0; + // if (line.speedDown || line.speedUp) delayslow = 1; + // if (line.delayUp || line.delayDown) delayslow += 2; + + // if (delayslow) { + // BitmapBuffer* delayslowbmp[] = {mixerSetupSlowIcon, mixerSetupDelayIcon, + // mixerSetupDelaySlowIcon}; + // const BitmapBuffer* mask = delayslowbmp[delayslow - 1]; + // coord_t w = lv_obj_get_width(lvobj); + // w -= mask->width(); + // dc->drawMask(w - border - pad_right, y, mask, textColor); + // } } ModelMixesPage::ModelMixesPage() : @@ -358,13 +324,16 @@ InputMixGroup* ModelMixesPage::getGroupByIndex(uint8_t index) InputMixGroup* ModelMixesPage::createGroup(FormGroup* form, mixsrc_t src) { auto group = new InputMixGroup(form, src); - group->addMixerMonitor(src - MIXSRC_CH1); + // TODO: make optional + // group->addMixerMonitor(src - MIXSRC_CH1); return group; } InputMixButton* ModelMixesPage::createLineButton(InputMixGroup *group, uint8_t index) { auto button = new MixLineButton(group, index); + button->refresh(); + lines.emplace_back(button); group->addLine(button); @@ -537,22 +506,37 @@ void ModelMixesPage::pasteMixAfter(uint8_t dst_idx) void ModelMixesPage::build(FormWindow * window) { + scroll_win = window->getParent(); window->setFlexLayout(); window->padRow(lv_dpx(8)); - + form = new FormGroup(window, rect_t{}); form->setFlexLayout(); - form->padRow(lv_dpx(8)); + form->padRow(lv_dpx(4)); auto form_obj = form->getLvObj(); lv_obj_set_width(form_obj, lv_pct(100)); + auto box = new FormGroup(window, rect_t{}); + box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8)); + box->padLeft(lv_dpx(8)); + + auto box_obj = box->getLvObj(); + lv_obj_set_width(box_obj, lv_pct(100)); + lv_obj_set_style_flex_cross_place(box_obj, LV_FLEX_ALIGN_CENTER, 0); + + new StaticText(box, rect_t{}, "Show mixer monitors", 0, COLOR_THEME_PRIMARY1); + new CheckBox( + box, rect_t{}, [=]() { return showMonitors; }, + [=](uint8_t val) { enableMonitors(val); }); + auto btn = new TextButton(window, rect_t{}, LV_SYMBOL_PLUS, [=]() { newMix(); return 0; }); auto btn_obj = btn->getLvObj(); lv_obj_set_width(btn_obj, lv_pct(100)); + lv_group_focus_obj(btn_obj); groups.clear(); lines.clear(); @@ -580,3 +564,24 @@ void ModelMixesPage::build(FormWindow * window) } } +void ModelMixesPage::enableMonitors(bool enabled) +{ + if (showMonitors == enabled) return; + showMonitors = enabled; + + auto form_obj = form->getLvObj(); + auto h = lv_obj_get_height(form_obj); + for(auto* group : groups) { + if (enabled) { + group->enableMixerMonitor(group->getMixSrc() - MIXSRC_CH1); + } else { + group->disableMixerMonitor(); + } + } + + lv_obj_update_layout(form_obj); + auto diff = h - lv_obj_get_height(form_obj); + auto scroll_obj = scroll_win->getLvObj(); + lv_obj_scroll_by_bounded(scroll_obj, 0, diff, LV_ANIM_OFF); + TRACE("diff = %d", diff); +} diff --git a/radio/src/gui/colorlcd/model_mixes.h b/radio/src/gui/colorlcd/model_mixes.h index 8107948e6..4a1656497 100644 --- a/radio/src/gui/colorlcd/model_mixes.h +++ b/radio/src/gui/colorlcd/model_mixes.h @@ -26,6 +26,9 @@ class ModelMixesPage : public ModelInputsPage { + bool showMonitors = false; + Window* scroll_win = nullptr; + public: ModelMixesPage(); @@ -48,4 +51,6 @@ class ModelMixesPage : public ModelInputsPage void pasteMix(uint8_t dst_idx, uint8_t channel); void pasteMixBefore(uint8_t dst_idx); void pasteMixAfter(uint8_t dst_idx); + + void enableMonitors(bool enabled); }; diff --git a/radio/src/gui/colorlcd/model_outputs.cpp b/radio/src/gui/colorlcd/model_outputs.cpp index ee5504f91..74c6b8930 100644 --- a/radio/src/gui/colorlcd/model_outputs.cpp +++ b/radio/src/gui/colorlcd/model_outputs.cpp @@ -21,98 +21,179 @@ #include "model_outputs.h" #include "output_edit.h" -#include "input_mix_button.h" +#include "list_line_button.h" #include "channel_bar.h" #include "opentx.h" #define SET_DIRTY() storageDirty(EE_MODEL) -#if LCD_W > LCD_H -static const coord_t btn_cols[] = { - 90, 158, 208, 262, 306, 326 +static const uint8_t _mask_textline_curve[] = { +#include "mask_textline_curve.lbm" }; -#else -static const coord_t btn_cols[] = { - 264, 66, 123, 180, 232, 264 +STATIC_LZ4_BITMAP(mask_textline_curve); + +#define CH_BAR_WIDTH 92 +#define CH_BAR_HEIGHT 14 + +#if LCD_W > LCD_H // Landscape + +#define CH_BAR_COL 7 +#define CH_BAR_COLSPAN 1 + +static const lv_coord_t col_dsc[] = { + 80, 50, 54, 44, 60, 18, 18, LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST }; + +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; +#else // Portrait + +#define CH_BAR_COL 3 +#define CH_BAR_COLSPAN 3 + +static const lv_coord_t col_dsc[] = { + 80, 50, 60, 18, 18, LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST +}; + +static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; #endif -class OutputLineButton : public InputMixButton +class OutputLineButton : public ListLineButton { + bool init = false; + + lv_obj_t* source = nullptr; + lv_obj_t* revert = nullptr; + lv_obj_t* min = nullptr; + lv_obj_t* max = nullptr; + lv_obj_t* offset = nullptr; + lv_obj_t* center = nullptr; + lv_obj_t* curve = nullptr; + OutputChannelBar* bar = nullptr; + + static lv_img_dsc_t curveIcon; + static void loadCurveIcon(); + + static void on_draw(lv_event_t * e) + { + lv_obj_t* target = lv_event_get_target(e); + auto line = (OutputLineButton*)lv_obj_get_user_data(target); + if (line && !line->init) line->delayed_init(e); + } + + void delayed_init(lv_event_t* e) + { + uint8_t col = 1, row = 0; + + min = lv_label_create(lvobj); + lv_obj_set_style_text_align(min, LV_TEXT_ALIGN_RIGHT, 0); + lv_obj_set_style_text_font(min, getFont(FONT(BOLD)), LV_STATE_USER_1); + lv_obj_set_grid_cell(min, LV_GRID_ALIGN_END, col++, 1, LV_GRID_ALIGN_START, + row, 1); + + max = lv_label_create(lvobj); + lv_obj_set_style_text_align(max, LV_TEXT_ALIGN_RIGHT, 0); + lv_obj_set_style_text_font(max, getFont(FONT(BOLD)), LV_STATE_USER_1); + lv_obj_set_grid_cell(max, LV_GRID_ALIGN_END, col++, 1, LV_GRID_ALIGN_START, + row, 1); + +#if LCD_H > LCD_W + col = 1; + row++; +#endif + + offset = lv_label_create(lvobj); + lv_obj_set_grid_cell(offset, LV_GRID_ALIGN_END, col++, 1, + LV_GRID_ALIGN_START, row, 1); + + center = lv_label_create(lvobj); + lv_obj_set_style_pad_left(center, 8, 0); + lv_obj_set_grid_cell(center, LV_GRID_ALIGN_START, col++, 1, + LV_GRID_ALIGN_START, row, 1); + + revert = lv_img_create(lvobj); + lv_img_set_src(revert, LV_SYMBOL_SHUFFLE); + lv_obj_set_grid_cell(revert, LV_GRID_ALIGN_START, col++, 1, + LV_GRID_ALIGN_START, row, 1); + + curve = lv_img_create(lvobj); + loadCurveIcon(); + lv_img_set_src(curve, &curveIcon); + lv_obj_set_style_img_recolor(curve, makeLvColor(COLOR_THEME_SECONDARY1), 0); + lv_obj_set_style_img_recolor_opa(curve, LV_OPA_COVER, 0); + lv_obj_set_grid_cell(curve, LV_GRID_ALIGN_START, col++, 1, + LV_GRID_ALIGN_START, row, 1); + + bar = new OutputChannelBar(this, rect_t{}, index); + bar->setWidth(CH_BAR_WIDTH); + bar->setHeight(CH_BAR_HEIGHT); + bar->setDrawLimits(false); + + lv_obj_set_grid_cell(bar->getLvObj(), LV_GRID_ALIGN_END, CH_BAR_COL, + CH_BAR_COLSPAN, LV_GRID_ALIGN_CENTER, 0, 1); + + init = true; + refresh(); + lv_obj_update_layout(lvobj); + + auto param = lv_event_get_param(e); + lv_event_send(lvobj, LV_EVENT_DRAW_MAIN, param); + } + public: OutputLineButton(Window* parent, uint8_t channel) : - InputMixButton(parent, channel) + ListLineButton(parent, channel) { -#if LCD_H > LCD_W - auto font_h = getFontHeight(FONT(STD)); - rect_t r{ 150, (font_h - 14) / 2, 100, 14 }; -#else - lv_obj_update_layout(lvobj); - auto font_h = getFontHeight(FONT(STD)); - auto x = lv_obj_get_content_width(lvobj) - 92; - auto y = (font_h - 14) / 2; + lv_obj_set_layout(lvobj, LV_LAYOUT_GRID); + lv_obj_set_grid_dsc_array(lvobj, col_dsc, row_dsc); - rect_t r{ x, y, 92, 14 }; -#endif - auto bar = new OutputChannelBar(this, r, channel); - bar->setDrawLimits(false); + source = lv_label_create(lvobj); + lv_obj_set_style_text_font(source, getFont(FONT(BOLD)), 0); + lv_obj_set_grid_cell(source, LV_GRID_ALIGN_START, 0, 1, + LV_GRID_ALIGN_START, 0, 1); + + lv_obj_add_event_cb(lvobj, OutputLineButton::on_draw, LV_EVENT_DRAW_MAIN, nullptr); } - void paint(BitmapBuffer *dc) override + void refresh() override { - LcdFlags textColor = COLOR_THEME_SECONDARY1; - + if (!init) return; + const LimitData* output = limitAddress(index); - int chanZero = output->ppmCenter; - coord_t border = lv_obj_get_style_border_width(lvobj, LV_PART_MAIN); - coord_t pad_left = lv_obj_get_style_pad_left(lvobj, LV_PART_MAIN); - coord_t left = pad_left + border; - - // first line ... - coord_t x = left; - coord_t y = border + lv_obj_get_style_pad_top(lvobj, LV_PART_MAIN); - - x = left; - dc->drawText(x, y, getSourceString(MIXSRC_CH1 + index), FONT(BOLD) | textColor); + lv_label_set_text(source, getSourceString(MIXSRC_CH1 + index)); if (output->revert) { - x = left + btn_cols[0]; - dc->drawText(x, y, LV_SYMBOL_SHUFFLE, textColor); + lv_obj_clear_flag(revert, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(revert, LV_OBJ_FLAG_HIDDEN); } -#if LCD_H > LCD_W - y += lv_obj_get_style_text_line_space(lvobj, LV_PART_MAIN) - + getFontHeight(FONT(STD)); -#endif - - // Min - LcdFlags txtFlags = (value < chanZero - 5) ? FONT(BOLD) | textColor : textColor; - x = left + btn_cols[1]; - drawValueOrGVar(dc, x, y, output->min, -GV_RANGELARGE, 0, RIGHT | PREC1 | txtFlags, - nullptr, -LIMITS_MIN_MAX_OFFSET); + char s[32]; + getValueOrGVarString(s, sizeof(s), output->min, -GV_RANGELARGE, 0, PREC1, + nullptr, -LIMITS_MIN_MAX_OFFSET); + lv_label_set_text(min, s); - // Max - txtFlags = (value > chanZero + 5) ? FONT(BOLD) | textColor : textColor; - x = left + btn_cols[2]; - drawValueOrGVar(dc, x, y, output->max, 0, GV_RANGELARGE, - RIGHT | PREC1 | txtFlags, nullptr, +LIMITS_MIN_MAX_OFFSET); + getValueOrGVarString(s, sizeof(s), output->max, 0, GV_RANGELARGE, PREC1, + nullptr, +LIMITS_MIN_MAX_OFFSET); + lv_label_set_text(max, s); - // Offset - x = left + btn_cols[3]; - drawValueOrGVar(dc, x, y, output->offset, -LIMIT_STD_MAX, - +LIMIT_STD_MAX, RIGHT | PREC1 | textColor, nullptr); + getValueOrGVarString(s, sizeof(s), output->offset, -LIMIT_STD_MAX, + +LIMIT_STD_MAX, PREC1); + lv_label_set_text(offset, s); - // PPM center - x = left + btn_cols[4]; - dc->drawNumber(x, y, PPM_CENTER + output->ppmCenter, RIGHT | textColor); - dc->drawText(x, y, output->symetrical ? "=" : STR_CHAR_DELTA, textColor); + lv_label_set_text_fmt(center, "%d%s", PPM_CENTER + output->ppmCenter, + output->symetrical ? " =" : STR_CHAR_DELTA); if (output->curve) { - x = left + btn_cols[5]; - // dc->drawText(x, y, getCurveString(output->curve), RIGHT | textColor); - dc->drawMask(x, y, mixerSetupCurveIcon, textColor); + lv_obj_clear_flag(curve, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(curve, LV_OBJ_FLAG_HIDDEN); } } @@ -120,26 +201,63 @@ class OutputLineButton : public InputMixButton int value = 0; bool isActive() const override { return false; } - size_t getLines() const override - { -#if LCD_H > LCD_W - return 2; -#else - return 1; -#endif - } void checkEvents() override { Window::checkEvents(); + if (!init) return; + int newValue = channelOutputs[index]; if (value != newValue) { value = newValue; - invalidate(); + + const LimitData* output = limitAddress(index); + int chanZero = output->ppmCenter; + + if (value < chanZero - 5) { + lv_obj_add_state(min, LV_STATE_USER_1); + } else { + lv_obj_clear_state(min, LV_STATE_USER_1); + } + + if (value > chanZero + 5) { + lv_obj_add_state(max, LV_STATE_USER_1); + } else { + lv_obj_clear_state(max, LV_STATE_USER_1); + } } } }; +lv_img_dsc_t OutputLineButton::curveIcon = { + .header = + { + .cf = LV_IMG_CF_ALPHA_8BIT, + .always_zero = 0, + .reserved = 0, + .w = 0, + .h = 0, + }, + .data_size = 0, + .data = nullptr, +}; + +void OutputLineButton::loadCurveIcon() +{ + if (curveIcon.data) return; + + auto mask = (const uint8_t*)mask_textline_curve; + auto mask_hdr = (const uint16_t*)mask; + mask += 4; + + auto w = mask_hdr[0]; + auto h = mask_hdr[1]; + curveIcon.header.w = w; + curveIcon.header.h = h; + curveIcon.data_size = w * h; + curveIcon.data = mask; +} + ModelOutputsPage::ModelOutputsPage() : PageTab(STR_MENULIMITS, ICON_MODEL_OUTPUTS) { @@ -148,16 +266,16 @@ ModelOutputsPage::ModelOutputsPage() : void ModelOutputsPage::build(FormWindow *window) { window->setFlexLayout(); - window->padRow(lv_dpx(8)); + window->padRow(lv_dpx(4)); auto form = new FormGroup(window, rect_t{}); form->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(16)); form->padRow(lv_dpx(8)); + form->padBottom(lv_dpx(4)); auto form_obj = form->getLvObj(); lv_obj_set_style_flex_cross_place(form_obj, LV_FLEX_ALIGN_CENTER, 0); - // auto btn = new TextButton(form, rect_t{}, STR_ADD_ALL_TRIMS_TO_SUBTRIMS, [=]() { moveTrimsToOffsets(); window->invalidate(); @@ -178,12 +296,13 @@ void ModelOutputsPage::build(FormWindow *window) // Channel settings auto btn = new OutputLineButton(window, ch); + // btn->refresh(); LimitData* output = limitAddress(ch); btn->setPressHandler([=]() -> uint8_t { Menu *menu = new Menu(window); menu->addLine(STR_EDIT, [=]() { - editOutput(ch); + editOutput(ch, btn); }); menu->addLine(STR_RESET, [=]() { output->min = 0; @@ -211,7 +330,10 @@ void ModelOutputsPage::build(FormWindow *window) } } -void ModelOutputsPage::editOutput(uint8_t channel) +void ModelOutputsPage::editOutput(uint8_t channel, OutputLineButton* btn) { - new OutputEditWindow(channel); + auto btn_obj = btn->getLvObj(); + auto edit = new OutputEditWindow(channel); + edit->setCloseHandler( + [=]() { lv_event_send(btn_obj, LV_EVENT_VALUE_CHANGED, nullptr); }); } diff --git a/radio/src/gui/colorlcd/model_outputs.h b/radio/src/gui/colorlcd/model_outputs.h index 0951901fe..8c5baa1fb 100644 --- a/radio/src/gui/colorlcd/model_outputs.h +++ b/radio/src/gui/colorlcd/model_outputs.h @@ -24,6 +24,8 @@ #include "tabsgroup.h" +class OutputLineButton; + class ModelOutputsPage : public PageTab { public: @@ -31,7 +33,7 @@ class ModelOutputsPage : public PageTab void build(FormWindow* window) override; protected: - void editOutput(uint8_t channel); + void editOutput(uint8_t channel, OutputLineButton* btn); }; #endif // _MODEL_OUTPUTS_H_ diff --git a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp index 6854fb8aa..b8b1088fa 100644 --- a/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp +++ b/radio/src/gui/colorlcd/themes/etx_lv_theme.cpp @@ -839,15 +839,17 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj) } else if (lv_obj_check_type(obj, &input_mix_line_class)) { lv_obj_add_style(obj, &styles.line_btn, 0); - lv_obj_add_style(obj, &styles.pad_small, 0); + lv_obj_add_style(obj, &styles.pad_tiny, 0); lv_obj_set_style_bg_color(obj, makeLvColor(COLOR_THEME_SECONDARY3), LV_STATE_CHECKED); lv_obj_add_style(obj, &styles.focus_border, LV_STATE_FOCUSED); + lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_SECONDARY1), 0); + lv_obj_set_style_text_font(obj, getFont(FONT(STD)), 0); } #endif else if (lv_obj_check_type(obj, &input_mix_group_class)) { lv_obj_add_style(obj, &styles.line_btn, 0); - lv_obj_add_style(obj, &styles.pad_small, 0); + lv_obj_add_style(obj, &styles.pad_tiny, 0); lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_SECONDARY1), 0); lv_obj_set_style_text_font(obj, getFont(FONT(BOLD)), 0); } diff --git a/radio/src/gui/colorlcd/themes/flysky.cpp b/radio/src/gui/colorlcd/themes/flysky.cpp index 5e2d87345..0d62a4cfa 100644 --- a/radio/src/gui/colorlcd/themes/flysky.cpp +++ b/radio/src/gui/colorlcd/themes/flysky.cpp @@ -250,14 +250,14 @@ class FlyskyTheme: public OpenTxTheme delete mixerSetupLabelIcon; mixerSetupLabelIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_label.png")); - delete mixerSetupCurveIcon; - mixerSetupCurveIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_curve.png")); + // delete mixerSetupCurveIcon; + // mixerSetupCurveIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_curve.png")); delete mixerSetupSwitchIcon; mixerSetupSwitchIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_switch.png")); - delete mixerSetupFlightmodeIcon; - mixerSetupFlightmodeIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_fm.png")); + // delete mixerSetupFlightmodeIcon; + // mixerSetupFlightmodeIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_fm.png")); // delete mixerSetupSlowIcon; // mixerSetupSlowIcon = BitmapBuffer::loadMask(getFilePath("mask_textline_slow.png")); diff --git a/radio/src/strhelpers.cpp b/radio/src/strhelpers.cpp index 9de086005..1626c65d1 100644 --- a/radio/src/strhelpers.cpp +++ b/radio/src/strhelpers.cpp @@ -391,6 +391,21 @@ char *getGVarString(char *dest, int idx) return dest; } +#if defined(LIBOPENUI) +char *getValueOrGVarString(char *dest, size_t len, gvar_t value, gvar_t vmin, gvar_t vmax, + LcdFlags flags, const char* suffix, gvar_t offset) +{ + if (GV_IS_GV_VALUE(value, vmin, vmax)) { + int index = GV_INDEX_CALC_DELTA(value, GV_GET_GV1_VALUE(vmin, vmax)); + return getGVarString(dest, index); + } + + value += offset; + BitmapBuffer::formatNumberAsString(dest, len, value, flags, 0, nullptr, suffix); + return dest; +} +#endif + char *getFlightModeString(char *dest, int8_t idx) { char *s = dest; diff --git a/radio/src/strhelpers.h b/radio/src/strhelpers.h index a92b6d45d..e55167d2d 100644 --- a/radio/src/strhelpers.h +++ b/radio/src/strhelpers.h @@ -76,8 +76,11 @@ char *getFormattedTimerString(char *dest, int32_t tme, TimerOptions timerOptions char *getCurveString(char *dest, int idx); char *getGVarString(char *dest, int idx); char *getGVarString(int idx); -const char* getSwitchWarnSymbol(uint8_t pos); -const char* getSwitchPositionSymbol(uint8_t pos); +char *getValueOrGVarString(char *dest, size_t len, gvar_t value, gvar_t vmin, + gvar_t vmax, LcdFlags flags = 0, + const char *suffix = nullptr, gvar_t offset = 0); +const char *getSwitchWarnSymbol(uint8_t pos); +const char *getSwitchPositionSymbol(uint8_t pos); char *getSwitchPositionName(char *dest, swsrc_t idx); char *getSwitchName(char *dest, swsrc_t idx);