More compact views for inputs, mixers and outputs
This commit is contained in:
committed by
Raphael Coeffic
parent
cd211cba59
commit
731d1834e3
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#include <list>
|
||||
|
||||
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(); }
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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); });
|
||||
}
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user