feat(color): Improvements to switch and source select menu (#4104)
This commit is contained in:
@@ -20,74 +20,104 @@
|
||||
*/
|
||||
|
||||
#include "sourcechoice.h"
|
||||
#include "menutoolbar.h"
|
||||
#include "menu.h"
|
||||
|
||||
#include "dataconstants.h"
|
||||
#include "lcd.h"
|
||||
#include "strhelpers.h"
|
||||
#include "draw_functions.h"
|
||||
#include "lcd.h"
|
||||
#include "menu.h"
|
||||
#include "menutoolbar.h"
|
||||
#include "opentx.h"
|
||||
#include "strhelpers.h"
|
||||
#include "switches.h"
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
#define FILTER_COLUMNS 3
|
||||
#else
|
||||
#define FILTER_COLUMNS 2
|
||||
#endif
|
||||
|
||||
class SourceChoiceMenuToolbar : public MenuToolbar
|
||||
{
|
||||
public:
|
||||
SourceChoiceMenuToolbar(SourceChoice * choice, Menu * menu):
|
||||
MenuToolbar(choice, menu)
|
||||
{
|
||||
addButton(STR_CHAR_INPUT, MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT);
|
||||
public:
|
||||
SourceChoiceMenuToolbar(SourceChoice *choice, Menu *menu) :
|
||||
MenuToolbar(choice, menu, FILTER_COLUMNS)
|
||||
{
|
||||
addButton(STR_CHAR_INPUT, MIXSRC_FIRST_INPUT, MIXSRC_LAST_INPUT, nullptr,
|
||||
STR_MENU_INPUTS);
|
||||
#if defined(LUA_MODEL_SCRIPTS)
|
||||
if (modelCustomScriptsEnabled())
|
||||
addButton(STR_CHAR_LUA, MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA);
|
||||
if (modelCustomScriptsEnabled())
|
||||
addButton(STR_CHAR_LUA, MIXSRC_FIRST_LUA, MIXSRC_LAST_LUA, nullptr,
|
||||
STR_MENU_LUA);
|
||||
#endif
|
||||
#if defined(PCBHORUS)
|
||||
auto lastSource = MIXSRC_LAST_SPACEMOUSE;
|
||||
auto lastSource = MIXSRC_LAST_SPACEMOUSE;
|
||||
#elif defined(IMU)
|
||||
auto lastSource = MIXSRC_TILT_Y;
|
||||
auto lastSource = MIXSRC_TILT_Y;
|
||||
#else
|
||||
auto lastSource = MIXSRC_LAST_STICK;
|
||||
auto lastSource = MIXSRC_LAST_STICK;
|
||||
#endif
|
||||
addButton(STR_CHAR_STICK, MIXSRC_FIRST_STICK, lastSource, [=](int16_t index) {
|
||||
if (index >= MIXSRC_FIRST_POT && index <= MIXSRC_LAST_POT)
|
||||
return false;
|
||||
addButton(
|
||||
STR_CHAR_STICK, MIXSRC_FIRST_STICK, lastSource,
|
||||
[=](int16_t index) {
|
||||
if (index >= MIXSRC_FIRST_POT && index <= MIXSRC_LAST_POT)
|
||||
return false;
|
||||
#if MAX_AXIS > 0
|
||||
if (index >= MIXSRC_FIRST_AXIS && index <= MIXSRC_LAST_AXIS)
|
||||
return false;
|
||||
if (index >= MIXSRC_FIRST_AXIS && index <= MIXSRC_LAST_AXIS)
|
||||
return false;
|
||||
#endif
|
||||
return index >= MIXSRC_FIRST_STICK && index <= lastSource;
|
||||
});
|
||||
addButton(STR_CHAR_POT, MIXSRC_FIRST_POT, MIXSRC_LAST_POT);
|
||||
addButton(STR_CHAR_FUNCTION, MIXSRC_MIN, MIXSRC_LAST_TIMER, [=](int16_t index) {
|
||||
return (index >= MIXSRC_MIN && index <= MIXSRC_MAX) || (index >= MIXSRC_TX_VOLTAGE && index <= MIXSRC_LAST_TIMER);
|
||||
});
|
||||
return index >= MIXSRC_FIRST_STICK && index <= lastSource;
|
||||
},
|
||||
STR_MENU_STICKS);
|
||||
addButton(STR_CHAR_POT, MIXSRC_FIRST_POT, MIXSRC_LAST_POT, nullptr,
|
||||
STR_MENU_POTS);
|
||||
addButton(
|
||||
STR_CHAR_FUNCTION, MIXSRC_MIN, MIXSRC_LAST_TIMER,
|
||||
[=](int16_t index) {
|
||||
return (index >= MIXSRC_MIN && index <= MIXSRC_MAX) ||
|
||||
(index >= MIXSRC_TX_VOLTAGE && index <= MIXSRC_LAST_TIMER);
|
||||
},
|
||||
STR_MENU_OTHER);
|
||||
#if defined(HELI)
|
||||
if (modelHeliEnabled())
|
||||
addButton(STR_CHAR_CYC, MIXSRC_FIRST_HELI, MIXSRC_LAST_HELI);
|
||||
if (modelHeliEnabled())
|
||||
addButton(STR_CHAR_CYC, MIXSRC_FIRST_HELI, MIXSRC_LAST_HELI, nullptr,
|
||||
STR_MENU_HELI);
|
||||
#endif
|
||||
addButton(STR_CHAR_TRIM, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM);
|
||||
addButton(STR_CHAR_SWITCH, MIXSRC_FIRST_SWITCH, MIXSRC_LAST_SWITCH);
|
||||
if (modelLSEnabled())
|
||||
addButton(STR_CHAR_SWITCH, MIXSRC_FIRST_LOGICAL_SWITCH, MIXSRC_LAST_LOGICAL_SWITCH);
|
||||
addButton(STR_CHAR_TRAINER, MIXSRC_FIRST_TRAINER, MIXSRC_LAST_TRAINER);
|
||||
addButton(STR_CHAR_CHANNEL, MIXSRC_FIRST_CH, MIXSRC_LAST_CH);
|
||||
addButton(STR_CHAR_TRIM, MIXSRC_FIRST_TRIM, MIXSRC_LAST_TRIM, nullptr,
|
||||
STR_MENU_TRIMS);
|
||||
addButton(STR_CHAR_SWITCH, MIXSRC_FIRST_SWITCH, MIXSRC_LAST_SWITCH, nullptr,
|
||||
STR_MENU_SWITCHES);
|
||||
if (modelLSEnabled())
|
||||
addButton("LS", MIXSRC_FIRST_LOGICAL_SWITCH, MIXSRC_LAST_LOGICAL_SWITCH,
|
||||
nullptr, STR_MENU_LOGICAL_SWITCHES);
|
||||
addButton(STR_CHAR_TRAINER, MIXSRC_FIRST_TRAINER, MIXSRC_LAST_TRAINER,
|
||||
nullptr, STR_MENU_TRAINER);
|
||||
addButton(STR_CHAR_CHANNEL, MIXSRC_FIRST_CH, MIXSRC_LAST_CH, nullptr,
|
||||
STR_MENU_CHANNELS);
|
||||
#if defined(GVARS)
|
||||
if (modelGVEnabled())
|
||||
addButton(STR_CHAR_SLIDER, MIXSRC_FIRST_GVAR, MIXSRC_LAST_GVAR);
|
||||
if (modelGVEnabled())
|
||||
addButton(STR_CHAR_SLIDER, MIXSRC_FIRST_GVAR, MIXSRC_LAST_GVAR, nullptr,
|
||||
STR_MENU_GVARS);
|
||||
#endif
|
||||
if (modelTelemetryEnabled())
|
||||
addButton(STR_CHAR_TELEMETRY, MIXSRC_FIRST_TELEM, MIXSRC_LAST_TELEM);
|
||||
}
|
||||
if (modelTelemetryEnabled())
|
||||
addButton(STR_CHAR_TELEMETRY, MIXSRC_FIRST_TELEM, MIXSRC_LAST_TELEM,
|
||||
nullptr, STR_MENU_TELEMETRY);
|
||||
|
||||
if ((nxtBtnPos > filterColumns) && choice->isValueAvailable &&
|
||||
choice->isValueAvailable(0))
|
||||
addButton(STR_SELECT_MENU_CLR, 0, 0, nullptr, nullptr, true);
|
||||
}
|
||||
};
|
||||
|
||||
// defined in gui/gui_common.cpp
|
||||
uint8_t switchToMix(uint8_t source);
|
||||
|
||||
SourceChoice::SourceChoice(Window* parent, const rect_t &rect, int16_t vmin,
|
||||
SourceChoice::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, LcdFlags textFlags) :
|
||||
Choice(parent, rect, vmin, vmax, getValue, setValue)
|
||||
{
|
||||
setMenuTitle(STR_SOURCE);
|
||||
setBeforeDisplayMenuHandler([=](Menu *menu) {
|
||||
auto tb = new SourceChoiceMenuToolbar(this, menu);
|
||||
menu->setToolbar(tb);
|
||||
@@ -122,5 +152,5 @@ SourceChoice::SourceChoice(Window* parent, const rect_t &rect, int16_t vmin,
|
||||
return std::string(getSourceString(value));
|
||||
});
|
||||
|
||||
setAvailableHandler([](int v){ return isSourceAvailable(v); });
|
||||
setAvailableHandler([](int v) { return isSourceAvailable(v); });
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "choice.h"
|
||||
#include "form.h"
|
||||
|
||||
class SourceChoiceMenuToolbar;
|
||||
|
||||
bool isSourceAvailable(int source);
|
||||
|
||||
class SourceChoice : public Choice
|
||||
@@ -35,6 +37,9 @@ class SourceChoice : public Choice
|
||||
std::function<void(int16_t)> setValue,
|
||||
WindowFlags windowFlags = 0, LcdFlags textFlags = 0);
|
||||
|
||||
protected:
|
||||
friend SourceChoiceMenuToolbar;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "SourceChoice"; }
|
||||
#endif
|
||||
|
||||
@@ -32,22 +32,69 @@ class SwitchChoiceMenuToolbar : public MenuToolbar
|
||||
{
|
||||
public:
|
||||
SwitchChoiceMenuToolbar(SwitchChoice* choice, Menu* menu) :
|
||||
MenuToolbar(choice, menu)
|
||||
MenuToolbar(choice, menu, 2)
|
||||
{
|
||||
addButton(STR_CHAR_SWITCH, SWSRC_FIRST_SWITCH, SWSRC_LAST_MULTIPOS_SWITCH);
|
||||
addButton(STR_CHAR_TRIM, SWSRC_FIRST_TRIM, SWSRC_LAST_TRIM);
|
||||
addButton(STR_CHAR_SWITCH, SWSRC_FIRST_LOGICAL_SWITCH, SWSRC_LAST_LOGICAL_SWITCH);
|
||||
addButton(STR_CHAR_TELEMETRY, SWSRC_FIRST_SENSOR, SWSRC_LAST_SENSOR);
|
||||
addButton(STR_CHAR_SWITCH, SWSRC_FIRST_SWITCH, SWSRC_LAST_MULTIPOS_SWITCH,
|
||||
nullptr, STR_MENU_SWITCHES);
|
||||
addButton(STR_CHAR_TRIM, SWSRC_FIRST_TRIM, SWSRC_LAST_TRIM, nullptr,
|
||||
STR_MENU_TRIMS);
|
||||
addButton("LS", SWSRC_FIRST_LOGICAL_SWITCH, SWSRC_LAST_LOGICAL_SWITCH,
|
||||
nullptr, STR_MENU_LOGICAL_SWITCHES);
|
||||
addButton("FM", SWSRC_FIRST_FLIGHT_MODE, SWSRC_LAST_FLIGHT_MODE, nullptr,
|
||||
STR_FLIGHT_MODE);
|
||||
addButton(STR_CHAR_TELEMETRY, SWSRC_FIRST_SENSOR, SWSRC_LAST_SENSOR,
|
||||
nullptr, STR_MENU_TELEMETRY);
|
||||
#if defined(DEBUG_LATENCY)
|
||||
auto lastSource = SWSRC_LATENCY_TOGGLE;
|
||||
#else
|
||||
auto lastSource = SWSRC_RADIO_ACTIVITY;
|
||||
#endif
|
||||
addButton(STR_CHAR_FUNCTION, SWSRC_TELEMETRY_STREAMING, lastSource, [=](int16_t index) {
|
||||
index = abs(index);
|
||||
return index == 0 || (index >= SWSRC_TELEMETRY_STREAMING && index <= lastSource && !(index >= SWSRC_FIRST_SENSOR && index <= SWSRC_LAST_SENSOR));
|
||||
addButton(
|
||||
STR_CHAR_FUNCTION, SWSRC_ON, lastSource,
|
||||
[=](int16_t index) {
|
||||
index = abs(index);
|
||||
return index == 0 || index == SWSRC_ON || index == SWSRC_ONE ||
|
||||
(index >= SWSRC_TELEMETRY_STREAMING && index <= lastSource &&
|
||||
!(index >= SWSRC_FIRST_SENSOR && index <= SWSRC_LAST_SENSOR));
|
||||
},
|
||||
STR_MENU_OTHER);
|
||||
|
||||
if ((nxtBtnPos > filterColumns) && choice->isValueAvailable &&
|
||||
choice->isValueAvailable(0))
|
||||
addButton(STR_SELECT_MENU_CLR, 0, 0, nullptr, nullptr, true);
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
coord_t y =
|
||||
height() - MENUS_TOOLBAR_BUTTON_WIDTH - MENUS_TOOLBAR_BUTTON_PADDING;
|
||||
coord_t w = width() - MENUS_TOOLBAR_BUTTON_PADDING * 2;
|
||||
|
||||
invertBtn = new MenuToolbarButton(
|
||||
this, {MENUS_TOOLBAR_BUTTON_PADDING, y, w, MENUS_TOOLBAR_BUTTON_WIDTH},
|
||||
STR_SELECT_MENU_INV);
|
||||
invertBtn->check(choice->inverted);
|
||||
|
||||
invertBtn->setPressHandler([=]() {
|
||||
lv_obj_clear_state(invertBtn->getLvObj(), LV_STATE_FOCUSED);
|
||||
longPress();
|
||||
return choice->inverted;
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
void longPress()
|
||||
{
|
||||
SwitchChoice* switchChoice = (SwitchChoice*)choice;
|
||||
switchChoice->inverted = !switchChoice->inverted;
|
||||
auto idx = menu->selection();
|
||||
switchChoice->fillMenu(menu, filter);
|
||||
menu->select(idx);
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
invertBtn->check(switchChoice->inverted);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
MenuToolbarButton* invertBtn = nullptr;
|
||||
};
|
||||
|
||||
void SwitchChoice::LongPressHandler(void* data)
|
||||
@@ -61,12 +108,33 @@ void SwitchChoice::LongPressHandler(void* data)
|
||||
}
|
||||
}
|
||||
|
||||
void SwitchChoice::setValue(int value)
|
||||
{
|
||||
if (inMenu) {
|
||||
if (inverted) value = -value;
|
||||
inMenu = false;
|
||||
}
|
||||
Choice::setValue(value);
|
||||
}
|
||||
|
||||
int SwitchChoice::getIntValue() const
|
||||
{
|
||||
int value = Choice::getIntValue();
|
||||
if (inMenu) value = abs(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
SwitchChoice::SwitchChoice(Window* parent, const rect_t& rect, int vmin,
|
||||
int vmax, std::function<int16_t()> getValue,
|
||||
std::function<void(int16_t)> setValue) :
|
||||
Choice(parent, rect, vmin, vmax, getValue, setValue)
|
||||
Choice(parent, rect, 0, vmax, getValue, setValue)
|
||||
{
|
||||
setMenuTitle(STR_SWITCH);
|
||||
|
||||
setBeforeDisplayMenuHandler([=](Menu* menu) {
|
||||
inverted = getValue() < 0;
|
||||
inMenu = true;
|
||||
|
||||
auto tb = new SwitchChoiceMenuToolbar(this, menu);
|
||||
menu->setToolbar(tb);
|
||||
|
||||
@@ -94,6 +162,8 @@ SwitchChoice::SwitchChoice(Window* parent, const rect_t& rect, int vmin,
|
||||
});
|
||||
|
||||
setTextHandler([=](int value) {
|
||||
if (inMenu && inverted) value = -value;
|
||||
|
||||
if (isValueAvailable && !isValueAvailable(value))
|
||||
return std::to_string(0); // we will fix this later
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "choice.h"
|
||||
#include "form.h"
|
||||
|
||||
class SwitchChoiceMenuToolbar;
|
||||
|
||||
class SwitchChoice : public Choice
|
||||
{
|
||||
public:
|
||||
@@ -35,6 +37,14 @@ class SwitchChoice : public Choice
|
||||
static void LongPressHandler(void* data);
|
||||
|
||||
protected:
|
||||
friend SwitchChoiceMenuToolbar;
|
||||
|
||||
bool inverted = false;
|
||||
bool inMenu = false;
|
||||
|
||||
void setValue(int value) override;
|
||||
int getIntValue() const override;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "SwitchChoice"; }
|
||||
#endif
|
||||
|
||||
@@ -820,6 +820,19 @@ const lv_obj_class_t etx_button_class = {
|
||||
.instance_size = sizeof(lv_btn_t),
|
||||
};
|
||||
|
||||
const lv_obj_class_t etx_menu_button_class = {
|
||||
.base_class = &lv_btn_class,
|
||||
.constructor_cb = etx_button_constructor,
|
||||
.destructor_cb = nullptr,
|
||||
.user_data = nullptr,
|
||||
.event_cb = nullptr,
|
||||
.width_def = LV_SIZE_CONTENT,
|
||||
.height_def = 32,
|
||||
.editable = LV_OBJ_CLASS_EDITABLE_INHERIT,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_FALSE,
|
||||
.instance_size = sizeof(lv_btn_t),
|
||||
};
|
||||
|
||||
const lv_obj_class_t etx_choice_class = {
|
||||
.base_class = &lv_obj_class,
|
||||
.constructor_cb = etx_choice_constructor,
|
||||
@@ -983,6 +996,11 @@ lv_obj_t* etx_button_create(lv_obj_t* parent)
|
||||
return etx_create(&etx_button_class, parent);
|
||||
}
|
||||
|
||||
lv_obj_t* etx_menu_button_create(lv_obj_t* parent)
|
||||
{
|
||||
return etx_create(&etx_menu_button_class, parent);
|
||||
}
|
||||
|
||||
lv_obj_t* etx_choice_create(lv_obj_t* parent)
|
||||
{
|
||||
return etx_create(&etx_choice_class, parent);
|
||||
|
||||
@@ -32,10 +32,6 @@ constexpr uint32_t ALERT_MESSAGE_LEFT = ALERT_TITLE_LEFT;
|
||||
|
||||
constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 132;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = INPUT_EDIT_CURVE_WIDTH;
|
||||
constexpr coord_t MENUS_LINE_HEIGHT = 35;
|
||||
constexpr coord_t MENUS_WIDTH = 200;
|
||||
constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 7);
|
||||
|
||||
constexpr rect_t MENUS_TOOLBAR_RECT = { 100, 51, 30, 209 };
|
||||
constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 7) + 8;
|
||||
|
||||
#define ROTARY_ENCODER_SPEED() rotencSpeed
|
||||
|
||||
@@ -32,11 +32,7 @@ constexpr uint32_t ALERT_MESSAGE_LEFT = 15;
|
||||
|
||||
constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 176;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = 132;
|
||||
constexpr coord_t MENUS_LINE_HEIGHT = 35;
|
||||
constexpr coord_t MENUS_WIDTH = 200;
|
||||
constexpr coord_t MENUS_MAX_HEIGHT = (MENUS_LINE_HEIGHT * 10);
|
||||
|
||||
constexpr rect_t MENUS_TOOLBAR_RECT = { 35, (LCD_H - MENUS_MAX_HEIGHT) / 2, 50, MENUS_MAX_HEIGHT };
|
||||
|
||||
// Disable rotary encoder, as the NV14 does not have one
|
||||
#define ROTARY_ENCODER_SPEED() 0
|
||||
|
||||
+36
-31
@@ -17,17 +17,18 @@
|
||||
*/
|
||||
|
||||
#include "choice.h"
|
||||
|
||||
#include "menu.h"
|
||||
#include "theme.h"
|
||||
|
||||
void choice_changed_cb(lv_event_t *e)
|
||||
void choice_changed_cb(lv_event_t* e)
|
||||
{
|
||||
auto code = lv_event_get_code(e);
|
||||
|
||||
if (code == LV_EVENT_VALUE_CHANGED) {
|
||||
lv_obj_t *target = lv_event_get_target(e);
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
if (target != nullptr) {
|
||||
ChoiceBase *cb = (ChoiceBase*)lv_obj_get_user_data(target);
|
||||
ChoiceBase* cb = (ChoiceBase*)lv_obj_get_user_data(target);
|
||||
if (cb) {
|
||||
std::string text = cb->getLabelText();
|
||||
lv_label_set_text(cb->label, text.c_str());
|
||||
@@ -38,20 +39,19 @@ void choice_changed_cb(lv_event_t *e)
|
||||
|
||||
ChoiceBase::ChoiceBase(Window* parent, const rect_t& rect, ChoiceType type,
|
||||
WindowFlags windowFlags) :
|
||||
FormField(parent, rect, windowFlags, 0, etx_choice_create),
|
||||
type(type)
|
||||
FormField(parent, rect, windowFlags, 0, etx_choice_create), type(type)
|
||||
{
|
||||
// lv_obj_set_height(lvobj, LV_SIZE_CONTENT);
|
||||
// lv_obj_set_width(lvobj, LV_SIZE_CONTENT);
|
||||
// lv_obj_set_height(lvobj, LV_SIZE_CONTENT);
|
||||
// lv_obj_set_width(lvobj, LV_SIZE_CONTENT);
|
||||
lv_obj_set_layout(lvobj, LV_LAYOUT_FLEX);
|
||||
lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW);
|
||||
|
||||
lv_obj_add_event_cb(lvobj, choice_changed_cb, LV_EVENT_VALUE_CHANGED, lvobj);
|
||||
label = lv_label_create(lvobj);
|
||||
|
||||
lv_group_t * def_group = lv_group_get_default();
|
||||
if(def_group) {
|
||||
lv_group_add_obj(def_group, lvobj);
|
||||
|
||||
lv_group_t* def_group = lv_group_get_default();
|
||||
if (def_group) {
|
||||
lv_group_add_obj(def_group, lvobj);
|
||||
}
|
||||
|
||||
lv_obj_set_style_pad_left(label, FIELD_PADDING_LEFT, LV_PART_MAIN);
|
||||
@@ -60,8 +60,9 @@ ChoiceBase::ChoiceBase(Window* parent, const rect_t& rect, ChoiceType type,
|
||||
// lv_obj_set
|
||||
|
||||
// add the image
|
||||
lv_obj_t *img = lv_img_create(lvobj);
|
||||
lv_img_set_src(img, type == CHOICE_TYPE_DROPOWN ? LV_SYMBOL_DOWN : LV_SYMBOL_DIRECTORY);
|
||||
lv_obj_t* img = lv_img_create(lvobj);
|
||||
lv_img_set_src(
|
||||
img, type == CHOICE_TYPE_DROPOWN ? LV_SYMBOL_DOWN : LV_SYMBOL_DIRECTORY);
|
||||
lv_obj_set_align(img, LV_ALIGN_RIGHT_MID);
|
||||
}
|
||||
|
||||
@@ -70,7 +71,9 @@ std::string Choice::getLabelText()
|
||||
std::string text;
|
||||
|
||||
if (textHandler != nullptr) {
|
||||
if (_getValue) { text = textHandler(_getValue()); }
|
||||
if (_getValue) {
|
||||
text = textHandler(_getValue());
|
||||
}
|
||||
} else if (_getValue) {
|
||||
int val = _getValue();
|
||||
val -= vmin;
|
||||
@@ -78,7 +81,7 @@ std::string Choice::getLabelText()
|
||||
text = values[val];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -111,8 +114,8 @@ Choice::Choice(Window* parent, const rect_t& rect, const char* const values[],
|
||||
|
||||
Choice::Choice(Window* parent, const rect_t& rect,
|
||||
std::vector<std::string> values, int vmin, int vmax,
|
||||
std::function<int()> _getValue, std::function<void(int)> _setValue,
|
||||
WindowFlags windowFlags) :
|
||||
std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue, WindowFlags windowFlags) :
|
||||
ChoiceBase(parent, rect, CHOICE_TYPE_DROPOWN, windowFlags),
|
||||
values(std::move(values)),
|
||||
vmin(vmin),
|
||||
@@ -146,17 +149,16 @@ Choice::Choice(Window* parent, const rect_t& rect, const char* values, int vmin,
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
void Choice::addValue(const char * value)
|
||||
void Choice::addValue(const char* value)
|
||||
{
|
||||
values.emplace_back(value);
|
||||
vmax += 1;
|
||||
}
|
||||
|
||||
void Choice::addValues(const char * const values[], uint8_t count)
|
||||
void Choice::addValues(const char* const values[], uint8_t count)
|
||||
{
|
||||
this->values.reserve(this->values.size() + count);
|
||||
for (uint8_t i = 0; i < count; i++)
|
||||
this->values.emplace_back(values[i]);
|
||||
for (uint8_t i = 0; i < count; i++) this->values.emplace_back(values[i]);
|
||||
vmax += count;
|
||||
}
|
||||
|
||||
@@ -165,7 +167,7 @@ void Choice::setValues(std::vector<std::string> values)
|
||||
this->values = std::move(values);
|
||||
}
|
||||
|
||||
void Choice::setValues(const char * const values[])
|
||||
void Choice::setValues(const char* const values[])
|
||||
{
|
||||
this->values.clear();
|
||||
if (values) {
|
||||
@@ -186,18 +188,17 @@ void Choice::setValue(int val)
|
||||
|
||||
void Choice::onClicked()
|
||||
{
|
||||
if (!longPressData.isLongPressed)
|
||||
openMenu();
|
||||
if (!longPressData.isLongPressed) openMenu();
|
||||
}
|
||||
|
||||
void Choice::fillMenu(Menu *menu, const FilterFct& filter)
|
||||
void Choice::fillMenu(Menu* menu, const FilterFct& filter)
|
||||
{
|
||||
menu->removeLines();
|
||||
auto value = _getValue();
|
||||
auto value = getIntValue();
|
||||
|
||||
int count = 0;
|
||||
int selectedIx = -1;
|
||||
int selectedIx0 = -1;
|
||||
selectedIx0 = -1;
|
||||
for (int i = vmin; i <= vmax; ++i) {
|
||||
if (filter && !filter(i)) continue;
|
||||
if (isValueAvailable && !isValueAvailable(i)) continue;
|
||||
@@ -208,8 +209,12 @@ void Choice::fillMenu(Menu *menu, const FilterFct& filter)
|
||||
} else {
|
||||
menu->addLineBuffered(std::to_string(i), [=]() { setValue(i); });
|
||||
}
|
||||
if (value == i) { selectedIx = count; }
|
||||
if (i == 0) { selectedIx0 = count; }
|
||||
if (value == i) {
|
||||
selectedIx = count;
|
||||
}
|
||||
if (i == 0) {
|
||||
selectedIx0 = count;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
if (fillMenuHandler) {
|
||||
@@ -234,12 +239,12 @@ void Choice::openMenu()
|
||||
auto menu = new Menu(this);
|
||||
if (!menuTitle.empty()) menu->setTitle(menuTitle);
|
||||
|
||||
fillMenu(menu);
|
||||
|
||||
if (beforeDisplayMenuHandler) {
|
||||
beforeDisplayMenuHandler(menu);
|
||||
}
|
||||
|
||||
fillMenu(menu);
|
||||
|
||||
menu->setCloseHandler([=]() { setEditMode(false); });
|
||||
}
|
||||
|
||||
|
||||
+126
-128
@@ -19,12 +19,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "form.h"
|
||||
|
||||
typedef void (*lvHandler_t)(void*);
|
||||
typedef void (*lvHandler_t)(void *);
|
||||
|
||||
typedef struct {
|
||||
void* userData;
|
||||
void *userData;
|
||||
bool isLongPressed;
|
||||
lvHandler_t lv_LongPressHandler;
|
||||
} lv_eventData_t;
|
||||
@@ -44,168 +45,165 @@ class ChoiceBase : public FormField
|
||||
ChoiceBase(Window *parent, const rect_t &rect,
|
||||
ChoiceType type = CHOICE_TYPE_DROPOWN,
|
||||
WindowFlags windowFlags = 0);
|
||||
|
||||
|
||||
protected:
|
||||
ChoiceType type;
|
||||
lv_obj_t* label;
|
||||
lv_obj_t *label;
|
||||
|
||||
friend void choice_changed_cb(lv_event_t *e);
|
||||
virtual std::string getLabelText() { return ""; };
|
||||
};
|
||||
|
||||
class Choice: public ChoiceBase {
|
||||
public:
|
||||
Choice(Window* parent, const rect_t &rect, int vmin, int vmax,
|
||||
std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
Choice(Window* parent, const rect_t &rect,
|
||||
std::vector<std::string> values, int vmin, int vmax,
|
||||
std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
Choice(Window* parent, const rect_t &rect, const char *const values[],
|
||||
int vmin, int vmax, std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
Choice(Window* parent, const rect_t &rect, const char *values, int vmin,
|
||||
int vmax, std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
class Choice : public ChoiceBase
|
||||
{
|
||||
public:
|
||||
Choice(Window *parent, const rect_t &rect, int vmin, int vmax,
|
||||
std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
Choice(Window *parent, const rect_t &rect, std::vector<std::string> values,
|
||||
int vmin, int vmax, std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
Choice(Window *parent, const rect_t &rect, const char *const values[],
|
||||
int vmin, int vmax, std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
Choice(Window *parent, const rect_t &rect, const char *values, int vmin,
|
||||
int vmax, std::function<int()> _getValue,
|
||||
std::function<void(int)> _setValue = nullptr,
|
||||
WindowFlags windowFlags = 0);
|
||||
|
||||
void addValue(const char *value);
|
||||
void addValue(const char *value);
|
||||
|
||||
void addValues(const char *const values[], uint8_t count);
|
||||
void addValues(const char *const values[], uint8_t count);
|
||||
|
||||
void setValues(std::vector<std::string> values);
|
||||
void setValues(std::vector<std::string> values);
|
||||
|
||||
void setValues(const char *const values[]);
|
||||
void setValues(const char *const values[]);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "Choice";
|
||||
}
|
||||
std::string getName() const override { return "Choice"; }
|
||||
#endif
|
||||
|
||||
void onClicked() override;
|
||||
void onClicked() override;
|
||||
|
||||
void setFillMenuHandler(std::function<void(Menu*, int, int&)> handler)
|
||||
{
|
||||
fillMenuHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setBeforeDisplayMenuHandler(std::function<void(Menu*)> handler)
|
||||
{
|
||||
beforeDisplayMenuHandler = std::move(handler);
|
||||
void setFillMenuHandler(std::function<void(Menu*, int, int&)> handler)
|
||||
{
|
||||
fillMenuHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setBeforeDisplayMenuHandler(std::function<void(Menu *)> handler)
|
||||
{
|
||||
beforeDisplayMenuHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setSetValueHandler(std::function<void(int)> handler)
|
||||
{
|
||||
_setValue = std::move(handler);
|
||||
}
|
||||
|
||||
void setGetValueHandler(std::function<int()> handler)
|
||||
{
|
||||
_getValue = std::move(handler);
|
||||
}
|
||||
|
||||
void setAvailableHandler(std::function<bool(int)> handler)
|
||||
{
|
||||
isValueAvailable = std::move(handler);
|
||||
}
|
||||
|
||||
unsigned getIndexFromValue(int value) const
|
||||
{
|
||||
if (!isValueAvailable) {
|
||||
return value - vmin;
|
||||
}
|
||||
|
||||
void setSetValueHandler(std::function<void(int)> handler)
|
||||
{
|
||||
_setValue = std::move(handler);
|
||||
}
|
||||
|
||||
void setGetValueHandler(std::function<int()> handler)
|
||||
{
|
||||
_getValue = std::move(handler);
|
||||
}
|
||||
|
||||
void setAvailableHandler(std::function<bool(int)> handler)
|
||||
{
|
||||
isValueAvailable = std::move(handler);
|
||||
}
|
||||
|
||||
unsigned getIndexFromValue(int value) const
|
||||
{
|
||||
if (!isValueAvailable) {
|
||||
return value - vmin;
|
||||
unsigned index = 0;
|
||||
for (int i = vmin; i < value; i++) {
|
||||
if (isValueAvailable(i)) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
unsigned index = 0;
|
||||
for (int i = vmin; i < value; i++) {
|
||||
if (isValueAvailable(i)) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
int getValueFromIndex(int index) const
|
||||
{
|
||||
if (!isValueAvailable) {
|
||||
return vmin + index;
|
||||
}
|
||||
|
||||
int getValueFromIndex(int index) const
|
||||
{
|
||||
if (!isValueAvailable) {
|
||||
return vmin + index;
|
||||
}
|
||||
|
||||
int value = vmin - 1;
|
||||
while (index >= 0) {
|
||||
index--;
|
||||
int value = vmin - 1;
|
||||
while (index >= 0) {
|
||||
index--;
|
||||
value++;
|
||||
while (value < vmax && !isValueAvailable(value)) {
|
||||
value++;
|
||||
while (value < vmax && !isValueAvailable(value)) {
|
||||
value++;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void setValue(int val);
|
||||
int getIntValue() const { return _getValue(); }
|
||||
virtual void setValue(int val);
|
||||
virtual int getIntValue() const { return _getValue(); }
|
||||
|
||||
unsigned getValuesCount() const
|
||||
{
|
||||
return getIndexFromValue(vmax + 1);
|
||||
}
|
||||
unsigned getValuesCount() const { return getIndexFromValue(vmax + 1); }
|
||||
|
||||
void setTextHandler(std::function<std::string(int)> handler)
|
||||
{
|
||||
textHandler = std::move(handler);
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
void setTextHandler(std::function<std::string(int)> handler)
|
||||
{
|
||||
textHandler = std::move(handler);
|
||||
lv_event_send(lvobj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
void setMenuTitle(std::string value)
|
||||
{
|
||||
menuTitle = std::move(value);
|
||||
}
|
||||
void setMenuTitle(std::string value) { menuTitle = std::move(value); }
|
||||
std::string getMenuTitle() const { return menuTitle; }
|
||||
|
||||
void setMin(int value)
|
||||
{
|
||||
vmin = value;
|
||||
invalidate();
|
||||
}
|
||||
void setMin(int value)
|
||||
{
|
||||
vmin = value;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void setMax(int value)
|
||||
{
|
||||
vmax = value;
|
||||
invalidate();
|
||||
}
|
||||
void setMax(int value)
|
||||
{
|
||||
vmax = value;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void set_lv_LongPressHandler(lvHandler_t longPressHandler, void* data);
|
||||
int getMin() const { return vmin; }
|
||||
int getMax() const { return vmax; }
|
||||
|
||||
protected:
|
||||
friend class MenuToolbar;
|
||||
void set_lv_LongPressHandler(lvHandler_t longPressHandler, void *data);
|
||||
|
||||
std::string getLabelText() override;
|
||||
std::vector<std::string> values;
|
||||
int vmin = 0;
|
||||
int vmax = 0;
|
||||
std::string menuTitle;
|
||||
std::function<int()> _getValue;
|
||||
std::function<void(int)> _setValue;
|
||||
std::function<bool(int)> isValueAvailable;
|
||||
std::function<std::string(int)> textHandler;
|
||||
std::function<void(Menu *, int, int&)> fillMenuHandler;
|
||||
std::function <void(Menu *)> beforeDisplayMenuHandler;
|
||||
int selectedIx0 = 0;
|
||||
|
||||
typedef std::function<bool(int16_t)> FilterFct;
|
||||
void fillMenu(Menu *menu, const FilterFct& filter = nullptr);
|
||||
protected:
|
||||
friend class MenuToolbar;
|
||||
|
||||
virtual void openMenu();
|
||||
std::string getLabelText() override;
|
||||
std::vector<std::string> values;
|
||||
int vmin = 0;
|
||||
int vmax = 0;
|
||||
std::string menuTitle;
|
||||
std::function<int()> _getValue;
|
||||
std::function<void(int)> _setValue;
|
||||
std::function<bool(int)> isValueAvailable;
|
||||
std::function<std::string(int)> textHandler;
|
||||
std::function<void(Menu *, int, int&)> fillMenuHandler;
|
||||
std::function<void(Menu *)> beforeDisplayMenuHandler;
|
||||
|
||||
lv_eventData_t longPressData;
|
||||
std::function<void(event_t)> longPressHandler = nullptr;
|
||||
typedef std::function<bool(int16_t)> FilterFct;
|
||||
void fillMenu(Menu *menu, const FilterFct &filter = nullptr);
|
||||
|
||||
static void ClickHandler(lv_event_t* e)
|
||||
{
|
||||
auto ch = (Choice*)lv_event_get_user_data(e);
|
||||
if (ch) ch->longPressData.isLongPressed = false;
|
||||
}
|
||||
virtual void openMenu();
|
||||
|
||||
lv_eventData_t longPressData;
|
||||
std::function<void(event_t)> longPressHandler = nullptr;
|
||||
|
||||
static void ClickHandler(lv_event_t *e)
|
||||
{
|
||||
auto ch = (Choice *)lv_event_get_user_data(e);
|
||||
if (ch) ch->longPressData.isLongPressed = false;
|
||||
}
|
||||
};
|
||||
|
||||
+5
-2
@@ -41,8 +41,8 @@ enum FontIndex
|
||||
constexpr uint32_t MENU_HEADER_BUTTON_WIDTH = 33;
|
||||
constexpr uint32_t MENU_HEADER_BUTTONS_LEFT = 47;
|
||||
|
||||
constexpr uint32_t MENUS_TOOLBAR_BUTTON_WIDTH = 30;
|
||||
constexpr uint32_t MENUS_TOOLBAR_BUTTON_PADDING = 3;
|
||||
constexpr uint32_t MENUS_TOOLBAR_BUTTON_WIDTH = 32;
|
||||
constexpr uint32_t MENUS_TOOLBAR_BUTTON_PADDING = 4;
|
||||
|
||||
constexpr uint32_t MENU_HEADER_HEIGHT = 45;
|
||||
constexpr uint32_t MENU_TITLE_TOP = 48;
|
||||
@@ -108,5 +108,8 @@ constexpr coord_t MODEL_SELECT_FOOTER_HEIGHT = 24;
|
||||
|
||||
#define LV_OBJ_FLAG_ENCODER_ACCEL LV_OBJ_FLAG_USER_1
|
||||
|
||||
constexpr coord_t MENUS_LINE_HEIGHT = 35;
|
||||
constexpr coord_t MENUS_WIDTH = 200;
|
||||
|
||||
#include "libopenui_config.h"
|
||||
|
||||
|
||||
+77
-69
@@ -17,12 +17,15 @@
|
||||
*/
|
||||
|
||||
#include "menu.h"
|
||||
#include "font.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
void MenuBody::onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc)
|
||||
#include "font.h"
|
||||
#include "menutoolbar.h"
|
||||
#include "theme.h"
|
||||
|
||||
void MenuBody::onDrawBegin(uint16_t row, uint16_t col,
|
||||
lv_obj_draw_part_dsc_t* dsc)
|
||||
{
|
||||
lv_canvas_t* icon = (lv_canvas_t*)lines[row].getIcon();
|
||||
if (!icon) return;
|
||||
@@ -32,15 +35,16 @@ void MenuBody::onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* d
|
||||
dsc->label_dsc->ofs_x = img->w + cell_left;
|
||||
}
|
||||
|
||||
void MenuBody::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc)
|
||||
void MenuBody::onDrawEnd(uint16_t row, uint16_t col,
|
||||
lv_obj_draw_part_dsc_t* dsc)
|
||||
{
|
||||
if(row >= lines.size()) return;
|
||||
if (row >= lines.size()) return;
|
||||
|
||||
lv_obj_t* icon = lines[row].getIcon();
|
||||
if (icon) {
|
||||
lv_draw_img_dsc_t img_dsc;
|
||||
lv_draw_img_dsc_init(&img_dsc);
|
||||
|
||||
|
||||
lv_img_dsc_t* img = lv_canvas_get_img(icon);
|
||||
lv_area_t coords;
|
||||
|
||||
@@ -51,12 +55,11 @@ void MenuBody::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc
|
||||
coords.x2 = coords.x1 + img->header.w - 1;
|
||||
coords.y1 = dsc->draw_area->y1 + (area_h - img->header.h) / 2;
|
||||
coords.y2 = coords.y1 + img->header.h - 1;
|
||||
|
||||
|
||||
lv_draw_img(dsc->draw_ctx, &img_dsc, &coords, img);
|
||||
}
|
||||
|
||||
if(lines[row].isChecked != nullptr &&
|
||||
lines[row].isChecked()) {
|
||||
if (lines[row].isChecked != nullptr && lines[row].isChecked()) {
|
||||
lv_area_t coords;
|
||||
lv_coord_t area_h = lv_area_get_height(dsc->draw_area);
|
||||
lv_coord_t cell_right = lv_obj_get_style_pad_right(lvobj, LV_PART_ITEMS);
|
||||
@@ -65,17 +68,28 @@ void MenuBody::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc
|
||||
coords.x2 = coords.x1 + font_h;
|
||||
coords.y1 = dsc->draw_area->y1 + (area_h - font_h) / 2;
|
||||
coords.y2 = coords.y1 + font_h - 1;
|
||||
lv_draw_label(dsc->draw_ctx, dsc->label_dsc, &coords, LV_SYMBOL_OK, nullptr);
|
||||
lv_draw_label(dsc->draw_ctx, dsc->label_dsc, &coords, LV_SYMBOL_OK,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void _force_editing(lv_group_t* g)
|
||||
static void _force_editing(lv_group_t* g) { lv_group_set_editing(g, true); }
|
||||
|
||||
static void localLongPressHandler(lv_event_t* e)
|
||||
{
|
||||
lv_group_set_editing(g, true);
|
||||
MenuBody* menuBody = (MenuBody*)lv_event_get_user_data(e);
|
||||
if (menuBody) menuBody->longPress();
|
||||
}
|
||||
|
||||
MenuBody::MenuBody(Window * parent, const rect_t & rect):
|
||||
TableField(parent, rect)
|
||||
void MenuBody::longPress()
|
||||
{
|
||||
isLongPressed = true;
|
||||
Menu* menu = getParentMenu();
|
||||
if (menu) menu->longPress();
|
||||
}
|
||||
|
||||
MenuBody::MenuBody(Window* parent, const rect_t& rect) :
|
||||
TableField(parent, rect)
|
||||
{
|
||||
// Allow encoder acceleration
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL);
|
||||
@@ -96,9 +110,12 @@ MenuBody::MenuBody(Window * parent, const rect_t & rect):
|
||||
});
|
||||
lv_group_set_editing(g, true);
|
||||
}
|
||||
|
||||
lv_obj_add_event_cb(lvobj, localLongPressHandler, LV_EVENT_LONG_PRESSED,
|
||||
this);
|
||||
}
|
||||
|
||||
void MenuBody::addLine(const std::string &text, std::function<void()> onPress,
|
||||
void MenuBody::addLine(const std::string& text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked, bool update)
|
||||
{
|
||||
lines.emplace_back(text, std::move(onPress), std::move(isChecked), nullptr);
|
||||
@@ -109,16 +126,15 @@ void MenuBody::addLine(const std::string &text, std::function<void()> onPress,
|
||||
}
|
||||
}
|
||||
|
||||
void MenuBody::addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
void MenuBody::addLine(const uint8_t* icon_mask, const std::string& text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked,
|
||||
bool update)
|
||||
std::function<bool()> isChecked, bool update)
|
||||
{
|
||||
lv_obj_t* canvas = lv_canvas_create(nullptr);
|
||||
lines.emplace_back(text, std::move(onPress), std::move(isChecked), canvas);
|
||||
|
||||
lv_coord_t w = *((uint16_t *)icon_mask);
|
||||
lv_coord_t h = *(((uint16_t *)icon_mask)+1);
|
||||
lv_coord_t w = *((uint16_t*)icon_mask);
|
||||
lv_coord_t h = *(((uint16_t*)icon_mask) + 1);
|
||||
void* buf = (void*)(icon_mask + 4);
|
||||
lv_canvas_set_buffer(canvas, buf, w, h, LV_IMG_CF_ALPHA_8BIT);
|
||||
|
||||
@@ -131,7 +147,7 @@ void MenuBody::addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
void MenuBody::updateLines()
|
||||
{
|
||||
setRowCount(lines.size());
|
||||
for(unsigned int idx = 0; idx < lines.size(); idx++) {
|
||||
for (unsigned int idx = 0; idx < lines.size(); idx++) {
|
||||
lv_table_set_cell_value(lvobj, idx, 0, lines[idx].text.c_str());
|
||||
}
|
||||
}
|
||||
@@ -146,14 +162,11 @@ void MenuBody::removeLines()
|
||||
lv_obj_scroll_to_y(lvobj, 0, LV_ANIM_OFF);
|
||||
}
|
||||
|
||||
coord_t MenuBody::getContentHeight()
|
||||
{
|
||||
return lv_obj_get_self_height(lvobj);
|
||||
}
|
||||
coord_t MenuBody::getContentHeight() { return lv_obj_get_self_height(lvobj); }
|
||||
|
||||
void MenuBody::onPress(size_t index)
|
||||
{
|
||||
Menu *menu = getParentMenu();
|
||||
Menu* menu = getParentMenu();
|
||||
if (index < lines.size()) {
|
||||
if (menu->multiple) {
|
||||
if (selectedIndex == (int)index)
|
||||
@@ -196,15 +209,14 @@ void MenuBody::setIndex(int index)
|
||||
table->col_act = LV_TABLE_CELL_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
table->row_act = index;
|
||||
table->col_act = 0;
|
||||
|
||||
lv_coord_t h_before = 0;
|
||||
for (uint16_t i = 0; i < table->row_act; i++)
|
||||
h_before += table->row_h[i];
|
||||
for (uint16_t i = 0; i < table->row_act; i++) h_before += table->row_h[i];
|
||||
|
||||
lv_coord_t row_h = table->row_h[table->row_act];
|
||||
lv_coord_t row_h = table->row_h[table->row_act];
|
||||
lv_coord_t scroll_y = lv_obj_get_scroll_y(lvobj);
|
||||
|
||||
lv_obj_update_layout(lvobj);
|
||||
@@ -225,24 +237,16 @@ void MenuBody::setIndex(int index)
|
||||
|
||||
void MenuBody::onPress(uint16_t row, uint16_t col)
|
||||
{
|
||||
onPress(row);
|
||||
if (!isLongPressed) onPress(row);
|
||||
isLongPressed = false;
|
||||
}
|
||||
|
||||
void MenuBody::selectNext(MENU_DIRECTION direction)
|
||||
{
|
||||
// look for the next non separator line
|
||||
int index = selectedIndex + direction;
|
||||
setIndex(rangeCheck(index));
|
||||
}
|
||||
|
||||
|
||||
void MenuBody::onEvent(event_t event)
|
||||
{
|
||||
#if defined(HARDWARE_KEYS)
|
||||
if (event == EVT_KEY_BREAK(KEY_EXIT)) {
|
||||
onCancel();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
TableField::onEvent(event);
|
||||
}
|
||||
#endif
|
||||
@@ -250,7 +254,7 @@ void MenuBody::onEvent(event_t event)
|
||||
|
||||
void MenuBody::onCancel()
|
||||
{
|
||||
if(_onCancel) _onCancel();
|
||||
if (_onCancel) _onCancel();
|
||||
TableField::onCancel();
|
||||
}
|
||||
|
||||
@@ -274,14 +278,14 @@ void MenuWindowContent::deleteLater(bool detach, bool trash)
|
||||
ModalWindowContent::deleteLater(detach, trash);
|
||||
}
|
||||
|
||||
Menu::Menu(Window * parent, bool multiple):
|
||||
ModalWindow(parent, true),
|
||||
content(new MenuWindowContent(this)),
|
||||
multiple(multiple)
|
||||
Menu::Menu(Window* parent, bool multiple) :
|
||||
ModalWindow(parent, true),
|
||||
content(new MenuWindowContent(this)),
|
||||
multiple(multiple)
|
||||
{
|
||||
}
|
||||
|
||||
void Menu::setToolbar(Window * window)
|
||||
void Menu::setToolbar(MenuToolbar* window)
|
||||
{
|
||||
toolbar = window;
|
||||
updatePosition();
|
||||
@@ -293,10 +297,10 @@ void Menu::setToolbar(Window * window)
|
||||
void Menu::setOutline(Window* obj)
|
||||
{
|
||||
lv_obj_set_style_outline_width(obj->getLvObj(), 2, LV_PART_MAIN);
|
||||
lv_obj_set_style_outline_color(obj->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY2), LV_PART_MAIN);
|
||||
lv_obj_set_style_outline_opa(obj->getLvObj(), LV_OPA_100, LV_PART_MAIN);
|
||||
lv_obj_set_style_outline_pad(obj->getLvObj(), 1, LV_PART_MAIN);
|
||||
|
||||
lv_obj_set_style_outline_color(
|
||||
obj->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY2), LV_PART_MAIN);
|
||||
lv_obj_set_style_outline_opa(obj->getLvObj(), LV_OPA_100, LV_PART_MAIN);
|
||||
lv_obj_set_style_outline_pad(obj->getLvObj(), 1, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
void Menu::updatePosition()
|
||||
@@ -304,10 +308,10 @@ void Menu::updatePosition()
|
||||
coord_t height = content->body.getContentHeight();
|
||||
|
||||
if (toolbar) {
|
||||
content->setLeft((LCD_W - content->width() + toolbar->width())/2);
|
||||
content->setLeft((LCD_W - content->width() + toolbar->width()) / 2);
|
||||
setOutline(toolbar);
|
||||
} else {
|
||||
content->setLeft((LCD_W - content->width())/2);
|
||||
content->setLeft((LCD_W - content->width()) / 2);
|
||||
auto headerHeight = content->getHeaderHeight();
|
||||
auto bodyHeight = min<coord_t>(height, MENUS_MAX_HEIGHT - headerHeight);
|
||||
content->setTop((LCD_H - headerHeight - bodyHeight) / 2);
|
||||
@@ -324,32 +328,35 @@ void Menu::setTitle(std::string text)
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::addLine(const std::string &text, std::function<void()> onPress,
|
||||
void Menu::addLine(const std::string& text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
{
|
||||
content->body.addLine(text, std::move(onPress), std::move(isChecked));
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
void Menu::addLine(const uint8_t* icon_mask, const std::string& text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
{
|
||||
content->body.addLine(icon_mask, text, std::move(onPress), std::move(isChecked));
|
||||
content->body.addLine(icon_mask, text, std::move(onPress),
|
||||
std::move(isChecked));
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void Menu::addLineBuffered(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
void Menu::addLineBuffered(const std::string& text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
{
|
||||
content->body.addLine(text, std::move(onPress), std::move(isChecked), false);
|
||||
}
|
||||
|
||||
void Menu::addLineBuffered(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
void Menu::addLineBuffered(const uint8_t* icon_mask, const std::string& text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked)
|
||||
{
|
||||
content->body.addLine(icon_mask, text, std::move(onPress), std::move(isChecked), false);
|
||||
content->body.addLine(icon_mask, text, std::move(onPress),
|
||||
std::move(isChecked), false);
|
||||
}
|
||||
|
||||
void Menu::updateLines()
|
||||
@@ -367,20 +374,21 @@ void Menu::removeLines()
|
||||
void Menu::onEvent(event_t event)
|
||||
{
|
||||
#if defined(HARDWARE_KEYS)
|
||||
if (toolbar &&
|
||||
(event == EVT_KEY_BREAK(KEY_PAGEDN) ||
|
||||
if (toolbar && (event == EVT_KEY_BREAK(KEY_PAGEDN) ||
|
||||
#if defined(KEYS_GPIO_REG_PAGEUP)
|
||||
event == EVT_KEY_BREAK(KEY_PAGEUP)
|
||||
event == EVT_KEY_BREAK(KEY_PAGEUP)
|
||||
#else
|
||||
event == EVT_KEY_LONG(KEY_PAGEDN)
|
||||
event == EVT_KEY_LONG(KEY_PAGEDN)
|
||||
#endif
|
||||
)) {
|
||||
)) {
|
||||
toolbar->onEvent(event);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Menu::onCancel()
|
||||
void Menu::onCancel() { deleteLater(); }
|
||||
|
||||
void Menu::longPress()
|
||||
{
|
||||
deleteLater();
|
||||
if (toolbar) toolbar->longPress();
|
||||
}
|
||||
|
||||
+123
-143
@@ -18,51 +18,49 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "modal_window.h"
|
||||
#include "table.h"
|
||||
|
||||
class Menu;
|
||||
class MenuWindowContent;
|
||||
class MenuToolbar;
|
||||
|
||||
struct lvobj_delete {
|
||||
constexpr lvobj_delete() = default;
|
||||
void operator()(lv_obj_t* obj) const {
|
||||
lv_obj_del(obj);
|
||||
}
|
||||
void operator()(lv_obj_t *obj) const { lv_obj_del(obj); }
|
||||
};
|
||||
|
||||
class MenuBody: public TableField
|
||||
class MenuBody : public TableField
|
||||
{
|
||||
friend class MenuWindowContent;
|
||||
friend class Menu;
|
||||
|
||||
enum MENU_DIRECTION
|
||||
{
|
||||
DIRECTION_UP = 1,
|
||||
DIRECTION_DOWN = -1
|
||||
};
|
||||
enum MENU_DIRECTION { DIRECTION_UP = 1, DIRECTION_DOWN = -1 };
|
||||
|
||||
class MenuLine
|
||||
{
|
||||
friend class MenuBody;
|
||||
|
||||
public:
|
||||
MenuLine(const std::string& text, std::function<void()> onPress, std::function<bool()> isChecked,
|
||||
lv_obj_t *icon) :
|
||||
text(text), onPress(std::move(onPress)), isChecked(std::move(isChecked)), icon(icon)
|
||||
MenuLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked, lv_obj_t *icon) :
|
||||
text(text),
|
||||
onPress(std::move(onPress)),
|
||||
isChecked(std::move(isChecked)),
|
||||
icon(icon)
|
||||
{
|
||||
}
|
||||
|
||||
MenuLine(MenuLine &) = delete;
|
||||
MenuLine(MenuLine &&) = default;
|
||||
|
||||
lv_obj_t* getIcon() { return icon.get(); }
|
||||
|
||||
lv_obj_t *getIcon() { return icon.get(); }
|
||||
|
||||
protected:
|
||||
std::string text;
|
||||
std::function<void()> onPress;
|
||||
@@ -70,175 +68,157 @@ class MenuBody: public TableField
|
||||
std::unique_ptr<lv_obj_t, lvobj_delete> icon;
|
||||
};
|
||||
|
||||
public:
|
||||
MenuBody(Window * parent, const rect_t & rect);
|
||||
public:
|
||||
MenuBody(Window *parent, const rect_t &rect);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "MenuBody";
|
||||
}
|
||||
std::string getName() const override { return "MenuBody"; }
|
||||
#endif
|
||||
|
||||
void setIndex(int index);
|
||||
void setIndex(int index);
|
||||
|
||||
int selection() const
|
||||
{
|
||||
return selectedIndex;
|
||||
}
|
||||
int selection() const { return selectedIndex; }
|
||||
|
||||
int count() const
|
||||
{
|
||||
return lines.size();
|
||||
}
|
||||
int count() const { return lines.size(); }
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void onCancel() override;
|
||||
void onEvent(event_t event) override;
|
||||
void onCancel() override;
|
||||
|
||||
void addLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked, bool update = true);
|
||||
void addLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked, bool update = true);
|
||||
|
||||
void addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked,
|
||||
bool update = true);
|
||||
void addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress, std::function<bool()> isChecked,
|
||||
bool update = true);
|
||||
|
||||
void updateLines();
|
||||
void updateLines();
|
||||
|
||||
void removeLines();
|
||||
void removeLines();
|
||||
|
||||
void setCancelHandler(std::function<void()> handler)
|
||||
{
|
||||
_onCancel = std::move(handler);
|
||||
}
|
||||
void setCancelHandler(std::function<void()> handler)
|
||||
{
|
||||
_onCancel = std::move(handler);
|
||||
}
|
||||
|
||||
coord_t getContentHeight();
|
||||
coord_t getContentHeight();
|
||||
|
||||
void onPress(size_t index);
|
||||
|
||||
protected:
|
||||
void onPress(uint16_t row, uint16_t col) override;
|
||||
void onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override;
|
||||
void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override;
|
||||
void onPress(size_t index);
|
||||
void longPress();
|
||||
|
||||
void selectNext(MENU_DIRECTION direction);
|
||||
int rangeCheck(int);
|
||||
protected:
|
||||
bool isLongPressed = false;
|
||||
|
||||
std::vector<MenuLine> lines;
|
||||
int selectedIndex = 0;
|
||||
std::function<void()> _onCancel;
|
||||
void onPress(uint16_t row, uint16_t col) override;
|
||||
void onDrawBegin(uint16_t row, uint16_t col,
|
||||
lv_obj_draw_part_dsc_t *dsc) override;
|
||||
void onDrawEnd(uint16_t row, uint16_t col,
|
||||
lv_obj_draw_part_dsc_t *dsc) override;
|
||||
|
||||
inline Menu * getParentMenu();
|
||||
int rangeCheck(int);
|
||||
|
||||
std::vector<MenuLine> lines;
|
||||
int selectedIndex = 0;
|
||||
std::function<void()> _onCancel;
|
||||
|
||||
inline Menu *getParentMenu();
|
||||
|
||||
void onSelected(uint16_t row, uint16_t col) override { selectedIndex = row; }
|
||||
};
|
||||
|
||||
class MenuWindowContent: public ModalWindowContent
|
||||
class MenuWindowContent : public ModalWindowContent
|
||||
{
|
||||
friend class Menu;
|
||||
|
||||
public:
|
||||
explicit MenuWindowContent(Menu * parent);
|
||||
public:
|
||||
explicit MenuWindowContent(Menu *parent);
|
||||
|
||||
coord_t getHeaderHeight() const;
|
||||
coord_t getHeaderHeight() const;
|
||||
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "MenuWindowContent";
|
||||
}
|
||||
std::string getName() const override { return "MenuWindowContent"; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
MenuBody body;
|
||||
protected:
|
||||
MenuBody body;
|
||||
};
|
||||
|
||||
class Menu: public ModalWindow
|
||||
class Menu : public ModalWindow
|
||||
{
|
||||
friend class MenuBody;
|
||||
|
||||
public:
|
||||
explicit Menu(Window * parent, bool multiple = false);
|
||||
public:
|
||||
explicit Menu(Window *parent, bool multiple = false);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "Menu";
|
||||
}
|
||||
std::string getName() const override { return "Menu"; }
|
||||
#endif
|
||||
|
||||
void setCancelHandler(std::function<void()> handler)
|
||||
{
|
||||
content->body.setCancelHandler(std::move(handler));
|
||||
|
||||
void setCancelHandler(std::function<void()> handler)
|
||||
{
|
||||
content->body.setCancelHandler(std::move(handler));
|
||||
}
|
||||
|
||||
void setWaitHandler(std::function<void()> handler)
|
||||
{
|
||||
waitHandler = std::move(handler);
|
||||
}
|
||||
|
||||
void setToolbar(MenuToolbar *window);
|
||||
|
||||
void setTitle(std::string text);
|
||||
|
||||
void addLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addLineBuffered(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addLineBuffered(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void updateLines();
|
||||
|
||||
void addSeparator();
|
||||
|
||||
void removeLines();
|
||||
|
||||
unsigned count() const { return content->body.count(); }
|
||||
|
||||
int selection() const { return content->body.selection(); }
|
||||
|
||||
void select(int index) { content->body.setIndex(index); }
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void onCancel() override;
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
ModalWindow::checkEvents();
|
||||
if (waitHandler) {
|
||||
waitHandler();
|
||||
}
|
||||
}
|
||||
|
||||
void setWaitHandler(std::function<void()> handler)
|
||||
{
|
||||
waitHandler = std::move(handler);
|
||||
}
|
||||
void longPress();
|
||||
|
||||
void setToolbar(Window* window);
|
||||
protected:
|
||||
MenuWindowContent *content;
|
||||
bool multiple;
|
||||
MenuToolbar *toolbar = nullptr;
|
||||
std::function<void()> waitHandler;
|
||||
void updatePosition();
|
||||
|
||||
void setTitle(std::string text);
|
||||
|
||||
void addLine(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addLine(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addLineBuffered(const std::string &text, std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void addLineBuffered(const uint8_t *icon_mask, const std::string &text,
|
||||
std::function<void()> onPress,
|
||||
std::function<bool()> isChecked = nullptr);
|
||||
|
||||
void updateLines();
|
||||
|
||||
void addSeparator();
|
||||
|
||||
void removeLines();
|
||||
|
||||
unsigned count() const
|
||||
{
|
||||
return content->body.count();
|
||||
}
|
||||
|
||||
int selection() const
|
||||
{
|
||||
return content->body.selection();
|
||||
}
|
||||
|
||||
void select(int index)
|
||||
{
|
||||
content->body.setIndex(index);
|
||||
}
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void onCancel() override;
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
ModalWindow::checkEvents();
|
||||
if (waitHandler) {
|
||||
waitHandler();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
MenuWindowContent* content;
|
||||
bool multiple;
|
||||
Window * toolbar = nullptr;
|
||||
std::function<void()> waitHandler;
|
||||
void updatePosition();
|
||||
|
||||
void setOutline(Window* obj);
|
||||
void setOutline(Window *obj);
|
||||
};
|
||||
|
||||
Menu * MenuBody::getParentMenu()
|
||||
Menu *MenuBody::getParentMenu()
|
||||
{
|
||||
return static_cast<Menu *>(getParent()->getParent());
|
||||
}
|
||||
|
||||
|
||||
+65
-55
@@ -17,8 +17,9 @@
|
||||
*/
|
||||
|
||||
#include "menutoolbar.h"
|
||||
#include "choice.h"
|
||||
|
||||
#include "font.h"
|
||||
#include "translations.h"
|
||||
|
||||
static void toolbar_btn_defocus(lv_event_t* event)
|
||||
{
|
||||
@@ -29,56 +30,49 @@ static void toolbar_btn_defocus(lv_event_t* event)
|
||||
|
||||
MenuToolbarButton::MenuToolbarButton(Window* parent, const rect_t& rect,
|
||||
const char* picto) :
|
||||
Button(parent, rect, nullptr, 0, 0, window_create), picto(picto)
|
||||
Button(parent, rect, nullptr, 0, 0, etx_menu_button_create)
|
||||
{
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_CLICK_FOCUSABLE);
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_SCROLL_ON_FOCUS);
|
||||
|
||||
lv_obj_add_event_cb(lvobj, toolbar_btn_defocus, LV_EVENT_DEFOCUSED, nullptr);
|
||||
|
||||
auto label = lv_label_create(lvobj);
|
||||
lv_label_set_text(label, picto);
|
||||
lv_obj_center(label);
|
||||
}
|
||||
|
||||
void MenuToolbarButton::paint(BitmapBuffer * dc)
|
||||
{
|
||||
lv_coord_t width = lv_obj_get_content_width(lvobj);
|
||||
if (checked()) {
|
||||
dc->drawSolidFilledRect(
|
||||
MENUS_TOOLBAR_BUTTON_PADDING, MENUS_TOOLBAR_BUTTON_PADDING,
|
||||
width - 2 * MENUS_TOOLBAR_BUTTON_PADDING,
|
||||
MENUS_TOOLBAR_BUTTON_WIDTH - 2 * MENUS_TOOLBAR_BUTTON_PADDING,
|
||||
COLOR_THEME_FOCUS);
|
||||
dc->drawText(width / 2, (rect.h - getFontHeight(FONT(L))) / 2 + 2,
|
||||
picto, FONT(L) | CENTERED | COLOR_THEME_PRIMARY2);
|
||||
} else {
|
||||
dc->drawText(width / 2, (rect.h - getFontHeight(FONT(L))) / 2 + 2,
|
||||
picto, FONT(L) | CENTERED | COLOR_THEME_PRIMARY1);
|
||||
}
|
||||
}
|
||||
|
||||
MenuToolbar::MenuToolbar(Choice* choice, Menu* menu) :
|
||||
Window(menu, MENUS_TOOLBAR_RECT, OPAQUE),
|
||||
MenuToolbar::MenuToolbar(Choice* choice, Menu* menu, const int columns) :
|
||||
Window(menu, {0, (LCD_H - MENUS_MAX_HEIGHT) / 2, 76, MENUS_MAX_HEIGHT},
|
||||
OPAQUE),
|
||||
choice(choice),
|
||||
menu(menu),
|
||||
filterColumns(columns),
|
||||
group(lv_group_create())
|
||||
{
|
||||
lv_group_add_obj(group, lvobj);
|
||||
lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_SECONDARY3), 0);
|
||||
|
||||
setWidth((MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING) *
|
||||
columns +
|
||||
MENUS_TOOLBAR_BUTTON_PADDING);
|
||||
|
||||
addButton(STR_SELECT_MENU_ALL, choice->getMin(), choice->getMax(), nullptr,
|
||||
nullptr, true);
|
||||
}
|
||||
|
||||
MenuToolbar::~MenuToolbar()
|
||||
{
|
||||
lv_group_del(group);
|
||||
}
|
||||
MenuToolbar::~MenuToolbar() { lv_group_del(group); }
|
||||
|
||||
void MenuToolbar::resetFilter()
|
||||
{
|
||||
if (lv_group_get_focused(group) != lvobj) {
|
||||
lv_group_focus_obj(lvobj);
|
||||
choice->fillMenu(menu);
|
||||
menu->setTitle(choice->menuTitle);
|
||||
}
|
||||
}
|
||||
|
||||
void MenuToolbar::onEvent(event_t event)
|
||||
{
|
||||
|
||||
if (event == EVT_KEY_BREAK(KEY_PAGEDN)) {
|
||||
lv_group_focus_next(group);
|
||||
}
|
||||
@@ -90,54 +84,70 @@ void MenuToolbar::onEvent(event_t event)
|
||||
#endif
|
||||
lv_group_focus_prev(group);
|
||||
}
|
||||
|
||||
|
||||
auto obj = lv_group_get_focused(group);
|
||||
if (!obj) {
|
||||
choice->fillMenu(menu);
|
||||
} else {
|
||||
lv_event_send(obj, LV_EVENT_CLICKED, nullptr);
|
||||
}
|
||||
lv_event_send(obj, LV_EVENT_CLICKED, nullptr);
|
||||
}
|
||||
|
||||
rect_t MenuToolbar::getButtonRect(size_t buttons)
|
||||
rect_t MenuToolbar::getButtonRect(bool wideButton)
|
||||
{
|
||||
coord_t y = buttons * (MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING);
|
||||
return {0, y, LV_PCT(100), MENUS_TOOLBAR_BUTTON_WIDTH};
|
||||
if (wideButton && (nxtBtnPos % filterColumns))
|
||||
nxtBtnPos = nxtBtnPos - (nxtBtnPos % filterColumns) + filterColumns;
|
||||
coord_t x = (nxtBtnPos % filterColumns) *
|
||||
(MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING) +
|
||||
MENUS_TOOLBAR_BUTTON_PADDING;
|
||||
coord_t y = (nxtBtnPos / filterColumns) *
|
||||
(MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING) +
|
||||
MENUS_TOOLBAR_BUTTON_PADDING;
|
||||
coord_t w =
|
||||
wideButton ? (MENUS_TOOLBAR_BUTTON_WIDTH + MENUS_TOOLBAR_BUTTON_PADDING) *
|
||||
(filterColumns - 1) +
|
||||
MENUS_TOOLBAR_BUTTON_WIDTH
|
||||
: MENUS_TOOLBAR_BUTTON_WIDTH;
|
||||
nxtBtnPos += wideButton ? filterColumns : 1;
|
||||
return {x, y, w, MENUS_TOOLBAR_BUTTON_WIDTH};
|
||||
}
|
||||
|
||||
bool MenuToolbar::filterMenu(MenuToolbarButton* btn, int16_t filtermin,
|
||||
int16_t filtermax, const FilterFct& filterFunc)
|
||||
int16_t filtermax, const Choice::FilterFct& filterFunc,
|
||||
const char* title)
|
||||
{
|
||||
btn->check(!btn->checked());
|
||||
|
||||
Choice::FilterFct filter = nullptr;
|
||||
filter = nullptr;
|
||||
if (btn->checked()) {
|
||||
if (title)
|
||||
menu->setTitle(title);
|
||||
else
|
||||
menu->setTitle(choice->menuTitle);
|
||||
filter = [=](int16_t index) {
|
||||
if (filterFunc)
|
||||
return filterFunc(index);
|
||||
if (filterFunc) return filterFunc(index);
|
||||
return index == 0 || (abs(index) >= filtermin && abs(index) <= filtermax);
|
||||
};
|
||||
lv_group_focus_obj(btn->getLvObj());
|
||||
choice->fillMenu(menu, filter);
|
||||
} else {
|
||||
lv_event_send(allBtn->getLvObj(), LV_EVENT_CLICKED, nullptr);
|
||||
}
|
||||
|
||||
choice->fillMenu(menu, filter);
|
||||
return btn->checked();
|
||||
}
|
||||
|
||||
typedef std::function<bool(int)> IsValueAvailable;
|
||||
static int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable)
|
||||
static bool checkFirstAvailable(int min, int max,
|
||||
IsValueAvailable isValueAvailable)
|
||||
{
|
||||
int retval = 0;
|
||||
for (int i = min; i <= max; i++) {
|
||||
if (isValueAvailable(i)) {
|
||||
retval = i;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
return false;
|
||||
}
|
||||
|
||||
void MenuToolbar::addButton(const char* picto, int16_t filtermin,
|
||||
int16_t filtermax, const FilterFct& filterFunc)
|
||||
int16_t filtermax, const Choice::FilterFct& filterFunc,
|
||||
const char* title, bool wideButton)
|
||||
{
|
||||
int vmin = choice->vmin;
|
||||
int vmax = choice->vmax;
|
||||
@@ -145,19 +155,19 @@ void MenuToolbar::addButton(const char* picto, int16_t filtermin,
|
||||
if (vmin > filtermin || vmax < filtermin) return;
|
||||
|
||||
if (choice->isValueAvailable &&
|
||||
getFirstAvailable(filtermin, filtermax, choice->isValueAvailable) == 0)
|
||||
!checkFirstAvailable(filtermin, filtermax, choice->isValueAvailable))
|
||||
return;
|
||||
|
||||
rect_t r = getButtonRect(children.size());
|
||||
rect_t r = getButtonRect(wideButton);
|
||||
auto button = new MenuToolbarButton(this, r, picto);
|
||||
|
||||
button->setPressHandler(
|
||||
std::bind(&MenuToolbar::filterMenu, this, button, filtermin, filtermax, filterFunc));
|
||||
button->setPressHandler(std::bind(&MenuToolbar::filterMenu, this, button,
|
||||
filtermin, filtermax, filterFunc, title));
|
||||
|
||||
lv_group_add_obj(group, button->getLvObj());
|
||||
}
|
||||
|
||||
void MenuToolbar::onClicked()
|
||||
{
|
||||
choice->fillMenu(menu);
|
||||
if (children.size() == 1) {
|
||||
allBtn = button;
|
||||
lv_event_send(allBtn->getLvObj(), LV_EVENT_CLICKED, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-9
@@ -19,6 +19,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "button.h"
|
||||
#include "choice.h"
|
||||
#include "menu.h"
|
||||
|
||||
class Choice;
|
||||
@@ -27,10 +28,8 @@ class MenuToolbarButton : public Button
|
||||
{
|
||||
public:
|
||||
MenuToolbarButton(Window* parent, const rect_t& rect, const char* picto);
|
||||
void paint(BitmapBuffer* dc) override;
|
||||
|
||||
protected:
|
||||
const char* picto;
|
||||
};
|
||||
|
||||
class MenuToolbar : public Window
|
||||
@@ -38,23 +37,29 @@ class MenuToolbar : public Window
|
||||
// friend Menu;
|
||||
|
||||
public:
|
||||
MenuToolbar(Choice* choice, Menu* menu);
|
||||
MenuToolbar(Choice* choice, Menu* menu, const int columns);
|
||||
~MenuToolbar();
|
||||
|
||||
void resetFilter();
|
||||
void onEvent(event_t event) override;
|
||||
|
||||
virtual void longPress() {}
|
||||
|
||||
protected:
|
||||
Choice* choice;
|
||||
Choice::FilterFct filter;
|
||||
Menu* menu;
|
||||
typedef std::function<bool(int16_t)> FilterFct;
|
||||
int nxtBtnPos = 0;
|
||||
int filterColumns = 0;
|
||||
MenuToolbarButton* allBtn = nullptr;
|
||||
|
||||
lv_group_t* group;
|
||||
|
||||
void addButton(const char* picto, int16_t filtermin, int16_t filtermax, const FilterFct& filterFunc = nullptr);
|
||||
bool filterMenu(MenuToolbarButton* btn, int16_t filtermin, int16_t filtermax, const FilterFct& filterFunc = nullptr);
|
||||
void addButton(const char* picto, int16_t filtermin, int16_t filtermax,
|
||||
const Choice::FilterFct& filterFunc = nullptr,
|
||||
const char* title = nullptr, bool wideButton = false);
|
||||
bool filterMenu(MenuToolbarButton* btn, int16_t filtermin, int16_t filtermax,
|
||||
const Choice::FilterFct& filterFunc, const char* title);
|
||||
|
||||
rect_t getButtonRect(size_t buttons);
|
||||
|
||||
void onClicked() override;
|
||||
rect_t getButtonRect(bool wideButton);
|
||||
};
|
||||
|
||||
@@ -35,6 +35,7 @@ lv_obj_t* etx_switch_create(lv_obj_t* parent);
|
||||
lv_obj_t* etx_slider_create(lv_obj_t* parent);
|
||||
lv_obj_t* etx_btnmatrix_create(lv_obj_t* parent);
|
||||
lv_obj_t* etx_button_create(lv_obj_t* parent);
|
||||
lv_obj_t* etx_menu_button_create(lv_obj_t* parent);
|
||||
lv_obj_t* etx_choice_create(lv_obj_t* parent);
|
||||
lv_obj_t* etx_modal_create(lv_obj_t* parent);
|
||||
lv_obj_t* etx_modal_content_create(lv_obj_t* parent);
|
||||
|
||||
@@ -1083,3 +1083,7 @@ const char STR_STICK_NAMES2[] = TR_STICK_NAMES2;
|
||||
const char STR_STICK_NAMES3[] = TR_STICK_NAMES3;
|
||||
const char STR_SURFACE_NAMES0[] = TR_SURFACE_NAMES0;
|
||||
const char STR_SURFACE_NAMES1[] = TR_SURFACE_NAMES1;
|
||||
|
||||
const char STR_SELECT_MENU_ALL[] = TR_SELECT_MENU_ALL;
|
||||
const char STR_SELECT_MENU_CLR[] = TR_SELECT_MENU_CLR;
|
||||
const char STR_SELECT_MENU_INV[] = TR_SELECT_MENU_INV;
|
||||
|
||||
@@ -1262,5 +1262,9 @@ extern const char* const STR_VUSBJOYSTICK_CIRC_COUTOUT[];
|
||||
extern const char STR_USBJOYSTICK_APPLY_CHANGES[];
|
||||
#endif
|
||||
|
||||
extern const char STR_SELECT_MENU_ALL[];
|
||||
extern const char STR_SELECT_MENU_CLR[];
|
||||
extern const char STR_SELECT_MENU_INV[];
|
||||
|
||||
#endif // _TRANSLATIONS_H_
|
||||
|
||||
|
||||
@@ -1240,3 +1240,7 @@
|
||||
#define TR_ENABLED_FEATURES "启用的功能"
|
||||
#define TR_RADIO_MENU_TABS "系统功能选项卡"
|
||||
#define TR_MODEL_MENU_TABS "模型功能选项卡"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1261,3 +1261,7 @@
|
||||
#define TR_ENABLED_FEATURES "Aktivní funkce"
|
||||
#define TR_RADIO_MENU_TABS "Rádiové menu záložky"
|
||||
#define TR_MODEL_MENU_TABS "Model menu záložky"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1266,3 +1266,7 @@
|
||||
#define TR_ENABLED_FEATURES "Aktiverede funktioner"
|
||||
#define TR_RADIO_MENU_TABS "Radio menu tab"
|
||||
#define TR_MODEL_MENU_TABS "Model menu tab"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1252,3 +1252,7 @@
|
||||
#define TR_ENABLED_FEATURES "Menüpunkte"
|
||||
#define TR_RADIO_MENU_TABS "Sender Menüpunkte"
|
||||
#define TR_MODEL_MENU_TABS "Modell Menüpunkte"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1249,3 +1249,7 @@
|
||||
#define TR_ENABLED_FEATURES "Enabled Features"
|
||||
#define TR_RADIO_MENU_TABS "Radio Menu Tabs"
|
||||
#define TR_MODEL_MENU_TABS "Model Menu Tabs"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1254,3 +1254,7 @@
|
||||
#define TR_ENABLED_FEATURES "Enabled Features"
|
||||
#define TR_RADIO_MENU_TABS "Radio Menu Tabs"
|
||||
#define TR_MODEL_MENU_TABS "Model Menu Tabs"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1270,3 +1270,7 @@
|
||||
#define TR_ENABLED_FEATURES "Enabled Features"
|
||||
#define TR_RADIO_MENU_TABS "Radio Menu Tabs"
|
||||
#define TR_MODEL_MENU_TABS "Model Menu Tabs"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1274,3 +1274,7 @@
|
||||
#define TR_ENABLED_FEATURES TR("Fonctions activées", "Fonctionnalités activées")
|
||||
#define TR_RADIO_MENU_TABS "Onglets Menu Radio"
|
||||
#define TR_MODEL_MENU_TABS "Onglets Menu Modèles"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1258,3 +1258,7 @@
|
||||
#define TR_ENABLED_FEATURES "אפשר יכולות"
|
||||
#define TR_RADIO_MENU_TABS "לשוניות תפריט רדיו"
|
||||
#define TR_MODEL_MENU_TABS "לשוניות תפריט מודל"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1249,3 +1249,7 @@
|
||||
#define TR_RADIO_MENU_TABS "Schede del Menu Radio"
|
||||
#define TR_MODEL_MENU_TABS "Schede del Menu Modello"
|
||||
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1244,3 +1244,7 @@
|
||||
#define TR_ENABLED_FEATURES "有効機能"
|
||||
#define TR_RADIO_MENU_TABS "送信機メニュータブ"
|
||||
#define TR_MODEL_MENU_TABS "モデルメニュータブ"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1261,3 +1261,7 @@
|
||||
#define TR_ENABLED_FEATURES "Enabled Features"
|
||||
#define TR_RADIO_MENU_TABS "Radio Menu Tabs"
|
||||
#define TR_MODEL_MENU_TABS "Model Menu Tabs"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1248,3 +1248,7 @@
|
||||
#define TR_ENABLED_FEATURES "Włączone opcje"
|
||||
#define TR_RADIO_MENU_TABS "Zakładki menu radia"
|
||||
#define TR_MODEL_MENU_TABS "Zakładki menu modelu"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1252,3 +1252,7 @@
|
||||
#define TR_ENABLED_FEATURES "Recursos ativos"
|
||||
#define TR_RADIO_MENU_TABS "Abas opcoes radio"
|
||||
#define TR_MODEL_MENU_TABS "Abas opcoes modelo"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1287,3 +1287,7 @@
|
||||
#define TR_ENABLED_FEATURES "Aktiverade funktioner"
|
||||
#define TR_RADIO_MENU_TABS "Radiomenyflikar"
|
||||
#define TR_MODEL_MENU_TABS "Modellmenyflikar"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
@@ -1246,3 +1246,7 @@
|
||||
#define TR_ENABLED_FEATURES "啟用的功能"
|
||||
#define TR_RADIO_MENU_TABS "系統功能選項卡"
|
||||
#define TR_MODEL_MENU_TABS "模型功能選項卡"
|
||||
|
||||
#define TR_SELECT_MENU_ALL "All"
|
||||
#define TR_SELECT_MENU_CLR "Clear"
|
||||
#define TR_SELECT_MENU_INV "Invert"
|
||||
|
||||
Reference in New Issue
Block a user