Move sourcechoice and switchchoice to ChoiceEx implementation (#691)

* move sourcechoice and switchchoice to ChoiceEx implementation

* removed getTicks parameter from ChoiceEx.  Turns out it can just access timer directly

* clean up keyboard support for topbar.cpp, protect against crash in keyboard

* Switch back to edgetx libpenui and sync

* Formatting

Co-authored-by: kkoenig1@optonline.com <kkoenig1@optonline.com>
Co-authored-by: Peter Feerick <peter.feerick@gmail.com>
This commit is contained in:
Kevin Koenig
2021-09-13 17:09:13 +10:00
committed by GitHub
co-authored by kkoenig1@optonline.com <kkoenig1@optonline.com> Peter Feerick
parent 9bb08c2c1f
commit 8f8374f3b9
11 changed files with 153 additions and 490 deletions
-1
View File
@@ -66,7 +66,6 @@ set(GUI_SRC
menu_screen.cpp
screen_setup.cpp
switch_warn_dialog.cpp
choiceex.cpp
)
macro(add_gui_src src)
-99
View File
@@ -1,99 +0,0 @@
/*
* 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 "choiceex.h"
void ChoiceEx::setLongPressHandler(std::function<void(event_t)> handler)
{
longPressHandler = handler;
}
ChoiceEx::ChoiceEx(FormGroup * parent, const rect_t & rect, int vmin, int vmax, std::function<int()> getValue, std::function<void(int)> setValue, WindowFlags windowFlags) :
Choice(parent, rect, vmin, vmax, getValue, setValue, windowFlags)
{
#if defined(HARDWARE_TOUCH)
duration10ms = 0;
#endif
}
#if defined(HARDWARE_KEYS)
void ChoiceEx::onEvent(event_t event)
{
if (event == EVT_KEY_LONG(KEY_ENTER)) {
if (longPressHandler) {
killEvents(event);
longPressHandler(event);
return;
}
}
Choice::onEvent(event);
}
#endif
#if defined(HARDWARE_TOUCH)
bool ChoiceEx::onTouchStart(coord_t x, coord_t y)
{
if (duration10ms == 0) {
duration10ms = get_tmr10ms();
}
return Choice::onTouchStart(x, y);
}
bool ChoiceEx::isLongPress()
{
tmr10ms_t curTimer = get_tmr10ms();
return (duration10ms != 0 && curTimer - duration10ms > LONG_PRESS_10MS);
}
void ChoiceEx::checkEvents(void)
{
event_t event = getEvent();
if (isLongPress()) {
if (longPressHandler) {
longPressHandler(event);
duration10ms = 0;
}
}
if (hasFocus())
onEvent(event);
else
pushEvent(event);
}
bool ChoiceEx::onTouchEnd(coord_t x, coord_t y)
{
if (isLongPress()) {
if (longPressHandler) {
longPressHandler(0);
duration10ms = 0;
return false;
}
}
duration10ms = 0;
return Choice::onTouchEnd(x,y);
}
#endif
-53
View File
@@ -1,53 +0,0 @@
/*
* 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 "libopenui.h"
class ChoiceEx : public Choice
{
public:
ChoiceEx(FormGroup * parent, const rect_t &rect, int vmin, int vmax, std::function<int()> getValue, std::function<void(int)> setValue = nullptr, WindowFlags windowFlags = 0);
void setLongPressHandler(std::function<void(event_t)> handler);
#if defined(HARDWARE_KEYS)
void onEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
bool onTouchStart(coord_t x, coord_t y) override;
void checkEvents(void) override;
bool isLongPress();
#endif
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "ChoceEx";
}
#endif
protected:
std::function<void(event_t)> longPressHandler = nullptr;
#if defined(HARDWARE_TOUCH)
tmr10ms_t duration10ms;
#endif
};
+18 -15
View File
@@ -28,24 +28,27 @@ static constexpr coord_t SENSOR_COL1 = 30;
static constexpr coord_t SENSOR_COL2 = SENSOR_COL1 + 70;
static constexpr coord_t SENSOR_COL3 = LCD_W - 50;
class SensorSourceChoice : public SourceChoice {
public:
SensorSourceChoice(Window * window, const rect_t &rect, uint8_t * source, IsValueAvailable isValueAvailable) :
class SensorSourceChoice : public SourceChoice
{
public:
SensorSourceChoice(FormGroup *window, const rect_t &rect, uint8_t *source,
IsValueAvailable isValueAvailable) :
SourceChoice(window, rect, MIXSRC_NONE, MIXSRC_LAST_TELEM,
GET_DEFAULT(*source ? MIXSRC_FIRST_TELEM + 3 * (*source - 1) : MIXSRC_NONE),
GET_DEFAULT(*source ? MIXSRC_FIRST_TELEM + 3 * (*source - 1)
: MIXSRC_NONE),
[=](uint8_t newValue) {
*source = newValue == MIXSRC_NONE ? 0 : (newValue - MIXSRC_FIRST_TELEM) / 3 + 1;
*source = newValue == MIXSRC_NONE
? 0
: (newValue - MIXSRC_FIRST_TELEM) / 3 + 1;
})
{
setAvailableHandler([=](int16_t value) {
if (value == MIXSRC_NONE)
return true;
if (value < MIXSRC_FIRST_TELEM)
return false;
auto qr = div(value - MIXSRC_FIRST_TELEM, 3);
return qr.rem == 0 && isValueAvailable(qr.quot + 1);
});
}
{
setAvailableHandler([=](int16_t value) {
if (value == MIXSRC_NONE) return true;
if (value < MIXSRC_FIRST_TELEM) return false;
auto qr = div(value - MIXSRC_FIRST_TELEM, 3);
return qr.rem == 0 && isValueAvailable(qr.quot + 1);
});
}
};
class SensorButton : public Button {
+3
View File
@@ -85,7 +85,10 @@ void Page::onEvent(event_t event)
#if defined(HARDWARE_TOUCH)
bool Page::onTouchEnd(coord_t x, coord_t y)
{
#if defined (SOFTWARE_KEYBOARD)
Keyboard::hide();
#endif
Window::onTouchEnd(x, y);
return true;
}
+44 -84
View File
@@ -55,27 +55,52 @@ class SourceChoiceMenuToolbar : public MenuToolbar<SourceChoice>
}
};
void SourceChoice::paint(BitmapBuffer * dc)
{
FormField::paint(dc);
unsigned value = getValue();
LcdFlags textColor;
if (editMode)
textColor = COLOR_THEME_PRIMARY2;
else if (hasFocus())
textColor = COLOR_THEME_PRIMARY2;
else
textColor = COLOR_THEME_PRIMARY1;
drawSource(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, value, textColor);
dc->drawBitmapPattern(rect.w - 20, (rect.h - 11) / 2, LBM_DROPDOWN, textColor);
}
// defined in gui/gui_common.cpp
uint8_t switchToMix(uint8_t source);
void SourceChoice::fillMenu(Menu * menu, const std::function<bool(int16_t)> & filter)
SourceChoice::SourceChoice(FormGroup *parent, const rect_t &rect, int16_t vmin,
int16_t vmax, std::function<int16_t()> getValue,
std::function<void(int16_t)> setValue,
WindowFlags windowFlags, LcdFlags textFlags) :
ChoiceEx(parent, rect, vmin, vmax, getValue, setValue)
{
setBeforeDisplayMenuHandler([=](Menu *menu) {
menu->setToolbar(new SourceChoiceMenuToolbar(this, menu));
#if defined(AUTOSOURCE)
menu->setWaitHandler([=]() {
int16_t val = getMovedSource(vmin);
if (val) {
if (setValue) {
setValue(val);
}
this->fillMenu(menu);
}
#if defined(AUTOSWITCH)
else {
swsrc_t swtch = abs(getMovedSwitch());
if (swtch && !IS_SWITCH_MULTIPOS(swtch)) {
val = switchToMix(swtch);
if (val && (val >= vmin) && (val <= vmax)) {
if (setValue) setValue(val);
this->fillMenu(menu);
}
}
}
#endif
});
#endif
});
setTextHandler([=](int value) {
if (isValueAvailable && !isValueAvailable(value))
return std::to_string(0); // we will fix this later
return std::string(getSourceString(value));
});
}
void SourceChoice::fillMenu(Menu *menu,
const std::function<bool(int16_t)> &filter)
{
auto value = getValue();
int count = 0;
@@ -95,69 +120,4 @@ void SourceChoice::fillMenu(Menu * menu, const std::function<bool(int16_t)> & fi
if (current >= 0) {
menu->select(current);
}
#if defined(AUTOSOURCE)
menu->setWaitHandler([=]() {
int16_t val = getMovedSource(vmin);
if (val) {
if (filter && filter(val)) {
return;
}
if (setValue) {
setValue(val);
}
this->fillMenu(menu);
}
#if defined(AUTOSWITCH)
else {
swsrc_t swtch = abs(getMovedSwitch());
if (swtch && !IS_SWITCH_MULTIPOS(swtch)) {
val = switchToMix(swtch);
if (val && (val >= vmin) && (val <= vmax)
&& (!filter || !filter(val))) {
if (setValue) setValue(val);
this->fillMenu(menu);
}
}
}
#endif
});
#endif
}
void SourceChoice::openMenu()
{
auto menu = new Menu(this);
fillMenu(menu);
menu->setToolbar(new SourceChoiceMenuToolbar(this, menu));
menu->setCloseHandler([=]() {
editMode = false;
setFocus(SET_FOCUS_DEFAULT);
});
}
#if defined(HARDWARE_KEYS)
void SourceChoice::onEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
if (event == EVT_KEY_BREAK(KEY_ENTER)) {
editMode = true;
invalidate();
openMenu();
}
else {
FormField::onEvent(event);
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool SourceChoice::onTouchEnd(coord_t, coord_t)
{
setFocus(SET_FOCUS_DEFAULT);
setEditMode(true);
openMenu();
return true;
}
#endif
+15 -42
View File
@@ -21,56 +21,29 @@
#ifndef _SOURCECHOICE_H_
#define _SOURCECHOICE_H_
#include "choiceex.h"
#include "form.h"
class Menu;
bool isSourceAvailable(int source);
class SourceChoice : public FormField {
template <class T> friend class MenuToolbar;
class SourceChoice : public ChoiceEx
{
template <class T>
friend class MenuToolbar;
public:
SourceChoice(Window * parent, const rect_t & rect, int16_t vmin, int16_t vmax, std::function<int16_t()> getValue,
std::function<void(int16_t)> setValue, WindowFlags windowFlags = 0, LcdFlags textFlags = 0):
FormField(parent, rect, windowFlags, textFlags),
vmin(vmin),
vmax(vmax),
getValue(std::move(getValue)),
setValue(std::move(setValue))
{
}
public:
SourceChoice(FormGroup* parent, const rect_t& rect, int16_t vmin,
int16_t vmax, std::function<int16_t()> getValue,
std::function<void(int16_t)> setValue,
WindowFlags windowFlags = 0, LcdFlags textFlags = 0);
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "SourceChoice";
}
std::string getName() const override { return "SourceChoice"; }
#endif
void paint(BitmapBuffer * dc) override;
#if defined(HARDWARE_KEYS)
void onEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
bool onTouchEnd(coord_t x, coord_t y) override;
#endif
void setAvailableHandler(std::function<bool(int)> handler)
{
isValueAvailable = std::move(handler);
}
protected:
int16_t vmin;
int16_t vmax;
std::function<int16_t()> getValue;
std::function<void(int16_t)> setValue;
std::function<bool(int)> isValueAvailable = isSourceAvailable;
void fillMenu(Menu * menu, const std::function<bool(int16_t)> & condition=nullptr);
void openMenu();
protected:
void fillMenu(Menu* menu,
const std::function<bool(int16_t)>& condition = nullptr);
};
#endif // _SOURCECHOICE_H_
#endif // _SOURCECHOICE_H_
+60 -145
View File
@@ -1,7 +1,8 @@
/*
* Copyright (C) OpenTX
* 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
@@ -17,49 +18,77 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "libopenui_config.h"
#include "switchchoice.h"
#include "menutoolbar.h"
#include "menu.h"
#include "draw_functions.h"
#include "strhelpers.h"
#include "dataconstants.h"
#include "draw_functions.h"
#include "libopenui_config.h"
#include "menu.h"
#include "menutoolbar.h"
#include "opentx.h"
#include "strhelpers.h"
class SwitchChoiceMenuToolbar : public MenuToolbar<SwitchChoice>
{
public:
SwitchChoiceMenuToolbar(SwitchChoice * choice, Menu * menu):
public:
SwitchChoiceMenuToolbar(SwitchChoice* choice, Menu* menu) :
MenuToolbar<SwitchChoice>(choice, menu)
{
addButton(CHAR_SWITCH, SWSRC_FIRST_SWITCH, SWSRC_LAST_SWITCH);
addButton(CHAR_TRIM, SWSRC_FIRST_TRIM, SWSRC_LAST_TRIM);
addButton(CHAR_SWITCH, SWSRC_FIRST_LOGICAL_SWITCH, SWSRC_LAST_LOGICAL_SWITCH);
}
{
addButton(CHAR_SWITCH, SWSRC_FIRST_SWITCH, SWSRC_LAST_SWITCH);
addButton(CHAR_TRIM, SWSRC_FIRST_TRIM, SWSRC_LAST_TRIM);
addButton(CHAR_SWITCH, SWSRC_FIRST_LOGICAL_SWITCH,
SWSRC_LAST_LOGICAL_SWITCH);
}
};
void SwitchChoice::paint(BitmapBuffer * dc)
SwitchChoice::SwitchChoice(FormGroup* parent, const rect_t& rect, int vmin,
int vmax, std::function<int16_t()> getValue,
std::function<void(int16_t)> setValue) :
ChoiceEx(parent, rect, vmin, vmax, getValue, setValue)
{
FormField::paint(dc);
setBeforeDisplayMenuHandler([=](Menu* menu) {
menu->setToolbar(new SwitchChoiceMenuToolbar(this, menu));
#if defined(AUTOSWITCH)
menu->setWaitHandler([menu, this, setValue]() {
swsrc_t val = 0;
swsrc_t swtch = getMovedSwitch();
if (swtch) {
div_t info = switchInfo(swtch);
if (IS_CONFIG_TOGGLE(info.quot)) {
if (info.rem != 0) {
val = (val == swtch ? swtch - 2 : swtch);
}
} else {
val = swtch;
}
if (val && (!isValueAvailable || isValueAvailable(val))) {
if (setValue) setValue(val);
this->fillMenu(menu);
}
}
});
#endif
});
unsigned value = getValue();
LcdFlags textColor;
if (editMode)
textColor = COLOR_THEME_PRIMARY2;
else if (hasFocus())
textColor = COLOR_THEME_PRIMARY2;
// else if (value == 0)
// textColor = COLOR_THEME_DISABLED;
else
textColor = COLOR_THEME_SECONDARY1;
setTextHandler([=](int value) {
if (isValueAvailable && !isValueAvailable(value))
return std::to_string(0); // we will fix this later
drawSwitch(dc, FIELD_PADDING_LEFT, FIELD_PADDING_TOP, value, textColor);
dc->drawBitmapPattern(rect.w - 20, (rect.h - 11) / 2, LBM_DROPDOWN,
textColor);
return std::string(getSwitchPositionName(value));
});
setLongPressHandler([=](event_t) {
int16_t val = getValue();
if (isValueAvailable && isValueAvailable(-val)) {
setValue(-val);
invalidate();
}
});
setAvailableHandler(isSwitchAvailableInMixes);
}
void SwitchChoice::fillMenu(Menu * menu, std::function<bool(int16_t)> filter)
void SwitchChoice::fillMenu(Menu* menu, std::function<bool(int16_t)> filter)
{
auto value = getValue();
int count = 0;
@@ -70,6 +99,7 @@ void SwitchChoice::fillMenu(Menu * menu, std::function<bool(int16_t)> filter)
for (int i = vmin; i <= vmax; ++i) {
if (filter && !filter(i)) continue;
if (isValueAvailable && !isValueAvailable(i)) continue;
menu->addLine(getSwitchPositionName(i), [=]() { setValue(i); });
if (value == i) {
current = count;
@@ -80,119 +110,4 @@ void SwitchChoice::fillMenu(Menu * menu, std::function<bool(int16_t)> filter)
if (current >= 0) {
menu->select(current);
}
#if defined(AUTOSWITCH)
menu->setWaitHandler([=]() {
swsrc_t val = 0;
swsrc_t swtch = getMovedSwitch();
if (swtch) {
div_t info = switchInfo(swtch);
if (IS_CONFIG_TOGGLE(info.quot)) {
if (info.rem != 0) {
val = (val == swtch ? swtch - 2 : swtch);
}
} else {
val = swtch;
}
if (val && (!isValueAvailable || isValueAvailable(val))) {
if (setValue) setValue(val);
this->fillMenu(menu);
}
}
});
#endif
}
void SwitchChoice::openMenu()
{
auto menu = new Menu(this);
fillMenu(menu);
menu->setToolbar(new SwitchChoiceMenuToolbar(this, menu));
menu->setCloseHandler([=]() {
editMode = false;
setFocus(SET_FOCUS_DEFAULT);
});
}
#if defined(HARDWARE_KEYS)
void SwitchChoice::onEvent(event_t event)
{
TRACE_WINDOWS("%s received event 0x%X", getWindowDebugString().c_str(), event);
static bool longPress = false;
if (event == EVT_KEY_LONG(KEY_ENTER)) {
int16_t val = getValue();
if (isValueAvailable && isValueAvailable(-val) ) {
setValue(-val);
invalidate();
longPress = true;
}
}
else if (event == EVT_KEY_BREAK(KEY_ENTER)) {
if(!longPress) {
editMode = true;
invalidate();
openMenu();
} else {
longPress = false;
}
}
else {
FormField::onEvent(event);
}
}
#endif
#if defined(HARDWARE_TOUCH)
bool SwitchChoice::isLongPress(tmr10ms_t longPressDuration)
{
if (duration10ms > 1) {
tmr10ms_t touchDuration10ms = get_tmr10ms() - duration10ms;
if (touchDuration10ms > longPressDuration) return true;
}
return false;
}
void SwitchChoice::checkEvents(void)
{
event_t event = getEvent();
if (isLongPress()) {
int16_t val = getValue();
if (isValueAvailable && isValueAvailable(-val) ) {
setValue(-val);
invalidate();
duration10ms = 1;
}
}
if (hasFocus())
onEvent(event);
else
pushEvent(event);
}
bool SwitchChoice::onTouchStart(coord_t x, coord_t y)
{
if (!duration10ms) {
duration10ms = get_tmr10ms();
}
return FormField::onTouchStart(x, y);
}
bool SwitchChoice::onTouchEnd(coord_t x, coord_t y)
{
setFocus(SET_FOCUS_DEFAULT);
if(duration10ms != 1) {
setEditMode(true);
openMenu();
}
duration10ms = 0;
return true;
}
#endif
+8 -50
View File
@@ -1,7 +1,8 @@
/*
* Copyright (C) OpenTX
* 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
@@ -17,70 +18,27 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _SWITCHCHOICE_H_
#define _SWITCHCHOICE_H_
#include "form.h"
#include "choiceex.h"
constexpr int LONG_PRESS_10MS = 100;
class Menu;
bool isSwitchAvailableInMixes(int swtch);
class SwitchChoice : public FormField
class SwitchChoice : public ChoiceEx
{
template <class T>
friend class MenuToolbar;
template <class T> friend class MenuToolbar;
public:
SwitchChoice(Window* parent, const rect_t& rect, int vmin, int vmax,
SwitchChoice(FormGroup* parent, const rect_t& rect, int vmin, int vmax,
std::function<int16_t()> getValue,
std::function<void(int16_t)> setValue) :
FormField(parent, rect),
vmin(vmin),
vmax(vmax),
getValue(std::move(getValue)),
setValue(std::move(setValue))
{
#if defined(HARDWARE_TOUCH)
duration10ms = 0;
#endif
}
std::function<void(int16_t)> setValue);
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "SwitchChoice"; }
#endif
void paint(BitmapBuffer* dc) override;
#if defined(HARDWARE_KEYS)
void onEvent(event_t event) override;
#endif
#if defined(HARDWARE_TOUCH)
void checkEvents(void) override;
bool onTouchEnd(coord_t x, coord_t y) override;
bool onTouchStart(coord_t x, coord_t y) override;
inline bool isLongPress(tmr10ms_t longPressDuration = LONG_PRESS_10MS);
#endif
void setAvailableHandler(std::function<bool(int)> handler)
{
isValueAvailable = std::move(handler);
}
protected:
int16_t vmin;
int16_t vmax;
#if defined(HARDWARE_TOUCH)
tmr10ms_t duration10ms;
#endif
std::function<int16_t()> getValue;
std::function<void(int16_t)> setValue;
std::function<bool(int)> isValueAvailable = isSwitchAvailableInMixes;
protected:
void fillMenu(Menu* menu, std::function<bool(int16_t)> condition = nullptr);
void openMenu();
};
#endif // _SWITCHCHOICE_H_
+4
View File
@@ -103,6 +103,10 @@ bool SetupTopBarWidgetsPage::onTouchSlide(coord_t x, coord_t y,
bool SetupTopBarWidgetsPage::onTouchEnd(coord_t x, coord_t y)
{
#if defined(SOFTWARE_KEYBOARD)
Keyboard::hide();
#endif
if (FormWindow::onTouchEnd(x, y))
return true;