Mixers rework
This commit is contained in:
committed by
Raphael Coeffic
parent
9aaca6595e
commit
86c72e3a2a
@@ -168,6 +168,7 @@ add_gui_src(sourcechoice.cpp)
|
||||
add_gui_src(switchchoice.cpp)
|
||||
add_gui_src(curveedit.cpp)
|
||||
add_gui_src(input_edit.cpp)
|
||||
add_gui_src(mixer_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)
|
||||
|
||||
@@ -116,15 +116,6 @@ static const uint8_t mask_monitor_lockch[] = {
|
||||
static const uint8_t mask_monitor_logsw[] = {
|
||||
#include "mask_monitor_logsw.lbm"
|
||||
};
|
||||
static const uint8_t mask_mplex_add[] = {
|
||||
#include "mask_mplex_add.lbm"
|
||||
};
|
||||
static const uint8_t mask_mplex_multi[] = {
|
||||
#include "mask_mplex_multi.lbm"
|
||||
};
|
||||
static const uint8_t mask_mplex_replace[] = {
|
||||
#include "mask_mplex_replace.lbm"
|
||||
};
|
||||
static const uint8_t mask_edgetx[] = {
|
||||
#include "mask_edgetx.lbm"
|
||||
};
|
||||
@@ -256,9 +247,6 @@ BitmapBuffer * chanMonInvertedBitmap = nullptr;
|
||||
BitmapBuffer * mixerSetupMixerBitmap = nullptr;
|
||||
BitmapBuffer * mixerSetupToBitmap = nullptr;
|
||||
BitmapBuffer * mixerSetupOutputBitmap = nullptr;
|
||||
BitmapBuffer * mixerSetupAddBitmap = nullptr;
|
||||
BitmapBuffer * mixerSetupMultiBitmap = nullptr;
|
||||
BitmapBuffer * mixerSetupReplaceBitmap = nullptr;
|
||||
BitmapBuffer * mixerSetupCurveIcon = nullptr;
|
||||
BitmapBuffer * mixerSetupSwitchIcon = nullptr;
|
||||
BitmapBuffer * mixerSetupLabelIcon = nullptr;
|
||||
@@ -295,9 +283,6 @@ static const _BuiltinBitmap _builtinBitmaps[] = {
|
||||
{BMP_8BIT, mask_sbar_to, &mixerSetupToBitmap},
|
||||
{BMP_8BIT, mask_sbar_output, &mixerSetupOutputBitmap},
|
||||
|
||||
{BMP_8BIT, mask_mplex_add, &mixerSetupAddBitmap},
|
||||
{BMP_8BIT, mask_mplex_multi, &mixerSetupMultiBitmap},
|
||||
{BMP_8BIT, mask_mplex_replace, &mixerSetupReplaceBitmap},
|
||||
|
||||
{BMP_8BIT, mask_textline_label, &mixerSetupLabelIcon},
|
||||
{BMP_8BIT, mask_textline_curve, &mixerSetupCurveIcon},
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "definitions.h"
|
||||
#include "lz4_bitmaps.h"
|
||||
|
||||
DEFINE_LZ4_BITMAP(LBM_POINT);
|
||||
@@ -59,3 +60,13 @@ extern BitmapBuffer * mixerSetupDelaySlowIcon;
|
||||
|
||||
void loadBuiltinBitmaps();
|
||||
const uint8_t* getBuiltinIcon(MenuIcons id);
|
||||
|
||||
PACK(struct _bitmap_mask {
|
||||
uint16_t w;
|
||||
uint16_t h;
|
||||
uint8_t mask[0];
|
||||
});
|
||||
|
||||
#define MASK_WIDTH(m) (((_bitmap_mask*)m)->w)
|
||||
#define MASK_HEIGHT(m) (((_bitmap_mask*)m)->h)
|
||||
#define MASK_DATA(m) (((_bitmap_mask*)m)->mask)
|
||||
|
||||
@@ -24,11 +24,30 @@
|
||||
|
||||
#include "lvgl_widgets/input_mix_line.h"
|
||||
|
||||
InputMixButton::InputMixButton(Window* parent, const rect_t& rect, uint8_t index) :
|
||||
Button(parent, rect, nullptr, 0, COLOR_THEME_PRIMARY1,
|
||||
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);
|
||||
|
||||
auto btn = (InputMixButton*)lv_obj_get_user_data(obj);
|
||||
if (!btn) return;
|
||||
|
||||
p->y = btn->calcHeight();
|
||||
}
|
||||
|
||||
void InputMixButton::value_changed(lv_event_t* e)
|
||||
{
|
||||
auto obj = lv_event_get_target(e);
|
||||
lv_obj_refresh_self_size(obj);
|
||||
}
|
||||
|
||||
InputMixButton::InputMixButton(Window* parent, uint8_t index) :
|
||||
Button(parent, rect_t{}, nullptr, 0, COLOR_THEME_PRIMARY1,
|
||||
input_mix_line_create),
|
||||
index(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);
|
||||
}
|
||||
|
||||
void InputMixButton::checkEvents()
|
||||
@@ -56,4 +75,19 @@ void InputMixButton::drawFlightModes(BitmapBuffer *dc, FlightModesType value,
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
class InputMixButton : public Button
|
||||
{
|
||||
public:
|
||||
InputMixButton(Window* parent, const rect_t& rect, uint8_t index);
|
||||
InputMixButton(Window* parent, uint8_t index);
|
||||
|
||||
uint8_t getIndex() const { return index; }
|
||||
void setIndex(uint8_t i) { index = i; }
|
||||
@@ -36,11 +36,13 @@ class InputMixButton : public Button
|
||||
void drawFlightModes(BitmapBuffer *dc, FlightModesType value,
|
||||
LcdFlags textColor, coord_t x, coord_t y);
|
||||
|
||||
// TODO: generic "getHeight()" and recalc on changes
|
||||
|
||||
protected:
|
||||
uint8_t index;
|
||||
bool active = false;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
const lv_obj_class_t input_mix_line_class = {
|
||||
.width_def = LV_PCT(100),
|
||||
.height_def = LV_DPI_DEF / 4,
|
||||
.height_def = LV_SIZE_CONTENT,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
|
||||
.instance_size = sizeof(lv_btn_t),
|
||||
.base_class = &lv_btn_class,
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* 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 "mixer_edit.h"
|
||||
#include "channel_bar.h"
|
||||
#include "gvar_numberedit.h"
|
||||
#include "model_curves.h"
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
#if (LCD_W > LCD_H)
|
||||
#define MIX_STATUS_BAR_WIDTH 250
|
||||
#define MIX_STATUS_BAR_MARGIN 3
|
||||
#define MIX_RIGHT_MARGIN 0
|
||||
#else
|
||||
#define MIX_STATUS_BAR_WIDTH 180
|
||||
#define MIX_STATUS_BAR_MARGIN 0
|
||||
#define MIX_RIGHT_MARGIN 3
|
||||
#endif
|
||||
|
||||
class MixerEditStatusBar : public Window
|
||||
{
|
||||
public:
|
||||
MixerEditStatusBar(Window *parent, const rect_t &rect, int8_t channel) :
|
||||
Window(parent, rect),
|
||||
_channel(channel)
|
||||
{
|
||||
channelBar = new ComboChannelBar(this, {MIX_STATUS_BAR_MARGIN, 0, rect.w - (MIX_STATUS_BAR_MARGIN * 2), rect.h}, channel);
|
||||
channelBar->setLeftMargin(0);
|
||||
channelBar->setTextColor(COLOR_THEME_PRIMARY2);
|
||||
channelBar->setOutputChannelBarLimitColor(COLOR_THEME_EDIT);
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer *dc) override
|
||||
{
|
||||
// dc->clear(COLOR_THEME_SECONDARY2);
|
||||
}
|
||||
|
||||
protected:
|
||||
ComboChannelBar *channelBar;
|
||||
int8_t _channel;
|
||||
};
|
||||
|
||||
MixEditWindow::MixEditWindow(int8_t channel, uint8_t mixIndex) :
|
||||
Page(ICON_MODEL_MIXER), channel(channel), mixIndex(mixIndex)
|
||||
{
|
||||
buildBody(&body);
|
||||
buildHeader(&header);
|
||||
}
|
||||
|
||||
void MixEditWindow::buildHeader(Window *window)
|
||||
{
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_MIXES, 0, COLOR_THEME_PRIMARY2);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
getSourceString(MIXSRC_CH1 + channel), 0,
|
||||
COLOR_THEME_PRIMARY2);
|
||||
|
||||
statusBar = new MixerEditStatusBar(
|
||||
window,
|
||||
{window->getRect().w - MIX_STATUS_BAR_WIDTH - MIX_RIGHT_MARGIN, 0,
|
||||
MIX_STATUS_BAR_WIDTH, MENU_HEADER_HEIGHT + 3},
|
||||
channel);
|
||||
}
|
||||
|
||||
void MixEditWindow::buildBody(FormWindow *window)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(8);
|
||||
|
||||
MixData *mix = mixAddress(mixIndex);
|
||||
|
||||
// Mix name
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXNAME, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
new ModelTextEdit(window, grid.getFieldSlot(), mix->name, sizeof(mix->name));
|
||||
grid.nextLine();
|
||||
|
||||
// Source
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SOURCE, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
new SourceChoice(window, grid.getFieldSlot(), 0, MIXSRC_LAST,
|
||||
GET_SET_DEFAULT(mix->srcRaw));
|
||||
grid.nextLine();
|
||||
|
||||
// Weight
|
||||
new StaticText(window, grid.getLabelSlot(), STR_WEIGHT, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
auto gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_WEIGHT_MIN,
|
||||
MIX_WEIGHT_MAX, GET_SET_DEFAULT(mix->weight));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
|
||||
// Offset
|
||||
new StaticText(window, grid.getLabelSlot(), STR_OFFSET, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_OFFSET_MIN,
|
||||
MIX_OFFSET_MAX, GET_SET_DEFAULT(mix->offset));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
|
||||
// Trim
|
||||
new StaticText(window, grid.getLabelSlot(), STR_TRIM, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(mix->carryTrim));
|
||||
grid.nextLine();
|
||||
|
||||
// Curve
|
||||
new StaticText(&body, grid.getLabelSlot(), STR_CURVE, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
new Choice(&body, grid.getFieldSlot(2, 0), "\004DiffExpoFuncCstm", 0,
|
||||
CURVE_REF_CUSTOM, GET_DEFAULT(mix->curve.type),
|
||||
[=](int32_t newValue) {
|
||||
mix->curve.type = newValue;
|
||||
mix->curve.value = 0;
|
||||
SET_DIRTY();
|
||||
updateCurveParamField(mix);
|
||||
});
|
||||
curveParamField =
|
||||
new FormGroup(&body, grid.getFieldSlot(2, 1) // , FORM_FORWARD_FOCUS
|
||||
);
|
||||
updateCurveParamField(mix);
|
||||
grid.nextLine();
|
||||
|
||||
#if defined(FLIGHT_MODES)
|
||||
// Flight modes
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FLMODE, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
for (uint32_t i = 0; i < MAX_FLIGHT_MODES; i++) {
|
||||
char fm[2] = {char('0' + i), '\0'};
|
||||
if (i > 0 && (i % 4) == 0) grid.nextLine();
|
||||
new TextButton(
|
||||
window, grid.getFieldSlot(4, i % 4), fm,
|
||||
[=]() -> uint32_t {
|
||||
BFBIT_FLIP(mix->flightModes, bfBit<uint32_t>(i));
|
||||
SET_DIRTY();
|
||||
return !(bfSingleBitGet(mix->flightModes, i));
|
||||
},
|
||||
OPAQUE | (bfSingleBitGet(mix->flightModes, i) ? 0 : BUTTON_CHECKED));
|
||||
}
|
||||
grid.nextLine();
|
||||
#endif
|
||||
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST_IN_MIXES,
|
||||
SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(mix->swtch));
|
||||
grid.nextLine();
|
||||
|
||||
// Warning
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXWARNING, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
auto edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, 3,
|
||||
GET_SET_DEFAULT(mix->mixWarn));
|
||||
edit->setZeroText(STR_OFF);
|
||||
grid.nextLine();
|
||||
|
||||
// Multiplex
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MULTPX, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
new Choice(window, grid.getFieldSlot(), STR_VMLTPX, 0, 2,
|
||||
GET_SET_DEFAULT(mix->mltpx));
|
||||
grid.nextLine();
|
||||
|
||||
// Delay up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYUP, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayUp),
|
||||
SET_VALUE(mix->delayUp, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Delay down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYDOWN, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayDown),
|
||||
SET_VALUE(mix->delayDown, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Slow up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWUP, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedUp),
|
||||
SET_VALUE(mix->speedUp, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Slow down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWDOWN, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedDown),
|
||||
SET_VALUE(mix->speedDown, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
}
|
||||
|
||||
// TODO share this code with INPUT
|
||||
void MixEditWindow::updateCurveParamField(MixData *line)
|
||||
{
|
||||
curveParamField->clear();
|
||||
|
||||
const rect_t rect = {0, 0, curveParamField->width(),
|
||||
curveParamField->height()};
|
||||
|
||||
switch (line->curve.type) {
|
||||
case CURVE_REF_DIFF:
|
||||
case CURVE_REF_EXPO: {
|
||||
GVarNumberEdit *edit = new GVarNumberEdit(
|
||||
curveParamField, rect, -100, 100, GET_SET_DEFAULT(line->curve.value));
|
||||
edit->setSuffix("%");
|
||||
break;
|
||||
}
|
||||
|
||||
case CURVE_REF_FUNC:
|
||||
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
break;
|
||||
|
||||
case CURVE_REF_CUSTOM: {
|
||||
auto choice = new ChoiceEx(curveParamField, rect, -MAX_CURVES, MAX_CURVES,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
choice->setTextHandler([](int value) { return getCurveString(value); });
|
||||
choice->setLongPressHandler([this](event_t event) {
|
||||
MixData *mix = mixAddress(mixIndex);
|
||||
// if no curve is specified then dont link to curve page
|
||||
if (mix->curve.value != 0)
|
||||
ModelCurvesPage::pushEditCurve(abs(mix->curve.value) - 1);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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 "page.h"
|
||||
#include "form.h"
|
||||
#include "curve.h"
|
||||
|
||||
struct MixData;
|
||||
class FormGroup;
|
||||
class MixerEditStatusBar;
|
||||
|
||||
class MixEditWindow : public Page
|
||||
{
|
||||
public:
|
||||
MixEditWindow(int8_t channel, uint8_t mixIndex);
|
||||
|
||||
protected:
|
||||
uint8_t channel;
|
||||
uint8_t mixIndex;
|
||||
FormGroup *curveParamField = nullptr;
|
||||
MixerEditStatusBar *statusBar = nullptr;
|
||||
|
||||
void buildHeader(Window *window);
|
||||
void buildBody(FormWindow *window);
|
||||
|
||||
// TODO share this code with INPUT
|
||||
void updateCurveParamField(MixData *line);
|
||||
};
|
||||
@@ -127,23 +127,7 @@ static bool getFreeInput(uint8_t& input, uint8_t& index)
|
||||
class InputLineButton : public InputMixButton
|
||||
{
|
||||
public:
|
||||
InputLineButton(Window* parent, uint8_t index) :
|
||||
InputMixButton(parent, rect_t{}, index)
|
||||
{
|
||||
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);
|
||||
|
||||
const ExpoData &line = g_model.expoData[index];
|
||||
if (line.swtch || line.curve.value != 0 || line.flightModes) {
|
||||
h += lv_obj_get_style_text_line_space(lvobj, LV_PART_MAIN);
|
||||
h += getFontHeight(FONT(STD));
|
||||
}
|
||||
setHeight(h);
|
||||
}
|
||||
|
||||
bool isActive() const override { return isExpoActive(index); }
|
||||
using InputMixButton::InputMixButton;
|
||||
|
||||
void paint(BitmapBuffer *dc) override
|
||||
{
|
||||
@@ -185,6 +169,17 @@ class InputLineButton : public InputMixButton
|
||||
drawFlightModes(dc, line.flightModes, textColor, 146, y);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
bool isActive() const override { return isExpoActive(index); }
|
||||
size_t getLines() const override {
|
||||
const ExpoData* line = expoAddress(index);
|
||||
if (line->swtch || line->curve.value != 0 || line->flightModes) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ModelInputsPage::ModelInputsPage():
|
||||
@@ -362,7 +357,14 @@ void ModelInputsPage::addLineButton(mixsrc_t src, uint8_t index)
|
||||
|
||||
void ModelInputsPage::editInput(uint8_t input, uint8_t index)
|
||||
{
|
||||
new InputEditWindow(input, index);
|
||||
auto line = getLineByIndex(index);
|
||||
if (!line) return;
|
||||
|
||||
auto line_obj = line->getLvObj();
|
||||
auto edit = new InputEditWindow(input, index);
|
||||
edit->setCloseHandler([=]() {
|
||||
lv_event_send(line_obj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
void ModelInputsPage::insertInput(uint8_t input, uint8_t index)
|
||||
|
||||
@@ -26,15 +26,30 @@
|
||||
#include "bitfield.h"
|
||||
#include "model_inputs.h"
|
||||
#include "gvar_numberedit.h"
|
||||
#include "model_curves.h"
|
||||
#include "dataconstants.h"
|
||||
#include "channel_bar.h"
|
||||
|
||||
#include "input_mix_group.h"
|
||||
#include "input_mix_button.h"
|
||||
#include "mixer_edit.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
#define PASTE_BEFORE -2
|
||||
#define PASTE_AFTER -1
|
||||
|
||||
static const uint8_t _mask_mplex_add[] = {
|
||||
#include "mask_mplex_add.lbm"
|
||||
};
|
||||
STATIC_LZ4_BITMAP(mask_mplex_add);
|
||||
|
||||
static const uint8_t _mask_mplex_multi[] = {
|
||||
#include "mask_mplex_multi.lbm"
|
||||
};
|
||||
STATIC_LZ4_BITMAP(mask_mplex_multi);
|
||||
|
||||
static const uint8_t _mask_mplex_replace[] = {
|
||||
#include "mask_mplex_replace.lbm"
|
||||
};
|
||||
STATIC_LZ4_BITMAP(mask_mplex_replace);
|
||||
|
||||
uint8_t getMixesCount()
|
||||
{
|
||||
uint8_t count = 0;
|
||||
@@ -58,298 +73,6 @@ bool reachMixesLimit()
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#if (LCD_W > LCD_H)
|
||||
#define MIX_STATUS_BAR_WIDTH 250
|
||||
#define MIX_STATUS_BAR_MARGIN 3
|
||||
#define MIX_RIGHT_MARGIN 0
|
||||
#else
|
||||
#define MIX_STATUS_BAR_WIDTH 180
|
||||
#define MIX_STATUS_BAR_MARGIN 0
|
||||
#define MIX_RIGHT_MARGIN 3
|
||||
#endif
|
||||
|
||||
class MixerEditStatusBar : public Window
|
||||
{
|
||||
public:
|
||||
MixerEditStatusBar(Window *parent, const rect_t &rect, int8_t channel) :
|
||||
Window(parent, rect),
|
||||
_channel(channel)
|
||||
{
|
||||
channelBar = new ComboChannelBar(this, {MIX_STATUS_BAR_MARGIN, 0, rect.w - (MIX_STATUS_BAR_MARGIN * 2), rect.h}, channel);
|
||||
channelBar->setLeftMargin(0);
|
||||
channelBar->setTextColor(COLOR_THEME_PRIMARY2);
|
||||
channelBar->setOutputChannelBarLimitColor(COLOR_THEME_EDIT);
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer *dc) override
|
||||
{
|
||||
// dc->clear(COLOR_THEME_SECONDARY2);
|
||||
}
|
||||
|
||||
protected:
|
||||
ComboChannelBar *channelBar;
|
||||
int8_t _channel;
|
||||
};
|
||||
|
||||
class MixEditWindow : public Page
|
||||
{
|
||||
public:
|
||||
MixEditWindow(int8_t channel, uint8_t mixIndex) :
|
||||
Page(ICON_MODEL_MIXER), channel(channel), mixIndex(mixIndex)
|
||||
{
|
||||
buildBody(&body);
|
||||
buildHeader(&header);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t channel;
|
||||
uint8_t mixIndex;
|
||||
FormGroup *curveParamField = nullptr;
|
||||
MixerEditStatusBar *statusBar = nullptr;
|
||||
|
||||
void buildHeader(Window *window)
|
||||
{
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_MIXES, 0, COLOR_THEME_PRIMARY2);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
getSourceString(MIXSRC_CH1 + channel), 0, COLOR_THEME_PRIMARY2);
|
||||
|
||||
statusBar = new MixerEditStatusBar(
|
||||
window, {window->getRect().w - MIX_STATUS_BAR_WIDTH - MIX_RIGHT_MARGIN, 0, MIX_STATUS_BAR_WIDTH, MENU_HEADER_HEIGHT + 3},
|
||||
channel);
|
||||
}
|
||||
|
||||
void buildBody(FormWindow *window)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(8);
|
||||
|
||||
MixData *mix = mixAddress(mixIndex);
|
||||
|
||||
// Mix name
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXNAME, 0, COLOR_THEME_PRIMARY1);
|
||||
new ModelTextEdit(window, grid.getFieldSlot(), mix->name,
|
||||
sizeof(mix->name));
|
||||
grid.nextLine();
|
||||
|
||||
// Source
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SOURCE, 0, COLOR_THEME_PRIMARY1);
|
||||
new SourceChoice(window, grid.getFieldSlot(), 0, MIXSRC_LAST,
|
||||
GET_SET_DEFAULT(mix->srcRaw));
|
||||
grid.nextLine();
|
||||
|
||||
// Weight
|
||||
new StaticText(window, grid.getLabelSlot(), STR_WEIGHT, 0, COLOR_THEME_PRIMARY1);
|
||||
auto gvar =
|
||||
new GVarNumberEdit(window, grid.getFieldSlot(), MIX_WEIGHT_MIN,
|
||||
MIX_WEIGHT_MAX, GET_SET_DEFAULT(mix->weight));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
|
||||
// Offset
|
||||
new StaticText(window, grid.getLabelSlot(), STR_OFFSET, 0, COLOR_THEME_PRIMARY1);
|
||||
gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_OFFSET_MIN,
|
||||
MIX_OFFSET_MAX, GET_SET_DEFAULT(mix->offset));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
|
||||
// Trim
|
||||
new StaticText(window, grid.getLabelSlot(), STR_TRIM, 0, COLOR_THEME_PRIMARY1);
|
||||
new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(mix->carryTrim));
|
||||
grid.nextLine();
|
||||
|
||||
// Curve
|
||||
new StaticText(&body, grid.getLabelSlot(), STR_CURVE, 0, COLOR_THEME_PRIMARY1);
|
||||
new Choice(&body, grid.getFieldSlot(2, 0), "\004DiffExpoFuncCstm", 0,
|
||||
CURVE_REF_CUSTOM, GET_DEFAULT(mix->curve.type),
|
||||
[=](int32_t newValue) {
|
||||
mix->curve.type = newValue;
|
||||
mix->curve.value = 0;
|
||||
SET_DIRTY();
|
||||
updateCurveParamField(mix);
|
||||
});
|
||||
curveParamField =
|
||||
new FormGroup(&body, grid.getFieldSlot(2, 1)// , FORM_FORWARD_FOCUS
|
||||
);
|
||||
updateCurveParamField(mix);
|
||||
grid.nextLine();
|
||||
|
||||
#if defined(FLIGHT_MODES)
|
||||
// Flight modes
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FLMODE, 0, COLOR_THEME_PRIMARY1);
|
||||
for (uint32_t i = 0; i < MAX_FLIGHT_MODES; i++) {
|
||||
char fm[2] = {char('0' + i), '\0'};
|
||||
if (i > 0 && (i % 4) == 0) grid.nextLine();
|
||||
new TextButton(
|
||||
window, grid.getFieldSlot(4, i % 4), fm,
|
||||
[=]() -> uint32_t {
|
||||
BFBIT_FLIP(mix->flightModes, bfBit<uint32_t>(i));
|
||||
SET_DIRTY();
|
||||
return !(bfSingleBitGet(mix->flightModes, i));
|
||||
},
|
||||
OPAQUE | (bfSingleBitGet(mix->flightModes, i) ? 0 : BUTTON_CHECKED));
|
||||
}
|
||||
grid.nextLine();
|
||||
#endif
|
||||
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH, 0, COLOR_THEME_PRIMARY1);
|
||||
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST_IN_MIXES,
|
||||
SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(mix->swtch));
|
||||
grid.nextLine();
|
||||
|
||||
// Warning
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXWARNING, 0, COLOR_THEME_PRIMARY1);
|
||||
auto edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, 3,
|
||||
GET_SET_DEFAULT(mix->mixWarn));
|
||||
edit->setZeroText(STR_OFF);
|
||||
grid.nextLine();
|
||||
|
||||
// Multiplex
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MULTPX, 0, COLOR_THEME_PRIMARY1);
|
||||
new Choice(window, grid.getFieldSlot(), STR_VMLTPX, 0, 2,
|
||||
GET_SET_DEFAULT(mix->mltpx));
|
||||
grid.nextLine();
|
||||
|
||||
// Delay up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYUP, 0, COLOR_THEME_PRIMARY1);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayUp),
|
||||
SET_VALUE(mix->delayUp, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Delay down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYDOWN, 0, COLOR_THEME_PRIMARY1);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayDown),
|
||||
SET_VALUE(mix->delayDown, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Slow up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWUP, 0, COLOR_THEME_PRIMARY1);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedUp),
|
||||
SET_VALUE(mix->speedUp, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Slow down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWDOWN, 0, COLOR_THEME_PRIMARY1);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedDown),
|
||||
SET_VALUE(mix->speedDown, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
}
|
||||
|
||||
// TODO share this code with INPUT
|
||||
void updateCurveParamField(MixData *line)
|
||||
{
|
||||
curveParamField->clear();
|
||||
|
||||
const rect_t rect = {0, 0, curveParamField->width(),
|
||||
curveParamField->height()};
|
||||
|
||||
switch (line->curve.type) {
|
||||
case CURVE_REF_DIFF:
|
||||
case CURVE_REF_EXPO: {
|
||||
GVarNumberEdit *edit =
|
||||
new GVarNumberEdit(curveParamField, rect, -100, 100,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
edit->setSuffix("%");
|
||||
break;
|
||||
}
|
||||
|
||||
case CURVE_REF_FUNC:
|
||||
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
break;
|
||||
|
||||
case CURVE_REF_CUSTOM: {
|
||||
auto choice = new ChoiceEx(curveParamField, rect, -MAX_CURVES, MAX_CURVES,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
choice->setTextHandler([](int value) { return getCurveString(value); });
|
||||
choice->setLongPressHandler([this](event_t event) {
|
||||
MixData *mix = mixAddress(mixIndex);
|
||||
// if no curve is specified then dont link to curve page
|
||||
if (mix->curve.value != 0)
|
||||
ModelCurvesPage::pushEditCurve(abs(mix->curve.value) - 1);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MixLineButton : public CommonInputOrMixButton
|
||||
{
|
||||
public:
|
||||
MixLineButton(FormGroup *parent, const rect_t &rect, uint8_t index) :
|
||||
CommonInputOrMixButton(parent, rect, index)
|
||||
{
|
||||
const MixData &mix = g_model.mixData[index];
|
||||
if (mix.swtch || mix.curve.value != 0 || mix.flightModes) {
|
||||
setHeight(height() + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP);
|
||||
}
|
||||
}
|
||||
|
||||
bool isActive() const override { return isMixActive(index); }
|
||||
|
||||
void paintBody(BitmapBuffer *dc) override
|
||||
{
|
||||
const MixData &line = g_model.mixData[index];
|
||||
|
||||
LcdFlags textColor = COLOR_THEME_SECONDARY1;
|
||||
|
||||
// first line ...
|
||||
drawValueOrGVar(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, line.weight,
|
||||
MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, textColor);
|
||||
drawSource(dc, 60, FIELD_PADDING_TOP, line.srcRaw, textColor);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, FIELD_PADDING_TOP, mixerSetupLabelIcon, textColor);
|
||||
dc->drawSizedText(166, FIELD_PADDING_TOP, line.name, sizeof(line.name),
|
||||
textColor);
|
||||
}
|
||||
|
||||
// second line ...
|
||||
if (line.swtch) {
|
||||
dc->drawMask(3, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupSwitchIcon, textColor);
|
||||
drawSwitch(dc, 21, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.swtch,
|
||||
textColor);
|
||||
}
|
||||
|
||||
if (line.curve.value) {
|
||||
dc->drawMask(60, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupCurveIcon, textColor);
|
||||
drawCurveRef(dc, 80, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.curve,
|
||||
textColor);
|
||||
}
|
||||
|
||||
if (line.flightModes) {
|
||||
drawFlightModes(dc, line.flightModes, textColor);
|
||||
}
|
||||
|
||||
// Put this icon on the first line, since we have more space there
|
||||
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};
|
||||
dc->drawMask(width() - 16, FIELD_PADDING_TOP, delayslowbmp[delayslow - 1], textColor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void insertMix(uint8_t idx, uint8_t channel)
|
||||
{
|
||||
pauseMixerCalculations();
|
||||
@@ -370,198 +93,6 @@ void insertMix(uint8_t idx, uint8_t channel)
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
|
||||
ModelMixesPage::ModelMixesPage() :
|
||||
PageTab(STR_MIXES, ICON_MODEL_MIXER)
|
||||
{
|
||||
setOnSetVisibleHandler([]() {
|
||||
// reset clipboard
|
||||
s_copyMode = 0;
|
||||
});
|
||||
}
|
||||
|
||||
void ModelMixesPage::rebuild(FormWindow * window, int8_t focusMixIndex)
|
||||
{
|
||||
auto scroll_y = lv_obj_get_scroll_y(window->getLvObj());
|
||||
window->clear();
|
||||
build(window, focusMixIndex);
|
||||
lv_obj_scroll_to_y(window->getLvObj(), scroll_y, LV_ANIM_OFF);
|
||||
}
|
||||
|
||||
void ModelMixesPage::editMix(FormWindow * window, uint8_t channel, uint8_t mixIndex)
|
||||
{
|
||||
// Window::clearFocus();
|
||||
Window *editWindow = new MixEditWindow(channel, mixIndex);
|
||||
editWindow->setCloseHandler([=]() {
|
||||
int8_t newIndex = mixIndex;
|
||||
if (is_memclear(&g_model.mixData[mixIndex], sizeof(MixData))) {
|
||||
deleteMix(mixIndex);
|
||||
newIndex--;
|
||||
}
|
||||
rebuild(window, newIndex);
|
||||
});
|
||||
}
|
||||
|
||||
class MixLineTitle : public StaticText
|
||||
{
|
||||
public:
|
||||
using StaticText::StaticText;
|
||||
|
||||
void setTextFlags(LcdFlags flags)
|
||||
{
|
||||
textFlags = flags;
|
||||
for (auto child : children) {
|
||||
auto bitmap = dynamic_cast<StaticBitmap*>(child);
|
||||
if (bitmap) bitmap->setMaskColor(flags & 0xFFFF0000);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void ModelMixesPage::build(FormWindow * window, int8_t focusMixIndex)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
grid.setLabelWidth(66);
|
||||
|
||||
const BitmapBuffer * const mixerMultiplexBitmap[] = {
|
||||
mixerSetupAddBitmap,
|
||||
mixerSetupMultiBitmap,
|
||||
mixerSetupReplaceBitmap
|
||||
};
|
||||
|
||||
int mixIndex = 0;
|
||||
MixData * mix = g_model.mixData;
|
||||
for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) {
|
||||
|
||||
bool skip_mix = (ch == 0 && is_memclear(mix, sizeof(MixData)));
|
||||
|
||||
if (mixIndex < MAX_MIXERS && mix->destCh == ch && !skip_mix) {
|
||||
|
||||
coord_t h = grid.getWindowHeight();
|
||||
auto txt = new MixLineTitle(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_CH1 + ch),
|
||||
BUTTON_BACKGROUND, COLOR_THEME_PRIMARY1 | CENTERED);
|
||||
|
||||
uint8_t count = 0;
|
||||
while (mixIndex < MAX_MIXERS && mix->destCh == ch && !skip_mix) {
|
||||
|
||||
Button * button = new MixLineButton(window, grid.getFieldSlot(), mixIndex);
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
button->bringToTop();
|
||||
Menu * menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
editMix(window, ch, mixIndex);
|
||||
});
|
||||
if (!reachMixesLimit()) {
|
||||
menu->addLine(STR_INSERT_BEFORE, [=]() {
|
||||
insertMix(mixIndex, ch);
|
||||
editMix(window, ch, mixIndex);
|
||||
});
|
||||
menu->addLine(STR_INSERT_AFTER, [=]() {
|
||||
insertMix(mixIndex + 1, ch);
|
||||
editMix(window, ch, mixIndex + 1);
|
||||
});
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
s_copyMode = COPY_MODE;
|
||||
s_copySrcIdx =mixIndex;
|
||||
});
|
||||
if (s_copyMode != 0) {
|
||||
menu->addLine(STR_PASTE_BEFORE, [=]() {
|
||||
copyMix(s_copySrcIdx, mixIndex, PASTE_BEFORE);
|
||||
if(s_copyMode == MOVE_MODE) {
|
||||
deleteMix((s_copySrcIdx > mixIndex) ? s_copySrcIdx+1 : s_copySrcIdx);
|
||||
s_copyMode = 0;
|
||||
}
|
||||
rebuild(window, mixIndex);
|
||||
});
|
||||
menu->addLine(STR_PASTE_AFTER, [=]() {
|
||||
copyMix(s_copySrcIdx, mixIndex, PASTE_AFTER);
|
||||
if(s_copyMode == MOVE_MODE) {
|
||||
deleteMix((s_copySrcIdx > mixIndex) ? s_copySrcIdx+1 : s_copySrcIdx);
|
||||
s_copyMode = 0;
|
||||
}
|
||||
rebuild(window, mixIndex+1);
|
||||
});
|
||||
}
|
||||
}
|
||||
menu->addLine(STR_MOVE, [=]() {
|
||||
s_copyMode = MOVE_MODE;
|
||||
s_copySrcIdx = mixIndex;
|
||||
});
|
||||
menu->addLine(STR_DELETE, [=]() {
|
||||
deleteMix(mixIndex);
|
||||
rebuild(window, -1);
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (count++ > 0) {
|
||||
new StaticBitmap(
|
||||
txt,
|
||||
{35 - txt->left(),
|
||||
button->top() - txt->top() + (button->height() - 18) / 2, 25,
|
||||
17},
|
||||
mixerMultiplexBitmap[mix->mltpx], COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(COLOR_THEME_FOCUS);
|
||||
txt->setTextFlags(COLOR_THEME_PRIMARY2 | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(COLOR_THEME_SECONDARY2);
|
||||
txt->setTextFlags(COLOR_THEME_PRIMARY1 | CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
if (focus) button->bringToTop();
|
||||
});
|
||||
|
||||
grid.spacer(button->height() - 1);
|
||||
++mixIndex;
|
||||
++mix;
|
||||
|
||||
skip_mix = (ch == 0 && is_memclear(mix, sizeof(MixData)));
|
||||
}
|
||||
|
||||
h = grid.getWindowHeight() - h + 1;
|
||||
txt->setHeight(h);
|
||||
|
||||
grid.spacer(7);
|
||||
}
|
||||
else {
|
||||
auto button = new TextButton(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_CH1 + ch));
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
button->bringToTop();
|
||||
Menu *menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
insertMix(mixIndex, ch);
|
||||
editMix(window, ch, mixIndex);
|
||||
return 0;
|
||||
});
|
||||
if (!reachMixesLimit()) {
|
||||
if (s_copyMode != 0) {
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
copyMix(s_copySrcIdx, mixIndex, ch);
|
||||
if (s_copyMode == MOVE_MODE) {
|
||||
deleteMix((s_copySrcIdx >= mixIndex) ? s_copySrcIdx + 1
|
||||
: s_copySrcIdx);
|
||||
s_copyMode = 0;
|
||||
}
|
||||
rebuild(window, -1);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
}
|
||||
|
||||
grid.nextLine();
|
||||
}
|
||||
|
||||
void deleteMix(uint8_t idx)
|
||||
{
|
||||
pauseMixerCalculations();
|
||||
@@ -589,20 +120,9 @@ void copyMix(uint8_t source, uint8_t dest, int8_t ch)
|
||||
memcpy(&sourceMix, mixAddress(source), sizeof(MixData));
|
||||
MixData *mix = mixAddress(dest);
|
||||
size_t trailingMixes = MAX_MIXERS - (dest + 1);
|
||||
if (ch == PASTE_AFTER) {
|
||||
trailingMixes--;
|
||||
memmove(mix + 2, mix + 1, trailingMixes * sizeof(MixData));
|
||||
memcpy(mix + 1, &sourceMix, sizeof(MixData));
|
||||
(mix + 1)->destCh = (mix)->destCh;
|
||||
} else if (ch == PASTE_BEFORE) {
|
||||
memmove(mix + 1, mix, trailingMixes * sizeof(MixData));
|
||||
memcpy(mix, &sourceMix, sizeof(MixData));
|
||||
mix->destCh = (mix + 1)->destCh;
|
||||
} else {
|
||||
memmove(mix + 1, mix, trailingMixes * sizeof(MixData));
|
||||
memcpy(mix, &sourceMix, sizeof(MixData));
|
||||
mix->destCh = ch;
|
||||
}
|
||||
memmove(mix + 1, mix, trailingMixes * sizeof(MixData));
|
||||
memcpy(mix, &sourceMix, sizeof(MixData));
|
||||
mix->destCh = ch;
|
||||
resumeMixerCalculations();
|
||||
storageDirty(EE_MODEL);
|
||||
}
|
||||
@@ -649,3 +169,420 @@ bool swapMixes(uint8_t &idx, uint8_t up)
|
||||
idx = tgt_idx;
|
||||
return true;
|
||||
}
|
||||
|
||||
class MixLineButton : public InputMixButton
|
||||
{
|
||||
public:
|
||||
MixLineButton(Window* parent, uint8_t index);
|
||||
void paint(BitmapBuffer* dc) override;
|
||||
|
||||
protected:
|
||||
size_t getLines() const override;
|
||||
bool isActive() const override { return isMixActive(index); }
|
||||
};
|
||||
|
||||
static void mix_draw_mplex(lv_event_t* e)
|
||||
{
|
||||
auto obj = (lv_obj_t*)lv_event_get_user_data(e);
|
||||
if (!obj || (lv_obj_get_index(obj) == 0)) return;
|
||||
|
||||
auto btn = (MixLineButton*)lv_obj_get_user_data(obj);
|
||||
if (!btn) return;
|
||||
|
||||
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
|
||||
if (dsc->part != LV_PART_MAIN) return;
|
||||
|
||||
MixData* mix = mixAddress(btn->getIndex());
|
||||
const uint8_t* mask_map = nullptr;
|
||||
if (mix->mltpx == MLTPX_ADD) {
|
||||
mask_map = mask_mplex_add;
|
||||
} else if (mix->mltpx == MLTPX_MUL) {
|
||||
mask_map = mask_mplex_multi;
|
||||
} else if (mix->mltpx == MLTPX_REPL) {
|
||||
mask_map = mask_mplex_replace;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
lv_area_t coords;
|
||||
lv_coord_t area_h = lv_area_get_height(&obj->coords);
|
||||
lv_coord_t mask_w = MASK_WIDTH(mask_map);
|
||||
lv_coord_t mask_h = MASK_HEIGHT(mask_map);
|
||||
lv_coord_t pad_left = lv_obj_get_style_pad_left(obj, LV_PART_MAIN);
|
||||
|
||||
coords.x1 = obj->coords.x1 - mask_w - pad_left;
|
||||
coords.x2 = coords.x1 + mask_w - 1;
|
||||
coords.y1 = obj->coords.y1 + (area_h - mask_h) / 2;
|
||||
coords.y2 = coords.y1 + mask_h - 1;
|
||||
|
||||
lv_draw_rect_dsc_t rect_dsc;
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
rect_dsc.bg_opa = LV_OPA_COVER;
|
||||
rect_dsc.bg_color = makeLvColor(COLOR_THEME_SECONDARY1);
|
||||
|
||||
lv_draw_mask_map_param_t m;
|
||||
int16_t mask_id;
|
||||
|
||||
lv_draw_mask_map_init(&m, &coords, MASK_DATA(mask_map));
|
||||
mask_id = lv_draw_mask_add(&m, NULL);
|
||||
|
||||
// draw masked symbol
|
||||
lv_draw_rect(dsc->draw_ctx, &rect_dsc, &coords);
|
||||
|
||||
// free ressources
|
||||
lv_draw_mask_free_param(&m);
|
||||
lv_draw_mask_remove_id(mask_id);
|
||||
}
|
||||
|
||||
MixLineButton::MixLineButton(Window* parent, uint8_t index) :
|
||||
InputMixButton(parent, index)
|
||||
{
|
||||
lv_obj_t* p_obj = parent->getLvObj();
|
||||
lv_obj_add_event_cb(p_obj, mix_draw_mplex, LV_EVENT_DRAW_PART_END, lvobj);
|
||||
}
|
||||
|
||||
size_t MixLineButton::getLines() const
|
||||
{
|
||||
const MixData* mix = mixAddress(index);
|
||||
if (mix->swtch || mix->curve.value != 0 || mix->flightModes) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void MixLineButton::paint(BitmapBuffer* dc)
|
||||
{
|
||||
const MixData& line = g_model.mixData[index];
|
||||
LcdFlags textColor = COLOR_THEME_SECONDARY1;
|
||||
|
||||
// first line ...
|
||||
coord_t y = 0;
|
||||
y += lv_obj_get_style_border_width(lvobj, LV_PART_MAIN);
|
||||
y += lv_obj_get_style_pad_top(lvobj, LV_PART_MAIN);
|
||||
|
||||
coord_t x = 0;
|
||||
x += lv_obj_get_style_border_width(lvobj, LV_PART_MAIN);
|
||||
x += lv_obj_get_style_pad_left(lvobj, LV_PART_MAIN);
|
||||
|
||||
drawValueOrGVar(dc, x, y, line.weight, MIX_WEIGHT_MIN, MIX_WEIGHT_MAX,
|
||||
textColor);
|
||||
drawSource(dc, x + 65, y, line.srcRaw, textColor);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, y, mixerSetupLabelIcon, textColor);
|
||||
dc->drawSizedText(166, y, line.name, sizeof(line.name), textColor);
|
||||
}
|
||||
|
||||
// second line ...
|
||||
y += lv_obj_get_style_text_line_space(lvobj, LV_PART_MAIN);
|
||||
y += getFontHeight(FONT(STD));
|
||||
|
||||
if (line.swtch) {
|
||||
dc->drawMask(x, y, mixerSetupSwitchIcon, textColor);
|
||||
drawSwitch(dc, x + 21, y, line.swtch, textColor);
|
||||
}
|
||||
|
||||
if (line.curve.value) {
|
||||
dc->drawMask(x + 65, y, mixerSetupCurveIcon, textColor);
|
||||
drawCurveRef(dc, x + 85, y, line.curve, textColor);
|
||||
}
|
||||
|
||||
if (line.flightModes) {
|
||||
drawFlightModes(dc, line.flightModes, textColor, 146, y);
|
||||
}
|
||||
|
||||
// Put this icon on the first line, since we have more space there
|
||||
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};
|
||||
dc->drawMask(width() - 16, y, delayslowbmp[delayslow - 1], textColor);
|
||||
}
|
||||
}
|
||||
|
||||
ModelMixesPage::ModelMixesPage() :
|
||||
ModelInputsPage()
|
||||
{
|
||||
setTitle(STR_MIXES);
|
||||
setIcon(ICON_MODEL_MIXER);
|
||||
}
|
||||
|
||||
InputMixGroup* ModelMixesPage::getGroupByIndex(uint8_t index)
|
||||
{
|
||||
MixData* mix = mixAddress(index);
|
||||
if (is_memclear(mix, sizeof(MixData))) return nullptr;
|
||||
|
||||
int ch = mix->destCh;
|
||||
return getGroupBySrc(MIXSRC_CH1 + ch);
|
||||
}
|
||||
|
||||
InputMixButton* ModelMixesPage::createLineButton(InputMixGroup *group, uint8_t index)
|
||||
{
|
||||
auto button = new MixLineButton(group, index);
|
||||
lines.emplace_back(button);
|
||||
group->addLine(button);
|
||||
|
||||
uint8_t ch = group->getMixSrc() - MIXSRC_CH1;
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
Menu *menu = new Menu(form);
|
||||
menu->addLine(STR_EDIT, [=]() { editMix(ch, index); });
|
||||
if (!reachMixesLimit()) {
|
||||
menu->addLine(STR_INSERT_BEFORE, [=]() {
|
||||
uint8_t idx = button->getIndex();
|
||||
insertMix(ch, idx);
|
||||
_copyMode = 0;
|
||||
});
|
||||
menu->addLine(STR_INSERT_AFTER, [=]() {
|
||||
uint8_t idx = button->getIndex();
|
||||
insertMix(ch, idx + 1);
|
||||
_copyMode = 0;
|
||||
});
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
_copyMode = COPY_MODE;
|
||||
_copySrc = button;
|
||||
});
|
||||
if (s_copyMode != 0) {
|
||||
menu->addLine(STR_PASTE_BEFORE, [=]() {
|
||||
uint8_t idx = button->getIndex();
|
||||
pasteMixBefore(idx);
|
||||
_copyMode = 0;
|
||||
});
|
||||
menu->addLine(STR_PASTE_AFTER, [=]() {
|
||||
uint8_t idx = button->getIndex();
|
||||
pasteMixAfter(idx);
|
||||
_copyMode = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
menu->addLine(STR_MOVE, [=]() {
|
||||
_copyMode = MOVE_MODE;
|
||||
_copySrc = button;
|
||||
});
|
||||
menu->addLine(STR_DELETE, [=]() {
|
||||
uint8_t idx = button->getIndex();
|
||||
deleteMix(idx);
|
||||
_copyMode = 0;
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
void ModelMixesPage::addLineButton(mixsrc_t src, uint8_t index)
|
||||
{
|
||||
ModelInputsPage::addLineButton(src, index);
|
||||
}
|
||||
|
||||
void ModelMixesPage::addLineButton(uint8_t index)
|
||||
{
|
||||
MixData* mix = mixAddress(index);
|
||||
if (is_memclear(mix, sizeof(MixData))) return;
|
||||
int channel = mix->destCh;
|
||||
|
||||
addLineButton(MIXSRC_CH1 + channel, index);
|
||||
}
|
||||
|
||||
void ModelMixesPage::newMix()
|
||||
{
|
||||
Menu* menu = new Menu(Layer::back());
|
||||
menu->setTitle(STR_MENU_CHANNELS);
|
||||
|
||||
uint8_t index = 0;
|
||||
MixData* line = mixAddress(0);
|
||||
|
||||
// search for unused channels
|
||||
for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) {
|
||||
if (index >= MAX_MIXERS) break;
|
||||
bool skip_mix = (ch == 0 && is_memclear(line, sizeof(MixData)));
|
||||
if (line->destCh == ch && !skip_mix) {
|
||||
while (index < MAX_MIXERS && (line->destCh == ch) && !skip_mix) {
|
||||
++index;
|
||||
++line;
|
||||
skip_mix = (ch == 0 && is_memclear(line, sizeof(MixData)));
|
||||
}
|
||||
} else {
|
||||
std::string ch_name(getSourceString(MIXSRC_CH1 + ch));
|
||||
menu->addLine(ch_name.c_str(), [=]() { insertMix(ch, index); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelMixesPage::editMix(uint8_t channel, uint8_t index)
|
||||
{
|
||||
auto line = getLineByIndex(index);
|
||||
if (!line) return;
|
||||
|
||||
auto line_obj = line->getLvObj();
|
||||
auto edit = new MixEditWindow(channel, index);
|
||||
edit->setCloseHandler([=]() {
|
||||
MixData* mix = mixAddress(index);
|
||||
if (is_memclear(mix, sizeof(MixData))) {
|
||||
deleteMix(index);
|
||||
} else {
|
||||
lv_event_send(line_obj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ModelMixesPage::insertMix(uint8_t channel, uint8_t index)
|
||||
{
|
||||
::insertMix(index, channel);
|
||||
addLineButton(MIXSRC_CH1 + channel, index);
|
||||
editMix(channel, index);
|
||||
}
|
||||
|
||||
void ModelMixesPage::deleteMix(uint8_t index)
|
||||
{
|
||||
auto group = getGroupByIndex(index);
|
||||
if (!group) return;
|
||||
|
||||
auto line = getLineByIndex(index);
|
||||
if (!line) return;
|
||||
|
||||
group->removeLine(line);
|
||||
if (group->getLineCount() == 0) {
|
||||
group->deleteLater();
|
||||
removeGroup(group);
|
||||
removeLine(line);
|
||||
} else {
|
||||
line->deleteLater();
|
||||
removeLine(line);
|
||||
}
|
||||
|
||||
::deleteMix(index);
|
||||
}
|
||||
|
||||
void ModelMixesPage::pasteMix(uint8_t dst_idx, uint8_t channel)
|
||||
{
|
||||
if (!_copyMode || !_copySrc) return;
|
||||
uint8_t src_idx = _copySrc->getIndex();
|
||||
|
||||
::copyMix(src_idx, dst_idx, channel);
|
||||
addLineButton(dst_idx);
|
||||
|
||||
if (_copyMode == MOVE_MODE) {
|
||||
deleteInput(src_idx);
|
||||
}
|
||||
}
|
||||
|
||||
static int _mixChnFromIndex(uint8_t index)
|
||||
{
|
||||
MixData* mix = mixAddress(index);
|
||||
if (is_memclear(mix, sizeof(MixData))) return -1;
|
||||
return mix->destCh;
|
||||
}
|
||||
|
||||
void ModelMixesPage::pasteMixBefore(uint8_t dst_idx)
|
||||
{
|
||||
int channel = _mixChnFromIndex(dst_idx);
|
||||
pasteInput(dst_idx, channel);
|
||||
}
|
||||
|
||||
void ModelMixesPage::pasteMixAfter(uint8_t dst_idx)
|
||||
{
|
||||
int channel = _mixChnFromIndex(dst_idx);
|
||||
pasteInput(dst_idx + 1, channel);
|
||||
}
|
||||
|
||||
void ModelMixesPage::build(FormWindow * window)
|
||||
{
|
||||
window->setFlexLayout(LV_FLEX_FLOW_COLUMN, 8);
|
||||
lv_obj_set_style_pad_all(window->getLvObj(), 8, 0);
|
||||
|
||||
form = new FormGroup(window, rect_t{});
|
||||
form->setFlexLayout(LV_FLEX_FLOW_COLUMN, 8);
|
||||
|
||||
auto form_obj = form->getLvObj();
|
||||
lv_obj_set_width(form_obj, lv_pct(100));
|
||||
|
||||
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));
|
||||
|
||||
groups.clear();
|
||||
lines.clear();
|
||||
|
||||
uint8_t index = 0;
|
||||
MixData* line = g_model.mixData;
|
||||
for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) {
|
||||
|
||||
if (index >= MAX_MIXERS) break;
|
||||
|
||||
bool skip_mix = (ch == 0 && is_memclear(line, sizeof(MixData)));
|
||||
if (line->destCh == ch && !skip_mix) {
|
||||
|
||||
// one group for the complete mixer channel
|
||||
auto group = new InputMixGroup(form, MIXSRC_CH1 + ch);
|
||||
groups.emplace_back(group);
|
||||
while (index < MAX_MIXERS && (line->destCh == ch) && !skip_mix) {
|
||||
// one button per input line
|
||||
createLineButton(group, index);
|
||||
++index;
|
||||
++line;
|
||||
skip_mix = (ch == 0 && is_memclear(line, sizeof(MixData)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// int mixIndex = 0;
|
||||
// MixData * mix = g_model.mixData;
|
||||
// for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) {
|
||||
|
||||
// bool skip_mix = (ch == 0 && is_memclear(mix, sizeof(MixData)));
|
||||
|
||||
// if (mixIndex < MAX_MIXERS && mix->destCh == ch && !skip_mix) {
|
||||
|
||||
// coord_t h = grid.getWindowHeight();
|
||||
// auto txt = new MixLineTitle(window, grid.getLabelSlot(),
|
||||
// getSourceString(MIXSRC_CH1 + ch),
|
||||
// BUTTON_BACKGROUND, COLOR_THEME_PRIMARY1 | CENTERED);
|
||||
|
||||
// uint8_t count = 0;
|
||||
// while (mixIndex < MAX_MIXERS && mix->destCh == ch && !skip_mix) {
|
||||
|
||||
// TODO:
|
||||
// if (count++ > 0) {
|
||||
// new StaticBitmap(
|
||||
// txt,
|
||||
// {35 - txt->left(),
|
||||
// button->top() - txt->top() + (button->height() - 18) / 2, 25,
|
||||
// 17},
|
||||
// mixerMultiplexBitmap[mix->mltpx], COLOR_THEME_SECONDARY1);
|
||||
// }
|
||||
|
||||
// button->setFocusHandler([=](bool focus) {
|
||||
// if (focus) {
|
||||
// txt->setBackgroundColor(COLOR_THEME_FOCUS);
|
||||
// txt->setTextFlags(COLOR_THEME_PRIMARY2 | CENTERED);
|
||||
// } else {
|
||||
// txt->setBackgroundColor(COLOR_THEME_SECONDARY2);
|
||||
// txt->setTextFlags(COLOR_THEME_PRIMARY1 | CENTERED);
|
||||
// }
|
||||
// txt->invalidate();
|
||||
// if (focus) button->bringToTop();
|
||||
// });
|
||||
|
||||
// grid.spacer(button->height() - 1);
|
||||
// ++mixIndex;
|
||||
// ++mix;
|
||||
|
||||
// skip_mix = (ch == 0 && is_memclear(mix, sizeof(MixData)));
|
||||
// }
|
||||
|
||||
// h = grid.getWindowHeight() - h + 1;
|
||||
// txt->setHeight(h);
|
||||
|
||||
// grid.spacer(7);
|
||||
// }
|
||||
// }
|
||||
|
||||
// grid.nextLine();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,25 +19,32 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _MODEL_MIXES_H_
|
||||
#define _MODEL_MIXES_H_
|
||||
#pragma once
|
||||
|
||||
#include "tabsgroup.h"
|
||||
#include "model_inputs.h"
|
||||
|
||||
class ModelMixesPage: public PageTab {
|
||||
public:
|
||||
ModelMixesPage();
|
||||
|
||||
void build(FormWindow * window) override
|
||||
{
|
||||
build(window, 0);
|
||||
}
|
||||
class ModelMixesPage : public ModelInputsPage
|
||||
{
|
||||
public:
|
||||
ModelMixesPage();
|
||||
|
||||
protected:
|
||||
void build(FormWindow * window, int8_t focusMixIndex);
|
||||
void rebuild(FormWindow * window, int8_t focusMixIndex);
|
||||
void editMix(FormWindow * window, uint8_t channel, uint8_t mixIndex);
|
||||
uint8_t s_copySrcIdx;
|
||||
void build(FormWindow* window) override;
|
||||
|
||||
protected:
|
||||
InputMixGroup* getGroupByIndex(uint8_t index) override;
|
||||
|
||||
void addLineButton(uint8_t index) override;
|
||||
void addLineButton(mixsrc_t src, uint8_t index) override;
|
||||
InputMixButton* createLineButton(InputMixGroup* group,
|
||||
uint8_t index) override;
|
||||
|
||||
void newMix();
|
||||
void editMix(uint8_t input, uint8_t index);
|
||||
void insertMix(uint8_t input, uint8_t index);
|
||||
void deleteMix(uint8_t index);
|
||||
|
||||
void pasteMix(uint8_t dst_idx, uint8_t channel);
|
||||
void pasteMixBefore(uint8_t dst_idx);
|
||||
void pasteMixAfter(uint8_t dst_idx);
|
||||
};
|
||||
|
||||
#endif // _MODEL_MIXES_H_
|
||||
@@ -662,7 +662,12 @@ char *getSourceString(char (&dest)[L], mixsrc_t idx)
|
||||
strAppendStringWithIndex(dest, STR_PPM_TRAINER,
|
||||
idx - MIXSRC_FIRST_TRAINER + 1);
|
||||
} else if (idx <= MIXSRC_LAST_CH) {
|
||||
strAppendStringWithIndex(dest, STR_CH, idx - MIXSRC_CH1 + 1);
|
||||
auto ch = idx - MIXSRC_CH1;
|
||||
if (g_model.limitData[ch].name[0] != '\0') {
|
||||
copyToTerminated(dest, g_model.limitData[ch].name);
|
||||
} else {
|
||||
strAppendStringWithIndex(dest, STR_CH, ch + 1);
|
||||
}
|
||||
} else if (idx <= MIXSRC_LAST_GVAR) {
|
||||
strAppendStringWithIndex(dest, STR_GV, idx - MIXSRC_GVAR1 + 1);
|
||||
} else if (idx < MIXSRC_FIRST_TIMER) {
|
||||
|
||||
Reference in New Issue
Block a user