Facelift round 4
This commit is contained in:
@@ -309,10 +309,9 @@ void ModelCurvesPage::build(FormWindow * window, int8_t focusIndex)
|
||||
|
||||
if (isCurveUsed(index)) {
|
||||
// Curve label
|
||||
auto text =
|
||||
auto txt =
|
||||
new StaticText(window, grid.getLabelSlot(), getCurveString(1 + index),
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
text->setBackgroundColor(FOCUS_COLOR);
|
||||
|
||||
// Curve drawing
|
||||
Button * button = new CurveButton(window, grid.getFieldSlot(), index);
|
||||
@@ -334,11 +333,25 @@ void ModelCurvesPage::build(FormWindow * window, int8_t focusIndex)
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
if (focusIndex == index) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
txt->setHeight(button->height());
|
||||
grid.spacer(button->height() + 5);
|
||||
} else {
|
||||
auto button = new TextButton(window, grid.getLabelSlot(),
|
||||
|
||||
@@ -30,7 +30,7 @@ class ModelCurvesPage: public PageTab {
|
||||
|
||||
virtual void build(FormWindow * window) override
|
||||
{
|
||||
build(window, -1);
|
||||
build(window, 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -64,9 +64,18 @@ void GVarButton::paint(BitmapBuffer * dc)
|
||||
currentFlightMode = getFlightMode();
|
||||
gvarSum = 0;
|
||||
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, FIELD_BGCOLOR);
|
||||
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, getGVarString(gvarIdx), 0);
|
||||
dc->drawSizedText(x, y, gvar->name, LEN_GVAR_NAME, 0);
|
||||
LcdFlags bgColor = FIELD_BGCOLOR;
|
||||
LcdFlags textColor = 0;
|
||||
if (hasFocus()) {
|
||||
bgColor = FOCUS_BGCOLOR;
|
||||
textColor = FOCUS_COLOR;
|
||||
}
|
||||
|
||||
dc->drawSolidFilledRect(0, 0, nameRectW, rect.h, bgColor);
|
||||
dc->drawSolidFilledRect(nameRectW, 0, rect.w - nameRectW, rect.h, FIELD_BGCOLOR);
|
||||
|
||||
dc->drawText(FIELD_PADDING_LEFT, FIELD_PADDING_TOP, getGVarString(gvarIdx), textColor);
|
||||
dc->drawSizedText(x, y, gvar->name, LEN_GVAR_NAME, textColor);
|
||||
|
||||
// values are right aligned
|
||||
x += GVAR_NAME_SIZE;
|
||||
|
||||
@@ -327,66 +327,67 @@ void CommonInputOrMixButton::drawFlightModes(BitmapBuffer *dc,
|
||||
void CommonInputOrMixButton::paint(BitmapBuffer * dc)
|
||||
{
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(),
|
||||
hasFocus() ? FOCUS_BGCOLOR : FIELD_BGCOLOR);
|
||||
/*hasFocus() ? FOCUS_BGCOLOR :*/ FIELD_BGCOLOR);
|
||||
paintBody(dc);
|
||||
|
||||
if (!hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FIELD_FRAME_COLOR);
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
}
|
||||
|
||||
class InputLineButton : public CommonInputOrMixButton {
|
||||
public:
|
||||
InputLineButton(FormGroup * parent, const rect_t & rect, uint8_t index):
|
||||
class InputLineButton : public CommonInputOrMixButton
|
||||
{
|
||||
public:
|
||||
InputLineButton(FormGroup *parent, const rect_t &rect, uint8_t index) :
|
||||
CommonInputOrMixButton(parent, rect, index)
|
||||
{
|
||||
const ExpoData & line = g_model.expoData[index];
|
||||
if (line.swtch || line.curve.value != 0 || line.flightModes) {
|
||||
setHeight(height() + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP);
|
||||
}
|
||||
{
|
||||
const ExpoData &line = g_model.expoData[index];
|
||||
if (line.swtch || line.curve.value != 0 || line.flightModes) {
|
||||
setHeight(height() + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP);
|
||||
}
|
||||
}
|
||||
|
||||
bool isActive() const override { return isExpoActive(index); }
|
||||
|
||||
void paintBody(BitmapBuffer *dc) override
|
||||
{
|
||||
const ExpoData &line = g_model.expoData[index];
|
||||
|
||||
LcdFlags textColor = DEFAULT_COLOR;
|
||||
// if (hasFocus())
|
||||
// textColor = FOCUS_COLOR;
|
||||
|
||||
// first line ...
|
||||
drawValueOrGVar(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, line.weight,
|
||||
-100, 100, textColor);
|
||||
drawSource(dc, 60, FIELD_PADDING_TOP, line.srcRaw, textColor);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, FIELD_PADDING_TOP, mixerSetupLabelIcon, textColor);
|
||||
dc->drawSizedText(166, FIELD_PADDING_TOP, line.name, sizeof(line.name),
|
||||
textColor);
|
||||
}
|
||||
|
||||
bool isActive() const override
|
||||
{
|
||||
return isExpoActive(index);
|
||||
// second line ...
|
||||
if (line.swtch) {
|
||||
dc->drawMask(3, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupSwitchIcon, textColor);
|
||||
drawSwitch(dc, 21, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.swtch,
|
||||
textColor);
|
||||
}
|
||||
|
||||
void paintBody(BitmapBuffer * dc) override
|
||||
{
|
||||
const ExpoData & line = g_model.expoData[index];
|
||||
|
||||
LcdFlags textColor = DEFAULT_COLOR;
|
||||
if (hasFocus())
|
||||
textColor = FOCUS_COLOR;
|
||||
|
||||
// first line ...
|
||||
drawValueOrGVar(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, line.weight,
|
||||
-100, 100, textColor);
|
||||
drawSource(dc, 60, FIELD_PADDING_TOP, line.srcRaw, textColor);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, FIELD_PADDING_TOP, mixerSetupLabelIcon, textColor);
|
||||
dc->drawSizedText(166, FIELD_PADDING_TOP, line.name, sizeof(line.name),
|
||||
textColor);
|
||||
}
|
||||
|
||||
// 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,
|
||||
if (line.curve.value != 0) {
|
||||
dc->drawMask(60, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupCurveIcon, textColor);
|
||||
drawCurveRef(dc, 80, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.curve,
|
||||
textColor);
|
||||
}
|
||||
|
||||
if (line.curve.value != 0 ) {
|
||||
dc->drawMask(60, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupCurveIcon, textColor);
|
||||
drawCurveRef(dc, 80, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.curve,
|
||||
textColor);
|
||||
}
|
||||
|
||||
if (line.flightModes) {
|
||||
drawFlightModes(dc, line.flightModes, textColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (line.flightModes) {
|
||||
drawFlightModes(dc, line.flightModes, textColor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ModelInputsPage::ModelInputsPage():
|
||||
@@ -411,31 +412,29 @@ void ModelInputsPage::editInput(FormWindow * window, uint8_t input, uint8_t inde
|
||||
});
|
||||
}
|
||||
|
||||
void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
void ModelInputsPage::build(FormWindow *window, int8_t focusIndex)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
grid.setLabelWidth(66);
|
||||
|
||||
int inputIndex = 0;
|
||||
ExpoData * line = g_model.expoData;
|
||||
ExpoData *line = g_model.expoData;
|
||||
for (uint8_t input = 0; input < MAX_INPUTS; input++) {
|
||||
if (inputIndex < MAX_EXPOS && line->chn == input && EXPO_VALID(line)) {
|
||||
coord_t h = grid.getWindowHeight();
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_FIRST_INPUT + input),
|
||||
0, CENTERED);
|
||||
txt->setBackgroundColor(FIELD_BGCOLOR);
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
while (inputIndex < MAX_EXPOS && line->chn == input && EXPO_VALID(line)) {
|
||||
Button * button = new InputLineButton(window, grid.getFieldSlot(), inputIndex);
|
||||
if (focusIndex == inputIndex)
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
Button *button =
|
||||
new InputLineButton(window, grid.getFieldSlot(), inputIndex);
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
button->bringToTop();
|
||||
Menu * menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
editInput(window, input, inputIndex);
|
||||
});
|
||||
Menu *menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT,
|
||||
[=]() { editInput(window, input, inputIndex); });
|
||||
if (!reachExposLimit()) {
|
||||
menu->addLine(STR_INSERT_BEFORE, [=]() {
|
||||
insertExpo(inputIndex, input);
|
||||
@@ -453,7 +452,8 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
menu->addLine(STR_PASTE_BEFORE, [=]() {
|
||||
copyExpo(s_copySrcIdx, inputIndex, PASTE_BEFORE);
|
||||
if (s_copyMode == MOVE_MODE) {
|
||||
deleteExpo((s_copySrcIdx > inputIndex) ? s_copySrcIdx+1 : s_copySrcIdx);
|
||||
deleteExpo((s_copySrcIdx > inputIndex) ? s_copySrcIdx + 1
|
||||
: s_copySrcIdx);
|
||||
s_copyMode = 0;
|
||||
}
|
||||
rebuild(window, inputIndex);
|
||||
@@ -461,10 +461,11 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
menu->addLine(STR_PASTE_AFTER, [=]() {
|
||||
copyExpo(s_copySrcIdx, inputIndex, PASTE_AFTER);
|
||||
if (s_copyMode == MOVE_MODE) {
|
||||
deleteExpo((s_copySrcIdx > inputIndex) ? s_copySrcIdx+1 : s_copySrcIdx);
|
||||
deleteExpo((s_copySrcIdx > inputIndex) ? s_copySrcIdx + 1
|
||||
: s_copySrcIdx);
|
||||
s_copyMode = 0;
|
||||
}
|
||||
rebuild(window, inputIndex+1);
|
||||
rebuild(window, inputIndex + 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -478,22 +479,39 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
grid.spacer(button->height() - 2);
|
||||
|
||||
if (focusIndex == inputIndex) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
grid.spacer(button->height() - 1);
|
||||
++inputIndex;
|
||||
++line;
|
||||
}
|
||||
|
||||
h = grid.getWindowHeight() - h + 1;
|
||||
txt->setHeight(h);
|
||||
|
||||
grid.spacer(7);
|
||||
}
|
||||
else {
|
||||
auto button = new TextButton(window, grid.getLabelSlot(), getSourceString(MIXSRC_FIRST_INPUT + input));
|
||||
if (focusIndex == inputIndex)
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
} else {
|
||||
auto button = new TextButton(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_FIRST_INPUT + input));
|
||||
if (focusIndex == inputIndex) button->setFocus(SET_FOCUS_DEFAULT);
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
button->bringToTop();
|
||||
Menu * menu = new Menu(window);
|
||||
Menu *menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
insertExpo(inputIndex, input);
|
||||
editInput(window, input, inputIndex);
|
||||
@@ -503,8 +521,9 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
if (s_copyMode != 0) {
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
copyExpo(s_copySrcIdx, inputIndex, input);
|
||||
if(s_copyMode == MOVE_MODE) {
|
||||
deleteExpo((s_copySrcIdx >= inputIndex) ? s_copySrcIdx+1 : s_copySrcIdx);
|
||||
if (s_copyMode == MOVE_MODE) {
|
||||
deleteExpo((s_copySrcIdx >= inputIndex) ? s_copySrcIdx + 1
|
||||
: s_copySrcIdx);
|
||||
s_copyMode = 0;
|
||||
}
|
||||
rebuild(window, -1);
|
||||
@@ -519,7 +538,7 @@ void ModelInputsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
}
|
||||
}
|
||||
|
||||
Window * focus = Window::getFocus();
|
||||
Window *focus = Window::getFocus();
|
||||
if (focus) {
|
||||
focus->bringToTop();
|
||||
}
|
||||
|
||||
@@ -241,95 +241,97 @@ static constexpr coord_t col1 = 20;
|
||||
static constexpr coord_t col2 = (LCD_W - 100) / 3 + col1;
|
||||
static constexpr coord_t col3 = ((LCD_W - 100) / 3) * 2 + col1;
|
||||
|
||||
class LogicalSwitchButton : public Button {
|
||||
public:
|
||||
LogicalSwitchButton(FormGroup * parent, const rect_t & rect, int lsIndex):
|
||||
Button(parent, rect),
|
||||
lsIndex(lsIndex),
|
||||
active(isActive())
|
||||
{
|
||||
LogicalSwitchData * ls = lswAddress(lsIndex);
|
||||
if (ls->andsw != SWSRC_NONE || ls->duration != 0 || ls->delay != 0)
|
||||
setHeight(height() + 20);
|
||||
if (lswFamily(ls->func) == LS_FAMILY_EDGE)
|
||||
setHeight(height() + 20);
|
||||
class LogicalSwitchButton : public Button
|
||||
{
|
||||
public:
|
||||
LogicalSwitchButton(FormGroup* parent, const rect_t& rect, int lsIndex) :
|
||||
Button(parent, rect), lsIndex(lsIndex), active(isActive())
|
||||
{
|
||||
LogicalSwitchData* ls = lswAddress(lsIndex);
|
||||
if (ls->andsw != SWSRC_NONE || ls->duration != 0 || ls->delay != 0)
|
||||
setHeight(height() + 20);
|
||||
if (lswFamily(ls->func) == LS_FAMILY_EDGE) setHeight(height() + 20);
|
||||
}
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + lsIndex);
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
active = !active;
|
||||
}
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return getSwitch(SWSRC_FIRST_LOGICAL_SWITCH + lsIndex);
|
||||
Button::checkEvents();
|
||||
}
|
||||
|
||||
void paintLogicalSwitchLine(BitmapBuffer* dc)
|
||||
{
|
||||
LogicalSwitchData* ls = lswAddress(lsIndex);
|
||||
uint8_t lsFamily = lswFamily(ls->func);
|
||||
|
||||
// CSW func
|
||||
dc->drawTextAtIndex(col1, line1, STR_VCSWFUNC, ls->func);
|
||||
|
||||
// CSW params
|
||||
if (lsFamily == LS_FAMILY_BOOL || lsFamily == LS_FAMILY_STICKY) {
|
||||
drawSwitch(dc, col2, line1, ls->v1);
|
||||
drawSwitch(dc, col3, line1, ls->v2);
|
||||
} else if (lsFamily == LS_FAMILY_EDGE) {
|
||||
drawSwitch(dc, col1, line2, ls->v1);
|
||||
putsEdgeDelayParam(dc, col2, line2, ls);
|
||||
} else if (lsFamily == LS_FAMILY_COMP) {
|
||||
drawSource(dc, col2, line1, ls->v1, 0);
|
||||
drawSource(dc, col3, line1, ls->v2, 0);
|
||||
} else if (lsFamily == LS_FAMILY_TIMER) {
|
||||
dc->drawNumber(col2, line1, lswTimerValue(ls->v1), LEFT | PREC1);
|
||||
dc->drawNumber(col3, line1, lswTimerValue(ls->v2), LEFT | PREC1);
|
||||
} else {
|
||||
drawSource(dc, col2, line1, ls->v1, 0);
|
||||
drawSourceCustomValue(
|
||||
dc, col3, line1, ls->v1,
|
||||
(ls->v1 <= MIXSRC_LAST_CH ? calc100toRESX(ls->v2) : ls->v2), 0);
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
active = !active;
|
||||
}
|
||||
// AND switch
|
||||
drawSwitch(dc, col1, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2,
|
||||
ls->andsw, 0);
|
||||
|
||||
Button::checkEvents();
|
||||
// CSW duration
|
||||
if (ls->duration > 0) {
|
||||
dc->drawNumber(col2, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2,
|
||||
ls->duration, PREC1 | LEFT);
|
||||
}
|
||||
|
||||
void paintLogicalSwitchLine(BitmapBuffer * dc)
|
||||
{
|
||||
LogicalSwitchData * ls = lswAddress(lsIndex);
|
||||
uint8_t lsFamily = lswFamily(ls->func);
|
||||
|
||||
// CSW func
|
||||
dc->drawTextAtIndex(col1, line1, STR_VCSWFUNC, ls->func);
|
||||
|
||||
// CSW params
|
||||
if (lsFamily == LS_FAMILY_BOOL || lsFamily == LS_FAMILY_STICKY) {
|
||||
drawSwitch(dc, col2, line1, ls->v1);
|
||||
drawSwitch(dc, col3, line1, ls->v2);
|
||||
}
|
||||
else if (lsFamily == LS_FAMILY_EDGE) {
|
||||
drawSwitch(dc, col1, line2, ls->v1);
|
||||
putsEdgeDelayParam(dc, col2, line2, ls);
|
||||
}
|
||||
else if (lsFamily == LS_FAMILY_COMP) {
|
||||
drawSource(dc, col2, line1, ls->v1, 0);
|
||||
drawSource(dc, col3, line1, ls->v2, 0);
|
||||
}
|
||||
else if (lsFamily == LS_FAMILY_TIMER) {
|
||||
dc->drawNumber(col2, line1, lswTimerValue(ls->v1), LEFT|PREC1);
|
||||
dc->drawNumber(col3, line1, lswTimerValue(ls->v2), LEFT|PREC1);
|
||||
}
|
||||
else {
|
||||
drawSource(dc, col2, line1, ls->v1, 0);
|
||||
drawSourceCustomValue(dc, col3, line1, ls->v1, (ls->v1 <= MIXSRC_LAST_CH ? calc100toRESX(ls->v2) : ls->v2), 0);
|
||||
}
|
||||
|
||||
// AND switch
|
||||
drawSwitch(dc, col1, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2, ls->andsw, 0);
|
||||
|
||||
// CSW duration
|
||||
if (ls->duration > 0) {
|
||||
dc->drawNumber(col2, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2, ls->duration, PREC1 | LEFT);
|
||||
}
|
||||
|
||||
// CSW delay
|
||||
if (lsFamily != LS_FAMILY_EDGE && ls->delay > 0) {
|
||||
dc->drawNumber(col3, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2, ls->delay, PREC1 | LEFT);
|
||||
}
|
||||
// CSW delay
|
||||
if (lsFamily != LS_FAMILY_EDGE && ls->delay > 0) {
|
||||
dc->drawNumber(col3, (lsFamily == LS_FAMILY_EDGE) ? line3 : line2,
|
||||
ls->delay, PREC1 | LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
if (active)
|
||||
dc->drawSolidFilledRect(2, 2, rect.w-4, rect.h-4, HIGHLIGHT_COLOR);
|
||||
else
|
||||
dc->drawSolidFilledRect(2, 2, rect.w-4, rect.h-4, FIELD_BGCOLOR);
|
||||
void paint(BitmapBuffer* dc) override
|
||||
{
|
||||
if (active)
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, HIGHLIGHT_COLOR);
|
||||
else
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, FIELD_BGCOLOR);
|
||||
|
||||
paintLogicalSwitchLine(dc);
|
||||
paintLogicalSwitchLine(dc);
|
||||
|
||||
// The bounding rect
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? CHECKBOX_COLOR : DISABLE_COLOR);
|
||||
}
|
||||
// The bounding rect
|
||||
if (hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t lsIndex;
|
||||
bool active;
|
||||
protected:
|
||||
uint8_t lsIndex;
|
||||
bool active;
|
||||
};
|
||||
|
||||
ModelLogicalSwitchesPage::ModelLogicalSwitchesPage():
|
||||
@@ -353,17 +355,18 @@ void ModelLogicalSwitchesPage::editLogicalSwitch(FormWindow * window, uint8_t ls
|
||||
});
|
||||
}
|
||||
|
||||
void ModelLogicalSwitchesPage::build(FormWindow * window, int8_t focusIndex)
|
||||
void ModelLogicalSwitchesPage::build(FormWindow* window, int8_t focusIndex)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
grid.setLabelWidth(66);
|
||||
|
||||
for (uint8_t i = 0; i < MAX_LOGICAL_SWITCHES; i++) {
|
||||
LogicalSwitchData * ls = lswAddress(i);
|
||||
LogicalSwitchData* ls = lswAddress(i);
|
||||
|
||||
if (ls->func == LS_FUNC_NONE) {
|
||||
auto button = new TextButton(window, grid.getLabelSlot(), getSwitchPositionName(SWSRC_SW1+i));
|
||||
auto button = new TextButton(window, grid.getLabelSlot(),
|
||||
getSwitchPositionName(SWSRC_SW1 + i));
|
||||
button->setPressHandler([=]() {
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH) {
|
||||
Menu* menu = new Menu(window);
|
||||
@@ -379,40 +382,54 @@ void ModelLogicalSwitchesPage::build(FormWindow * window, int8_t focusIndex)
|
||||
return 0;
|
||||
});
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
else {
|
||||
new StaticText(window, grid.getLabelSlot(), getSwitchPositionName(SWSRC_SW1 + i), BUTTON_BACKGROUND, CENTERED);
|
||||
} else {
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(),
|
||||
getSwitchPositionName(SWSRC_SW1 + i),
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
auto button = new LogicalSwitchButton(window, grid.getFieldSlot(), i);
|
||||
button->setPressHandler([=]() {
|
||||
Menu * menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
editLogicalSwitch(window, i);
|
||||
Menu* menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() { editLogicalSwitch(window, i); });
|
||||
if (ls->func)
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
clipboard.type = CLIPBOARD_TYPE_CUSTOM_SWITCH;
|
||||
clipboard.data.csw = *ls;
|
||||
});
|
||||
if (ls->func)
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
clipboard.type = CLIPBOARD_TYPE_CUSTOM_SWITCH;
|
||||
clipboard.data.csw = *ls;
|
||||
});
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH)
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
*ls = clipboard.data.csw;
|
||||
storageDirty(EE_MODEL);
|
||||
rebuild(window, i);
|
||||
});
|
||||
if (ls->func || ls->v1 || ls->v2 || ls->delay || ls->duration || ls->andsw)
|
||||
menu->addLine(STR_CLEAR, [=]() {
|
||||
memset(ls, 0, sizeof(LogicalSwitchData));
|
||||
storageDirty(EE_MODEL);
|
||||
rebuild(window, i);
|
||||
});
|
||||
return 0;
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_SWITCH)
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
*ls = clipboard.data.csw;
|
||||
storageDirty(EE_MODEL);
|
||||
rebuild(window, i);
|
||||
});
|
||||
if (ls->func || ls->v1 || ls->v2 || ls->delay || ls->duration ||
|
||||
ls->andsw)
|
||||
menu->addLine(STR_CLEAR, [=]() {
|
||||
memset(ls, 0, sizeof(LogicalSwitchData));
|
||||
storageDirty(EE_MODEL);
|
||||
rebuild(window, i);
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
if (focusIndex == i) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
txt->setHeight(button->height());
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
|
||||
virtual void build(FormWindow * window) override
|
||||
{
|
||||
build(window, -1);
|
||||
build(window, 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -53,245 +53,253 @@ bool reachMixesLimit()
|
||||
return false;
|
||||
}
|
||||
|
||||
class MixEditWindow : public Page {
|
||||
public:
|
||||
MixEditWindow(int8_t channel, uint8_t mixIndex) :
|
||||
Page(ICON_MODEL_MIXER),
|
||||
channel(channel),
|
||||
mixIndex(mixIndex)
|
||||
{
|
||||
buildBody(&body);
|
||||
buildHeader(&header);
|
||||
class MixEditWindow : public Page
|
||||
{
|
||||
public:
|
||||
MixEditWindow(int8_t channel, uint8_t mixIndex) :
|
||||
Page(ICON_MODEL_MIXER), channel(channel), mixIndex(mixIndex)
|
||||
{
|
||||
buildBody(&body);
|
||||
buildHeader(&header);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t channel;
|
||||
uint8_t mixIndex;
|
||||
FormGroup *curveParamField = nullptr;
|
||||
|
||||
void buildHeader(Window *window)
|
||||
{
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT,
|
||||
PAGE_LINE_HEIGHT},
|
||||
STR_MIXES, 0, MENU_COLOR);
|
||||
new StaticText(window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT},
|
||||
getSourceString(MIXSRC_CH1 + channel), 0, MENU_COLOR);
|
||||
}
|
||||
|
||||
void buildBody(FormWindow *window)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(8);
|
||||
|
||||
MixData *mix = mixAddress(mixIndex);
|
||||
|
||||
// Mix name
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXNAME);
|
||||
new RadioTextEdit(window, grid.getFieldSlot(), mix->name,
|
||||
sizeof(mix->name));
|
||||
grid.nextLine();
|
||||
|
||||
// Source
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SOURCE);
|
||||
new SourceChoice(window, grid.getFieldSlot(), 0, MIXSRC_LAST,
|
||||
GET_SET_DEFAULT(mix->srcRaw));
|
||||
grid.nextLine();
|
||||
|
||||
// Weight
|
||||
new StaticText(window, grid.getLabelSlot(), STR_WEIGHT);
|
||||
auto gvar =
|
||||
new GVarNumberEdit(window, grid.getFieldSlot(), MIX_WEIGHT_MIN,
|
||||
MIX_WEIGHT_MAX, GET_SET_DEFAULT(mix->weight));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
|
||||
// Offset
|
||||
new StaticText(window, grid.getLabelSlot(), STR_OFFSET);
|
||||
gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_OFFSET_MIN,
|
||||
MIX_OFFSET_MAX, GET_SET_DEFAULT(mix->offset));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
|
||||
// Trim
|
||||
new StaticText(window, grid.getLabelSlot(), STR_TRIM);
|
||||
new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(mix->carryTrim));
|
||||
grid.nextLine();
|
||||
|
||||
// Curve
|
||||
new StaticText(&body, grid.getLabelSlot(), STR_CURVE);
|
||||
new Choice(&body, grid.getFieldSlot(2, 0), "\004DiffExpoFuncCstm", 0,
|
||||
CURVE_REF_CUSTOM, GET_DEFAULT(mix->curve.type),
|
||||
[=](int32_t newValue) {
|
||||
mix->curve.type = newValue;
|
||||
mix->curve.value = 0;
|
||||
SET_DIRTY();
|
||||
updateCurveParamField(mix);
|
||||
});
|
||||
curveParamField =
|
||||
new FormGroup(&body, grid.getFieldSlot(2, 1), FORM_FORWARD_FOCUS);
|
||||
updateCurveParamField(mix);
|
||||
grid.nextLine();
|
||||
|
||||
// Flight modes
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FLMODE);
|
||||
for (uint8_t i = 0; i < MAX_FLIGHT_MODES; i++) {
|
||||
char fm[2] = {char('0' + i), '\0'};
|
||||
if (i > 0 && (i % 4) == 0) grid.nextLine();
|
||||
new TextButton(
|
||||
window, grid.getFieldSlot(4, i % 4), fm,
|
||||
[=]() -> uint8_t {
|
||||
BFBIT_FLIP(mix->flightModes, bfBit<uint8_t>(i));
|
||||
SET_DIRTY();
|
||||
return !(bfSingleBitGet(mix->flightModes, i));
|
||||
},
|
||||
OPAQUE | (bfSingleBitGet(mix->flightModes, i) ? 0 : BUTTON_CHECKED));
|
||||
}
|
||||
grid.nextLine();
|
||||
|
||||
protected:
|
||||
uint8_t channel;
|
||||
uint8_t mixIndex;
|
||||
FormGroup * curveParamField = nullptr;
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH);
|
||||
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST_IN_MIXES,
|
||||
SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(mix->swtch));
|
||||
grid.nextLine();
|
||||
|
||||
void buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, STR_MIXES, 0, MENU_COLOR);
|
||||
new StaticText(window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, PAGE_LINE_HEIGHT}, getSourceString(MIXSRC_CH1 + channel), 0, MENU_COLOR);
|
||||
}
|
||||
// Warning
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXWARNING);
|
||||
auto edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, 3,
|
||||
GET_SET_DEFAULT(mix->mixWarn));
|
||||
edit->setZeroText(STR_OFF);
|
||||
grid.nextLine();
|
||||
|
||||
void buildBody(FormWindow * window)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(8);
|
||||
// Multiplex
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MULTPX);
|
||||
new Choice(window, grid.getFieldSlot(), STR_VMLTPX, 0, 2,
|
||||
GET_SET_DEFAULT(mix->mltpx));
|
||||
grid.nextLine();
|
||||
|
||||
MixData * mix = mixAddress(mixIndex);
|
||||
// Delay up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYUP);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayUp),
|
||||
SET_VALUE(mix->delayUp, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Mix name
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXNAME);
|
||||
new RadioTextEdit(window, grid.getFieldSlot(), mix->name, sizeof(mix->name));
|
||||
grid.nextLine();
|
||||
// Delay down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYDOWN);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayDown),
|
||||
SET_VALUE(mix->delayDown, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Source
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SOURCE);
|
||||
new SourceChoice(window, grid.getFieldSlot(), 0, MIXSRC_LAST, GET_SET_DEFAULT(mix->srcRaw));
|
||||
grid.nextLine();
|
||||
// Slow up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWUP);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedUp),
|
||||
SET_VALUE(mix->speedUp, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Weight
|
||||
new StaticText(window, grid.getLabelSlot(), STR_WEIGHT);
|
||||
auto gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, GET_SET_DEFAULT(mix->weight));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
// Slow down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWDOWN);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedDown),
|
||||
SET_VALUE(mix->speedDown, newValue), 0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Offset
|
||||
new StaticText(window, grid.getLabelSlot(), STR_OFFSET);
|
||||
gvar = new GVarNumberEdit(window, grid.getFieldSlot(), MIX_OFFSET_MIN, MIX_OFFSET_MAX, GET_SET_DEFAULT(mix->offset));
|
||||
gvar->setSuffix("%");
|
||||
grid.nextLine();
|
||||
window->setInnerHeight(grid.getWindowHeight());
|
||||
}
|
||||
|
||||
// Trim
|
||||
new StaticText(window, grid.getLabelSlot(), STR_TRIM);
|
||||
new CheckBox(window, grid.getFieldSlot(), GET_SET_INVERTED(mix->carryTrim));
|
||||
grid.nextLine();
|
||||
// TODO share this code with INPUT
|
||||
void updateCurveParamField(MixData *line)
|
||||
{
|
||||
curveParamField->clear();
|
||||
|
||||
// Curve
|
||||
new StaticText(&body, grid.getLabelSlot(), STR_CURVE);
|
||||
new Choice(&body, grid.getFieldSlot(2, 0), "\004DiffExpoFuncCstm", 0, CURVE_REF_CUSTOM,
|
||||
GET_DEFAULT(mix->curve.type),
|
||||
[=](int32_t newValue) {
|
||||
mix->curve.type = newValue;
|
||||
mix->curve.value = 0;
|
||||
SET_DIRTY();
|
||||
updateCurveParamField(mix);
|
||||
});
|
||||
curveParamField = new FormGroup(&body, grid.getFieldSlot(2, 1), FORM_FORWARD_FOCUS);
|
||||
updateCurveParamField(mix);
|
||||
grid.nextLine();
|
||||
const rect_t rect = {0, 0, curveParamField->width(),
|
||||
curveParamField->height()};
|
||||
|
||||
// Flight modes
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FLMODE);
|
||||
for (uint8_t i = 0; i < MAX_FLIGHT_MODES; i++) {
|
||||
char fm[2] = {char('0' + i), '\0'};
|
||||
if (i > 0 && (i % 4) == 0)
|
||||
grid.nextLine();
|
||||
new TextButton(window, grid.getFieldSlot(4, i % 4), fm,
|
||||
[=]() -> uint8_t {
|
||||
BFBIT_FLIP(mix->flightModes, bfBit<uint8_t>(i));
|
||||
SET_DIRTY();
|
||||
return !(bfSingleBitGet(mix->flightModes, i));
|
||||
},
|
||||
OPAQUE | (bfSingleBitGet(mix->flightModes, i) ? 0 : BUTTON_CHECKED));
|
||||
switch (line->curve.type) {
|
||||
case CURVE_REF_DIFF:
|
||||
case CURVE_REF_EXPO: {
|
||||
GVarNumberEdit *edit =
|
||||
new GVarNumberEdit(curveParamField, rect, -100, 100,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
edit->setSuffix("%");
|
||||
break;
|
||||
}
|
||||
grid.nextLine();
|
||||
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH);
|
||||
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(mix->swtch));
|
||||
grid.nextLine();
|
||||
case CURVE_REF_FUNC:
|
||||
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
break;
|
||||
|
||||
// Warning
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MIXWARNING);
|
||||
auto edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, 3, GET_SET_DEFAULT(mix->mixWarn));
|
||||
edit->setZeroText(STR_OFF);
|
||||
grid.nextLine();
|
||||
|
||||
// Multiplex
|
||||
new StaticText(window, grid.getLabelSlot(), STR_MULTPX);
|
||||
new Choice(window, grid.getFieldSlot(), STR_VMLTPX, 0, 2, GET_SET_DEFAULT(mix->mltpx));
|
||||
grid.nextLine();
|
||||
|
||||
// Delay up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYUP);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayUp),
|
||||
SET_VALUE(mix->delayUp, newValue),
|
||||
0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Delay down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_DELAYDOWN);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->delayDown),
|
||||
SET_VALUE(mix->delayDown, newValue),
|
||||
0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Slow up
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWUP);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedUp),
|
||||
SET_VALUE(mix->speedUp, newValue),
|
||||
0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
// Slow down
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SLOWDOWN);
|
||||
edit = new NumberEdit(window, grid.getFieldSlot(2, 0), 0, DELAY_MAX,
|
||||
GET_DEFAULT(mix->speedDown),
|
||||
SET_VALUE(mix->speedDown, newValue),
|
||||
0, PREC1);
|
||||
edit->setSuffix("s");
|
||||
grid.nextLine();
|
||||
|
||||
window->setInnerHeight(grid.getWindowHeight());
|
||||
}
|
||||
|
||||
// TODO share this code with INPUT
|
||||
void updateCurveParamField(MixData * line)
|
||||
{
|
||||
curveParamField->clear();
|
||||
|
||||
const rect_t rect = {0, 0, curveParamField->width(), curveParamField->height()};
|
||||
|
||||
switch (line->curve.type) {
|
||||
case CURVE_REF_DIFF:
|
||||
case CURVE_REF_EXPO:
|
||||
{
|
||||
GVarNumberEdit * edit = new GVarNumberEdit(curveParamField, rect, -100, 100, GET_SET_DEFAULT(line->curve.value));
|
||||
edit->setSuffix("%");
|
||||
break;
|
||||
}
|
||||
|
||||
case CURVE_REF_FUNC:
|
||||
new Choice(curveParamField, rect, STR_VCURVEFUNC, 0, CURVE_BASE - 1, GET_SET_DEFAULT(line->curve.value));
|
||||
break;
|
||||
|
||||
case CURVE_REF_CUSTOM:
|
||||
{
|
||||
auto choice = new Choice(curveParamField, rect, -MAX_CURVES, MAX_CURVES, GET_SET_DEFAULT(line->curve.value));
|
||||
choice->setTextHandler([](int value) {
|
||||
return getCurveString(value);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case CURVE_REF_CUSTOM: {
|
||||
auto choice = new Choice(curveParamField, rect, -MAX_CURVES, MAX_CURVES,
|
||||
GET_SET_DEFAULT(line->curve.value));
|
||||
choice->setTextHandler([](int value) { return getCurveString(value); });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class MixLineButton : public CommonInputOrMixButton {
|
||||
public:
|
||||
MixLineButton(FormGroup * parent, const rect_t & rect, uint8_t index) :
|
||||
class MixLineButton : public CommonInputOrMixButton
|
||||
{
|
||||
public:
|
||||
MixLineButton(FormGroup *parent, const rect_t &rect, uint8_t index) :
|
||||
CommonInputOrMixButton(parent, rect, index)
|
||||
{
|
||||
const MixData & mix = g_model.mixData[index];
|
||||
if (mix.swtch || mix.curve.value != 0 || mix.flightModes) {
|
||||
setHeight(height() + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP);
|
||||
}
|
||||
{
|
||||
const MixData &mix = g_model.mixData[index];
|
||||
if (mix.swtch || mix.curve.value != 0 || mix.flightModes) {
|
||||
setHeight(height() + PAGE_LINE_HEIGHT + FIELD_PADDING_TOP);
|
||||
}
|
||||
}
|
||||
|
||||
bool isActive() const override { return isMixActive(index); }
|
||||
|
||||
void paintBody(BitmapBuffer *dc) override
|
||||
{
|
||||
const MixData &line = g_model.mixData[index];
|
||||
|
||||
LcdFlags textColor = DEFAULT_COLOR;
|
||||
|
||||
// first line ...
|
||||
drawValueOrGVar(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, line.weight,
|
||||
MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, textColor);
|
||||
drawSource(dc, 60, FIELD_PADDING_TOP, line.srcRaw, textColor);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, FIELD_PADDING_TOP, mixerSetupLabelIcon, textColor);
|
||||
dc->drawSizedText(166, FIELD_PADDING_TOP, line.name, sizeof(line.name),
|
||||
textColor);
|
||||
}
|
||||
|
||||
bool isActive() const override
|
||||
{
|
||||
return isMixActive(index);
|
||||
// second line ...
|
||||
if (line.swtch) {
|
||||
dc->drawMask(3, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP,
|
||||
mixerSetupSwitchIcon, textColor);
|
||||
drawSwitch(dc, 21, PAGE_LINE_HEIGHT + FIELD_PADDING_TOP, line.swtch,
|
||||
textColor);
|
||||
}
|
||||
|
||||
void paintBody(BitmapBuffer * dc) override
|
||||
{
|
||||
const MixData & line = g_model.mixData[index];
|
||||
|
||||
LcdFlags textColor = DEFAULT_COLOR;
|
||||
if (hasFocus())
|
||||
textColor = FOCUS_COLOR;
|
||||
|
||||
// first line ...
|
||||
drawValueOrGVar(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, line.weight,
|
||||
MIX_WEIGHT_MIN, MIX_WEIGHT_MAX, textColor);
|
||||
drawSource(dc, 60, FIELD_PADDING_TOP, line.srcRaw, textColor);
|
||||
|
||||
if (line.name[0]) {
|
||||
dc->drawMask(146, FIELD_PADDING_TOP, mixerSetupLabelIcon, textColor);
|
||||
dc->drawSizedText(166, FIELD_PADDING_TOP, line.name, sizeof(line.name),
|
||||
textColor);
|
||||
}
|
||||
|
||||
// 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,
|
||||
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.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);
|
||||
}
|
||||
}
|
||||
|
||||
if (line.flightModes) {
|
||||
drawFlightModes(dc, line.flightModes, textColor);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void insertMix(uint8_t idx, uint8_t channel)
|
||||
{
|
||||
pauseMixerCalculations();
|
||||
MixData * mix = mixAddress(idx);
|
||||
MixData *mix = mixAddress(idx);
|
||||
memmove(mix + 1, mix, (MAX_MIXERS - (idx + 1)) * sizeof(MixData));
|
||||
memclear(mix, sizeof(MixData));
|
||||
mix->destCh = channel;
|
||||
mix->srcRaw = channel + 1;
|
||||
if (!isSourceAvailable(mix->srcRaw)) {
|
||||
mix->srcRaw = (channel > 3 ? MIXSRC_Rud - 1 + channel : MIXSRC_Rud - 1 + channelOrder(channel));
|
||||
mix->srcRaw = (channel > 3 ? MIXSRC_Rud - 1 + channel
|
||||
: MIXSRC_Rud - 1 + channelOrder(channel));
|
||||
while (!isSourceAvailable(mix->srcRaw)) {
|
||||
mix->srcRaw += 1;
|
||||
}
|
||||
@@ -339,15 +347,15 @@ void ModelMixesPage::build(FormWindow * window, int8_t focusMixIndex)
|
||||
MixData * mix = g_model.mixData;
|
||||
for (uint8_t ch = 0; ch < MAX_OUTPUT_CHANNELS; ch++) {
|
||||
if (mixIndex < MAX_MIXERS && mix->srcRaw > 0 && mix->destCh == ch) {
|
||||
|
||||
coord_t h = grid.getWindowHeight();
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_CH1 + ch), 0,
|
||||
CENTERED);
|
||||
txt->setBackgroundColor(FIELD_BGCOLOR);
|
||||
getSourceString(MIXSRC_CH1 + ch),
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
uint8_t count = 0;
|
||||
while (mixIndex < MAX_MIXERS && mix->srcRaw > 0 && mix->destCh == ch) {
|
||||
Button * button = new MixLineButton(window, grid.getFieldSlot(), mixIndex);
|
||||
if (focusMixIndex == mixIndex)
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
button->setPressHandler([=]() -> uint8_t {
|
||||
button->bringToTop();
|
||||
Menu * menu = new Menu(window);
|
||||
@@ -396,16 +404,38 @@ void ModelMixesPage::build(FormWindow * window, int8_t focusMixIndex)
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
if (count++ > 0) {
|
||||
new StaticBitmap(window, {35, button->top() + (button->height() - 18) / 2, 25, 17}, mixerMultiplexBitmap[mix->mltpx]);
|
||||
if (focusMixIndex == mixIndex) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
grid.spacer(button->height() - 2);
|
||||
if (count++ > 0) {
|
||||
new StaticBitmap(
|
||||
window, {35, button->top() + (button->height() - 18) / 2, 25, 17},
|
||||
mixerMultiplexBitmap[mix->mltpx]);
|
||||
}
|
||||
|
||||
grid.spacer(button->height() - 1);
|
||||
++mixIndex;
|
||||
++mix;
|
||||
}
|
||||
|
||||
h = grid.getWindowHeight() - h + 1;
|
||||
txt->setHeight(h);
|
||||
|
||||
grid.spacer(7);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -129,11 +129,6 @@ class OutputLineButton : public Button {
|
||||
LcdFlags textColor = DEFAULT_COLOR;
|
||||
LcdFlags bgColor = FIELD_BGCOLOR;
|
||||
|
||||
if (hasFocus()) {
|
||||
textColor = FOCUS_COLOR;
|
||||
bgColor = FOCUS_BGCOLOR;
|
||||
}
|
||||
|
||||
dc->drawSolidFilledRect(0, 0, width(), height(), bgColor);
|
||||
|
||||
// first line
|
||||
@@ -165,8 +160,10 @@ class OutputLineButton : public Button {
|
||||
}
|
||||
|
||||
// bounding rect
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2,
|
||||
hasFocus() ? FOCUS_BGCOLOR : FIELD_FRAME_COLOR);
|
||||
if (hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -197,9 +194,8 @@ void ModelOutputsPage::build(FormWindow * window, int8_t focusChannel)
|
||||
|
||||
// Channel label
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(),
|
||||
getSourceString(MIXSRC_CH1 + ch), 0,
|
||||
CENTERED);
|
||||
txt->setBackgroundColor(FIELD_BGCOLOR);
|
||||
getSourceString(MIXSRC_CH1 + ch),
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
// Channel settings
|
||||
Button * button = new OutputLineButton(window, grid.getFieldSlot(), output);
|
||||
@@ -231,11 +227,25 @@ void ModelOutputsPage::build(FormWindow * window, int8_t focusChannel)
|
||||
});
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
if (focusChannel == ch) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
txt->setHeight(button->height());
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class ModelOutputsPage: public PageTab {
|
||||
|
||||
virtual void build(FormWindow * window) override
|
||||
{
|
||||
build(window, -1);
|
||||
build(window, 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -24,235 +24,301 @@
|
||||
|
||||
#define SET_DIRTY() storageDirty(functions == g_model.customFn ? EE_MODEL : EE_GENERAL)
|
||||
|
||||
class SpecialFunctionEditPage : public Page {
|
||||
public:
|
||||
SpecialFunctionEditPage(CustomFunctionData * functions, uint8_t index) :
|
||||
Page(functions == g_model.customFn ? ICON_MODEL_SPECIAL_FUNCTIONS : ICON_RADIO_GLOBAL_FUNCTIONS),
|
||||
class SpecialFunctionEditPage : public Page
|
||||
{
|
||||
public:
|
||||
SpecialFunctionEditPage(CustomFunctionData *functions, uint8_t index) :
|
||||
Page(functions == g_model.customFn ? ICON_MODEL_SPECIAL_FUNCTIONS
|
||||
: ICON_RADIO_GLOBAL_FUNCTIONS),
|
||||
functions(functions),
|
||||
index(index)
|
||||
{
|
||||
buildHeader(&header);
|
||||
buildBody(&body);
|
||||
{
|
||||
buildHeader(&header);
|
||||
buildBody(&body);
|
||||
}
|
||||
|
||||
protected:
|
||||
CustomFunctionData *functions;
|
||||
uint8_t index;
|
||||
FormGroup *specialFunctionOneWindow = nullptr;
|
||||
StaticText *headerSF = nullptr;
|
||||
bool active = false;
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return ((functions == g_model.customFn
|
||||
? modelFunctionsContext.activeSwitches
|
||||
: globalFunctionsContext.activeSwitches) &
|
||||
((MASK_CFN_TYPE)1 << index)
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Page::checkEvents();
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
headerSF->setTextFlags(isActive() ? FONT(BOLD) | HIGHLIGHT_COLOR
|
||||
: MENU_COLOR);
|
||||
active = !active;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
CustomFunctionData * functions;
|
||||
uint8_t index;
|
||||
FormGroup * specialFunctionOneWindow = nullptr;
|
||||
StaticText * headerSF = nullptr;
|
||||
bool active = false;
|
||||
void buildHeader(Window *window)
|
||||
{
|
||||
new StaticText(
|
||||
window, {PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, 20},
|
||||
functions == g_model.customFn ? STR_MENUCUSTOMFUNC
|
||||
: STR_MENUSPECIALFUNCS,
|
||||
0, MENU_COLOR);
|
||||
headerSF = new StaticText(
|
||||
window,
|
||||
{PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT,
|
||||
LCD_W - PAGE_TITLE_LEFT, 20},
|
||||
(functions == g_model.customFn ? "SF" : "GF") + std::to_string(index),
|
||||
0, MENU_COLOR);
|
||||
}
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return ((functions == g_model.customFn ? modelFunctionsContext.activeSwitches : globalFunctionsContext.activeSwitches) & ((MASK_CFN_TYPE)1 << index) ? 1 : 0);
|
||||
}
|
||||
void updateSpecialFunctionOneWindow()
|
||||
{
|
||||
FormGridLayout grid;
|
||||
specialFunctionOneWindow->clear();
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Page::checkEvents();
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
headerSF->setTextFlags(isActive() ? FONT(BOLD) |HIGHLIGHT_COLOR : MENU_COLOR);
|
||||
active = !active;
|
||||
}
|
||||
}
|
||||
CustomFunctionData *cfn = &functions[index];
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
|
||||
void buildHeader(Window * window)
|
||||
{
|
||||
new StaticText(window, { PAGE_TITLE_LEFT, PAGE_TITLE_TOP, LCD_W - PAGE_TITLE_LEFT, 20 }, functions == g_model.customFn ? STR_MENUCUSTOMFUNC : STR_MENUSPECIALFUNCS, 0, MENU_COLOR);
|
||||
headerSF = new StaticText(window, { PAGE_TITLE_LEFT, PAGE_TITLE_TOP + PAGE_LINE_HEIGHT, LCD_W - PAGE_TITLE_LEFT, 20 }, (functions == g_model.customFn ? "SF" : "GF" ) + std::to_string(index), 0, MENU_COLOR);
|
||||
}
|
||||
|
||||
void updateSpecialFunctionOneWindow()
|
||||
{
|
||||
FormGridLayout grid;
|
||||
specialFunctionOneWindow->clear();
|
||||
|
||||
CustomFunctionData * cfn = &functions[index];
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
|
||||
// Func param
|
||||
switch (func) {
|
||||
case FUNC_OVERRIDE_CHANNEL:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_CH);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 1, MAX_OUTPUT_CHANNELS, GET_SET_VALUE_WITH_OFFSET(CFN_CH_INDEX(cfn), 1));
|
||||
grid.nextLine();
|
||||
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), -100, 100, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_TRAINER: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
auto choice = new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0,NUM_STICKS + 1,GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
choice->setTextHandler([=](int32_t value) {
|
||||
if (value == 0)
|
||||
return std::string(STR_STICKS);
|
||||
else if (value == NUM_STICKS + 1)
|
||||
return std::string(STR_CHANS);
|
||||
else
|
||||
return TEXT_AT_INDEX(STR_VSRCRAW, value);;
|
||||
});
|
||||
grid.nextLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case FUNC_RESET:
|
||||
if (CFN_PARAM(cfn) < FUNC_RESET_PARAM_FIRST_TELEM) {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_RESET);
|
||||
auto choice = new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
FUNC_RESET_PARAM_FIRST_TELEM + lastUsedTelemetryIndex(),
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
choice->setAvailableHandler(isSourceAvailableInResetSpecialFunction);
|
||||
choice->setTextHandler([=](int32_t value) {
|
||||
if (value < FUNC_RESET_PARAM_FIRST_TELEM)
|
||||
return TEXT_AT_INDEX(STR_VFSWRESET, value);
|
||||
else
|
||||
return std::string(g_model.telemetrySensors[value - FUNC_RESET_PARAM_FIRST_TELEM].label, TELEM_LABEL_LEN);
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
break;
|
||||
|
||||
case FUNC_VOLUME:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VOLUME);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0, MIXSRC_LAST_CH, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_BACKLIGHT:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0, MIXSRC_LAST_CH, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_SOUND:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(), STR_FUNCSOUNDS, 0,
|
||||
AU_SPECIAL_SOUND_LAST - AU_SPECIAL_SOUND_FIRST - 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_TRACK:
|
||||
case FUNC_BACKGND_MUSIC:
|
||||
case FUNC_PLAY_SCRIPT:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new FileChoice(specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
func == FUNC_PLAY_SCRIPT ? SCRIPTS_FUNCS_PATH : std::string(SOUNDS_PATH, SOUNDS_PATH_LNG_OFS) +
|
||||
std::string(currentLanguagePack->id, 2),
|
||||
func == FUNC_PLAY_SCRIPT ? SCRIPTS_EXT : SOUNDS_EXT,
|
||||
sizeof(cfn->play.name),
|
||||
[=]() {
|
||||
return std::string(cfn->play.name, ZLEN(cfn->play.name));
|
||||
},
|
||||
[=](std::string newValue) {
|
||||
strncpy(cfn->play.name, newValue.c_str(), sizeof(cfn->play.name));
|
||||
SET_DIRTY();
|
||||
}, true); // strip extension
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_SET_TIMER: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_TIMER);
|
||||
auto timerchoice = new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0, TIMERS - 1, GET_SET_DEFAULT(CFN_TIMER_INDEX(cfn)));
|
||||
timerchoice->setTextHandler([](int32_t value) {
|
||||
return std::string(STR_TIMER) + std::to_string(value + 1);
|
||||
});
|
||||
grid.nextLine();
|
||||
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new TimeEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0, 9 * 60 * 60 - 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case FUNC_SET_FAILSAFE:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_MODULE);
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(), "\004Int.Ext.", 0, NUM_MODULES - 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_VALUE:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0, MIXSRC_LAST_TELEM, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_HAPTIC:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0, 3, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_LOGS: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_VALUE);
|
||||
auto edit = new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0, 255, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
edit->setDisplayHandler([=](BitmapBuffer * dc, LcdFlags flags, int32_t value) {
|
||||
dc->drawNumber(2, 2, CFN_PARAM(cfn), PREC1, sizeof(CFN_PARAM(cfn)), nullptr, "s");
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (HAS_ENABLE_PARAM(func)) {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_ENABLE);
|
||||
new CheckBox(specialFunctionOneWindow, grid.getFieldSlot(), GET_SET_DEFAULT(CFN_ACTIVE(cfn)));
|
||||
// Func param
|
||||
switch (func) {
|
||||
case FUNC_OVERRIDE_CHANNEL:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_CH);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 1,
|
||||
MAX_OUTPUT_CHANNELS,
|
||||
GET_SET_VALUE_WITH_OFFSET(CFN_CH_INDEX(cfn), 1));
|
||||
grid.nextLine();
|
||||
}
|
||||
else if (HAS_REPEAT_PARAM(func)) { // !1x 1x 1s 2s 3s ...
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_REPEAT);
|
||||
auto repeat = new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(2, 1), -1, 60/CFN_PLAY_REPEAT_MUL, GET_SET_DEFAULT(CFN_PLAY_REPEAT(cfn)));
|
||||
repeat->setDisplayHandler([](BitmapBuffer * dc, LcdFlags flags, int32_t value) {
|
||||
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), -100, 100,
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_TRAINER: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
auto choice =
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
NUM_STICKS + 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
choice->setTextHandler([=](int32_t value) {
|
||||
if (value == 0)
|
||||
dc->drawText(3, 0, "1x", flags);
|
||||
else if (value == CFN_PLAY_REPEAT_NOSTART)
|
||||
dc->drawText(3, 0, "!1x", flags);
|
||||
return std::string(STR_STICKS);
|
||||
else if (value == NUM_STICKS + 1)
|
||||
return std::string(STR_CHANS);
|
||||
else
|
||||
dc->drawNumber(3, 0, value * CFN_PLAY_REPEAT_MUL, flags, 0, nullptr, "s");
|
||||
return TEXT_AT_INDEX(STR_VSRCRAW, value);
|
||||
;
|
||||
});
|
||||
grid.nextLine();
|
||||
break;
|
||||
}
|
||||
|
||||
specialFunctionOneWindow->adjustHeight();
|
||||
case FUNC_RESET:
|
||||
if (CFN_PARAM(cfn) < FUNC_RESET_PARAM_FIRST_TELEM) {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_RESET);
|
||||
auto choice = new Choice(
|
||||
specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
FUNC_RESET_PARAM_FIRST_TELEM + lastUsedTelemetryIndex(),
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
choice->setAvailableHandler(isSourceAvailableInResetSpecialFunction);
|
||||
choice->setTextHandler([=](int32_t value) {
|
||||
if (value < FUNC_RESET_PARAM_FIRST_TELEM)
|
||||
return TEXT_AT_INDEX(STR_VFSWRESET, value);
|
||||
else
|
||||
return std::string(
|
||||
g_model.telemetrySensors[value - FUNC_RESET_PARAM_FIRST_TELEM]
|
||||
.label,
|
||||
TELEM_LABEL_LEN);
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
break;
|
||||
|
||||
case FUNC_VOLUME:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VOLUME);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
MIXSRC_LAST_CH, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_BACKLIGHT:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
MIXSRC_LAST_CH, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_SOUND:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
STR_FUNCSOUNDS, 0,
|
||||
AU_SPECIAL_SOUND_LAST - AU_SPECIAL_SOUND_FIRST - 1,
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_TRACK:
|
||||
case FUNC_BACKGND_MUSIC:
|
||||
case FUNC_PLAY_SCRIPT:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new FileChoice(
|
||||
specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
func == FUNC_PLAY_SCRIPT
|
||||
? SCRIPTS_FUNCS_PATH
|
||||
: std::string(SOUNDS_PATH, SOUNDS_PATH_LNG_OFS) +
|
||||
std::string(currentLanguagePack->id, 2),
|
||||
func == FUNC_PLAY_SCRIPT ? SCRIPTS_EXT : SOUNDS_EXT,
|
||||
sizeof(cfn->play.name),
|
||||
[=]() { return std::string(cfn->play.name, ZLEN(cfn->play.name)); },
|
||||
[=](std::string newValue) {
|
||||
strncpy(cfn->play.name, newValue.c_str(), sizeof(cfn->play.name));
|
||||
SET_DIRTY();
|
||||
},
|
||||
true); // strip extension
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_SET_TIMER: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_TIMER);
|
||||
auto timerchoice =
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
TIMERS - 1, GET_SET_DEFAULT(CFN_TIMER_INDEX(cfn)));
|
||||
timerchoice->setTextHandler([](int32_t value) {
|
||||
return std::string(STR_TIMER) + std::to_string(value + 1);
|
||||
});
|
||||
grid.nextLine();
|
||||
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new TimeEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
9 * 60 * 60 - 1, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case FUNC_SET_FAILSAFE:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_MODULE);
|
||||
new Choice(specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
"\004Int.Ext.", 0, NUM_MODULES - 1,
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_VALUE:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new SourceChoice(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
MIXSRC_LAST_TELEM, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_HAPTIC:
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0, 3,
|
||||
GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
grid.nextLine();
|
||||
break;
|
||||
|
||||
case FUNC_LOGS: {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(),
|
||||
STR_VALUE);
|
||||
auto edit =
|
||||
new NumberEdit(specialFunctionOneWindow, grid.getFieldSlot(), 0,
|
||||
255, GET_SET_DEFAULT(CFN_PARAM(cfn)));
|
||||
edit->setDisplayHandler(
|
||||
[=](BitmapBuffer *dc, LcdFlags flags, int32_t value) {
|
||||
dc->drawNumber(2, 2, CFN_PARAM(cfn), PREC1,
|
||||
sizeof(CFN_PARAM(cfn)), nullptr, "s");
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void buildBody(FormWindow * window)
|
||||
{
|
||||
// SF.one
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
|
||||
CustomFunctionData * cfn = &functions[index];
|
||||
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH);
|
||||
auto switchChoice = new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST, SWSRC_LAST, GET_SET_DEFAULT(CFN_SWITCH(cfn)));
|
||||
switchChoice->setAvailableHandler([=](int value) {
|
||||
return (functions == g_model.customFn ? isSwitchAvailable(value, ModelCustomFunctionsContext)
|
||||
: isSwitchAvailable(value,
|
||||
GeneralCustomFunctionsContext));
|
||||
});
|
||||
if (HAS_ENABLE_PARAM(func)) {
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_ENABLE);
|
||||
new CheckBox(specialFunctionOneWindow, grid.getFieldSlot(),
|
||||
GET_SET_DEFAULT(CFN_ACTIVE(cfn)));
|
||||
grid.nextLine();
|
||||
|
||||
// Function
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FUNC);
|
||||
auto functionChoice = new Choice(window, grid.getFieldSlot(), STR_VFSWFUNC, 0, FUNC_MAX - 1, GET_DEFAULT(CFN_FUNC(cfn)));
|
||||
functionChoice->setSetValueHandler([=](int32_t newValue) {
|
||||
CFN_FUNC(cfn) = newValue;
|
||||
CFN_RESET(cfn);
|
||||
SET_DIRTY();
|
||||
updateSpecialFunctionOneWindow();
|
||||
});
|
||||
functionChoice->setAvailableHandler([=](int value) {
|
||||
return isAssignableFunctionAvailable(value, functions);
|
||||
});
|
||||
} else if (HAS_REPEAT_PARAM(func)) { // !1x 1x 1s 2s 3s ...
|
||||
new StaticText(specialFunctionOneWindow, grid.getLabelSlot(), STR_REPEAT);
|
||||
auto repeat = new NumberEdit(
|
||||
specialFunctionOneWindow, grid.getFieldSlot(2, 1), -1,
|
||||
60 / CFN_PLAY_REPEAT_MUL, GET_SET_DEFAULT(CFN_PLAY_REPEAT(cfn)));
|
||||
repeat->setDisplayHandler(
|
||||
[](BitmapBuffer *dc, LcdFlags flags, int32_t value) {
|
||||
if (value == 0)
|
||||
dc->drawText(3, 0, "1x", flags);
|
||||
else if (value == CFN_PLAY_REPEAT_NOSTART)
|
||||
dc->drawText(3, 0, "!1x", flags);
|
||||
else
|
||||
dc->drawNumber(3, 0, value * CFN_PLAY_REPEAT_MUL, flags, 0,
|
||||
nullptr, "s");
|
||||
});
|
||||
grid.nextLine();
|
||||
}
|
||||
|
||||
specialFunctionOneWindow = new FormGroup(window, {0, grid.getWindowHeight(), LCD_W, 0}, FORM_FORWARD_FOCUS);
|
||||
specialFunctionOneWindow->adjustHeight();
|
||||
}
|
||||
|
||||
void buildBody(FormWindow *window)
|
||||
{
|
||||
// SF.one
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
|
||||
CustomFunctionData *cfn = &functions[index];
|
||||
|
||||
// Switch
|
||||
new StaticText(window, grid.getLabelSlot(), STR_SWITCH);
|
||||
auto switchChoice =
|
||||
new SwitchChoice(window, grid.getFieldSlot(), SWSRC_FIRST, SWSRC_LAST,
|
||||
GET_SET_DEFAULT(CFN_SWITCH(cfn)));
|
||||
switchChoice->setAvailableHandler([=](int value) {
|
||||
return (functions == g_model.customFn
|
||||
? isSwitchAvailable(value, ModelCustomFunctionsContext)
|
||||
: isSwitchAvailable(value, GeneralCustomFunctionsContext));
|
||||
});
|
||||
grid.nextLine();
|
||||
|
||||
// Function
|
||||
new StaticText(window, grid.getLabelSlot(), STR_FUNC);
|
||||
auto functionChoice =
|
||||
new Choice(window, grid.getFieldSlot(), STR_VFSWFUNC, 0, FUNC_MAX - 1,
|
||||
GET_DEFAULT(CFN_FUNC(cfn)));
|
||||
functionChoice->setSetValueHandler([=](int32_t newValue) {
|
||||
CFN_FUNC(cfn) = newValue;
|
||||
CFN_RESET(cfn);
|
||||
SET_DIRTY();
|
||||
updateSpecialFunctionOneWindow();
|
||||
grid.addWindow(specialFunctionOneWindow);
|
||||
}
|
||||
});
|
||||
functionChoice->setAvailableHandler([=](int value) {
|
||||
return isAssignableFunctionAvailable(value, functions);
|
||||
});
|
||||
grid.nextLine();
|
||||
|
||||
specialFunctionOneWindow = new FormGroup(
|
||||
window, {0, grid.getWindowHeight(), LCD_W, 0}, FORM_FORWARD_FOCUS);
|
||||
updateSpecialFunctionOneWindow();
|
||||
grid.addWindow(specialFunctionOneWindow);
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr coord_t line1 = FIELD_PADDING_TOP;
|
||||
@@ -261,161 +327,178 @@ static constexpr coord_t col1 = 20;
|
||||
static constexpr coord_t col2 = (LCD_W - 100) / 3 + col1;
|
||||
static constexpr coord_t col3 = ((LCD_W - 100) / 3) * 2 + col1 + 20;
|
||||
|
||||
class SpecialFunctionButton : public Button {
|
||||
public:
|
||||
SpecialFunctionButton(FormWindow * parent, const rect_t &rect, CustomFunctionData * functions, uint8_t index) :
|
||||
Button(parent, rect),
|
||||
functions(functions),
|
||||
index(index)
|
||||
{
|
||||
const CustomFunctionData * cfn = &functions[index];
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
if (!cfn->isEmpty() &&
|
||||
(HAS_ENABLE_PARAM(func) || HAS_REPEAT_PARAM(func) || (func == FUNC_PLAY_TRACK || func == FUNC_BACKGND_MUSIC || func == FUNC_PLAY_SCRIPT))) {
|
||||
setHeight(line2 + PAGE_LINE_HEIGHT);
|
||||
}
|
||||
class SpecialFunctionButton : public Button
|
||||
{
|
||||
public:
|
||||
SpecialFunctionButton(FormWindow *parent, const rect_t &rect,
|
||||
CustomFunctionData *functions, uint8_t index) :
|
||||
Button(parent, rect), functions(functions), index(index)
|
||||
{
|
||||
const CustomFunctionData *cfn = &functions[index];
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
if (!cfn->isEmpty() &&
|
||||
(HAS_ENABLE_PARAM(func) || HAS_REPEAT_PARAM(func) ||
|
||||
(func == FUNC_PLAY_TRACK || func == FUNC_BACKGND_MUSIC ||
|
||||
func == FUNC_PLAY_SCRIPT))) {
|
||||
setHeight(line2 + PAGE_LINE_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "SpecialFunctionButton";
|
||||
}
|
||||
std::string getName() const override { return "SpecialFunctionButton"; }
|
||||
#endif
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return ((functions == g_model.customFn ? modelFunctionsContext.activeSwitches : globalFunctionsContext.activeSwitches) & ((MASK_CFN_TYPE)1 << index) ? 1 : 0);
|
||||
bool isActive() const
|
||||
{
|
||||
return ((functions == g_model.customFn
|
||||
? modelFunctionsContext.activeSwitches
|
||||
: globalFunctionsContext.activeSwitches) &
|
||||
((MASK_CFN_TYPE)1 << index)
|
||||
? 1
|
||||
: 0);
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Button::checkEvents();
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
active = !active;
|
||||
}
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Button::checkEvents();
|
||||
if (active != isActive()) {
|
||||
invalidate();
|
||||
active = !active;
|
||||
}
|
||||
void paintSpecialFunctionLine(BitmapBuffer *dc)
|
||||
{
|
||||
const CustomFunctionData *cfn = &functions[index];
|
||||
if (functions[index].func == FUNC_OVERRIDE_CHANNEL &&
|
||||
functions != g_model.customFn) {
|
||||
functions[index].func = FUNC_OVERRIDE_CHANNEL + 1;
|
||||
}
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
|
||||
void paintSpecialFunctionLine(BitmapBuffer * dc)
|
||||
{
|
||||
const CustomFunctionData * cfn = &functions[index];
|
||||
if (functions[index].func == FUNC_OVERRIDE_CHANNEL && functions != g_model.customFn) {
|
||||
functions[index].func = FUNC_OVERRIDE_CHANNEL + 1;
|
||||
}
|
||||
uint8_t func = CFN_FUNC(cfn);
|
||||
drawSwitch(dc, col1, line1, CFN_SWITCH(cfn), 0);
|
||||
if (cfn->isEmpty()) return;
|
||||
|
||||
drawSwitch(dc, col1, line1, CFN_SWITCH(cfn), 0);
|
||||
if (cfn->isEmpty())
|
||||
return;
|
||||
dc->drawTextAtIndex(col2, line1, STR_VFSWFUNC, func, 0);
|
||||
int16_t val_min = 0;
|
||||
int16_t val_max = 255;
|
||||
|
||||
dc->drawTextAtIndex(col2, line1, STR_VFSWFUNC, func, 0);
|
||||
int16_t val_min = 0;
|
||||
int16_t val_max = 255;
|
||||
switch (func) {
|
||||
case FUNC_OVERRIDE_CHANNEL:
|
||||
drawChn(dc, col1, line2, CFN_CH_INDEX(cfn) + 1, 0);
|
||||
getMixSrcRange(MIXSRC_FIRST_CH, val_min, val_max);
|
||||
dc->drawNumber(col2, line2, CFN_PARAM(cfn));
|
||||
break;
|
||||
|
||||
switch (func) {
|
||||
case FUNC_OVERRIDE_CHANNEL:
|
||||
drawChn(dc, col1, line2, CFN_CH_INDEX(cfn) + 1, 0);
|
||||
getMixSrcRange(MIXSRC_FIRST_CH, val_min, val_max);
|
||||
dc->drawNumber(col2, line2, CFN_PARAM(cfn));
|
||||
break;
|
||||
case FUNC_TRAINER:
|
||||
drawSource(
|
||||
dc, col1, line2,
|
||||
CFN_CH_INDEX(cfn) == 0 ? 0 : MIXSRC_Rud + CFN_CH_INDEX(cfn) - 1);
|
||||
break;
|
||||
|
||||
case FUNC_TRAINER:
|
||||
drawSource(dc, col1, line2, CFN_CH_INDEX(cfn) == 0 ? 0 : MIXSRC_Rud + CFN_CH_INDEX(cfn) - 1);
|
||||
break;
|
||||
|
||||
case FUNC_RESET:
|
||||
if (CFN_PARAM(cfn) < FUNC_RESET_PARAM_FIRST_TELEM) {
|
||||
dc->drawTextAtIndex(col1, line2, STR_VFSWRESET, CFN_PARAM(cfn));
|
||||
}
|
||||
else {
|
||||
TelemetrySensor * sensor = &g_model.telemetrySensors[CFN_PARAM(cfn) - FUNC_RESET_PARAM_FIRST_TELEM];
|
||||
dc->drawSizedText(col1, line2, sensor->label, TELEM_LABEL_LEN);
|
||||
}
|
||||
break;
|
||||
|
||||
case FUNC_VOLUME:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_BACKLIGHT:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_SOUND:
|
||||
dc->drawTextAtIndex(col1, line2, STR_FUNCSOUNDS, CFN_PARAM(cfn));
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_TRACK:
|
||||
case FUNC_BACKGND_MUSIC:
|
||||
case FUNC_PLAY_SCRIPT:
|
||||
if (ZEXIST(cfn->play.name))
|
||||
dc->drawSizedText(col1, line2, cfn->play.name, sizeof(cfn->play.name), 0);
|
||||
else
|
||||
dc->drawTextAtIndex(col1, line2, STR_VCSWFUNC, 0, 0);
|
||||
break;
|
||||
|
||||
case FUNC_SET_TIMER:
|
||||
drawStringWithIndex(dc, col1, line2, STR_TIMER, CFN_TIMER_INDEX(cfn) + 1, 0);
|
||||
break;
|
||||
|
||||
case FUNC_SET_FAILSAFE:
|
||||
dc->drawTextAtIndex(col1, line2, "\004Int.Ext.", CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_VALUE:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_HAPTIC:
|
||||
dc->drawNumber(col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_LOGS:
|
||||
dc->drawNumber(col3, line1, CFN_PARAM(cfn), PREC1, sizeof(CFN_PARAM(cfn)), nullptr, "s");
|
||||
break;
|
||||
}
|
||||
if (HAS_ENABLE_PARAM(func)) {
|
||||
theme->drawCheckBox(dc, CFN_ACTIVE(cfn), col3, line2);
|
||||
}
|
||||
else if (HAS_REPEAT_PARAM(func)) {
|
||||
if (CFN_PLAY_REPEAT(cfn) == 0) {
|
||||
dc->drawText(col3, line2, "1x", 0);
|
||||
}
|
||||
else if (CFN_PLAY_REPEAT(cfn) == CFN_PLAY_REPEAT_NOSTART) {
|
||||
dc->drawText(col3, line2, "!1x", 0);
|
||||
}
|
||||
else {
|
||||
dc->drawNumber(col3 + 12, line2, CFN_PLAY_REPEAT(cfn) * CFN_PLAY_REPEAT_MUL, 0 | RIGHT, 0, nullptr, "s");
|
||||
case FUNC_RESET:
|
||||
if (CFN_PARAM(cfn) < FUNC_RESET_PARAM_FIRST_TELEM) {
|
||||
dc->drawTextAtIndex(col1, line2, STR_VFSWRESET, CFN_PARAM(cfn));
|
||||
} else {
|
||||
TelemetrySensor *sensor =
|
||||
&g_model.telemetrySensors[CFN_PARAM(cfn) -
|
||||
FUNC_RESET_PARAM_FIRST_TELEM];
|
||||
dc->drawSizedText(col1, line2, sensor->label, TELEM_LABEL_LEN);
|
||||
}
|
||||
break;
|
||||
|
||||
case FUNC_VOLUME:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_BACKLIGHT:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_SOUND:
|
||||
dc->drawTextAtIndex(col1, line2, STR_FUNCSOUNDS, CFN_PARAM(cfn));
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_TRACK:
|
||||
case FUNC_BACKGND_MUSIC:
|
||||
case FUNC_PLAY_SCRIPT:
|
||||
if (ZEXIST(cfn->play.name))
|
||||
dc->drawSizedText(col1, line2, cfn->play.name, sizeof(cfn->play.name),
|
||||
0);
|
||||
else
|
||||
dc->drawTextAtIndex(col1, line2, STR_VCSWFUNC, 0, 0);
|
||||
break;
|
||||
|
||||
case FUNC_SET_TIMER:
|
||||
drawStringWithIndex(dc, col1, line2, STR_TIMER,
|
||||
CFN_TIMER_INDEX(cfn) + 1, 0);
|
||||
break;
|
||||
|
||||
case FUNC_SET_FAILSAFE:
|
||||
dc->drawTextAtIndex(col1, line2, "\004Int.Ext.", CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_PLAY_VALUE:
|
||||
drawSource(dc, col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_HAPTIC:
|
||||
dc->drawNumber(col1, line2, CFN_PARAM(cfn), 0);
|
||||
break;
|
||||
|
||||
case FUNC_LOGS:
|
||||
dc->drawNumber(col3, line1, CFN_PARAM(cfn), PREC1,
|
||||
sizeof(CFN_PARAM(cfn)), nullptr, "s");
|
||||
break;
|
||||
}
|
||||
if (HAS_ENABLE_PARAM(func)) {
|
||||
theme->drawCheckBox(dc, CFN_ACTIVE(cfn), col3, line2);
|
||||
} else if (HAS_REPEAT_PARAM(func)) {
|
||||
if (CFN_PLAY_REPEAT(cfn) == 0) {
|
||||
dc->drawText(col3, line2, "1x", 0);
|
||||
} else if (CFN_PLAY_REPEAT(cfn) == CFN_PLAY_REPEAT_NOSTART) {
|
||||
dc->drawText(col3, line2, "!1x", 0);
|
||||
} else {
|
||||
dc->drawNumber(col3 + 12, line2,
|
||||
CFN_PLAY_REPEAT(cfn) * CFN_PLAY_REPEAT_MUL, 0 | RIGHT, 0,
|
||||
nullptr, "s");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
if (active)
|
||||
dc->drawSolidFilledRect(2, 2, rect.w - 4, rect.h - 4, HIGHLIGHT_COLOR);
|
||||
void paint(BitmapBuffer *dc) override
|
||||
{
|
||||
if (active)
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, HIGHLIGHT_COLOR);
|
||||
else
|
||||
dc->drawSolidFilledRect(0, 0, rect.w, rect.h, FIELD_BGCOLOR);
|
||||
|
||||
paintSpecialFunctionLine(dc);
|
||||
paintSpecialFunctionLine(dc);
|
||||
|
||||
// The bounding rect
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, hasFocus() ? CHECKBOX_COLOR : DISABLE_COLOR);
|
||||
}
|
||||
// The bounding rect
|
||||
if (hasFocus())
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 2, FOCUS_BGCOLOR);
|
||||
else
|
||||
dc->drawSolidRect(0, 0, rect.w, rect.h, 1, FIELD_FRAME_COLOR);
|
||||
}
|
||||
|
||||
protected:
|
||||
CustomFunctionData * functions;
|
||||
uint8_t index;
|
||||
bool active = false;
|
||||
protected:
|
||||
CustomFunctionData *functions;
|
||||
uint8_t index;
|
||||
bool active = false;
|
||||
};
|
||||
|
||||
SpecialFunctionsPage::SpecialFunctionsPage(CustomFunctionData * functions) :
|
||||
PageTab(functions == g_model.customFn ? STR_MENUCUSTOMFUNC : STR_MENUSPECIALFUNCS,
|
||||
functions == g_model.customFn ? ICON_MODEL_SPECIAL_FUNCTIONS : ICON_RADIO_GLOBAL_FUNCTIONS),
|
||||
functions(functions)
|
||||
SpecialFunctionsPage::SpecialFunctionsPage(CustomFunctionData *functions) :
|
||||
PageTab(functions == g_model.customFn ? STR_MENUCUSTOMFUNC
|
||||
: STR_MENUSPECIALFUNCS,
|
||||
functions == g_model.customFn ? ICON_MODEL_SPECIAL_FUNCTIONS
|
||||
: ICON_RADIO_GLOBAL_FUNCTIONS),
|
||||
functions(functions)
|
||||
{
|
||||
}
|
||||
|
||||
void SpecialFunctionsPage::rebuild(FormWindow * window, int8_t focusSpecialFunctionIndex)
|
||||
void SpecialFunctionsPage::rebuild(FormWindow *window,
|
||||
int8_t focusSpecialFunctionIndex)
|
||||
{
|
||||
coord_t scrollPosition = window->getScrollPositionY();
|
||||
window->clear();
|
||||
@@ -423,15 +506,14 @@ void SpecialFunctionsPage::rebuild(FormWindow * window, int8_t focusSpecialFunct
|
||||
window->setScrollPositionY(scrollPosition);
|
||||
}
|
||||
|
||||
void SpecialFunctionsPage::editSpecialFunction(FormWindow * window, uint8_t index)
|
||||
void SpecialFunctionsPage::editSpecialFunction(FormWindow *window,
|
||||
uint8_t index)
|
||||
{
|
||||
auto editPage = new SpecialFunctionEditPage(functions, index);
|
||||
editPage->setCloseHandler([=]() {
|
||||
rebuild(window, index);
|
||||
});
|
||||
editPage->setCloseHandler([=]() { rebuild(window, index); });
|
||||
}
|
||||
|
||||
void SpecialFunctionsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
void SpecialFunctionsPage::build(FormWindow *window, int8_t focusIndex)
|
||||
{
|
||||
FormGridLayout grid;
|
||||
grid.spacer(PAGE_PADDING);
|
||||
@@ -440,11 +522,10 @@ void SpecialFunctionsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
Window::clearFocus();
|
||||
|
||||
char s[] = "SFxx";
|
||||
if (functions == g_eeGeneral.customFn)
|
||||
s[0] = 'G';
|
||||
if (functions == g_eeGeneral.customFn) s[0] = 'G';
|
||||
|
||||
for (uint8_t i = 0; i < MAX_SPECIAL_FUNCTIONS; i++) {
|
||||
CustomFunctionData * cfn = &functions[i];
|
||||
CustomFunctionData *cfn = &functions[i];
|
||||
strAppendUnsigned(&s[2], i);
|
||||
|
||||
if (cfn->swtch == 0) {
|
||||
@@ -464,64 +545,82 @@ void SpecialFunctionsPage::build(FormWindow * window, int8_t focusIndex)
|
||||
return 0;
|
||||
});
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
else {
|
||||
new StaticText(window, grid.getLabelSlot(), s, BUTTON_BACKGROUND, CENTERED);
|
||||
} else {
|
||||
auto txt = new StaticText(window, grid.getLabelSlot(), s,
|
||||
BUTTON_BACKGROUND, CENTERED);
|
||||
|
||||
auto button = new SpecialFunctionButton(window, grid.getFieldSlot(), functions, i);
|
||||
auto button =
|
||||
new SpecialFunctionButton(window, grid.getFieldSlot(), functions, i);
|
||||
button->setPressHandler([=]() {
|
||||
button->bringToTop();
|
||||
Menu * menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() {
|
||||
editSpecialFunction(window, i);
|
||||
button->bringToTop();
|
||||
Menu *menu = new Menu(window);
|
||||
menu->addLine(STR_EDIT, [=]() { editSpecialFunction(window, i); });
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
clipboard.type = CLIPBOARD_TYPE_CUSTOM_FUNCTION;
|
||||
clipboard.data.cfn = *cfn;
|
||||
});
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_FUNCTION) {
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
*cfn = clipboard.data.cfn;
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
menu->addLine(STR_COPY, [=]() {
|
||||
clipboard.type = CLIPBOARD_TYPE_CUSTOM_FUNCTION;
|
||||
clipboard.data.cfn = *cfn;
|
||||
}
|
||||
if (functions[MAX_SPECIAL_FUNCTIONS - 1].isEmpty()) {
|
||||
menu->addLine(STR_INSERT, [=]() {
|
||||
memmove(
|
||||
cfn + 1, cfn,
|
||||
(MAX_SPECIAL_FUNCTIONS - i - 1) * sizeof(CustomFunctionData));
|
||||
memset(cfn, 0, sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
if (clipboard.type == CLIPBOARD_TYPE_CUSTOM_FUNCTION) {
|
||||
menu->addLine(STR_PASTE, [=]() {
|
||||
*cfn = clipboard.data.cfn;
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
}
|
||||
if (functions[MAX_SPECIAL_FUNCTIONS - 1].isEmpty()) {
|
||||
menu->addLine(STR_INSERT, [=]() {
|
||||
memmove(cfn + 1, cfn, (MAX_SPECIAL_FUNCTIONS - i - 1) * sizeof(CustomFunctionData));
|
||||
memset(cfn, 0, sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
}
|
||||
menu->addLine(STR_CLEAR, [=]() {
|
||||
memset(cfn, 0, sizeof(CustomFunctionData));
|
||||
}
|
||||
menu->addLine(STR_CLEAR, [=]() {
|
||||
memset(cfn, 0, sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
});
|
||||
for (int j = i; j < MAX_SPECIAL_FUNCTIONS; j++) {
|
||||
if (!functions[j].isEmpty()) {
|
||||
menu->addLine(STR_DELETE, [=]() {
|
||||
memmove(
|
||||
cfn, cfn + 1,
|
||||
(MAX_SPECIAL_FUNCTIONS - i - 1) * sizeof(CustomFunctionData));
|
||||
memset(&functions[MAX_SPECIAL_FUNCTIONS - 1], 0,
|
||||
sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
});
|
||||
for (int j = i; j < MAX_SPECIAL_FUNCTIONS; j++) {
|
||||
if (!functions[j].isEmpty()) {
|
||||
menu->addLine(STR_DELETE, [=]() {
|
||||
memmove(cfn, cfn + 1, (MAX_SPECIAL_FUNCTIONS - i - 1) * sizeof(CustomFunctionData));
|
||||
memset(&functions[MAX_SPECIAL_FUNCTIONS - 1], 0, sizeof(CustomFunctionData));
|
||||
SET_DIRTY();
|
||||
rebuild(window, i);
|
||||
});
|
||||
break;
|
||||
}
|
||||
rebuild(window, i);
|
||||
});
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
button->setFocusHandler([=](bool focus) {
|
||||
if (focus) {
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
} else {
|
||||
txt->setBackgroundColor(FIELD_FRAME_COLOR);
|
||||
txt->setTextFlags(CENTERED);
|
||||
}
|
||||
txt->invalidate();
|
||||
});
|
||||
|
||||
if (focusIndex == i) {
|
||||
button->setFocus(SET_FOCUS_DEFAULT);
|
||||
txt->setBackgroundColor(FOCUS_BGCOLOR);
|
||||
txt->setTextFlags(FOCUS_COLOR | CENTERED);
|
||||
txt->invalidate();
|
||||
}
|
||||
|
||||
txt->setHeight(button->height());
|
||||
grid.spacer(button->height() + 5);
|
||||
}
|
||||
}
|
||||
|
||||
grid.nextLine();
|
||||
|
||||
// window->setLastField();
|
||||
// window->setLastField();
|
||||
window->setInnerHeight(grid.getWindowHeight());
|
||||
}
|
||||
|
||||
@@ -31,11 +31,7 @@ class SpecialFunctionsPage: public PageTab {
|
||||
|
||||
void build(FormWindow * window) override
|
||||
{
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
build(window, -1);
|
||||
#else
|
||||
build(window, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user