Mixers: add channel bar to mixer groups

This commit is contained in:
Raphael Coeffic
2022-06-11 15:38:08 +02:00
committed by Raphael Coeffic
parent 710ed6c4db
commit 46c4095cd2
10 changed files with 254 additions and 200 deletions
+1
View File
@@ -173,6 +173,7 @@ add_gui_src(output_edit.cpp)
add_gui_src(input_mix_group.cpp)
add_gui_src(input_mix_button.cpp)
add_gui_src(lvgl_widgets/input_mix_line.c)
add_gui_src(channel_bar.cpp)
if(HARDWARE_TOUCH)
add_gui_src(keyboard_curve.cpp)
+2 -2
View File
@@ -837,9 +837,9 @@ void RxOptions::update()
hwSettings.receiverSettings.outputsMapping[i] = val;
if (val <= channelsMax) {
chBar->setChannel(getShiftedChannel(moduleIdx, val));
chBar->setEnabled(true);
lv_obj_clear_flag(chBar->getLvObj(), LV_OBJ_FLAG_HIDDEN);
} else {
chBar->setEnabled(false);
lv_obj_add_flag(chBar->getLvObj(), LV_OBJ_FLAG_HIDDEN);
}
});
chDn->setTextHandler(
+187
View File
@@ -0,0 +1,187 @@
/*
* 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 "channel_bar.h"
#define VIEW_CHANNELS_LIMIT_PCT \
(g_model.extendedLimits ? LIMIT_EXT_PERCENT : LIMIT_STD_PERCENT)
#define CHANNELS_LIMIT (g_model.extendedLimits ? LIMIT_EXT_MAX : LIMIT_STD_MAX)
ChannelBar::ChannelBar(Window* parent, const rect_t& rect, uint8_t channel) :
Window(parent, rect), channel(channel)
{
lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_PRIMARY2), 0);
lv_obj_set_style_bg_opa(lvobj, LV_OPA_COVER, 0);
}
void MixerChannelBar::paint(BitmapBuffer * dc)
{
int chanVal = calcRESXto100(ex_chans[channel]);
const int displayVal = chanVal;
// this could be handled nicer, but slower, by checking actual range for this
// mixer
chanVal =
limit<int>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
// Draw mixer bar
if (chanVal > 0) {
dc->drawSolidFilledRect(
0 + width() / 2, 0,
divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2),
height(), COLOR_THEME_FOCUS);
dc->drawNumber(width() / 2 - 10, -2, displayVal,
FONT(XS) | COLOR_THEME_SECONDARY1 | 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(),
COLOR_THEME_FOCUS);
dc->drawNumber(10 + width() / 2, -2, displayVal,
FONT(XS) | COLOR_THEME_SECONDARY1, 0, nullptr, "%");
}
// Draw middle bar
dc->drawSolidVerticalLine(width() / 2, 0, height(), COLOR_THEME_SECONDARY1);
}
void MixerChannelBar::checkEvents()
{
Window::checkEvents();
int newValue = ex_chans[channel];
if (value != newValue) {
value = newValue;
invalidate();
}
}
static inline unsigned posOnBar(coord_t width, int value_to100)
{
return divRoundClosest(
(value_to100 + VIEW_CHANNELS_LIMIT_PCT) * (width - 1),
VIEW_CHANNELS_LIMIT_PCT * 2);
}
static void drawOutputBarLimits(BitmapBuffer* dc, coord_t left, coord_t right,
LcdFlags color)
{
dc->drawSolidVerticalLine(left, 0, BAR_HEIGHT, color);
dc->drawSolidHorizontalLine(left, 0, 3, color);
dc->drawSolidHorizontalLine(left, BAR_HEIGHT - 1, 3, color);
dc->drawSolidVerticalLine(right, 0, BAR_HEIGHT, color);
dc->drawSolidHorizontalLine(right - 3, 0, 3, color);
dc->drawSolidHorizontalLine(right - 3, BAR_HEIGHT - 1, 3, color);
}
void OutputChannelBar::paint(BitmapBuffer* dc)
{
int chanVal = calcRESXto100(channelOutputs[channel]);
int displayVal = chanVal;
chanVal =
limit<int>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
// Draw output bar
if (chanVal > 0) {
dc->drawSolidFilledRect(
width() / 2, 0,
divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2),
height(), COLOR_THEME_ACTIVE);
dc->drawNumber(width() / 2 - 10, -2, displayVal,
FONT(XS) | COLOR_THEME_SECONDARY1 | 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(),
COLOR_THEME_ACTIVE);
dc->drawNumber(width() / 2 + 10, -2, displayVal,
FONT(XS) | COLOR_THEME_SECONDARY1, 0, nullptr, "%");
}
// Draw middle bar
dc->drawSolidVerticalLine(width() / 2, 0, height(), COLOR_THEME_SECONDARY1);
if (drawLimits) {
// Draw output limits bars
int limit = CHANNELS_LIMIT;
LimitData* ld = limitAddress(channel);
int32_t ldMax;
int32_t ldMin;
if (GV_IS_GV_VALUE(ld->min, -limit, 0)) {
ldMin = limMin;
} else {
ldMin = ld->min;
}
if (GV_IS_GV_VALUE(ld->max, 0, limit)) {
ldMax = limMax;
} else {
ldMax = ld->max;
}
if (ld && ld->revert) {
drawOutputBarLimits(dc, posOnBar(width(), -100 - ldMax / 10),
posOnBar(width(), 100 - ldMin / 10),
outputBarLimitsColor);
} else if (ld) {
drawOutputBarLimits(dc, posOnBar(width(), -100 + ldMin / 10),
posOnBar(width(), 100 + ldMax / 10),
outputBarLimitsColor);
}
}
}
void OutputChannelBar::checkEvents()
{
Window::checkEvents();
int newValue = channelOutputs[channel];
if (value != newValue) {
value = newValue;
invalidate();
}
int limit = CHANNELS_LIMIT;
LimitData* lim = limitAddress(channel);
if (GV_IS_GV_VALUE(lim->min, -limit, 0)) {
int ldMin = GET_GVAR_PREC1(lim->min, -limit, 0, mixerCurrentFlightMode) +
LIMIT_STD_MAX;
if (limMin != ldMin) invalidate();
limMin = ldMin;
}
if (GV_IS_GV_VALUE(lim->max, 0, limit)) {
int ldMax = GET_GVAR_PREC1(lim->max, 0, limit, mixerCurrentFlightMode) -
LIMIT_STD_MAX;
if (limMax != ldMax) invalidate();
limMax = ldMax;
}
}
+30 -195
View File
@@ -27,20 +27,12 @@
constexpr coord_t ROW_HEIGHT = 42;
constexpr coord_t BAR_HEIGHT = 13;
constexpr coord_t COLUMN_SIZE = 200;
constexpr coord_t X_OFFSET = 25;
constexpr coord_t LEG_COLORBOX = 15;
#define VIEW_CHANNELS_LIMIT_PCT (g_model.extendedLimits ? LIMIT_EXT_PERCENT : LIMIT_STD_PERCENT)
#define CHANNELS_LIMIT (g_model.extendedLimits ? LIMIT_EXT_MAX : LIMIT_STD_MAX)
class ChannelBar : public Window
{
public:
ChannelBar(Window* parent, const rect_t& rect, uint8_t channel) :
Window(parent, rect), channel(channel)
{
}
ChannelBar(Window* parent, const rect_t& rect, uint8_t channel);
void setChannel(uint8_t ch)
{
@@ -48,213 +40,57 @@ class ChannelBar : public Window
invalidate();
}
void setEnabled(bool en)
{
enabled = en;
}
protected:
uint8_t channel = 0;
bool enabled = true;
};
class MixerChannelBar : public ChannelBar
{
public:
using ChannelBar::ChannelBar;
public:
using ChannelBar::ChannelBar;
void paint(BitmapBuffer * dc) override
{
if (!enabled) return;
int chanVal = calcRESXto100(ex_chans[channel]);
const int displayVal = chanVal;
void paint(BitmapBuffer* dc) override;
void checkEvents() override;
// this could be handled nicer, but slower, by checking actual range for this mixer
chanVal = limit<int>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
// Draw Background
dc->drawSolidFilledRect(0, 0, width(), height(), COLOR_THEME_PRIMARY2);
// Draw mixer bar
if (chanVal > 0) {
dc->drawSolidFilledRect(
0 + width() / 2, 0,
divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2),
height(), COLOR_THEME_FOCUS);
dc->drawNumber(width() / 2 - 10, -2, displayVal,
FONT(XS) | COLOR_THEME_SECONDARY1 | 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(),
COLOR_THEME_FOCUS);
dc->drawNumber(10 + width() / 2, -2, displayVal,
FONT(XS) | COLOR_THEME_SECONDARY1, 0, nullptr, "%");
}
// Draw middle bar
dc->drawSolidVerticalLine(width() / 2, 0, height(), COLOR_THEME_SECONDARY1);
}
void checkEvents() override
{
Window::checkEvents();
int newValue = ex_chans[channel];
if (value != newValue) {
value = newValue;
invalidate();
}
}
protected:
int value = 0;
protected:
int value = 0;
};
class OutputChannelBar : public ChannelBar
{
public:
using ChannelBar::ChannelBar;
public:
using ChannelBar::ChannelBar;
void setOutputBarLimitColor(uint32_t color)
{
outputBarLimitsColor = color;
}
void setDrawLimits(bool enable) { drawLimits = enable; }
void setOutputBarLimitColor(uint32_t color) { outputBarLimitsColor = color; }
void paint(BitmapBuffer * dc) override
{
if (!enabled) return;
int chanVal = calcRESXto100(channelOutputs[channel]);
int displayVal = chanVal;
void paint(BitmapBuffer* dc) override;
void checkEvents() override;
chanVal = limit<int>(-VIEW_CHANNELS_LIMIT_PCT, chanVal,
VIEW_CHANNELS_LIMIT_PCT);
// Draw Background
dc->drawSolidFilledRect(0, 0, width(), height(), COLOR_THEME_PRIMARY2);
// Draw output bar
if (chanVal > 0) {
dc->drawSolidFilledRect(
width() / 2, 0,
divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2),
height(), COLOR_THEME_ACTIVE);
dc->drawNumber(width() / 2 - 10, -2, displayVal,
FONT(XS) | COLOR_THEME_SECONDARY1 | 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(),
COLOR_THEME_ACTIVE);
dc->drawNumber(width() / 2 + 10, -2, displayVal,
FONT(XS) | COLOR_THEME_SECONDARY1, 0, nullptr, "%");
}
// Draw middle bar
dc->drawSolidVerticalLine(width() / 2, 0, height(), COLOR_THEME_SECONDARY1);
// Draw output limits bars
int limit = CHANNELS_LIMIT;
LimitData* ld = limitAddress(channel);
int32_t ldMax;
int32_t ldMin;
if (GV_IS_GV_VALUE(ld->min, -limit, 0)) {
ldMin = limMin;
} else {
ldMin = ld->min;
}
if (GV_IS_GV_VALUE(ld->max, 0, limit)) {
ldMax = limMax;
} else {
ldMax = ld->max;
}
if (ld && ld->revert) {
drawOutputBarLimits(dc, posOnBar(-100 - ldMax / 10),
posOnBar(100 - ldMin / 10));
} else if (ld) {
drawOutputBarLimits(dc, posOnBar(-100 + ldMin / 10),
posOnBar(100 + ldMax / 10));
}
}
inline unsigned posOnBar(int value_to100)
{
return divRoundClosest((value_to100 + VIEW_CHANNELS_LIMIT_PCT) * (width() - 1), VIEW_CHANNELS_LIMIT_PCT * 2);
}
void drawOutputBarLimits(BitmapBuffer * dc, coord_t left, coord_t right)
{
dc->drawSolidVerticalLine(left, 0, BAR_HEIGHT, outputBarLimitsColor);
dc->drawSolidHorizontalLine(left, 0, 3, outputBarLimitsColor);
dc->drawSolidHorizontalLine(left, BAR_HEIGHT - 1, 3, outputBarLimitsColor);
dc->drawSolidVerticalLine(right, 0, BAR_HEIGHT, outputBarLimitsColor);
dc->drawSolidHorizontalLine(right - 3, 0, 3, outputBarLimitsColor);
dc->drawSolidHorizontalLine(right - 3, BAR_HEIGHT - 1, 3, outputBarLimitsColor);
}
void checkEvents() override
{
Window::checkEvents();
int newValue = channelOutputs[channel];
if (value != newValue) {
value = newValue;
invalidate();
}
int limit = CHANNELS_LIMIT;
LimitData* lim = limitAddress(channel);
if (GV_IS_GV_VALUE(lim->min, -limit, 0)) {
int ldMin =
GET_GVAR_PREC1(lim->min, -limit, 0, mixerCurrentFlightMode)
+ LIMIT_STD_MAX;
if (limMin != ldMin) invalidate();
limMin = ldMin;
}
if (GV_IS_GV_VALUE(lim->max, 0, limit)) {
int ldMax =
GET_GVAR_PREC1(lim->max, 0, limit, mixerCurrentFlightMode)
- LIMIT_STD_MAX;
if (limMax != ldMax) invalidate();
limMax = ldMax;
}
}
protected:
int value = 0;
int limMax = 0;
int limMin = 0;
uint32_t outputBarLimitsColor = COLOR_THEME_SECONDARY1;
protected:
int value = 0;
int limMax = 0;
int limMin = 0;
bool drawLimits = true;
LcdFlags outputBarLimitsColor = COLOR_THEME_SECONDARY1;
};
constexpr coord_t lmargin = 25;
class ComboChannelBar : public ChannelBar
class ComboChannelBar : public Window
{
public:
using ChannelBar::ChannelBar;
// using ChannelBar::ChannelBar;
ComboChannelBar(Window * parent, const rect_t & rect, uint8_t channel):
ChannelBar(parent, rect, channel)
Window(parent, rect), channel(channel)
{
outputChannelBar = new OutputChannelBar(this, {leftMargin, BAR_HEIGHT, width() - leftMargin, BAR_HEIGHT}, channel);
new MixerChannelBar(this, {leftMargin, 2 * BAR_HEIGHT + 1, width() - leftMargin, BAR_HEIGHT}, channel);
outputChannelBar = new OutputChannelBar(
this, {leftMargin, BAR_HEIGHT, width() - leftMargin, BAR_HEIGHT},
channel);
new MixerChannelBar(
this,
{leftMargin, 2 * BAR_HEIGHT + 1, width() - leftMargin, BAR_HEIGHT},
channel);
}
void setOutputChannelBarLimitColor(uint32_t color)
@@ -277,8 +113,6 @@ class ComboChannelBar : public ChannelBar
void paint(BitmapBuffer * dc) override
{
if (!enabled) return;
char chanString[] = "CH32 ";
int usValue = PPM_CH_CENTER(channel) + channelOutputs[channel] / 2;
@@ -324,6 +158,7 @@ class ComboChannelBar : public ChannelBar
}
protected:
uint8_t channel;
OutputChannelBar *outputChannelBar = nullptr;
int value = 0;
int leftMargin = lmargin;
@@ -20,6 +20,8 @@
*/
#include "input_mix_group.h"
#include "channel_bar.h"
#include "opentx.h"
#include <algorithm>
@@ -61,9 +63,22 @@ InputMixGroup::InputMixGroup(Window* parent, mixsrc_t idx) :
line_container = window_create(box);
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);
}
void InputMixGroup::addMixerMonitor(uint8_t channel)
{
rect_t r{ 0, 0, 100, 14 };
auto mon = new MixerChannelBar(this, r, channel);
lv_obj_t* mon_obj = mon->getLvObj();
lv_obj_set_parent(mon_obj, line_container);
lv_obj_set_style_border_width(mon_obj, lv_dpx(1), 0);
lv_obj_set_style_border_color(mon_obj, makeLvColor(COLOR_THEME_SECONDARY1), 0);
lv_obj_set_style_radius(mon_obj, lv_dpx(8), 0);
}
void InputMixGroup::addLine(Window* line, const uint8_t* symbol)
{
lines.emplace_back(line, symbol);
+2
View File
@@ -46,6 +46,8 @@ class InputMixGroup : public Window
public:
InputMixGroup(Window* parent, mixsrc_t idx);
void addMixerMonitor(uint8_t channel);
mixsrc_t getMixSrc() { return idx; }
size_t getLineCount() { return lines.size(); }
+7 -2
View File
@@ -264,6 +264,11 @@ void ModelInputsPage::removeLine(InputMixButton* l)
}
}
InputMixGroup* ModelInputsPage::createGroup(FormGroup* form, mixsrc_t src)
{
return new InputMixGroup(form, src);
}
InputMixButton* ModelInputsPage::createLineButton(InputMixGroup *group,
uint8_t index)
{
@@ -333,7 +338,7 @@ void ModelInputsPage::addLineButton(mixsrc_t src, uint8_t index)
{
InputMixGroup* group_w = getGroupBySrc(src);
if (!group_w) {
group_w = new InputMixGroup(form, src);
group_w = createGroup(form, src);
// insertion sort
groups.emplace_back(group_w);
auto g = groups.rbegin();
@@ -478,7 +483,7 @@ void ModelInputsPage::build(FormWindow *window)
if (line->chn == input && EXPO_VALID(line)) {
// one group for the complete input channel
auto group = new InputMixGroup(form, MIXSRC_FIRST_INPUT + input);
auto group = createGroup(form, MIXSRC_FIRST_INPUT + input);
groups.emplace_back(group);
while (index < MAX_EXPOS && line->chn == input && EXPO_VALID(line)) {
// one button per input line
+1
View File
@@ -49,6 +49,7 @@ class ModelInputsPage : public PageTab
virtual void addLineButton(uint8_t index);
virtual void addLineButton(mixsrc_t src, uint8_t index);
virtual InputMixGroup* createGroup(FormGroup* form, mixsrc_t src);
virtual InputMixButton* createLineButton(InputMixGroup *group, uint8_t index);
void editInput(uint8_t input, uint8_t index);
+8 -1
View File
@@ -355,6 +355,13 @@ InputMixGroup* ModelMixesPage::getGroupByIndex(uint8_t index)
return getGroupBySrc(MIXSRC_CH1 + ch);
}
InputMixGroup* ModelMixesPage::createGroup(FormGroup* form, mixsrc_t src)
{
auto group = new InputMixGroup(form, src);
group->addMixerMonitor(src - MIXSRC_CH1);
return group;
}
InputMixButton* ModelMixesPage::createLineButton(InputMixGroup *group, uint8_t index)
{
auto button = new MixLineButton(group, index);
@@ -555,7 +562,7 @@ void ModelMixesPage::build(FormWindow * window)
if (line->destCh == ch && !skip_mix) {
// one group for the complete mixer channel
auto group = new InputMixGroup(form, MIXSRC_CH1 + ch);
auto group = createGroup(form, MIXSRC_CH1 + ch);
groups.emplace_back(group);
while (index < MAX_MIXERS && (line->destCh == ch) && !skip_mix) {
// one button per input line
+1
View File
@@ -36,6 +36,7 @@ class ModelMixesPage : public ModelInputsPage
void addLineButton(uint8_t index) override;
void addLineButton(mixsrc_t src, uint8_t index) override;
InputMixGroup* createGroup(FormGroup* form, mixsrc_t src) override;
InputMixButton* createLineButton(InputMixGroup* group,
uint8_t index) override;