refactor(color): use LVGL styles and objects for UI, legacy cleanup (#4407)
@@ -19,7 +19,6 @@ set(BITMAP_LZ4_ARGS ${BITMAP_ARGS} --lz4)
|
||||
set(MASK_LZ4_ARGS ${MASK_ARGS} --lz4)
|
||||
|
||||
add_bitmaps_target(${BITMAP_TARGET_PREFIX}_splash_logo "${RADIO_SRC_DIR}/bitmaps/480x272/splash_logo.png" "4/4/4/4" "${BITMAP_LZ4_ARGS}")
|
||||
add_bitmaps_target(${BITMAP_TARGET_PREFIX}_button_bitmaps "${RADIO_SRC_DIR}/bitmaps/480x272/button/alpha_*.png" "4/4/4/4" "${BITMAP_LZ4_ARGS}")
|
||||
add_bitmaps_target(${BITMAP_TARGET_PREFIX}_masks "${RADIO_SRC_DIR}/bitmaps/480x272/mask_*.png" 8bits "${MASK_LZ4_ARGS}")
|
||||
add_bitmaps_target(${BITMAP_TARGET_PREFIX}_slider_masks "${RADIO_SRC_DIR}/bitmaps/480x272/slider/*.png" 8bits "${MASK_LZ4_ARGS}")
|
||||
add_bitmaps_target(${BITMAP_TARGET_PREFIX}_volume_masks ${RADIO_SRC_DIR}/bitmaps/480x272/volume/*.png 8bits "${MASK_LZ4_ARGS}")
|
||||
@@ -27,18 +26,15 @@ add_bitmaps_target(${BITMAP_TARGET_PREFIX}_themes_masks "${RADIO_SRC_DIR}/bitmap
|
||||
add_bitmaps_target(${BITMAP_TARGET_PREFIX}_themes_alpha "${RADIO_SRC_DIR}/bitmaps/480x272/default_theme/alpha_*.png" "4/4/4/4" "${BITMAP_LZ4_ARGS}")
|
||||
|
||||
add_bitmaps_target(${BITMAP_TARGET_PREFIX}_bootloader_bitmaps "${RADIO_SRC_DIR}/bitmaps/480x272/bootloader/bmp_*.png" "4/4/4/4" "${BITMAP_LZ4_ARGS}")
|
||||
add_bitmaps_target(${BITMAP_TARGET_PREFIX}_bootloader_icons "${RADIO_SRC_DIR}/bitmaps/480x272/bootloader/icon_*.png" 8bits "${MASK_LZ4_ARGS}")
|
||||
|
||||
add_custom_target(${BITMAP_TARGET_PREFIX}_bitmaps)
|
||||
|
||||
add_dependencies(${BITMAP_TARGET_PREFIX}_bitmaps
|
||||
${BITMAP_TARGET_PREFIX}_splash_logo
|
||||
${BITMAP_TARGET_PREFIX}_button_bitmaps
|
||||
${BITMAP_TARGET_PREFIX}_masks
|
||||
${BITMAP_TARGET_PREFIX}_slider_masks
|
||||
${BITMAP_TARGET_PREFIX}_themes_masks
|
||||
${BITMAP_TARGET_PREFIX}_themes_alpha
|
||||
${BITMAP_TARGET_PREFIX}_volume_masks
|
||||
${BITMAP_TARGET_PREFIX}_bootloader_bitmaps
|
||||
${BITMAP_TARGET_PREFIX}_bootloader_icons
|
||||
)
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 641 B |
|
Before Width: | Height: | Size: 276 B |
|
Before Width: | Height: | Size: 696 B |
|
Before Width: | Height: | Size: 823 B |
|
Before Width: | Height: | Size: 514 B |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 251 B |
|
Before Width: | Height: | Size: 369 B |
|
Before Width: | Height: | Size: 222 B |
|
Before Width: | Height: | Size: 212 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 210 B |
|
Before Width: | Height: | Size: 310 B After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 866 B After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 833 B After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 922 B After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1012 B After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 604 B After Width: | Height: | Size: 3.4 KiB |
@@ -24,7 +24,6 @@
|
||||
#include "stm32_gpio_driver.h"
|
||||
|
||||
#include "definitions.h"
|
||||
#include "opentx_constants.h"
|
||||
#include "myeeprom.h"
|
||||
|
||||
// generated switch structs
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _DATACONSTANTS_H_
|
||||
#define _DATACONSTANTS_H_
|
||||
#pragma once
|
||||
|
||||
#include "board.h"
|
||||
#include "storage/yaml/yaml_defs.h"
|
||||
@@ -683,5 +682,3 @@ enum PPMUnit {
|
||||
PPM_PERCENT_PREC1,
|
||||
PPM_US
|
||||
};
|
||||
|
||||
#endif // _DATACONSTANTS_H_
|
||||
|
||||
@@ -17,87 +17,103 @@ file(GLOB WIDGETS_SRC RELATIVE ${RADIO_SRC_DIR}/gui/colorlcd
|
||||
|
||||
set(GUI_SRC
|
||||
${GUI_SRC}
|
||||
colors.cpp
|
||||
lcd.cpp
|
||||
splash.cpp
|
||||
fonts.cpp
|
||||
curves.cpp
|
||||
bitmaps.cpp
|
||||
lz4_bitmaps.cpp
|
||||
theme.cpp
|
||||
theme_manager.cpp
|
||||
color_editor.cpp
|
||||
color_picker.cpp
|
||||
color_list.cpp
|
||||
preview_window.cpp
|
||||
file_browser.cpp
|
||||
file_preview.cpp
|
||||
file_carosell.cpp
|
||||
listbox.cpp
|
||||
tabsgroup.cpp
|
||||
page.cpp
|
||||
select_fab_button.cpp
|
||||
select_fab_carousel.cpp
|
||||
topbar.cpp
|
||||
layout.cpp
|
||||
widget.cpp
|
||||
widget_settings.cpp
|
||||
${THEMES_SRC}
|
||||
${LAYOUTS_SRC}
|
||||
${WIDGETS_SRC}
|
||||
draw_functions.cpp
|
||||
menu_model.cpp
|
||||
model_select.cpp
|
||||
bind_menu_d16.cpp
|
||||
trainer_setup.cpp
|
||||
custom_failsafe.cpp
|
||||
ppm_settings.cpp
|
||||
bitmaps.cpp
|
||||
channel_bar.cpp
|
||||
channel_range.cpp
|
||||
module_setup.cpp
|
||||
timer_setup.cpp
|
||||
trims_setup.cpp
|
||||
throttle_params.cpp
|
||||
preflight_checks.cpp
|
||||
model_setup.cpp
|
||||
color_editor.cpp
|
||||
color_list.cpp
|
||||
color_picker.cpp
|
||||
colors.cpp
|
||||
curve.cpp
|
||||
file_browser.cpp
|
||||
file_preview.cpp
|
||||
fonts.cpp
|
||||
fullscreen_dialog.cpp
|
||||
special_functions.cpp
|
||||
layout.cpp
|
||||
lcd.cpp
|
||||
list_line_button.cpp
|
||||
listbox.cpp
|
||||
LvglWrapper.cpp
|
||||
menu_model.cpp
|
||||
menu_radio.cpp
|
||||
menu_screen.cpp
|
||||
page.cpp
|
||||
popups.cpp
|
||||
screen_setup.cpp
|
||||
screen_user_interface.cpp
|
||||
select_fab_carousel.cpp
|
||||
sourcechoice.cpp
|
||||
startup_shutdown.cpp
|
||||
switch_warn_dialog.cpp
|
||||
switchchoice.cpp
|
||||
tabsgroup.cpp
|
||||
theme_manager.cpp
|
||||
theme.cpp
|
||||
topbar.cpp
|
||||
view_about.cpp
|
||||
view_channels.cpp
|
||||
view_logical_switches.cpp
|
||||
view_main_decoration.cpp
|
||||
view_main_menu.cpp
|
||||
view_main.cpp
|
||||
view_statistics.cpp
|
||||
view_text.cpp
|
||||
widget_settings.cpp
|
||||
widget.cpp
|
||||
widgets_setup.cpp
|
||||
curve_param.cpp
|
||||
curveedit.cpp
|
||||
fm_matrix.cpp
|
||||
gvar_numberedit.cpp
|
||||
input_edit_adv.cpp
|
||||
input_edit.cpp
|
||||
input_mix_button.cpp
|
||||
input_mix_group.cpp
|
||||
input_source.cpp
|
||||
mixer_edit_adv.cpp
|
||||
mixer_edit.cpp
|
||||
model_curves.cpp
|
||||
model_flightmodes.cpp
|
||||
model_gvars.cpp
|
||||
model_inputs.cpp
|
||||
model_logical_switches.cpp
|
||||
model_mixes.cpp
|
||||
model_outputs.cpp
|
||||
model_curves.cpp
|
||||
model_gvars.cpp
|
||||
model_templates.cpp
|
||||
model_logical_switches.cpp
|
||||
special_functions.cpp
|
||||
model_select.cpp
|
||||
model_setup.cpp
|
||||
model_telemetry.cpp
|
||||
menu_radio.cpp
|
||||
radio_setup.cpp
|
||||
model_templates.cpp
|
||||
output_edit.cpp
|
||||
preflight_checks.cpp
|
||||
throttle_params.cpp
|
||||
timeedit.cpp
|
||||
timer_setup.cpp
|
||||
trainer_setup.cpp
|
||||
trims_setup.cpp
|
||||
bind_menu_d16.cpp
|
||||
custom_failsafe.cpp
|
||||
hw_extmodule.cpp
|
||||
hw_intmodule.cpp
|
||||
module_setup.cpp
|
||||
ppm_settings.cpp
|
||||
file_carosell.cpp
|
||||
hw_inputs.cpp
|
||||
hw_serial.cpp
|
||||
preview_window.cpp
|
||||
radio_calibration.cpp
|
||||
radio_diaganas.cpp
|
||||
radio_diagkeys.cpp
|
||||
radio_hardware.cpp
|
||||
radio_sdmanager.cpp
|
||||
radio_setup.cpp
|
||||
radio_theme.cpp
|
||||
radio_tools.cpp
|
||||
radio_trainer.cpp
|
||||
radio_version.cpp
|
||||
hw_intmodule.cpp
|
||||
hw_extmodule.cpp
|
||||
hw_inputs.cpp
|
||||
hw_serial.cpp
|
||||
radio_hardware.cpp
|
||||
radio_diagkeys.cpp
|
||||
radio_diaganas.cpp
|
||||
radio_theme.cpp
|
||||
radio_calibration.cpp
|
||||
view_about.cpp
|
||||
view_main.cpp
|
||||
view_main_menu.cpp
|
||||
view_main_decoration.cpp
|
||||
view_channels.cpp
|
||||
view_logical_switches.cpp
|
||||
view_statistics.cpp
|
||||
view_text.cpp
|
||||
menu_screen.cpp
|
||||
screen_user_interface.cpp
|
||||
widgets_setup.cpp
|
||||
screen_setup.cpp
|
||||
switch_warn_dialog.cpp
|
||||
LvglWrapper.cpp
|
||||
)
|
||||
|
||||
macro(add_gui_src src)
|
||||
@@ -124,10 +140,6 @@ if(HELI)
|
||||
add_gui_src(model_heli.cpp)
|
||||
endif()
|
||||
|
||||
if(PXX2 OR LUA OR MULTIMODULE)
|
||||
add_gui_src(radio_tools.cpp)
|
||||
endif()
|
||||
|
||||
if(PXX2 OR MULTIMODULE)
|
||||
add_gui_src(radio_spectrum_analyser.cpp)
|
||||
endif()
|
||||
@@ -193,31 +205,6 @@ set(SRC ${SRC} ${LVGL_FONT_SOURCES})
|
||||
|
||||
add_definitions(-DLIBOPENUI)
|
||||
|
||||
add_gui_src(fullscreen_dialog.cpp)
|
||||
add_gui_src(message_dialog.cpp)
|
||||
add_gui_src(confirm_dialog.cpp)
|
||||
add_gui_src(popups.cpp)
|
||||
add_gui_src(timeedit.cpp)
|
||||
add_gui_src(curve.cpp)
|
||||
add_gui_src(sourcechoice.cpp)
|
||||
add_gui_src(switchchoice.cpp)
|
||||
add_gui_src(curveedit.cpp)
|
||||
add_gui_src(gvar_numberedit.cpp)
|
||||
add_gui_src(curve_param.cpp)
|
||||
add_gui_src(fm_matrix.cpp)
|
||||
add_gui_src(input_source.cpp)
|
||||
add_gui_src(input_edit.cpp)
|
||||
add_gui_src(input_edit_adv.cpp)
|
||||
add_gui_src(mixer_edit.cpp)
|
||||
add_gui_src(mixer_edit_adv.cpp)
|
||||
add_gui_src(output_edit.cpp)
|
||||
add_gui_src(input_mix_group.cpp)
|
||||
add_gui_src(input_mix_button.cpp)
|
||||
add_gui_src(channel_bar.cpp)
|
||||
|
||||
add_gui_src(list_line_button.cpp)
|
||||
|
||||
if(USBJ_EX)
|
||||
add_gui_src(model_usbjoystick.cpp)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -306,32 +306,6 @@ int8_t rotaryEncoderGetAccel() { return 0; }
|
||||
|
||||
#endif // defined(ROTARY_ENCODER_NAVIGATION)
|
||||
|
||||
// Return 32 bit version of color (for recolor of buttons)
|
||||
uint32_t makeLvColor32(uint32_t colorFlags)
|
||||
{
|
||||
auto color = COLOR_VAL(colorFlags);
|
||||
return (GET_RED(color) << 16u) | (GET_GREEN(color) << 8) | GET_BLUE(color);
|
||||
}
|
||||
|
||||
// Create recolor version of string value
|
||||
std::string makeRecolor(std::string value, uint32_t colorFlags)
|
||||
{
|
||||
char s[32];
|
||||
snprintf(s, 32, "#%06" PRIx32 " %s#", makeLvColor32(colorFlags), value.c_str());
|
||||
return std::string(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to translate a colorFlags value to a lv_color_t suitable
|
||||
* for passing to an lv_obj function
|
||||
* @param colorFlags a textFlags value. This value will contain the color shifted by 16 bits.
|
||||
*/
|
||||
lv_color_t makeLvColor(uint32_t colorFlags)
|
||||
{
|
||||
auto color = COLOR_VAL(colorFlags);
|
||||
return lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color));
|
||||
}
|
||||
|
||||
static void init_lvgl_drivers()
|
||||
{
|
||||
// Register the driver and save the created display object
|
||||
@@ -371,6 +345,9 @@ LvglWrapper::LvglWrapper()
|
||||
{
|
||||
init_lvgl_drivers();
|
||||
|
||||
extern void lv_stb_init();
|
||||
lv_stb_init();
|
||||
|
||||
// Create main window and load that screen
|
||||
auto window = MainWindow::instance();
|
||||
window->setActiveScreen();
|
||||
|
||||
@@ -19,18 +19,13 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _LVGLWRAPPER_H_
|
||||
#define _LVGLWRAPPER_H_
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
#include "opentx_types.h"
|
||||
|
||||
void initLvglTheme();
|
||||
|
||||
uint32_t makeLvColor32(uint32_t colorFlags);
|
||||
std::string makeRecolor(std::string value, uint32_t colorFlags);
|
||||
lv_color_t makeLvColor(uint32_t colorFlags);
|
||||
|
||||
typedef std::function<lv_obj_t *(lv_obj_t *parent)> LvObjConstructor;
|
||||
|
||||
class LvglWrapper
|
||||
@@ -57,5 +52,3 @@ class LvglWrapper
|
||||
|
||||
// multiplication factor between 0 and 25
|
||||
int8_t rotaryEncoderGetAccel();
|
||||
|
||||
#endif // _LVGLWRAPPER_H_
|
||||
|
||||
@@ -19,15 +19,70 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "access_settings.h"
|
||||
#include "channel_bar.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
#include "channel_bar.h"
|
||||
#include "opentx.h"
|
||||
|
||||
namespace pxx2 {
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
namespace pxx2
|
||||
{
|
||||
|
||||
class BindRxChoiceMenu : public Menu
|
||||
{
|
||||
public:
|
||||
BindRxChoiceMenu(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx);
|
||||
|
||||
protected:
|
||||
uint8_t moduleIdx;
|
||||
uint8_t receiverIdx;
|
||||
};
|
||||
|
||||
class BindWaitDialog : public BaseDialog
|
||||
{
|
||||
public:
|
||||
BindWaitDialog(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx);
|
||||
|
||||
void checkEvents() override;
|
||||
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
|
||||
protected:
|
||||
uint8_t moduleIdx;
|
||||
uint8_t receiverIdx;
|
||||
};
|
||||
|
||||
class RxOptions : public BaseDialog
|
||||
{
|
||||
public:
|
||||
RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx);
|
||||
void checkEvents() override;
|
||||
|
||||
protected:
|
||||
enum {
|
||||
RO_Init = 0,
|
||||
RO_ReadModuleInfo,
|
||||
RO_ReadModuleSettings,
|
||||
RO_ReadReceiverSettings,
|
||||
RO_DisplaySettings,
|
||||
RO_WriteSettings,
|
||||
RO_WritingSettings,
|
||||
};
|
||||
|
||||
uint8_t moduleIdx;
|
||||
uint8_t receiverIdx;
|
||||
uint8_t state = RO_Init;
|
||||
|
||||
std::string statusText;
|
||||
|
||||
uint8_t getRxSettingsState();
|
||||
|
||||
void update();
|
||||
void writeSettings();
|
||||
};
|
||||
|
||||
static void startBindWaitDialog(Window* parent, uint8_t moduleIdx,
|
||||
uint8_t receiverIdx)
|
||||
@@ -80,7 +135,6 @@ BindRxChoiceMenu::BindRxChoiceMenu(Window* parent, uint8_t moduleIdx,
|
||||
bindInfo.selectedReceiverIndex = i;
|
||||
if (isModuleR9MAccess(moduleIdx) &&
|
||||
modInfo.information.variant == PXX2_VARIANT_EU) {
|
||||
|
||||
auto& modSetup = getPXX2ModuleSetupBuffer();
|
||||
if (modSetup.moduleSettings.txPower <= 14) {
|
||||
// with telemetry
|
||||
@@ -110,18 +164,6 @@ BindRxChoiceMenu::BindRxChoiceMenu(Window* parent, uint8_t moduleIdx,
|
||||
setCancelHandler([=]() { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; });
|
||||
}
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool BindRxChoiceMenu::onTouchEnd(coord_t x, coord_t y)
|
||||
{
|
||||
// Note: onCancel() is not called when the menu is discarded
|
||||
// by clicking outside the menu window and the onCancel
|
||||
// handler is not accessible from here
|
||||
moduleState[moduleIdx].mode = MODULE_MODE_NORMAL;
|
||||
deleteLater();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
@@ -130,23 +172,18 @@ static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
|
||||
|
||||
BindWaitDialog::BindWaitDialog(Window* parent, uint8_t moduleIdx,
|
||||
uint8_t receiverIdx) :
|
||||
Dialog(parent, STR_BIND, rect_t{}),
|
||||
BaseDialog(parent, STR_BIND, true),
|
||||
moduleIdx(moduleIdx),
|
||||
receiverIdx(receiverIdx)
|
||||
{
|
||||
setCloseWhenClickOutside(true);
|
||||
auto form = &content->form;
|
||||
new StaticText(form, rect_t{}, STR_WAITING_FOR_RX, 0, COLOR_THEME_PRIMARY1);
|
||||
|
||||
content->setWidth(LCD_W * 0.8);
|
||||
content->updateSize();
|
||||
new StaticText(form, rect_t{}, STR_WAITING_FOR_RX);
|
||||
|
||||
setCloseHandler([=]() { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; });
|
||||
}
|
||||
|
||||
void BindWaitDialog::deleteLater(bool detach, bool trash)
|
||||
{
|
||||
Dialog::deleteLater(detach, trash);
|
||||
BaseDialog::deleteLater(detach, trash);
|
||||
}
|
||||
|
||||
void BindWaitDialog::checkEvents()
|
||||
@@ -154,7 +191,6 @@ void BindWaitDialog::checkEvents()
|
||||
auto& bindInfo = getPXX2BindInformationBuffer();
|
||||
|
||||
if (moduleState[moduleIdx].mode == MODULE_MODE_NORMAL) {
|
||||
|
||||
// returned to normal after bind
|
||||
if (bindInfo.step > BIND_INIT) {
|
||||
removePXX2ReceiverIfEmpty(moduleIdx, receiverIdx);
|
||||
@@ -168,33 +204,32 @@ void BindWaitDialog::checkEvents()
|
||||
|
||||
// pre-bind phase: fetching info for R9M
|
||||
auto& modSetup = getPXX2ModuleSetupBuffer();
|
||||
switch(bindInfo.step) {
|
||||
case BIND_MODULE_TX_INFORMATION_REQUEST:
|
||||
if (modSetup.moduleInformation.information.variant == PXX2_VARIANT_EU) {
|
||||
// In EU mode we will need the power of the module to know if telemetry
|
||||
// can be proposed
|
||||
bindInfo.step = BIND_MODULE_TX_SETTINGS_REQUEST;
|
||||
switch (bindInfo.step) {
|
||||
case BIND_MODULE_TX_INFORMATION_REQUEST:
|
||||
if (modSetup.moduleInformation.information.variant == PXX2_VARIANT_EU) {
|
||||
// In EU mode we will need the power of the module to know if
|
||||
// telemetry can be proposed
|
||||
bindInfo.step = BIND_MODULE_TX_SETTINGS_REQUEST;
|
||||
#if defined(SIMU)
|
||||
modSetup.moduleSettings.txPower = 14;
|
||||
modSetup.moduleSettings.txPower = 14;
|
||||
#else
|
||||
moduleState[moduleIdx].readModuleSettings(&modSetup.moduleSettings);
|
||||
moduleState[moduleIdx].readModuleSettings(&modSetup.moduleSettings);
|
||||
#endif
|
||||
} else {
|
||||
} else {
|
||||
bindInfo.step = 0;
|
||||
moduleState[moduleIdx].startBind(&bindInfo);
|
||||
}
|
||||
break;
|
||||
case BIND_MODULE_TX_SETTINGS_REQUEST:
|
||||
// We just receive the module settings (for TX power)
|
||||
bindInfo.step = 0;
|
||||
moduleState[moduleIdx].startBind(&bindInfo);
|
||||
}
|
||||
break;
|
||||
case BIND_MODULE_TX_SETTINGS_REQUEST:
|
||||
// We just receive the module settings (for TX power)
|
||||
bindInfo.step = 0;
|
||||
moduleState[moduleIdx].startBind(&bindInfo);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (bindInfo.step == BIND_INIT && bindInfo.candidateReceiversCount > 0) {
|
||||
|
||||
// prevent module mode being reset to NORMAL before exiting
|
||||
setCloseHandler(nullptr);
|
||||
deleteLater();
|
||||
@@ -204,11 +239,11 @@ void BindWaitDialog::checkEvents()
|
||||
return;
|
||||
}
|
||||
|
||||
Dialog::checkEvents();
|
||||
BaseDialog::checkEvents();
|
||||
}
|
||||
|
||||
ReceiverButton::ReceiverButton(Window* parent, rect_t rect,
|
||||
uint8_t moduleIdx, uint8_t receiverIdx) :
|
||||
ReceiverButton::ReceiverButton(Window* parent, rect_t rect, uint8_t moduleIdx,
|
||||
uint8_t receiverIdx) :
|
||||
TextButton(parent, rect, STR_BIND,
|
||||
std::bind(&ReceiverButton::pressBind, this)),
|
||||
moduleIdx(moduleIdx),
|
||||
@@ -308,45 +343,47 @@ void ReceiverButton::checkEvents()
|
||||
}
|
||||
|
||||
RegisterDialog::RegisterDialog(Window* parent, uint8_t moduleIdx) :
|
||||
Dialog(parent, STR_REGISTER, rect_t{}), moduleIdx(moduleIdx)
|
||||
BaseDialog(parent, STR_REGISTER, true, DIALOG_DEFAULT_WIDTH,
|
||||
LV_SIZE_CONTENT),
|
||||
moduleIdx(moduleIdx)
|
||||
{
|
||||
setCloseWhenClickOutside(true);
|
||||
auto form = &content->form;
|
||||
|
||||
FlexGridLayout grid(line_col_dsc, line_row_dsc);
|
||||
|
||||
// Register ID
|
||||
auto line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_REG_ID, 0, COLOR_THEME_PRIMARY1);
|
||||
auto line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_REG_ID);
|
||||
reg_id = new ModelTextEdit(line, rect_t{}, g_model.modelRegistrationID,
|
||||
sizeof(g_model.modelRegistrationID));
|
||||
|
||||
// UID
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, "UID", 0, COLOR_THEME_PRIMARY1);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, "UID");
|
||||
|
||||
auto* modSetup = &(getPXX2ModuleSetupBuffer());
|
||||
uid = new NumberEdit(line, rect_t{}, 0, 2, GET_SET_DEFAULT(modSetup->registerLoopIndex));
|
||||
uid = new NumberEdit(line, rect_t{}, 0, 2,
|
||||
GET_SET_DEFAULT(modSetup->registerLoopIndex));
|
||||
|
||||
// RX name
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_RX_NAME, 0, COLOR_THEME_PRIMARY1);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_RX_NAME);
|
||||
|
||||
start(); // clears registration data buffer
|
||||
rx_name = new ModelTextEdit(line, rect_t{}, modSetup->registerRxName, PXX2_LEN_RX_NAME);
|
||||
//lv_textarea_set_text(rx_name->getLvObj(), STR_WAITING_FOR_RX);
|
||||
lv_obj_add_state(rx_name->getLvObj(), LV_STATE_DISABLED);
|
||||
start(); // clears registration data buffer
|
||||
rx_name = new ModelTextEdit(line, rect_t{}, modSetup->registerRxName,
|
||||
PXX2_LEN_RX_NAME);
|
||||
// lv_textarea_set_text(rx_name->getLvObj(), STR_WAITING_FOR_RX);
|
||||
rx_name->disable();
|
||||
|
||||
// Status
|
||||
// line = form->newLine(&grid);
|
||||
// new StaticText(line, rect_t{}, STR_STATUS, 0, COLOR_THEME_PRIMARY1);
|
||||
// status = new StaticText(line, rect_t{}, STR_WAITING_FOR_RX, 0, COLOR_THEME_PRIMARY1);
|
||||
// line = form->newLine(grid);
|
||||
// new StaticText(line, rect_t{}, STR_STATUS);
|
||||
// status = new StaticText(line, rect_t{}, STR_WAITING_FOR_RX);
|
||||
|
||||
auto box = new Window(form, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_MEDIUM);
|
||||
lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY,
|
||||
0);
|
||||
box->padAll(PAD_MEDIUM);
|
||||
|
||||
auto box = new FormWindow(form, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8));
|
||||
lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0);
|
||||
box->padAll(lv_dpx(8));
|
||||
|
||||
new TextButton(box, rect_t{}, STR_CANCEL, [=]() -> int8_t {
|
||||
this->deleteLater();
|
||||
return 0;
|
||||
@@ -356,20 +393,17 @@ RegisterDialog::RegisterDialog(Window* parent, uint8_t moduleIdx) :
|
||||
modSetup->registerStep = REGISTER_RX_NAME_SELECTED;
|
||||
return 0;
|
||||
});
|
||||
lv_obj_add_flag(btn_ok->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
content->setWidth(LCD_W * 0.8);
|
||||
content->updateSize();
|
||||
btn_ok->hide();
|
||||
|
||||
setCloseHandler([=]() { moduleState[moduleIdx].mode = MODULE_MODE_NORMAL; });
|
||||
}
|
||||
|
||||
void RegisterDialog::start()
|
||||
{
|
||||
auto& pxx2Setup = getPXX2ModuleSetupBuffer();
|
||||
memclear(&pxx2Setup, sizeof(pxx2Setup));
|
||||
moduleState[moduleIdx].mode = MODULE_MODE_REGISTER;
|
||||
old_registerStep = REGISTER_INIT;
|
||||
auto& pxx2Setup = getPXX2ModuleSetupBuffer();
|
||||
memclear(&pxx2Setup, sizeof(pxx2Setup));
|
||||
moduleState[moduleIdx].mode = MODULE_MODE_REGISTER;
|
||||
old_registerStep = REGISTER_INIT;
|
||||
}
|
||||
|
||||
void RegisterDialog::checkEvents()
|
||||
@@ -385,14 +419,14 @@ void RegisterDialog::checkEvents()
|
||||
moduleState[moduleIdx].mode = MODULE_MODE_NORMAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (old_registerStep != modSetup.registerStep) {
|
||||
old_registerStep = modSetup.registerStep;
|
||||
|
||||
if (modSetup.registerStep == REGISTER_RX_NAME_RECEIVED) {
|
||||
lv_obj_clear_state(rx_name->getLvObj(), LV_STATE_DISABLED);
|
||||
lv_obj_clear_flag(btn_ok->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
// lv_obj_add_flag(status->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
rx_name->enable();
|
||||
btn_ok->show();
|
||||
// status->hide();
|
||||
rx_name->update();
|
||||
} else if (modSetup.registerStep == REGISTER_OK) {
|
||||
deleteLater();
|
||||
@@ -403,19 +437,13 @@ void RegisterDialog::checkEvents()
|
||||
}
|
||||
}
|
||||
|
||||
Dialog::checkEvents();
|
||||
BaseDialog::checkEvents();
|
||||
}
|
||||
|
||||
ModuleOptions::ModuleOptions(Window* parent, uint8_t moduleIdx):
|
||||
Dialog(parent, STR_MODULE_OPTIONS, rect_t{}),
|
||||
moduleIdx(moduleIdx)
|
||||
ModuleOptions::ModuleOptions(Window* parent, uint8_t moduleIdx) :
|
||||
BaseDialog(parent, STR_MODULE_OPTIONS, true), moduleIdx(moduleIdx)
|
||||
{
|
||||
setCloseWhenClickOutside(true);
|
||||
auto form = &content->form;
|
||||
new StaticText(form, rect_t{}, STR_WAITING_FOR_MODULE, COLOR_THEME_PRIMARY1);
|
||||
|
||||
content->setWidth(LCD_W * 0.8);
|
||||
content->updateSize();
|
||||
new StaticText(form, rect_t{}, STR_WAITING_FOR_MODULE);
|
||||
|
||||
#if defined(SIMU)
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
@@ -460,7 +488,7 @@ void ModuleOptions::checkEvents()
|
||||
state = MO_WritingSettings;
|
||||
break;
|
||||
|
||||
case MO_WritingSettings:
|
||||
case MO_WritingSettings:
|
||||
#if defined(SIMU)
|
||||
statusText.clear();
|
||||
deleteLater();
|
||||
@@ -473,11 +501,11 @@ void ModuleOptions::checkEvents()
|
||||
#endif
|
||||
break;
|
||||
|
||||
default: // MO_DisplaySettings
|
||||
default: // MO_DisplaySettings
|
||||
break;
|
||||
}
|
||||
|
||||
Dialog::checkEvents();
|
||||
BaseDialog::checkEvents();
|
||||
}
|
||||
|
||||
uint8_t ModuleOptions::getModuleSettingsState()
|
||||
@@ -488,7 +516,6 @@ uint8_t ModuleOptions::getModuleSettingsState()
|
||||
|
||||
void ModuleOptions::update()
|
||||
{
|
||||
auto form = &content->form;
|
||||
form->clear();
|
||||
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
@@ -501,43 +528,42 @@ void ModuleOptions::update()
|
||||
hwSettings.modules[moduleIdx].information.variant = PXX2_VARIANT_FCC;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
uint8_t optionsAvailable =
|
||||
getPXX2ModuleOptions(modelId) &
|
||||
((1 << MODULE_OPTION_EXTERNAL_ANTENNA) | (1 << MODULE_OPTION_POWER));
|
||||
|
||||
FlexGridLayout grid(line_col_dsc, line_row_dsc, 2);
|
||||
FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY);
|
||||
|
||||
auto line = form->newLine(&grid);
|
||||
auto line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_MODULE);
|
||||
new StaticText(line, rect_t{}, getPXX2ModuleName(modelId));
|
||||
|
||||
if (!optionsAvailable) {
|
||||
// no options available
|
||||
line = form->newLine(&grid);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_NO_TX_OPTIONS, 0);
|
||||
} else {
|
||||
// some options available
|
||||
if (optionsAvailable & (1 << MODULE_OPTION_EXTERNAL_ANTENNA)) {
|
||||
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_EXT_ANTENNA, 0, COLOR_THEME_PRIMARY1);
|
||||
new ToggleSwitch(line, rect_t{},
|
||||
[]() {
|
||||
const auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
return hwSettings.moduleSettings.externalAntenna;
|
||||
},
|
||||
[&](uint8_t val) {
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
hwSettings.moduleSettings.externalAntenna = val;
|
||||
});
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_EXT_ANTENNA);
|
||||
new ToggleSwitch(
|
||||
line, rect_t{},
|
||||
[]() {
|
||||
const auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
return hwSettings.moduleSettings.externalAntenna;
|
||||
},
|
||||
[&](uint8_t val) {
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
hwSettings.moduleSettings.externalAntenna = val;
|
||||
});
|
||||
}
|
||||
|
||||
if (optionsAvailable & (1 << MODULE_OPTION_POWER)) {
|
||||
|
||||
// TODO: use isTelemetryAvailable() to check if rebind is necessary
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_POWER, 0, COLOR_THEME_PRIMARY1);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_POWER);
|
||||
auto txPower = new Choice(
|
||||
line, rect_t{}, 0, 30,
|
||||
[]() {
|
||||
@@ -547,7 +573,7 @@ void ModuleOptions::update()
|
||||
[&](int val) {
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
hwSettings.moduleSettings.txPower = val;
|
||||
//state = MO_WriteSettings;
|
||||
// state = MO_WriteSettings;
|
||||
});
|
||||
|
||||
txPower->setTextHandler([](int val) {
|
||||
@@ -571,20 +597,22 @@ void ModuleOptions::update()
|
||||
|
||||
txPower->setAvailableHandler([=](int val) {
|
||||
const auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
return isPXX2PowerAvailable(hwSettings.modules[moduleIdx].information, val);
|
||||
return isPXX2PowerAvailable(hwSettings.modules[moduleIdx].information,
|
||||
val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
line = form->newLine(&grid);
|
||||
line = form->newLine(grid);
|
||||
new DynamicText(line, rect_t{}, [=]() { return statusText; });
|
||||
|
||||
line = form->newLine(&grid);
|
||||
line = form->newLine(grid);
|
||||
|
||||
auto box = new FormWindow(form, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8));
|
||||
lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0);
|
||||
box->padAll(lv_dpx(8));
|
||||
auto box = new Window(form, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_MEDIUM);
|
||||
lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY,
|
||||
0);
|
||||
box->padAll(PAD_MEDIUM);
|
||||
|
||||
new TextButton(box, rect_t{}, STR_CANCEL, [=]() -> int8_t {
|
||||
this->deleteLater();
|
||||
@@ -595,8 +623,6 @@ void ModuleOptions::update()
|
||||
this->writeSettings();
|
||||
return 0;
|
||||
});
|
||||
|
||||
content->updateSize();
|
||||
}
|
||||
|
||||
void ModuleOptions::writeSettings()
|
||||
@@ -607,17 +633,12 @@ void ModuleOptions::writeSettings()
|
||||
}
|
||||
}
|
||||
|
||||
RxOptions::RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx):
|
||||
Dialog(parent, STR_RECEIVER_OPTIONS, rect_t{}),
|
||||
moduleIdx(moduleIdx),
|
||||
receiverIdx(rxIdx)
|
||||
RxOptions::RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx) :
|
||||
BaseDialog(parent, STR_RECEIVER_OPTIONS, true),
|
||||
moduleIdx(moduleIdx),
|
||||
receiverIdx(rxIdx)
|
||||
{
|
||||
setCloseWhenClickOutside(true);
|
||||
auto form = &content->form;
|
||||
new StaticText(form, rect_t{}, STR_WAITING_FOR_RX, 0, COLOR_THEME_PRIMARY1);
|
||||
|
||||
content->setWidth(LCD_W * 0.8);
|
||||
content->updateSize();
|
||||
new StaticText(form, rect_t{}, STR_WAITING_FOR_RX);
|
||||
|
||||
#if defined(SIMU)
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
@@ -626,10 +647,11 @@ RxOptions::RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx):
|
||||
hwSettings.receiverSettings.state = PXX2_SETTINGS_OK;
|
||||
moduleState[moduleIdx].mode = MODULE_MODE_NORMAL;
|
||||
state = RO_ReadReceiverSettings;
|
||||
auto& rxInfo = hwSettings.modules[moduleIdx].receivers[receiverIdx].information;
|
||||
auto& rxInfo =
|
||||
hwSettings.modules[moduleIdx].receivers[receiverIdx].information;
|
||||
rxInfo.capabilities = 0xFFFFFFFF;
|
||||
hwSettings.receiverSettings.outputsCount = 6;
|
||||
for (int i=0; i<6; i++) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
hwSettings.receiverSettings.outputsMapping[i] = i;
|
||||
}
|
||||
#endif
|
||||
@@ -661,7 +683,8 @@ void RxOptions::checkEvents()
|
||||
moduleState[moduleIdx].readModuleSettings(&hwSettings.moduleSettings);
|
||||
state = RO_ReadModuleSettings;
|
||||
} else {
|
||||
moduleState[moduleIdx].readReceiverSettings(&hwSettings.receiverSettings);
|
||||
moduleState[moduleIdx].readReceiverSettings(
|
||||
&hwSettings.receiverSettings);
|
||||
state = RO_ReadReceiverSettings;
|
||||
}
|
||||
}
|
||||
@@ -670,7 +693,8 @@ void RxOptions::checkEvents()
|
||||
// this one does NOT timeout (see pxx2.cpp)
|
||||
if (moduleState[moduleIdx].mode == MODULE_MODE_NORMAL &&
|
||||
hwSettings.moduleSettings.state == PXX2_SETTINGS_OK) {
|
||||
moduleState[moduleIdx].readReceiverSettings(&hwSettings.receiverSettings);
|
||||
moduleState[moduleIdx].readReceiverSettings(
|
||||
&hwSettings.receiverSettings);
|
||||
state = RO_ReadReceiverSettings;
|
||||
}
|
||||
break;
|
||||
@@ -683,7 +707,8 @@ void RxOptions::checkEvents()
|
||||
break;
|
||||
case RO_WriteSettings:
|
||||
// TODO: ask for confirmation ???
|
||||
moduleState[moduleIdx].writeReceiverSettings(&hwSettings.receiverSettings);
|
||||
moduleState[moduleIdx].writeReceiverSettings(
|
||||
&hwSettings.receiverSettings);
|
||||
state = RO_WritingSettings;
|
||||
break;
|
||||
|
||||
@@ -700,11 +725,11 @@ void RxOptions::checkEvents()
|
||||
#endif
|
||||
break;
|
||||
|
||||
default: // RO_DisplaySettings
|
||||
default: // RO_DisplaySettings
|
||||
break;
|
||||
}
|
||||
|
||||
Dialog::checkEvents();
|
||||
BaseDialog::checkEvents();
|
||||
}
|
||||
|
||||
static uint8_t getShiftedChannel(int8_t moduleIdx, int ch)
|
||||
@@ -731,7 +756,7 @@ class OutputMappingChoice : public Choice
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
hwSettings.receiverSettings.outputsMapping[rx_pin] = val;
|
||||
}
|
||||
|
||||
|
||||
std::string getChannelText(int val)
|
||||
{
|
||||
if (val < channels) {
|
||||
@@ -743,34 +768,39 @@ class OutputMappingChoice : public Choice
|
||||
void addMenuItem(int item, Menu* menu, int val, int& selectedIx)
|
||||
{
|
||||
menu->addLineBuffered(textHandler(item), [=]() { setValue(item); });
|
||||
if (item == val) { selectedIx = menu->count() - 1; }
|
||||
if (item == val) {
|
||||
selectedIx = menu->count() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
OutputMappingChoice(Window* parent, uint32_t capabilities, uint8_t rx_model_id,
|
||||
uint8_t module, uint8_t channels, uint8_t output_pin) :
|
||||
OutputMappingChoice(Window* parent, uint32_t capabilities,
|
||||
uint8_t rx_model_id, uint8_t module, uint8_t channels,
|
||||
uint8_t output_pin) :
|
||||
Choice(parent, rect_t{}, 0, channels - 1,
|
||||
std::bind(&OutputMappingChoice::getOutputMapping, this),
|
||||
std::bind(&OutputMappingChoice::setOutputMapping, this,
|
||||
std::placeholders::_1), 0),
|
||||
std::placeholders::_1),
|
||||
0),
|
||||
capabilities(capabilities),
|
||||
ch_offset(getShiftedChannel(module, 0)),
|
||||
channels(channels),
|
||||
rx_pin(output_pin)
|
||||
{
|
||||
if (isPXX2ReceiverOptionAvailable(rx_model_id, RECEIVER_OPTION_D_TELE_PORT)) {
|
||||
setTextHandler([=] (int val) {
|
||||
switch(val) {
|
||||
case CH_MAP_SBUS_IN:
|
||||
return std::string(STR_SBUSIN);
|
||||
case CH_MAP_SBUS_OUT:
|
||||
return std::string(STR_SBUSOUT);
|
||||
case CH_MAP_SPORT:
|
||||
return std::string(STR_SPORT);
|
||||
case CH_MAP_FBUS:
|
||||
return std::string(STR_FBUS);
|
||||
default:
|
||||
return getChannelText(val);
|
||||
if (isPXX2ReceiverOptionAvailable(rx_model_id,
|
||||
RECEIVER_OPTION_D_TELE_PORT)) {
|
||||
setTextHandler([=](int val) {
|
||||
switch (val) {
|
||||
case CH_MAP_SBUS_IN:
|
||||
return std::string(STR_SBUSIN);
|
||||
case CH_MAP_SBUS_OUT:
|
||||
return std::string(STR_SBUSOUT);
|
||||
case CH_MAP_SPORT:
|
||||
return std::string(STR_SPORT);
|
||||
case CH_MAP_FBUS:
|
||||
return std::string(STR_FBUS);
|
||||
default:
|
||||
return getChannelText(val);
|
||||
}
|
||||
});
|
||||
setFillMenuHandler([=](Menu* menu, int val, int& selectedIx) {
|
||||
@@ -783,17 +813,17 @@ class OutputMappingChoice : public Choice
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (capabilities & (1 << RECEIVER_CAPABILITY_ENABLE_PWM_CH5_CH6)) {
|
||||
if (CH_ENABLE_SPORT == output_pin) {
|
||||
setTextHandler([=] (int val) {
|
||||
setTextHandler([=](int val) {
|
||||
if (val == channels) return std::string(STR_SPORT);
|
||||
return getChannelText(val);
|
||||
});
|
||||
setMax(channels);
|
||||
return;
|
||||
} else if (CH_ENABLE_SBUS == output_pin) {
|
||||
setTextHandler([=] (int val) {
|
||||
setTextHandler([=](int val) {
|
||||
if (val == channels) return std::string(STR_SBUSOUT);
|
||||
return getChannelText(val);
|
||||
});
|
||||
@@ -809,25 +839,24 @@ class OutputMappingChoice : public Choice
|
||||
|
||||
void RxOptions::update()
|
||||
{
|
||||
auto form = &content->form;
|
||||
form->clear();
|
||||
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
auto& rxInfo = hwSettings.modules[moduleIdx].receivers[receiverIdx].information;
|
||||
auto& rxInfo =
|
||||
hwSettings.modules[moduleIdx].receivers[receiverIdx].information;
|
||||
uint8_t rxModelId = rxInfo.modelID;
|
||||
uint8_t rxVariant = rxInfo.variant;
|
||||
uint8_t capabilities = rxInfo.capabilities;
|
||||
|
||||
FlexGridLayout grid(line_col_dsc, line_row_dsc, 2);
|
||||
FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY);
|
||||
|
||||
auto line = form->newLine(&grid);
|
||||
auto line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_RECEIVER);
|
||||
new StaticText(line, rect_t{},
|
||||
g_model.moduleData[moduleIdx].pxx2.receiverName[receiverIdx]);
|
||||
|
||||
// PWM rate
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, isModuleR9MAccess(moduleIdx) ? "6.67ms PWM" : "7ms PWM");
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{},
|
||||
isModuleR9MAccess(moduleIdx) ? "6.67ms PWM" : "7ms PWM");
|
||||
new ToggleSwitch(
|
||||
line, rect_t{},
|
||||
[]() {
|
||||
@@ -840,18 +869,18 @@ void RxOptions::update()
|
||||
});
|
||||
|
||||
// telemetry disabled
|
||||
line = form->newLine(&grid);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_TELEMETRY_DISABLED);
|
||||
auto tele25mw = new ToggleSwitch(
|
||||
line, rect_t{},
|
||||
[]() {
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
return hwSettings.receiverSettings.telemetryDisabled;
|
||||
},
|
||||
[](int val) {
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
hwSettings.receiverSettings.telemetryDisabled = val;
|
||||
});
|
||||
line, rect_t{},
|
||||
[]() {
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
return hwSettings.receiverSettings.telemetryDisabled;
|
||||
},
|
||||
[](int val) {
|
||||
auto& hwSettings = getPXX2HardwareAndSettingsBuffer();
|
||||
hwSettings.receiverSettings.telemetryDisabled = val;
|
||||
});
|
||||
|
||||
if (isModuleR9MAccess(moduleIdx) && rxVariant == PXX2_VARIANT_EU &&
|
||||
hwSettings.moduleSettings.txPower > 14 /*25mW*/) {
|
||||
@@ -861,7 +890,7 @@ void RxOptions::update()
|
||||
|
||||
if (capabilities & (1 << RECEIVER_CAPABILITY_TELEMETRY_25MW)) {
|
||||
// telemetry 25 mW
|
||||
line = form->newLine(&grid);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, "25mw Tele");
|
||||
new ToggleSwitch(
|
||||
line, rect_t{},
|
||||
@@ -877,9 +906,8 @@ void RxOptions::update()
|
||||
|
||||
if (capabilities &
|
||||
((1 << RECEIVER_CAPABILITY_FPORT) | (1 << RECEIVER_CAPABILITY_FPORT2))) {
|
||||
|
||||
// SPORT modes
|
||||
line = form->newLine(&grid);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_PROTOCOL);
|
||||
auto sportModes = new Choice(
|
||||
line, rect_t{}, STR_SPORT_MODES, 0, 2,
|
||||
@@ -907,7 +935,7 @@ void RxOptions::update()
|
||||
}
|
||||
|
||||
if (capabilities & (1 << RECEIVER_CAPABILITY_SBUS24)) {
|
||||
line = form->newLine(&grid);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_SBUS24);
|
||||
new ToggleSwitch(
|
||||
line, rect_t{},
|
||||
@@ -921,23 +949,26 @@ void RxOptions::update()
|
||||
});
|
||||
}
|
||||
|
||||
auto outputsCount = min<uint8_t>(16, hwSettings.receiverSettings.outputsCount);
|
||||
auto outputsCount =
|
||||
min<uint8_t>(16, hwSettings.receiverSettings.outputsCount);
|
||||
for (uint8_t i = 0; i < outputsCount; i++) {
|
||||
line = form->newLine(&grid);
|
||||
std::string i_str = std::to_string(i+1);
|
||||
line = form->newLine(grid);
|
||||
std::string i_str = std::to_string(i + 1);
|
||||
new StaticText(line, rect_t{}, std::string(STR_PIN) + i_str);
|
||||
|
||||
uint8_t channels = sentModuleChannels(moduleIdx);
|
||||
new OutputMappingChoice(line, capabilities, rxModelId, moduleIdx, channels, i);
|
||||
new OutputMappingChoice(line, capabilities, rxModelId, moduleIdx, channels,
|
||||
i);
|
||||
}
|
||||
|
||||
line = form->newLine(&grid);
|
||||
line = form->newLine(grid);
|
||||
new DynamicText(line, rect_t{}, [=]() { return statusText; });
|
||||
|
||||
auto box = new FormWindow(form, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8));
|
||||
lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0);
|
||||
box->padAll(lv_dpx(8));
|
||||
auto box = new Window(form, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_MEDIUM);
|
||||
lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY,
|
||||
0);
|
||||
box->padAll(PAD_MEDIUM);
|
||||
|
||||
new TextButton(box, rect_t{}, STR_CANCEL, [=]() -> int8_t {
|
||||
this->deleteLater();
|
||||
@@ -948,8 +979,6 @@ void RxOptions::update()
|
||||
this->writeSettings();
|
||||
return 0;
|
||||
});
|
||||
|
||||
content->updateSize();
|
||||
}
|
||||
|
||||
void RxOptions::writeSettings()
|
||||
@@ -960,4 +989,4 @@ void RxOptions::writeSettings()
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}; // namespace pxx2
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "menu.h"
|
||||
#include "static.h"
|
||||
#include "button.h"
|
||||
#include "dialog.h"
|
||||
@@ -29,33 +28,6 @@
|
||||
#include "numberedit.h"
|
||||
|
||||
namespace pxx2 {
|
||||
|
||||
class BindRxChoiceMenu : public Menu
|
||||
{
|
||||
public:
|
||||
BindRxChoiceMenu(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx);
|
||||
|
||||
protected:
|
||||
uint8_t moduleIdx;
|
||||
uint8_t receiverIdx;
|
||||
|
||||
#if defined(HARDWARE_TOUCH)
|
||||
bool onTouchEnd(coord_t x, coord_t y) override;
|
||||
#endif
|
||||
};
|
||||
|
||||
class BindWaitDialog : public Dialog
|
||||
{
|
||||
public:
|
||||
BindWaitDialog(Window* parent, uint8_t moduleIdx, uint8_t receiverIdx);
|
||||
void checkEvents() override;
|
||||
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
|
||||
protected:
|
||||
uint8_t moduleIdx;
|
||||
uint8_t receiverIdx;
|
||||
};
|
||||
|
||||
class ReceiverButton : public TextButton
|
||||
{
|
||||
@@ -72,7 +44,7 @@ class ReceiverButton : public TextButton
|
||||
uint8_t receiverIdx;
|
||||
};
|
||||
|
||||
class RegisterDialog : public Dialog
|
||||
class RegisterDialog : public BaseDialog
|
||||
{
|
||||
public:
|
||||
RegisterDialog(Window* parent, uint8_t moduleIdx);
|
||||
@@ -90,7 +62,7 @@ class RegisterDialog : public Dialog
|
||||
Window* btn_ok = nullptr;
|
||||
};
|
||||
|
||||
class ModuleOptions : public Dialog
|
||||
class ModuleOptions : public BaseDialog
|
||||
{
|
||||
public:
|
||||
ModuleOptions(Window* parent, uint8_t moduleIdx);
|
||||
@@ -118,34 +90,4 @@ class ModuleOptions : public Dialog
|
||||
void writeSettings();
|
||||
};
|
||||
|
||||
class RxOptions : public Dialog
|
||||
{
|
||||
public:
|
||||
RxOptions(Window* parent, uint8_t moduleIdx, uint8_t rxIdx);
|
||||
void checkEvents() override;
|
||||
|
||||
protected:
|
||||
|
||||
enum {
|
||||
RO_Init=0,
|
||||
RO_ReadModuleInfo,
|
||||
RO_ReadModuleSettings,
|
||||
RO_ReadReceiverSettings,
|
||||
RO_DisplaySettings,
|
||||
RO_WriteSettings,
|
||||
RO_WritingSettings,
|
||||
};
|
||||
|
||||
uint8_t moduleIdx;
|
||||
uint8_t receiverIdx;
|
||||
uint8_t state = RO_Init;
|
||||
|
||||
std::string statusText;
|
||||
|
||||
uint8_t getRxSettingsState();
|
||||
|
||||
void update();
|
||||
void writeSettings();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
class FSProtoOpts : public FormWindow
|
||||
class FSProtoOpts : public Window
|
||||
{
|
||||
std::function<uint8_t()> _getMode;
|
||||
std::function<void(uint8_t)> _setMode;
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
|
||||
FSProtoOpts::FSProtoOpts(Window* parent, std::function<uint8_t()> getMode,
|
||||
std::function<void(uint8_t)> setMode) :
|
||||
FormWindow(parent, rect_t{}),
|
||||
Window(parent, rect_t{}),
|
||||
_getMode(std::move(getMode)),
|
||||
_setMode(std::move(setMode))
|
||||
{
|
||||
@@ -65,18 +65,18 @@ FSProtoOpts::FSProtoOpts(Window* parent, std::function<uint8_t()> getMode,
|
||||
|
||||
AFHDS2ASettings::AFHDS2ASettings(Window* parent, const FlexGridLayout& g,
|
||||
uint8_t moduleIdx) :
|
||||
FormWindow(parent, rect_t{}),
|
||||
Window(parent, rect_t{}),
|
||||
moduleIdx(moduleIdx),
|
||||
md(&g_model.moduleData[moduleIdx]),
|
||||
grid(g)
|
||||
{
|
||||
setFlexLayout();
|
||||
|
||||
FormWindow::Line* line;
|
||||
FormLine* line;
|
||||
|
||||
// RX options:
|
||||
line = newLine(&grid);
|
||||
afhds2OptionsLabel = new StaticText(line, rect_t{}, STR_OPTIONS, 0, COLOR_THEME_PRIMARY1);
|
||||
line = newLine(grid);
|
||||
afhds2OptionsLabel = new StaticText(line, rect_t{}, STR_OPTIONS);
|
||||
|
||||
afhds2ProtoOpts = new FSProtoOpts(
|
||||
line, [=]() { return md->flysky.mode; },
|
||||
@@ -84,7 +84,7 @@ AFHDS2ASettings::AFHDS2ASettings(Window* parent, const FlexGridLayout& g,
|
||||
|
||||
#if defined(PCBNV14)
|
||||
if (getNV14RfFwVersion() >= 0x1000E) {
|
||||
line = newLine(&grid);
|
||||
line = newLine(grid);
|
||||
static const char* _rf_power[] = {"Default", "High"};
|
||||
afhds2RFPowerText = new StaticText(line, rect_t{}, STR_MULTI_RFPOWER);
|
||||
afhds2RFPowerChoice = new Choice(line, rect_t{}, _rf_power, 0, 1,
|
||||
@@ -101,33 +101,33 @@ AFHDS2ASettings::AFHDS2ASettings(Window* parent, const FlexGridLayout& g,
|
||||
|
||||
void AFHDS2ASettings::hideAFHDS2Options()
|
||||
{
|
||||
lv_obj_add_flag(afhds2OptionsLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(afhds2ProtoOpts->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
afhds2OptionsLabel->hide();
|
||||
afhds2ProtoOpts->hide();
|
||||
#if defined(PCBNV14)
|
||||
if (afhds2RFPowerText != nullptr)
|
||||
lv_obj_add_flag(afhds2RFPowerText->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
afhds2RFPowerText->hide();
|
||||
if (afhds2RFPowerChoice != nullptr)
|
||||
lv_obj_add_flag(afhds2RFPowerChoice->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
afhds2RFPowerChoice->hide();
|
||||
#endif
|
||||
}
|
||||
|
||||
void AFHDS2ASettings::showAFHDS2Options()
|
||||
{
|
||||
lv_obj_clear_flag(afhds2OptionsLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(afhds2ProtoOpts->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
afhds2OptionsLabel->show();
|
||||
afhds2ProtoOpts->show();
|
||||
#if defined(PCBNV14)
|
||||
if (afhds2RFPowerText != nullptr)
|
||||
lv_obj_clear_flag(afhds2RFPowerText->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
afhds2RFPowerText->show();
|
||||
if (afhds2RFPowerChoice != nullptr)
|
||||
{
|
||||
lv_obj_clear_flag(afhds2RFPowerChoice->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
afhds2RFPowerChoice->show();
|
||||
lv_event_send(afhds2RFPowerChoice->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AFHDS2ASettings::checkEvents() {
|
||||
FormWindow::checkEvents();
|
||||
Window::checkEvents();
|
||||
}
|
||||
|
||||
void AFHDS2ASettings::update()
|
||||
|
||||
@@ -21,13 +21,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
#include "choice.h"
|
||||
#include "window.h"
|
||||
#include "module_setup.h"
|
||||
|
||||
struct ModuleData;
|
||||
|
||||
class AFHDS2ASettings : public FormWindow, public ModuleOptions
|
||||
class AFHDS2ASettings : public Window, public ModuleOptions
|
||||
{
|
||||
uint8_t moduleIdx;
|
||||
ModuleData* md;
|
||||
|
||||
@@ -73,10 +73,9 @@ static void pwmfreq_changedV0(lv_event_t* e)
|
||||
}
|
||||
}
|
||||
PWMfrequencyChoice::PWMfrequencyChoice(Window* parent, uint8_t moduleIdx, uint8_t channelIdx) :
|
||||
FormWindow(parent, rect_t{})
|
||||
Window(parent, rect_t{})
|
||||
{
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_width(lvobj, LV_SIZE_CONTENT);
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY, LV_SIZE_CONTENT);
|
||||
uint16_t &pwmvalue_type = _v1_pwmvalue_type[moduleIdx][channelIdx];
|
||||
auto cfg = afhds3::getConfig(moduleIdx);
|
||||
auto vCfg = &cfg->v1;
|
||||
@@ -110,10 +109,9 @@ PWMfrequencyChoice::PWMfrequencyChoice(Window* parent, uint8_t moduleIdx, uint8_
|
||||
}
|
||||
|
||||
PWMfrequencyChoice::PWMfrequencyChoice(Window* parent, uint8_t moduleIdx ) :
|
||||
FormWindow(parent, rect_t{})
|
||||
Window(parent, rect_t{})
|
||||
{
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_width(lvobj, LV_SIZE_CONTENT);
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY, LV_SIZE_CONTENT);
|
||||
uint16_t &pwmvalue_type = _v1_pwmvalue_type[moduleIdx][0];
|
||||
auto cfg = afhds3::getConfig(moduleIdx);
|
||||
auto vCfg = &cfg->v0;
|
||||
@@ -154,28 +152,26 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
|
||||
cfg = afhds3::getConfig(moduleIdx);
|
||||
std::string title =
|
||||
moduleIdx == INTERNAL_MODULE ? STR_INTERNALRF : STR_EXTERNALRF;
|
||||
header.setTitle(title);
|
||||
header->setTitle(title);
|
||||
|
||||
title = "AFHDS3 (";
|
||||
title += (moduleIdx == INTERNAL_MODULE ? "INRM301" : "FRM303");
|
||||
title += ")";
|
||||
header.setTitle2(title);
|
||||
header->setTitle2(title);
|
||||
|
||||
auto form = new FormWindow(&body, rect_t{});
|
||||
form->setFlexLayout();
|
||||
form->padAll(lv_dpx(8));
|
||||
body->setFlexLayout();
|
||||
|
||||
FlexGridLayout grid(col_dsc, row_dsc, 2);
|
||||
FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY);
|
||||
|
||||
if (cfg->version == 0) {
|
||||
auto vCfg = &cfg->v0;
|
||||
|
||||
auto line = form->newLine(&grid);
|
||||
auto line = body->newLine(grid);
|
||||
std::string temp_str = "PWM";
|
||||
temp_str += TR_POWERMETER_FREQ;
|
||||
new StaticText(line, rect_t{}, temp_str);
|
||||
new PWMfrequencyChoice(line, moduleIdx);
|
||||
line = form->newLine(&grid);
|
||||
line = body->newLine(grid);
|
||||
|
||||
temp_str = "PWM";
|
||||
temp_str += " ";
|
||||
@@ -183,7 +179,7 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
|
||||
new StaticText(line, rect_t{}, temp_str);
|
||||
new ToggleSwitch(line, rect_t{}, GET_SET_AND_SYNC(cfg, vCfg->PWMFrequency.Synchronized,
|
||||
afhds3::DirtyConfig::DC_RX_CMD_FREQUENCY_V0));
|
||||
line = form->newLine(&grid);
|
||||
line = body->newLine(grid);
|
||||
|
||||
temp_str = STR_CH;
|
||||
temp_str += " 1";
|
||||
@@ -192,7 +188,7 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
|
||||
afhds3::SES_ANALOG_OUTPUT_PWM, afhds3::SES_ANALOG_OUTPUT_PPM,
|
||||
GET_SET_AND_SYNC(cfg, vCfg->AnalogOutput, afhds3::DirtyConfig::DC_RX_CMD_OUT_PWM_PPM_MODE));
|
||||
|
||||
line = form->newLine(&grid);
|
||||
line = body->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_SERIAL_BUS);
|
||||
new Choice(line, rect_t{}, _bus_types, 0, 2,
|
||||
GET_SET_AND_SYNC(cfg, cfg->others.ExternalBusType, afhds3::DirtyConfig::DC_RX_CMD_BUS_TYPE_V0));
|
||||
@@ -201,10 +197,10 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
|
||||
for (uint8_t i = 0; i < channel_num[vCfg->PhyMode]; i++) {
|
||||
std::string temp_str = STR_CH;
|
||||
temp_str += " " + std::to_string(i+1);
|
||||
auto line = form->newLine(&grid);
|
||||
auto line = body->newLine(grid);
|
||||
new StaticText(line, rect_t{}, temp_str);
|
||||
new PWMfrequencyChoice(line, moduleIdx, i);
|
||||
line = form->newLine(&grid);
|
||||
line = body->newLine(grid);
|
||||
|
||||
temp_str = "PWM";
|
||||
temp_str += " ";
|
||||
@@ -220,7 +216,7 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < SES_NPT_NB_MAX_PORTS; i++) {
|
||||
auto line = form->newLine(&grid);
|
||||
auto line = body->newLine(grid);
|
||||
std::string portName = "NP";
|
||||
portName += 'A' + i;
|
||||
new StaticText(line, rect_t{}, portName.c_str());
|
||||
@@ -249,7 +245,7 @@ AFHDS3_Options::AFHDS3_Options(uint8_t moduleIdx) : Page(ICON_MODEL_SETUP)
|
||||
});
|
||||
}
|
||||
}
|
||||
auto line = form->newLine(&grid);
|
||||
auto line = body->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_SIGNAL_OUTPUT);
|
||||
std::vector<std::string> signed_strength_ch;
|
||||
signed_strength_ch.emplace_back(STR_OFF);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "page.h"
|
||||
#include "pulses/afhds3_config.h"
|
||||
|
||||
struct PWMfrequencyChoice : public FormWindow {
|
||||
struct PWMfrequencyChoice : public Window {
|
||||
PWMfrequencyChoice(Window* parent, uint8_t moduleIdx, uint8_t channelIdx);
|
||||
PWMfrequencyChoice(Window* parent, uint8_t moduleIdx);
|
||||
void update() const;
|
||||
|
||||
@@ -20,80 +20,84 @@
|
||||
*/
|
||||
|
||||
#include "afhds3_settings.h"
|
||||
|
||||
#include "afhds3_options.h"
|
||||
#include "opentx.h"
|
||||
|
||||
static const char* const _afhds3_region[] = { "CE", "FCC" };
|
||||
static const char* const _afhds3_region[] = {"CE", "FCC"};
|
||||
|
||||
static const char* const _afhds3_phy_mode[] = {
|
||||
// V0
|
||||
"Classic 18ch",
|
||||
"C-Fast 10ch",
|
||||
// V1
|
||||
"Routine 18ch",
|
||||
"Fast 8ch",
|
||||
"Lora 12ch",
|
||||
// V0
|
||||
"Classic 18ch",
|
||||
"C-Fast 10ch",
|
||||
// V1
|
||||
"Routine 18ch",
|
||||
"Fast 8ch",
|
||||
"Lora 12ch",
|
||||
};
|
||||
|
||||
#include "pulses/flysky.h"
|
||||
#include "pulses/afhds3.h"
|
||||
#include "pulses/afhds3_config.h"
|
||||
#include "pulses/flysky.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
AFHDS3Settings::AFHDS3Settings(Window* parent, const FlexGridLayout& g,
|
||||
uint8_t moduleIdx) :
|
||||
FormWindow(parent, rect_t{}),
|
||||
Window(parent, rect_t{}),
|
||||
moduleIdx(moduleIdx),
|
||||
md(&g_model.moduleData[moduleIdx]),
|
||||
grid(g)
|
||||
{
|
||||
setFlexLayout();
|
||||
|
||||
FormWindow::Line* line;
|
||||
FormLine* line;
|
||||
|
||||
// Status
|
||||
line = newLine(&grid);
|
||||
afhds3StatusLabel = new StaticText(line, rect_t{}, STR_MODULE_STATUS, 0, COLOR_THEME_PRIMARY1);
|
||||
line = newLine(grid);
|
||||
afhds3StatusLabel = new StaticText(line, rect_t{}, STR_MODULE_STATUS);
|
||||
afhds3StatusText = new DynamicText(line, rect_t{}, [=] {
|
||||
char msg[64] = "";
|
||||
getModuleStatusString(moduleIdx, msg);
|
||||
return std::string(msg);
|
||||
});
|
||||
char msg[64] = "";
|
||||
getModuleStatusString(moduleIdx, msg);
|
||||
return std::string(msg);
|
||||
});
|
||||
|
||||
// TYPE
|
||||
line = newLine(&grid);
|
||||
afhds3TypeLabel = new StaticText(line, rect_t{}, STR_TYPE, 0, COLOR_THEME_PRIMARY1);
|
||||
line = newLine(grid);
|
||||
afhds3TypeLabel =
|
||||
new StaticText(line, rect_t{}, STR_TYPE);
|
||||
|
||||
afhds3TypeForm = new FormWindow(line, rect_t{});
|
||||
afhds3TypeForm = new Window(line, rect_t{});
|
||||
afhds3TypeForm->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP);
|
||||
lv_obj_set_style_grid_cell_x_align(afhds3TypeForm->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
|
||||
lv_obj_set_style_grid_cell_x_align(afhds3TypeForm->getLvObj(),
|
||||
LV_GRID_ALIGN_STRETCH, 0);
|
||||
|
||||
afhds3PhyMode = new Choice(afhds3TypeForm, rect_t{}, _afhds3_phy_mode, 0, afhds3::PHYMODE_MAX,
|
||||
GET_SET_DEFAULT(md->afhds3.phyMode));
|
||||
lv_obj_set_style_bg_color(afhds3PhyMode->getLvObj(), makeLvColor(COLOR_THEME_DISABLED), LV_PART_MAIN | LV_STATE_DISABLED);
|
||||
afhds3PhyMode =
|
||||
new Choice(afhds3TypeForm, rect_t{}, _afhds3_phy_mode, 0,
|
||||
afhds3::PHYMODE_MAX, GET_SET_DEFAULT(md->afhds3.phyMode));
|
||||
|
||||
afhds3Emi = new Choice(afhds3TypeForm, rect_t{}, _afhds3_region,
|
||||
afhds3::LNK_ES_CE, afhds3::LNK_ES_FCC,
|
||||
GET_SET_DEFAULT(md->afhds3.emi));
|
||||
lv_obj_set_style_bg_color(afhds3Emi->getLvObj(), makeLvColor(COLOR_THEME_DISABLED), LV_PART_MAIN | LV_STATE_DISABLED);
|
||||
afhds3Emi =
|
||||
new Choice(afhds3TypeForm, rect_t{}, _afhds3_region, afhds3::LNK_ES_CE,
|
||||
afhds3::LNK_ES_FCC, GET_SET_DEFAULT(md->afhds3.emi));
|
||||
|
||||
new TextButton(afhds3TypeForm, rect_t{}, STR_MODULE_OPTIONS,
|
||||
[=]() {
|
||||
afhds3::applyModelConfig(moduleIdx);
|
||||
new AFHDS3_Options(moduleIdx);
|
||||
return 0;
|
||||
});
|
||||
new TextButton(afhds3TypeForm, rect_t{}, STR_MODULE_OPTIONS, [=]() {
|
||||
afhds3::applyModelConfig(moduleIdx);
|
||||
new AFHDS3_Options(moduleIdx);
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (moduleIdx == EXTERNAL_MODULE) {
|
||||
line = newLine(&grid);
|
||||
line = newLine(grid);
|
||||
auto cfg = afhds3::getConfig(moduleIdx);
|
||||
new StaticText(line, rect_t{}, STR_MULTI_RFPOWER);
|
||||
afhds3RfPower = new Choice(line, rect_t{}, STR_AFHDS3_POWERS, 0, AFHDS3_FRM303_POWER_MAX,
|
||||
GET_DEFAULT(md->afhds3.rfPower),
|
||||
[=](int32_t newValue) { md->afhds3.rfPower = newValue;
|
||||
cfg->others.dirtyFlag |= (uint32_t) 1 << afhds3::DirtyConfig::DC_RX_CMD_TX_PWR;
|
||||
SET_DIRTY();});
|
||||
afhds3RfPower = new Choice(
|
||||
line, rect_t{}, STR_AFHDS3_POWERS, 0, AFHDS3_FRM303_POWER_MAX,
|
||||
GET_DEFAULT(md->afhds3.rfPower), [=](int32_t newValue) {
|
||||
md->afhds3.rfPower = newValue;
|
||||
cfg->others.dirtyFlag |= (uint32_t)1
|
||||
<< afhds3::DirtyConfig::DC_RX_CMD_TX_PWR;
|
||||
SET_DIRTY();
|
||||
});
|
||||
}
|
||||
|
||||
hideAFHDS3Options();
|
||||
@@ -101,41 +105,39 @@ AFHDS3Settings::AFHDS3Settings(Window* parent, const FlexGridLayout& g,
|
||||
|
||||
void AFHDS3Settings::hideAFHDS3Options()
|
||||
{
|
||||
lv_obj_add_flag(afhds3StatusLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(afhds3StatusText->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(afhds3TypeLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(afhds3TypeForm->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
afhds3StatusLabel->hide();
|
||||
afhds3StatusText->hide();
|
||||
afhds3TypeLabel->hide();
|
||||
afhds3TypeForm->hide();
|
||||
}
|
||||
|
||||
void AFHDS3Settings::showAFHDS3Options()
|
||||
{
|
||||
lv_obj_clear_flag(afhds3StatusLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(afhds3StatusText->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(afhds3TypeLabel->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_clear_flag(afhds3TypeForm->getLvObj(), LV_OBJ_FLAG_HIDDEN);
|
||||
afhds3StatusLabel->show();
|
||||
afhds3StatusText->show();
|
||||
afhds3TypeLabel->show();
|
||||
afhds3TypeForm->show();
|
||||
lv_event_send(afhds3StatusText->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
lv_event_send(afhds3PhyMode->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
lv_event_send(afhds3Emi->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
if (moduleIdx == EXTERNAL_MODULE) {
|
||||
lv_event_send(afhds3RfPower->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
lv_event_send(afhds3RfPower->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
if (afhds3::getConfig(moduleIdx)->others.isConnected)
|
||||
{
|
||||
lv_obj_add_state(afhds3PhyMode->getLvObj(), LV_STATE_DISABLED);
|
||||
lv_obj_add_state(afhds3Emi->getLvObj(), LV_STATE_DISABLED);
|
||||
}
|
||||
else
|
||||
{
|
||||
lv_obj_clear_state(afhds3PhyMode->getLvObj(), LV_STATE_DISABLED);
|
||||
lv_obj_clear_state(afhds3Emi->getLvObj(), LV_STATE_DISABLED);
|
||||
if (afhds3::getConfig(moduleIdx)->others.isConnected) {
|
||||
afhds3PhyMode->disable();
|
||||
afhds3Emi->disable();
|
||||
} else {
|
||||
afhds3PhyMode->enable();
|
||||
afhds3Emi->enable();
|
||||
}
|
||||
}
|
||||
|
||||
void AFHDS3Settings::checkEvents() {
|
||||
void AFHDS3Settings::checkEvents()
|
||||
{
|
||||
if (afhds3::getConfig(moduleIdx)->others.lastUpdated > lastRefresh) {
|
||||
update();
|
||||
}
|
||||
FormWindow::checkEvents();
|
||||
Window::checkEvents();
|
||||
}
|
||||
|
||||
void AFHDS3Settings::update()
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
#include "window.h"
|
||||
#include "choice.h"
|
||||
#include "module_setup.h"
|
||||
|
||||
struct ModuleData;
|
||||
|
||||
class AFHDS3Settings : public FormWindow, public ModuleOptions
|
||||
class AFHDS3Settings : public Window, public ModuleOptions
|
||||
{
|
||||
uint8_t moduleIdx;
|
||||
ModuleData* md;
|
||||
@@ -37,7 +37,7 @@ class AFHDS3Settings : public FormWindow, public ModuleOptions
|
||||
Window* afhds3StatusLabel = nullptr;
|
||||
Window* afhds3StatusText = nullptr;
|
||||
Window* afhds3TypeLabel = nullptr;
|
||||
FormWindow* afhds3TypeForm = nullptr;
|
||||
Window* afhds3TypeForm = nullptr;
|
||||
Choice *afhds3PhyMode = nullptr;
|
||||
Choice *afhds3Emi = nullptr;
|
||||
Choice *afhds3RfPower = nullptr;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
BindChoiceMenu::BindChoiceMenu(Window *parent, uint8_t moduleIdx,
|
||||
std::function<void()> onPress,
|
||||
std::function<void()> onCancel) :
|
||||
std::function<void()> onCancelFn) :
|
||||
Menu(parent), moduleIdx(moduleIdx), onPressHandler(std::move(onPress))
|
||||
{
|
||||
if (isTelemAllowedOnBind(moduleIdx)) {
|
||||
@@ -47,7 +47,7 @@ BindChoiceMenu::BindChoiceMenu(Window *parent, uint8_t moduleIdx,
|
||||
setTitle(STR_SELECT_MODE);
|
||||
setCancelHandler([=] {
|
||||
moduleState[moduleIdx].mode = MODULE_MODE_NORMAL;
|
||||
onCancel();
|
||||
onCancelFn();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,52 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "bitmaps.h"
|
||||
|
||||
const uint8_t _LBM_POINT[] = {
|
||||
#include "mask_point.lbm"
|
||||
};
|
||||
IMPL_LZ4_BITMAP(LBM_POINT);
|
||||
#include "libopenui.h"
|
||||
#include "libopenui/thirdparty/lz4/lz4.h"
|
||||
#include "opentx_helpers.h"
|
||||
|
||||
LZ4BitmapBuffer::LZ4BitmapBuffer(uint8_t format, const LZ4Bitmap* lz4Data) :
|
||||
BitmapBuffer(format, 0, 0, nullptr)
|
||||
{
|
||||
_width = lz4Data->width;
|
||||
_height = lz4Data->height;
|
||||
|
||||
uint32_t pixels = _width * _height;
|
||||
data = (uint16_t*)malloc(align32(pixels * sizeof(uint16_t)));
|
||||
|
||||
LZ4_decompress_safe((const char*)lz4Data->data, (char*)data,
|
||||
lz4Data->compressedSize, pixels * sizeof(uint16_t));
|
||||
data_end = data + pixels;
|
||||
}
|
||||
|
||||
LZ4BitmapBuffer::~LZ4BitmapBuffer() { free(data); }
|
||||
|
||||
#if !defined(BOOT)
|
||||
|
||||
MaskBitmap* _decompressed_mask(const uint8_t* lz4_compressed)
|
||||
{
|
||||
const uint16_t* hdr = (const uint16_t*)lz4_compressed;
|
||||
uint16_t width = hdr[0];
|
||||
uint16_t height = hdr[1];
|
||||
|
||||
size_t len = *(uint32_t*)&hdr[2];
|
||||
|
||||
// skip 8 bytes header
|
||||
lz4_compressed += 8;
|
||||
|
||||
uint32_t pixels = width * height;
|
||||
MaskBitmap* raw = (MaskBitmap*)malloc(align32(pixels + 4));
|
||||
|
||||
raw->width = width;
|
||||
raw->height = height;
|
||||
|
||||
LZ4_decompress_safe((const char*)lz4_compressed, (char*)&raw->data, len,
|
||||
pixels);
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
static const uint8_t mask_menu_model[] = {
|
||||
#include "mask_menu_model.lbm"
|
||||
@@ -81,7 +121,7 @@ static const uint8_t mask_model_usb[] = {
|
||||
#include "mask_model_usb.lbm"
|
||||
};
|
||||
static const uint8_t mask_menu_model_select[] = {
|
||||
#include "mask_menu_model_select.lbm" //TODO: someone may want to make proper icon
|
||||
#include "mask_menu_model_select.lbm" //TODO: someone may want to make proper icon
|
||||
};
|
||||
static const uint8_t mask_monitor[] = {
|
||||
#include "mask_monitor.lbm"
|
||||
@@ -98,12 +138,6 @@ static const uint8_t mask_monitor_channels3[] = {
|
||||
static const uint8_t mask_monitor_channels4[] = {
|
||||
#include "mask_monitor_channels4.lbm"
|
||||
};
|
||||
static const uint8_t mask_monitor_inver[] = {
|
||||
#include "mask_monitor_inver.lbm"
|
||||
};
|
||||
static const uint8_t mask_monitor_lockch[] = {
|
||||
#include "mask_monitor_lockch.lbm"
|
||||
};
|
||||
static const uint8_t mask_monitor_logsw[] = {
|
||||
#include "mask_monitor_logsw.lbm"
|
||||
};
|
||||
@@ -185,12 +219,131 @@ static const uint8_t mask_theme_view9[] = {
|
||||
static const uint8_t mask_theme_view10[] = {
|
||||
#include "mask_theme_view10.lbm"
|
||||
};
|
||||
static const uint8_t stick_pointer[] = {
|
||||
#include "alpha_stick_pointer.lbm"
|
||||
|
||||
static const uint8_t mask_chan_locked[] = {
|
||||
#include "mask_monitor_lockch.lbm"
|
||||
};
|
||||
static const uint8_t stick_background[] = {
|
||||
#include "alpha_stick_background.lbm"
|
||||
static const uint8_t mask_chan_inverted[] = {
|
||||
#include "mask_monitor_inver.lbm"
|
||||
};
|
||||
|
||||
static const uint8_t mask_shutdown_circle0[] = {
|
||||
#include "mask_shutdown_circle0.lbm"
|
||||
};
|
||||
static const uint8_t mask_shutdown_circle1[] = {
|
||||
#include "mask_shutdown_circle1.lbm"
|
||||
};
|
||||
static const uint8_t mask_shutdown_circle2[] = {
|
||||
#include "mask_shutdown_circle2.lbm"
|
||||
};
|
||||
static const uint8_t mask_shutdown_circle3[] = {
|
||||
#include "mask_shutdown_circle3.lbm"
|
||||
};
|
||||
|
||||
static const uint8_t mask_shutdown[] = {
|
||||
#include "mask_shutdown.lbm"
|
||||
};
|
||||
|
||||
const uint8_t mask_topleft_bg[] = {
|
||||
#include "mask_topleft.lbm"
|
||||
};
|
||||
|
||||
const uint8_t mask_currentmenu_bg[] = {
|
||||
#include "mask_currentmenu_bg.lbm"
|
||||
};
|
||||
const uint8_t mask_currentmenu_shadow[] = {
|
||||
#include "mask_currentmenu_shadow.lbm"
|
||||
};
|
||||
const uint8_t mask_currentmenu_dot[] = {
|
||||
#include "mask_currentmenu_dot.lbm"
|
||||
};
|
||||
|
||||
static const uint8_t mask_dot[] = {
|
||||
#include "mask_dot.lbm"
|
||||
};
|
||||
|
||||
static const uint8_t mask_topmenu_usb[] = {
|
||||
#include "mask_topmenu_usb.lbm"
|
||||
};
|
||||
static const uint8_t mask_topmenu_vol0[] = {
|
||||
#include "mask_volume_0.lbm"
|
||||
};
|
||||
static const uint8_t mask_topmenu_vol1[] = {
|
||||
#include "mask_volume_1.lbm"
|
||||
};
|
||||
static const uint8_t mask_topmenu_vol2[] = {
|
||||
#include "mask_volume_2.lbm"
|
||||
};
|
||||
static const uint8_t mask_topmenu_vol3[] = {
|
||||
#include "mask_volume_3.lbm"
|
||||
};
|
||||
static const uint8_t mask_topmenu_vol4[] = {
|
||||
#include "mask_volume_4.lbm"
|
||||
};
|
||||
static const uint8_t mask_topmenu_vol_scale[] = {
|
||||
#include "mask_volume_scale.lbm"
|
||||
};
|
||||
static const uint8_t mask_topmenu_txbatt[] = {
|
||||
#include "mask_txbat.lbm"
|
||||
};
|
||||
#if defined(USB_CHARGER)
|
||||
static const uint8_t mask_topmenu_txbatt_charging[] = {
|
||||
#include "mask_txbat_charging.lbm"
|
||||
};
|
||||
#endif
|
||||
#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
|
||||
static const uint8_t mask_topmenu_antenna[] = {
|
||||
#include "mask_antenna.lbm"
|
||||
};
|
||||
#endif
|
||||
#if defined(INTERNAL_GPS)
|
||||
static const uint8_t mask_topmenu_gps[] = {
|
||||
#include "mask_topmenu_gps_18.lbm"
|
||||
};
|
||||
#endif
|
||||
|
||||
static const uint8_t mask_error[] = {
|
||||
#include "mask_error.lbm"
|
||||
};
|
||||
static const uint8_t mask_busy[] = {
|
||||
#include "mask_busy.lbm"
|
||||
};
|
||||
|
||||
static const uint8_t mask_usb_plugged[] = {
|
||||
#include "mask_usb_symbol.lbm"
|
||||
};
|
||||
|
||||
static const uint8_t mask_timer[] = {
|
||||
#include "mask_timer.lbm"
|
||||
};
|
||||
static const uint8_t mask_timer_bg[] = {
|
||||
#include "mask_timer_bg.lbm"
|
||||
};
|
||||
|
||||
static const uint8_t mask_textline_curve[] = {
|
||||
#include "mask_textline_curve.lbm"
|
||||
};
|
||||
static const uint8_t mask_textline_fm[] = {
|
||||
#include "mask_textline_fm.lbm"
|
||||
};
|
||||
|
||||
static const uint8_t mask_mplex_add[] = {
|
||||
#include "mask_mplex_add.lbm"
|
||||
};
|
||||
static const uint8_t mask_mplex_multi[] = {
|
||||
#include "mask_mplex_multi.lbm"
|
||||
};
|
||||
static const uint8_t mask_mplex_replace[] = {
|
||||
#include "mask_mplex_replace.lbm"
|
||||
};
|
||||
|
||||
const uint8_t mask_round_title_left[]{
|
||||
#include "mask_round_title_left.lbm"
|
||||
};
|
||||
const uint8_t mask_round_title_right[]{
|
||||
#include "mask_round_title_right.lbm"
|
||||
};
|
||||
|
||||
static const uint8_t mask_model_grid_large[] = {
|
||||
#include "mask_model_grid_large.lbm"
|
||||
};
|
||||
@@ -204,106 +357,137 @@ static const uint8_t mask_model_list_two[] = {
|
||||
#include "mask_model_list_two.lbm"
|
||||
};
|
||||
|
||||
BitmapBuffer * calibStick = nullptr;
|
||||
BitmapBuffer * calibStickBackground = nullptr;
|
||||
BitmapBuffer * chanMonLockedBitmap = nullptr;
|
||||
BitmapBuffer * chanMonInvertedBitmap = nullptr;
|
||||
|
||||
struct _BuiltinBitmap {
|
||||
|
||||
BitmapFormats type;
|
||||
const uint8_t* lz4_compressed_bitmap;
|
||||
BitmapBuffer** uncompressed_bitmap;
|
||||
};
|
||||
|
||||
static const _BuiltinBitmap _builtinBitmaps[] = {
|
||||
{BMP_ARGB4444, stick_pointer, &calibStick},
|
||||
{BMP_ARGB4444, stick_background, &calibStickBackground},
|
||||
|
||||
{BMP_8BIT, mask_monitor_lockch, &chanMonLockedBitmap},
|
||||
{BMP_8BIT, mask_monitor_inver, &chanMonInvertedBitmap},
|
||||
};
|
||||
|
||||
void loadBuiltinBitmaps()
|
||||
{
|
||||
for (const auto& bm : _builtinBitmaps) {
|
||||
|
||||
delete *bm.uncompressed_bitmap;
|
||||
*bm.uncompressed_bitmap = nullptr;
|
||||
|
||||
if (bm.type == BMP_ARGB4444 ||
|
||||
bm.type == BMP_RGB565) {
|
||||
*bm.uncompressed_bitmap = new LZ4Bitmap(bm.type, bm.lz4_compressed_bitmap);
|
||||
} else if (bm.type == BMP_8BIT) {
|
||||
*bm.uncompressed_bitmap = BitmapBuffer::load8bitMaskLZ4(bm.lz4_compressed_bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct _BuiltinIcon {
|
||||
MenuIcons id;
|
||||
const uint8_t* lz4_compressed_bitmap;
|
||||
};
|
||||
|
||||
static const _BuiltinIcon _builtinIcons[] = {
|
||||
{ICON_EDGETX, mask_edgetx},
|
||||
{ICON_RADIO, mask_menu_radio},
|
||||
{ICON_RADIO_SETUP, mask_radio_setup},
|
||||
{ICON_RADIO_SD_MANAGER, mask_radio_sd_browser},
|
||||
{ICON_RADIO_TOOLS, mask_radio_tools},
|
||||
{ICON_RADIO_GLOBAL_FUNCTIONS, mask_radio_global_functions},
|
||||
{ICON_RADIO_TRAINER, mask_radio_trainer},
|
||||
{ICON_RADIO_HARDWARE, mask_radio_hardware},
|
||||
{ICON_RADIO_CALIBRATION, mask_radio_calibration},
|
||||
{ICON_RADIO_EDIT_THEME, mask_radio_edit_theme},
|
||||
{ICON_RADIO_VERSION, mask_radio_version},
|
||||
{ICON_MODEL, mask_menu_model},
|
||||
{ICON_MODEL_SETUP, mask_model_setup},
|
||||
{ICON_MODEL_HELI, mask_model_heli},
|
||||
{ICON_MODEL_FLIGHT_MODES, mask_model_flight_modes},
|
||||
{ICON_MODEL_INPUTS, mask_model_inputs},
|
||||
{ICON_MODEL_MIXER, mask_model_mixer},
|
||||
{ICON_MODEL_NOTES, mask_menu_notes},
|
||||
{ICON_MODEL_OUTPUTS, mask_model_outputs},
|
||||
{ICON_MODEL_CURVES, mask_model_curves},
|
||||
{ICON_MODEL_GVARS, mask_model_gvars},
|
||||
{ICON_MODEL_LOGICAL_SWITCHES, mask_model_logical_switches},
|
||||
{ICON_MODEL_SPECIAL_FUNCTIONS, mask_model_special_functions},
|
||||
{ICON_MODEL_LUA_SCRIPTS, mask_model_lua_scripts},
|
||||
{ICON_MODEL_TELEMETRY, mask_model_telemetry},
|
||||
{ICON_MODEL_USB, mask_model_usb},
|
||||
{ICON_MODEL_SELECT, mask_menu_model_select},
|
||||
{ICON_THEME, mask_menu_theme},
|
||||
{ICON_THEME_SETUP, mask_theme_setup},
|
||||
{ICON_THEME_VIEW1, mask_theme_view1},
|
||||
{ICON_THEME_VIEW2, mask_theme_view2},
|
||||
{ICON_THEME_VIEW3, mask_theme_view3},
|
||||
{ICON_THEME_VIEW4, mask_theme_view4},
|
||||
{ICON_THEME_VIEW5, mask_theme_view5},
|
||||
{ICON_THEME_VIEW6, mask_theme_view6},
|
||||
{ICON_THEME_VIEW7, mask_theme_view7},
|
||||
{ICON_THEME_VIEW8, mask_theme_view8},
|
||||
{ICON_THEME_VIEW9, mask_theme_view9},
|
||||
{ICON_THEME_VIEW10, mask_theme_view10},
|
||||
{ICON_THEME_ADD_VIEW, mask_theme_add_view},
|
||||
{ICON_STATS, mask_menu_stats},
|
||||
{ICON_STATS_THROTTLE_GRAPH, mask_stats_throttle_graph},
|
||||
{ICON_STATS_TIMERS, mask_stats_timers},
|
||||
{ICON_STATS_ANALOGS, mask_stats_analogs},
|
||||
{ICON_STATS_DEBUG, mask_stats_debug},
|
||||
{ICON_MONITOR, mask_monitor},
|
||||
{ICON_MONITOR_CHANNELS1, mask_monitor_channels1},
|
||||
{ICON_MONITOR_CHANNELS2, mask_monitor_channels2},
|
||||
{ICON_MONITOR_CHANNELS3, mask_monitor_channels3},
|
||||
{ICON_MONITOR_CHANNELS4, mask_monitor_channels4},
|
||||
{ICON_MONITOR_LOGICAL_SWITCHES, mask_monitor_logsw},
|
||||
{ICON_MODEL_GRID_LARGE, mask_model_grid_large},
|
||||
{ICON_MODEL_GRID_SMALL, mask_model_grid_small},
|
||||
{ICON_MODEL_LIST_TWO, mask_model_list_two},
|
||||
{ICON_MODEL_LIST_ONE, mask_model_list_one},
|
||||
#define BI(icon, mask) \
|
||||
{ \
|
||||
mask \
|
||||
}
|
||||
|
||||
// Note: Order must match EdgeTxIcon enum
|
||||
static const _BuiltinIcon _builtinIcons[EDGETX_ICONS_COUNT] = {
|
||||
BI(ICON_EDGETX, mask_edgetx),
|
||||
BI(ICON_RADIO, mask_menu_radio),
|
||||
BI(ICON_RADIO_SETUP, mask_radio_setup),
|
||||
BI(ICON_RADIO_SD_MANAGER, mask_radio_sd_browser),
|
||||
BI(ICON_RADIO_TOOLS, mask_radio_tools),
|
||||
BI(ICON_RADIO_GLOBAL_FUNCTIONS, mask_radio_global_functions),
|
||||
BI(ICON_RADIO_TRAINER, mask_radio_trainer),
|
||||
BI(ICON_RADIO_HARDWARE, mask_radio_hardware),
|
||||
BI(ICON_RADIO_CALIBRATION, mask_radio_calibration),
|
||||
BI(ICON_RADIO_EDIT_THEME, mask_radio_edit_theme),
|
||||
BI(ICON_RADIO_VERSION, mask_radio_version),
|
||||
BI(ICON_MODEL, mask_menu_model),
|
||||
BI(ICON_MODEL_SETUP, mask_model_setup),
|
||||
BI(ICON_MODEL_HELI, mask_model_heli),
|
||||
BI(ICON_MODEL_FLIGHT_MODES, mask_model_flight_modes),
|
||||
BI(ICON_MODEL_INPUTS, mask_model_inputs),
|
||||
BI(ICON_MODEL_MIXER, mask_model_mixer),
|
||||
BI(ICON_MODEL_NOTES, mask_menu_notes),
|
||||
BI(ICON_MODEL_OUTPUTS, mask_model_outputs),
|
||||
BI(ICON_MODEL_CURVES, mask_model_curves),
|
||||
BI(ICON_MODEL_GVARS, mask_model_gvars),
|
||||
BI(ICON_MODEL_LOGICAL_SWITCHES, mask_model_logical_switches),
|
||||
BI(ICON_MODEL_SPECIAL_FUNCTIONS, mask_model_special_functions),
|
||||
BI(ICON_MODEL_LUA_SCRIPTS, mask_model_lua_scripts),
|
||||
BI(ICON_MODEL_TELEMETRY, mask_model_telemetry),
|
||||
BI(ICON_MODEL_USB, mask_model_usb),
|
||||
BI(ICON_MODEL_SELECT, mask_menu_model_select),
|
||||
BI(ICON_THEME, mask_menu_theme),
|
||||
BI(ICON_THEME_SETUP, mask_theme_setup),
|
||||
BI(ICON_THEME_VIEW1, mask_theme_view1),
|
||||
BI(ICON_THEME_VIEW2, mask_theme_view2),
|
||||
BI(ICON_THEME_VIEW3, mask_theme_view3),
|
||||
BI(ICON_THEME_VIEW4, mask_theme_view4),
|
||||
BI(ICON_THEME_VIEW5, mask_theme_view5),
|
||||
BI(ICON_THEME_VIEW6, mask_theme_view6),
|
||||
BI(ICON_THEME_VIEW7, mask_theme_view7),
|
||||
BI(ICON_THEME_VIEW8, mask_theme_view8),
|
||||
BI(ICON_THEME_VIEW9, mask_theme_view9),
|
||||
BI(ICON_THEME_VIEW10, mask_theme_view10),
|
||||
BI(ICON_THEME_ADD_VIEW, mask_theme_add_view),
|
||||
BI(ICON_STATS, mask_menu_stats),
|
||||
BI(ICON_STATS_THROTTLE_GRAPH, mask_stats_throttle_graph),
|
||||
BI(ICON_STATS_TIMERS, mask_stats_timers),
|
||||
BI(ICON_STATS_ANALOGS, mask_stats_analogs),
|
||||
BI(ICON_STATS_DEBUG, mask_stats_debug),
|
||||
BI(ICON_MONITOR, mask_monitor),
|
||||
BI(ICON_MONITOR_CHANNELS1, mask_monitor_channels1),
|
||||
BI(ICON_MONITOR_CHANNELS2, mask_monitor_channels2),
|
||||
BI(ICON_MONITOR_CHANNELS3, mask_monitor_channels3),
|
||||
BI(ICON_MONITOR_CHANNELS4, mask_monitor_channels4),
|
||||
BI(ICON_MONITOR_LOGICAL_SWITCHES, mask_monitor_logsw),
|
||||
|
||||
BI(ICON_CHAN_MONITOR_LOCKED, mask_chan_locked),
|
||||
BI(ICON_CHAN_MONITOR_INVERTED, mask_chan_inverted),
|
||||
|
||||
BI(ICON_SHUTDOWN_CIRCLE0, mask_shutdown_circle0),
|
||||
BI(ICON_SHUTDOWN_CIRCLE1, mask_shutdown_circle1),
|
||||
BI(ICON_SHUTDOWN_CIRCLE2, mask_shutdown_circle2),
|
||||
BI(ICON_SHUTDOWN_CIRCLE3, mask_shutdown_circle3),
|
||||
BI(ICON_SHUTDOWN, mask_shutdown),
|
||||
|
||||
BI(ICON_TOPLEFT_BG, mask_topleft_bg),
|
||||
BI(ICON_CURRENTMENU_BG, mask_currentmenu_bg),
|
||||
BI(ICON_CURRENTMENU_SHADOW, mask_currentmenu_shadow),
|
||||
BI(ICON_CURRENTMENU_DOT, mask_currentmenu_dot),
|
||||
|
||||
BI(ICON_DOT, mask_dot),
|
||||
|
||||
BI(ICON_TOPMENU_USB, mask_topmenu_usb),
|
||||
BI(ICON_TOPMENU_VOLUME_0, mask_topmenu_vol0),
|
||||
BI(ICON_TOPMENU_VOLUME_1, mask_topmenu_vol1),
|
||||
BI(ICON_TOPMENU_VOLUME_2, mask_topmenu_vol2),
|
||||
BI(ICON_TOPMENU_VOLUME_3, mask_topmenu_vol3),
|
||||
BI(ICON_TOPMENU_VOLUME_4, mask_topmenu_vol4),
|
||||
BI(ICON_TOPMENU_VOLUME_SCALE, mask_topmenu_vol_scale),
|
||||
BI(ICON_TOPMENU_TXBATT, mask_topmenu_txbatt),
|
||||
#if defined(USB_CHARGER)
|
||||
BI(ICON_TOPMENU_TXBATT_CHARGE, mask_topmenu_txbatt_charging),
|
||||
#endif
|
||||
#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
|
||||
BI(ICON_TOPMENU_ANTENNA, mask_topmenu_antenna),
|
||||
#endif
|
||||
#if defined(INTERNAL_GPS)
|
||||
BI(ICON_TOPMENU_GPS, mask_topmenu_gps),
|
||||
#endif
|
||||
|
||||
BI(ICON_ERROR, mask_error),
|
||||
BI(ICON_BUSY, mask_busy),
|
||||
|
||||
BI(ICON_USB_PLUGGED, mask_usb_plugged),
|
||||
|
||||
BI(ICON_TIMER_BG, mask_timer_bg),
|
||||
BI(ICON_TIMER, mask_timer),
|
||||
|
||||
BI(ICON_TEXTLINE_CURVE, mask_textline_curve),
|
||||
BI(ICON_TEXTLINE_FM, mask_textline_fm),
|
||||
|
||||
BI(ICON_MPLEX_ADD, mask_mplex_add),
|
||||
BI(ICON_MPLEX_MULTIPLY, mask_mplex_multi),
|
||||
BI(ICON_MPLEX_REPLACE, mask_mplex_replace),
|
||||
|
||||
BI(ICON_ROUND_TITLE_LEFT, mask_round_title_left),
|
||||
BI(ICON_ROUND_TITLE_RIGHT, mask_round_title_right),
|
||||
BI(ICON_MODEL_GRID_LARGE, mask_model_grid_large),
|
||||
BI(ICON_MODEL_GRID_SMALL, mask_model_grid_small),
|
||||
BI(ICON_MODEL_LIST_TWO, mask_model_list_two),
|
||||
BI(ICON_MODEL_LIST_ONE, mask_model_list_one),
|
||||
};
|
||||
|
||||
const uint8_t* getBuiltinIcon(MenuIcons id)
|
||||
static MaskBitmap* _builtinIconsDecompressed[EDGETX_ICONS_COUNT] = {0};
|
||||
|
||||
const MaskBitmap* getBuiltinIcon(EdgeTxIcon id)
|
||||
{
|
||||
return _builtinIcons[id].lz4_compressed_bitmap;
|
||||
// Icons are stored LZ4 compressed and de-compresssed on first use
|
||||
if (_builtinIconsDecompressed[id] == nullptr) {
|
||||
_builtinIconsDecompressed[id] =
|
||||
_decompressed_mask(_builtinIcons[id].lz4_compressed_bitmap);
|
||||
}
|
||||
|
||||
return _builtinIconsDecompressed[id];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,28 +21,139 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "definitions.h"
|
||||
#include "lz4_bitmaps.h"
|
||||
#include "bitmapbuffer.h"
|
||||
|
||||
DEFINE_LZ4_BITMAP(LBM_POINT);
|
||||
enum EdgeTxIcon {
|
||||
ICON_EDGETX,
|
||||
ICON_RADIO,
|
||||
ICON_RADIO_SETUP,
|
||||
ICON_RADIO_SD_MANAGER,
|
||||
ICON_RADIO_TOOLS,
|
||||
ICON_RADIO_GLOBAL_FUNCTIONS,
|
||||
ICON_RADIO_TRAINER,
|
||||
ICON_RADIO_HARDWARE,
|
||||
ICON_RADIO_CALIBRATION,
|
||||
ICON_RADIO_EDIT_THEME,
|
||||
ICON_RADIO_VERSION,
|
||||
ICON_MODEL,
|
||||
ICON_MODEL_SETUP,
|
||||
ICON_MODEL_HELI,
|
||||
ICON_MODEL_FLIGHT_MODES,
|
||||
ICON_MODEL_INPUTS,
|
||||
ICON_MODEL_MIXER,
|
||||
ICON_MODEL_NOTES,
|
||||
ICON_MODEL_OUTPUTS,
|
||||
ICON_MODEL_CURVES,
|
||||
ICON_MODEL_GVARS,
|
||||
ICON_MODEL_LOGICAL_SWITCHES,
|
||||
ICON_MODEL_SPECIAL_FUNCTIONS,
|
||||
ICON_MODEL_LUA_SCRIPTS,
|
||||
ICON_MODEL_TELEMETRY,
|
||||
ICON_MODEL_USB,
|
||||
ICON_MODEL_SELECT,
|
||||
ICON_THEME,
|
||||
ICON_THEME_SETUP,
|
||||
ICON_THEME_VIEW1,
|
||||
ICON_THEME_VIEW2,
|
||||
ICON_THEME_VIEW3,
|
||||
ICON_THEME_VIEW4,
|
||||
ICON_THEME_VIEW5,
|
||||
ICON_THEME_VIEW6,
|
||||
ICON_THEME_VIEW7,
|
||||
ICON_THEME_VIEW8,
|
||||
ICON_THEME_VIEW9,
|
||||
ICON_THEME_VIEW10,
|
||||
ICON_THEME_ADD_VIEW,
|
||||
ICON_STATS,
|
||||
ICON_STATS_THROTTLE_GRAPH,
|
||||
ICON_STATS_TIMERS,
|
||||
ICON_STATS_ANALOGS,
|
||||
ICON_STATS_DEBUG,
|
||||
ICON_MONITOR,
|
||||
ICON_MONITOR_CHANNELS1,
|
||||
ICON_MONITOR_CHANNELS2,
|
||||
ICON_MONITOR_CHANNELS3,
|
||||
ICON_MONITOR_CHANNELS4,
|
||||
ICON_MONITOR_LOGICAL_SWITCHES,
|
||||
|
||||
// calibration bitmaps
|
||||
extern BitmapBuffer * calibStick;
|
||||
extern BitmapBuffer * calibStickBackground;
|
||||
ICON_CHAN_MONITOR_LOCKED,
|
||||
ICON_CHAN_MONITOR_INVERTED,
|
||||
|
||||
// Channels monitor bitmaps
|
||||
extern BitmapBuffer * chanMonLockedBitmap;
|
||||
extern BitmapBuffer * chanMonInvertedBitmap;
|
||||
ICON_SHUTDOWN_CIRCLE0,
|
||||
ICON_SHUTDOWN_CIRCLE1,
|
||||
ICON_SHUTDOWN_CIRCLE2,
|
||||
ICON_SHUTDOWN_CIRCLE3,
|
||||
ICON_SHUTDOWN,
|
||||
|
||||
void loadBuiltinBitmaps();
|
||||
const uint8_t* getBuiltinIcon(MenuIcons id);
|
||||
ICON_TOPLEFT_BG,
|
||||
ICON_CURRENTMENU_BG,
|
||||
ICON_CURRENTMENU_SHADOW,
|
||||
ICON_CURRENTMENU_DOT,
|
||||
|
||||
PACK(struct _bitmap_mask {
|
||||
uint16_t w;
|
||||
uint16_t h;
|
||||
uint8_t mask[0];
|
||||
});
|
||||
ICON_DOT,
|
||||
|
||||
#define MASK_WIDTH(m) (((_bitmap_mask*)m)->w)
|
||||
#define MASK_HEIGHT(m) (((_bitmap_mask*)m)->h)
|
||||
#define MASK_DATA(m) (((_bitmap_mask*)m)->mask)
|
||||
ICON_TOPMENU_USB,
|
||||
ICON_TOPMENU_VOLUME_0,
|
||||
ICON_TOPMENU_VOLUME_1,
|
||||
ICON_TOPMENU_VOLUME_2,
|
||||
ICON_TOPMENU_VOLUME_3,
|
||||
ICON_TOPMENU_VOLUME_4,
|
||||
ICON_TOPMENU_VOLUME_SCALE,
|
||||
ICON_TOPMENU_TXBATT,
|
||||
#if defined(USB_CHARGER)
|
||||
ICON_TOPMENU_TXBATT_CHARGE,
|
||||
#endif
|
||||
#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
|
||||
ICON_TOPMENU_ANTENNA,
|
||||
#endif
|
||||
#if defined(INTERNAL_GPS)
|
||||
ICON_TOPMENU_GPS,
|
||||
#endif
|
||||
|
||||
ICON_ERROR,
|
||||
ICON_BUSY,
|
||||
|
||||
ICON_USB_PLUGGED,
|
||||
|
||||
ICON_TIMER_BG,
|
||||
ICON_TIMER,
|
||||
|
||||
ICON_TEXTLINE_CURVE,
|
||||
ICON_TEXTLINE_FM,
|
||||
|
||||
ICON_MPLEX_ADD,
|
||||
ICON_MPLEX_MULTIPLY,
|
||||
ICON_MPLEX_REPLACE,
|
||||
|
||||
ICON_ROUND_TITLE_LEFT,
|
||||
ICON_ROUND_TITLE_RIGHT,
|
||||
|
||||
ICON_MODEL_GRID_LARGE,
|
||||
ICON_MODEL_GRID_SMALL,
|
||||
ICON_MODEL_LIST_TWO,
|
||||
ICON_MODEL_LIST_ONE,
|
||||
|
||||
EDGETX_ICONS_COUNT
|
||||
};
|
||||
|
||||
struct MaskBitmap {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
const MaskBitmap* getBuiltinIcon(EdgeTxIcon id);
|
||||
|
||||
struct LZ4Bitmap {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
uint32_t compressedSize;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
class LZ4BitmapBuffer : public BitmapBuffer
|
||||
{
|
||||
public:
|
||||
LZ4BitmapBuffer(uint8_t format, const LZ4Bitmap* compressed_data);
|
||||
~LZ4BitmapBuffer();
|
||||
};
|
||||
|
||||
@@ -21,169 +21,249 @@
|
||||
|
||||
#include "channel_bar.h"
|
||||
|
||||
#include "bitmaps.h"
|
||||
#include "themes/etx_lv_theme.h"
|
||||
|
||||
#define VIEW_CHANNELS_LIMIT_PCT \
|
||||
(g_model.extendedLimits ? LIMIT_EXT_PERCENT : LIMIT_STD_PERCENT)
|
||||
|
||||
#define CHANNELS_LIMIT (g_model.extendedLimits ? LIMIT_EXT_MAX : LIMIT_STD_MAX)
|
||||
|
||||
ChannelBar::ChannelBar(Window* parent, const rect_t& rect, uint8_t channel) :
|
||||
Window(parent, rect), channel(channel)
|
||||
ChannelBar::ChannelBar(Window* parent, const rect_t& rect,
|
||||
std::function<int16_t()> getValueFunc, LcdFlags barColor,
|
||||
LcdFlags txtColor) :
|
||||
Window(parent, rect), getValue(std::move(getValueFunc))
|
||||
{
|
||||
lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_PRIMARY2), 0);
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_COVER, 0);
|
||||
etx_solid_bg(lvobj, COLOR_THEME_PRIMARY2_INDEX);
|
||||
|
||||
bar = lv_obj_create(lvobj);
|
||||
etx_solid_bg(bar, indexFromColor(barColor));
|
||||
lv_obj_set_pos(bar, width() / 2, 0);
|
||||
lv_obj_set_size(bar, 0, height());
|
||||
|
||||
valText = lv_label_create(lvobj);
|
||||
lv_obj_set_pos(valText, width() / 2 + 5, -2);
|
||||
lv_obj_set_size(valText, 45, 12);
|
||||
etx_obj_add_style(valText, styles->text_align_left, LV_PART_MAIN);
|
||||
lv_obj_set_style_translate_x(valText, -54, LV_STATE_USER_1);
|
||||
etx_obj_add_style(valText, styles->text_align_right, LV_STATE_USER_1);
|
||||
etx_font(valText, FONT_XS_INDEX);
|
||||
etx_txt_color(valText, indexFromColor(txtColor));
|
||||
lv_label_set_text(valText, "");
|
||||
|
||||
divPoints[0] = {(lv_coord_t)(width() / 2), 0};
|
||||
divPoints[1] = {(lv_coord_t)(width() / 2), (lv_coord_t)height()};
|
||||
|
||||
lv_obj_t* divLine = lv_line_create(lvobj);
|
||||
etx_obj_add_style(divLine, styles->div_line, LV_PART_MAIN);
|
||||
lv_line_set_points(divLine, divPoints, 2);
|
||||
|
||||
checkEvents();
|
||||
}
|
||||
|
||||
void MixerChannelBar::paint(BitmapBuffer * dc)
|
||||
{
|
||||
int chanVal = calcRESXto100(ex_chans[channel]);
|
||||
const int displayVal = chanVal;
|
||||
|
||||
// this could be handled nicer, but slower, by checking actual range for this
|
||||
// mixer
|
||||
chanVal =
|
||||
limit<int>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
|
||||
|
||||
// Draw mixer bar
|
||||
if (chanVal >= 0) {
|
||||
dc->drawSolidFilledRect(
|
||||
0 + width() / 2, 0,
|
||||
divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2),
|
||||
height(), COLOR_THEME_FOCUS);
|
||||
|
||||
dc->drawNumber(width() / 2 - 10, -2, displayVal,
|
||||
FONT(XS) | COLOR_THEME_SECONDARY1 | RIGHT, 0, nullptr, "%");
|
||||
|
||||
} else if (chanVal < 0) {
|
||||
const unsigned endpoint = width() / 2;
|
||||
const unsigned size =
|
||||
divRoundClosest(-chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2);
|
||||
|
||||
dc->drawSolidFilledRect(endpoint - size, 0, size, height(),
|
||||
COLOR_THEME_FOCUS);
|
||||
|
||||
dc->drawNumber(10 + width() / 2, -2, displayVal,
|
||||
FONT(XS) | COLOR_THEME_SECONDARY1, 0, nullptr, "%");
|
||||
}
|
||||
|
||||
if (drawMiddleBar) {
|
||||
// Draw middle bar
|
||||
dc->drawSolidVerticalLine(width() / 2, 0, height(), COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
|
||||
void MixerChannelBar::checkEvents()
|
||||
void ChannelBar::checkEvents()
|
||||
{
|
||||
Window::checkEvents();
|
||||
int newValue = ex_chans[channel];
|
||||
|
||||
int newValue = getValue();
|
||||
|
||||
if (value != newValue) {
|
||||
value = newValue;
|
||||
invalidate();
|
||||
|
||||
lv_obj_enable_style_refresh(false);
|
||||
|
||||
lv_label_set_text_fmt(valText, "%d%%", value);
|
||||
|
||||
if (newValue < 0)
|
||||
lv_obj_clear_state(valText, LV_STATE_USER_1);
|
||||
else
|
||||
lv_obj_add_state(valText, LV_STATE_USER_1);
|
||||
|
||||
int chanVal =
|
||||
limit<int>(-VIEW_CHANNELS_LIMIT_PCT, value, VIEW_CHANNELS_LIMIT_PCT);
|
||||
|
||||
uint16_t size =
|
||||
divRoundClosest(abs(chanVal) * width(), VIEW_CHANNELS_LIMIT_PCT * 2);
|
||||
|
||||
int16_t x = width() / 2 - ((chanVal > 0) ? 0 : size);
|
||||
|
||||
lv_obj_set_pos(bar, x, 0);
|
||||
lv_obj_set_size(bar, size, height());
|
||||
|
||||
lv_obj_enable_style_refresh(true);
|
||||
lv_obj_refresh_style(lvobj, LV_PART_ANY, LV_STYLE_PROP_ANY);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
MixerChannelBar::MixerChannelBar(Window* parent, const rect_t& rect,
|
||||
uint8_t channel) :
|
||||
ChannelBar(
|
||||
parent, rect, [=] { return calcRESXto100(ex_chans[channel]); },
|
||||
COLOR_THEME_FOCUS)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
OutputChannelBar::OutputChannelBar(Window* parent, const rect_t& rect,
|
||||
uint8_t channel, bool editColor,
|
||||
bool drawLimits) :
|
||||
ChannelBar(
|
||||
parent, rect,
|
||||
[=] { return calcRESXto100(channelOutputs[channel]); },
|
||||
COLOR_THEME_ACTIVE),
|
||||
channel(channel),
|
||||
drawLimits(drawLimits)
|
||||
{
|
||||
if (drawLimits) {
|
||||
leftLim = lv_line_create(lvobj);
|
||||
if (editColor)
|
||||
etx_obj_add_style(leftLim, styles->div_line_edit, LV_PART_MAIN);
|
||||
else
|
||||
etx_obj_add_style(leftLim, styles->div_line, LV_PART_MAIN);
|
||||
rightLim = lv_line_create(lvobj);
|
||||
if (editColor)
|
||||
etx_obj_add_style(rightLim, styles->div_line_edit, LV_PART_MAIN);
|
||||
else
|
||||
etx_obj_add_style(rightLim, styles->div_line, LV_PART_MAIN);
|
||||
drawLimitLines(true);
|
||||
}
|
||||
}
|
||||
|
||||
static inline unsigned posOnBar(coord_t width, int value_to100)
|
||||
{
|
||||
return divRoundClosest(
|
||||
(value_to100 + VIEW_CHANNELS_LIMIT_PCT) * (width - 1),
|
||||
VIEW_CHANNELS_LIMIT_PCT * 2);
|
||||
return divRoundClosest((value_to100 + VIEW_CHANNELS_LIMIT_PCT) * (width - 1),
|
||||
VIEW_CHANNELS_LIMIT_PCT * 2);
|
||||
}
|
||||
|
||||
static void drawOutputBarLimits(BitmapBuffer* dc, coord_t left, coord_t right,
|
||||
LcdFlags color)
|
||||
void OutputChannelBar::drawLimitLines(bool forced)
|
||||
{
|
||||
dc->drawSolidVerticalLine(left, 0, BAR_HEIGHT, color);
|
||||
dc->drawSolidHorizontalLine(left, 0, 3, color);
|
||||
dc->drawSolidHorizontalLine(left, BAR_HEIGHT - 1, 3, color);
|
||||
|
||||
dc->drawSolidVerticalLine(right, 0, BAR_HEIGHT, color);
|
||||
dc->drawSolidHorizontalLine(right - 3, 0, 3, color);
|
||||
dc->drawSolidHorizontalLine(right - 3, BAR_HEIGHT - 1, 3, color);
|
||||
}
|
||||
|
||||
void OutputChannelBar::paint(BitmapBuffer* dc)
|
||||
{
|
||||
int chanVal = calcRESXto100(channelOutputs[channel]);
|
||||
int displayVal = chanVal;
|
||||
|
||||
chanVal =
|
||||
limit<int>(-VIEW_CHANNELS_LIMIT_PCT, chanVal, VIEW_CHANNELS_LIMIT_PCT);
|
||||
|
||||
// Draw output bar
|
||||
if (chanVal >= 0) {
|
||||
dc->drawSolidFilledRect(
|
||||
width() / 2, 0,
|
||||
divRoundClosest(chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2),
|
||||
height(), COLOR_THEME_ACTIVE);
|
||||
|
||||
dc->drawNumber(width() / 2 - 10, -2, displayVal,
|
||||
FONT(XS) | COLOR_THEME_SECONDARY1 | RIGHT, 0, nullptr, "%");
|
||||
|
||||
} else if (chanVal < 0) {
|
||||
unsigned endpoint = width() / 2;
|
||||
unsigned size =
|
||||
divRoundClosest(-chanVal * width(), VIEW_CHANNELS_LIMIT_PCT * 2);
|
||||
|
||||
dc->drawSolidFilledRect(endpoint - size, 0, size, height(),
|
||||
COLOR_THEME_ACTIVE);
|
||||
|
||||
dc->drawNumber(width() / 2 + 10, -2, displayVal,
|
||||
FONT(XS) | COLOR_THEME_SECONDARY1, 0, nullptr, "%");
|
||||
}
|
||||
|
||||
// Draw middle bar
|
||||
dc->drawSolidVerticalLine(width() / 2, 0, height(), COLOR_THEME_SECONDARY1);
|
||||
|
||||
if (drawLimits) {
|
||||
// Draw output limits bars
|
||||
int limit = CHANNELS_LIMIT;
|
||||
bool changed = forced;
|
||||
LimitData* ld = limitAddress(channel);
|
||||
int32_t ldMax;
|
||||
int32_t ldMin;
|
||||
int32_t ldMax;
|
||||
|
||||
if (GV_IS_GV_VALUE(ld->min, -limit, 0)) {
|
||||
ldMin = limMin;
|
||||
if (GV_IS_GV_VALUE(ld->min, -CHANNELS_LIMIT, 0)) {
|
||||
ldMin =
|
||||
GET_GVAR_PREC1(ld->min, -CHANNELS_LIMIT, 0, mixerCurrentFlightMode) +
|
||||
LIMIT_STD_MAX;
|
||||
} else {
|
||||
ldMin = ld->min;
|
||||
}
|
||||
if (limMin != ldMin) {
|
||||
changed = true;
|
||||
limMin = ldMin;
|
||||
}
|
||||
|
||||
if (GV_IS_GV_VALUE(ld->max, 0, limit)) {
|
||||
ldMax = limMax;
|
||||
if (GV_IS_GV_VALUE(ld->max, 0, CHANNELS_LIMIT)) {
|
||||
ldMax =
|
||||
GET_GVAR_PREC1(ld->max, 0, CHANNELS_LIMIT, mixerCurrentFlightMode) -
|
||||
LIMIT_STD_MAX;
|
||||
} else {
|
||||
ldMax = ld->max;
|
||||
}
|
||||
if (limMax != ldMax) {
|
||||
changed = true;
|
||||
limMax = ldMax;
|
||||
}
|
||||
|
||||
if (ld && ld->revert) {
|
||||
drawOutputBarLimits(dc, posOnBar(width(), -100 - ldMax / 10),
|
||||
posOnBar(width(), 100 - ldMin / 10),
|
||||
outputBarLimitsColor);
|
||||
} else if (ld) {
|
||||
drawOutputBarLimits(dc, posOnBar(width(), -100 + ldMin / 10),
|
||||
posOnBar(width(), 100 + ldMax / 10),
|
||||
outputBarLimitsColor);
|
||||
if (changed) {
|
||||
lv_coord_t left, right;
|
||||
lv_coord_t h = height() - 1;
|
||||
|
||||
if (ld->revert) {
|
||||
left = posOnBar(width(), -100 - ldMax / 10);
|
||||
right = posOnBar(width(), 100 - ldMin / 10);
|
||||
} else {
|
||||
left = posOnBar(width(), -100 + ldMin / 10);
|
||||
right = posOnBar(width(), 100 + ldMax / 10);
|
||||
}
|
||||
|
||||
limPoints[0] = {(lv_coord_t)(left + 3), 0};
|
||||
limPoints[1] = {(lv_coord_t)(left), 0};
|
||||
limPoints[2] = {(lv_coord_t)(left), h};
|
||||
limPoints[3] = {(lv_coord_t)(left + 3), h};
|
||||
limPoints[4] = {(lv_coord_t)(right - 2), 0};
|
||||
limPoints[5] = {(lv_coord_t)(right), 0};
|
||||
limPoints[6] = {(lv_coord_t)(right), h};
|
||||
limPoints[7] = {(lv_coord_t)(right - 2), h};
|
||||
// Workaround for bugs in LVGL line drawing
|
||||
limPoints[8] = {(lv_coord_t)(right + 1), h};
|
||||
|
||||
lv_line_set_points(leftLim, &limPoints[0], 4);
|
||||
lv_line_set_points(rightLim, &limPoints[4], 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OutputChannelBar::checkEvents()
|
||||
{
|
||||
Window::checkEvents();
|
||||
int newValue = channelOutputs[channel];
|
||||
if (value != newValue) {
|
||||
value = newValue;
|
||||
invalidate();
|
||||
}
|
||||
int limit = CHANNELS_LIMIT;
|
||||
LimitData* lim = limitAddress(channel);
|
||||
ChannelBar::checkEvents();
|
||||
drawLimitLines(false);
|
||||
}
|
||||
|
||||
if (GV_IS_GV_VALUE(lim->min, -limit, 0)) {
|
||||
int ldMin = GET_GVAR_PREC1(lim->min, -limit, 0, mixerCurrentFlightMode) +
|
||||
LIMIT_STD_MAX;
|
||||
if (limMin != ldMin) invalidate();
|
||||
limMin = ldMin;
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
ComboChannelBar::ComboChannelBar(Window* parent, const rect_t& rect,
|
||||
uint8_t _channel, bool isInHeader) :
|
||||
Window(parent, rect), channel(_channel)
|
||||
{
|
||||
LcdFlags textColor =
|
||||
isInHeader ? COLOR_THEME_PRIMARY2 : COLOR_THEME_SECONDARY1;
|
||||
|
||||
outputChannelBar = new OutputChannelBar(
|
||||
this, {LMARGIN, BAR_HEIGHT + TMARGIN, width() - LMARGIN, BAR_HEIGHT},
|
||||
channel, isInHeader);
|
||||
|
||||
new MixerChannelBar(
|
||||
this,
|
||||
{LMARGIN, (2 * BAR_HEIGHT) + TMARGIN + 1, width() - LMARGIN, BAR_HEIGHT},
|
||||
channel);
|
||||
|
||||
// Channel number
|
||||
char chanString[] = TR_CH "32 ";
|
||||
strAppendSigned(&chanString[2], channel + 1, 2);
|
||||
new StaticText(this, {LMARGIN, 0, LV_SIZE_CONTENT, 12}, chanString,
|
||||
textColor | FONT(XS) | LEFT);
|
||||
|
||||
// Channel name
|
||||
if (g_model.limitData[channel].name[0]) {
|
||||
char nm[LEN_CHANNEL_NAME + 1];
|
||||
strAppend(nm, g_model.limitData[channel].name, LEN_CHANNEL_NAME);
|
||||
new StaticText(this, {LMARGIN + 45, 0, LV_SIZE_CONTENT, 12}, nm,
|
||||
textColor | FONT(XS) | LEFT);
|
||||
}
|
||||
if (GV_IS_GV_VALUE(lim->max, 0, limit)) {
|
||||
int ldMax = GET_GVAR_PREC1(lim->max, 0, limit, mixerCurrentFlightMode) -
|
||||
LIMIT_STD_MAX;
|
||||
if (limMax != ldMax) invalidate();
|
||||
limMax = ldMax;
|
||||
|
||||
// Channel value in µS
|
||||
new DynamicNumber<int16_t>(
|
||||
this, {width() - 45, 0, 45, 12},
|
||||
[=] { return PPM_CH_CENTER(channel) + channelOutputs[channel] / 2; },
|
||||
textColor | FONT(XS) | RIGHT, "", STR_US);
|
||||
|
||||
// Override icon
|
||||
#if defined(OVERRIDE_CHANNEL_FUNCTION)
|
||||
overrideIcon = new StaticIcon(
|
||||
this, 0, 5, ICON_CHAN_MONITOR_LOCKED, textColor);
|
||||
overrideIcon->show(safetyCh[channel] != OVERRIDE_CHANNEL_UNDEFINED);
|
||||
#endif
|
||||
|
||||
// Channel reverted icon
|
||||
LimitData* ld = limitAddress(channel);
|
||||
if (ld && ld->revert) {
|
||||
new StaticIcon(this, 0, 25, ICON_CHAN_MONITOR_INVERTED,
|
||||
textColor);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(OVERRIDE_CHANNEL_FUNCTION)
|
||||
void ComboChannelBar::checkEvents()
|
||||
{
|
||||
Window::checkEvents();
|
||||
|
||||
overrideIcon->show(safetyCh[channel] != OVERRIDE_CHANNEL_UNDEFINED);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -22,151 +22,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "opentx.h"
|
||||
#include "libopenui.h"
|
||||
#include "static.h"
|
||||
|
||||
constexpr coord_t ROW_HEIGHT = 42;
|
||||
constexpr coord_t BAR_HEIGHT = 13;
|
||||
constexpr coord_t LEG_COLORBOX = 15;
|
||||
constexpr coord_t LMARGIN = 15;
|
||||
constexpr coord_t TMARGIN = 2;
|
||||
|
||||
class ChannelBar : public Window
|
||||
{
|
||||
public:
|
||||
ChannelBar(Window* parent, const rect_t& rect, uint8_t channel);
|
||||
|
||||
void setChannel(uint8_t ch)
|
||||
{
|
||||
channel = ch;
|
||||
invalidate();
|
||||
}
|
||||
ChannelBar(Window* parent, const rect_t& rect,
|
||||
std::function<int16_t()> getValue, LcdFlags barColor,
|
||||
LcdFlags textColor = COLOR_THEME_SECONDARY1);
|
||||
|
||||
protected:
|
||||
uint8_t channel = 0;
|
||||
int16_t value = -10000;
|
||||
std::function<int16_t()> getValue;
|
||||
lv_obj_t* valText = nullptr;
|
||||
lv_point_t divPoints[2];
|
||||
lv_obj_t* bar = nullptr;
|
||||
|
||||
void checkEvents() override;
|
||||
};
|
||||
|
||||
class MixerChannelBar : public ChannelBar
|
||||
{
|
||||
public:
|
||||
using ChannelBar::ChannelBar;
|
||||
|
||||
void setDrawMiddleBar(bool enable) { drawMiddleBar = enable; }
|
||||
|
||||
void paint(BitmapBuffer* dc) override;
|
||||
void checkEvents() override;
|
||||
|
||||
protected:
|
||||
bool drawMiddleBar = true;
|
||||
int value = 0;
|
||||
MixerChannelBar(Window* parent, const rect_t& rect, uint8_t channel);
|
||||
};
|
||||
|
||||
class OutputChannelBar : public ChannelBar
|
||||
{
|
||||
public:
|
||||
using ChannelBar::ChannelBar;
|
||||
|
||||
void setDrawLimits(bool enable) { drawLimits = enable; }
|
||||
void setOutputBarLimitColor(uint32_t color) { outputBarLimitsColor = color; }
|
||||
|
||||
void paint(BitmapBuffer* dc) override;
|
||||
void checkEvents() override;
|
||||
OutputChannelBar(Window* parent, const rect_t& rect, uint8_t channel,
|
||||
bool editColor = false, bool drawLimits = true);
|
||||
|
||||
protected:
|
||||
int value = 0;
|
||||
uint8_t channel = 0;
|
||||
int limMax = 0;
|
||||
int limMin = 0;
|
||||
bool drawLimits = true;
|
||||
LcdFlags outputBarLimitsColor = COLOR_THEME_SECONDARY1;
|
||||
lv_point_t limPoints[9];
|
||||
lv_obj_t* leftLim = nullptr;
|
||||
lv_obj_t* rightLim = nullptr;
|
||||
|
||||
void drawLimitLines(bool forced);
|
||||
|
||||
void checkEvents() override;
|
||||
};
|
||||
|
||||
class ComboChannelBar : public Window
|
||||
{
|
||||
public:
|
||||
// using ChannelBar::ChannelBar;
|
||||
ComboChannelBar(Window * parent, const rect_t & rect, uint8_t channel):
|
||||
Window(parent, rect), channel(channel)
|
||||
{
|
||||
outputChannelBar = new OutputChannelBar(
|
||||
this, {leftMargin, BAR_HEIGHT + TMARGIN, width() - leftMargin, BAR_HEIGHT},
|
||||
channel);
|
||||
new MixerChannelBar(
|
||||
this,
|
||||
{leftMargin, (2 * BAR_HEIGHT) + TMARGIN + 1, width() - leftMargin, BAR_HEIGHT},
|
||||
channel);
|
||||
}
|
||||
public:
|
||||
// using ChannelBar::ChannelBar;
|
||||
ComboChannelBar(Window* parent, const rect_t& rect, uint8_t channel,
|
||||
bool isInHeader = false);
|
||||
|
||||
void setOutputChannelBarLimitColor(uint32_t color)
|
||||
{
|
||||
if (outputChannelBar != nullptr) {
|
||||
outputChannelBar->setOutputBarLimitColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
void setTextColor(uint32_t color)
|
||||
{
|
||||
textColor = color;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void setLeftMargin(int margin)
|
||||
{
|
||||
leftMargin = margin;
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer * dc) override
|
||||
{
|
||||
char chanString[] = TR_CH"32 ";
|
||||
int usValue = PPM_CH_CENTER(channel) + channelOutputs[channel] / 2;
|
||||
|
||||
// Channel number
|
||||
strAppendSigned(&chanString[2], channel + 1, 2);
|
||||
dc->drawText(leftMargin, 0, chanString, FONT(XS) | textColor | LEFT);
|
||||
|
||||
// Channel name
|
||||
dc->drawSizedText(leftMargin + 45, 0, g_model.limitData[channel].name, sizeof(g_model.limitData[channel].name), FONT(XS) | textColor | LEFT);
|
||||
|
||||
// Channel value in µS
|
||||
dc->drawNumber(width(), 0, usValue, FONT(XS) | textColor | RIGHT, 0, nullptr, STR_US);
|
||||
|
||||
// Override icon
|
||||
protected:
|
||||
uint8_t channel;
|
||||
OutputChannelBar* outputChannelBar = nullptr;
|
||||
#if defined(OVERRIDE_CHANNEL_FUNCTION)
|
||||
if (safetyCh[channel] != OVERRIDE_CHANNEL_UNDEFINED)
|
||||
dc->drawMask(0, 5, chanMonLockedBitmap, textColor);
|
||||
#endif
|
||||
StaticIcon* overrideIcon = nullptr;
|
||||
|
||||
// Channel reverted icon
|
||||
LimitData * ld = limitAddress(channel);
|
||||
if (ld && ld->revert) {
|
||||
dc->drawMask(0, 25, chanMonInvertedBitmap, textColor);
|
||||
}
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
Window::checkEvents();
|
||||
int newValue = channelOutputs[channel];
|
||||
if (value != newValue) {
|
||||
value = newValue;
|
||||
invalidate();
|
||||
}
|
||||
#if defined(OVERRIDE_CHANNEL_FUNCTION)
|
||||
int newSafetyChValue = safetyCh[channel];
|
||||
if (safetyChValue != newSafetyChValue)
|
||||
{
|
||||
safetyChValue = newSafetyChValue;
|
||||
invalidate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t channel;
|
||||
OutputChannelBar *outputChannelBar = nullptr;
|
||||
int value = 0;
|
||||
int leftMargin = LMARGIN;
|
||||
uint32_t textColor = COLOR_THEME_SECONDARY1;
|
||||
#if defined(OVERRIDE_CHANNEL_FUNCTION)
|
||||
int safetyChValue = OVERRIDE_CHANNEL_UNDEFINED;
|
||||
void checkEvents() override;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -20,55 +20,55 @@
|
||||
*/
|
||||
|
||||
#include "channel_range.h"
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
inline int16_t ppmFrameLen(int8_t chCount) {
|
||||
#define PPM_PULSE_LEN_MAX (4 * PPM_STEP_SIZE) // let's assume roughly 2ms max pulse length
|
||||
|
||||
if(chCount > 0)
|
||||
return((PPM_PULSE_LEN_MAX * chCount) + PPM_DEF_PERIOD); // for more than 8 channels update frame length
|
||||
else
|
||||
return(PPM_DEF_PERIOD); // else leave frame Length at default (22.5ms)
|
||||
}
|
||||
|
||||
void cb_value_changed(lv_event_t* e) {
|
||||
ChannelRange* chRangeEditObject = (ChannelRange*)lv_event_get_user_data(e);
|
||||
if(!chRangeEditObject)
|
||||
return;
|
||||
|
||||
NumberEdit* ppmFrameLenEditObject = chRangeEditObject->getPpmFrameLenEditObject();
|
||||
if(!ppmFrameLenEditObject)
|
||||
return;
|
||||
|
||||
ppmFrameLenEditObject->setValue(ppmFrameLen(chRangeEditObject->getChannelsCount()));
|
||||
}
|
||||
|
||||
ChannelRange::ChannelRange(Window* parent) :
|
||||
FormWindow(parent, rect_t{})
|
||||
inline int16_t ppmFrameLen(int8_t chCount)
|
||||
{
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_width(lvobj, LV_SIZE_CONTENT);
|
||||
#define PPM_PULSE_LEN_MAX \
|
||||
(4 * PPM_STEP_SIZE) // let's assume roughly 2ms max pulse length
|
||||
|
||||
if (chCount > 0)
|
||||
return ((PPM_PULSE_LEN_MAX * chCount) +
|
||||
PPM_DEF_PERIOD); // for more than 8 channels update frame length
|
||||
else
|
||||
return (PPM_DEF_PERIOD); // else leave frame Length at default (22.5ms)
|
||||
}
|
||||
|
||||
void cb_value_changed(lv_event_t* e)
|
||||
{
|
||||
ChannelRange* chRangeEditObject = (ChannelRange*)lv_event_get_user_data(e);
|
||||
if (!chRangeEditObject) return;
|
||||
|
||||
NumberEdit* ppmFrameLenEditObject =
|
||||
chRangeEditObject->getPpmFrameLenEditObject();
|
||||
if (!ppmFrameLenEditObject) return;
|
||||
|
||||
ppmFrameLenEditObject->setValue(
|
||||
ppmFrameLen(chRangeEditObject->getChannelsCount()));
|
||||
}
|
||||
|
||||
ChannelRange::ChannelRange(Window* parent) : Window(parent, rect_t{})
|
||||
{
|
||||
padAll(PAD_TINY);
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW, PAD_SMALL, LV_SIZE_CONTENT);
|
||||
}
|
||||
|
||||
void ChannelRange::build()
|
||||
{
|
||||
chStart = new NumberEdit(this, rect_t{}, 1, 1, GET_DEFAULT(1 + getChannelsStart()));
|
||||
chStart = new NumberEdit(this, rect_t{0, 0, 80, 0}, 1, 1,
|
||||
GET_DEFAULT(1 + getChannelsStart()));
|
||||
chStart->setSetValueHandler([=](int newValue) { setStart(newValue); });
|
||||
chStart->setPrefix(STR_CH);
|
||||
#if LCD_H > LCD_W
|
||||
chStart->setWidth(LCD_W/3-10);
|
||||
#endif
|
||||
|
||||
chEnd = new NumberEdit(this, rect_t{}, 8, 8,
|
||||
GET_DEFAULT(getChannelsStart() + 8 + getChannelsCount()));
|
||||
chEnd =
|
||||
new NumberEdit(this, rect_t{0, 0, 80, 0}, 8, 8,
|
||||
GET_DEFAULT(getChannelsStart() + 8 + getChannelsCount()));
|
||||
|
||||
chEnd->setPrefix(STR_CH);
|
||||
chEnd->setSetValueHandler([=](int newValue) { setEnd(newValue); });
|
||||
#if LCD_H > LCD_W
|
||||
chEnd->setWidth(LCD_W/3-10);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ChannelRange::setStart(uint8_t newValue)
|
||||
@@ -110,11 +110,13 @@ void ChannelRange::update()
|
||||
updateEnd();
|
||||
}
|
||||
|
||||
NumberEdit* ChannelRange::getPpmFrameLenEditObject() {
|
||||
NumberEdit* ChannelRange::getPpmFrameLenEditObject()
|
||||
{
|
||||
return this->ppmFrameLenEditObject;
|
||||
}
|
||||
|
||||
void ChannelRange::setPpmFrameLenEditObject(NumberEdit* ppmFrameLenEditObject) {
|
||||
void ChannelRange::setPpmFrameLenEditObject(NumberEdit* ppmFrameLenEditObject)
|
||||
{
|
||||
this->ppmFrameLenEditObject = ppmFrameLenEditObject;
|
||||
}
|
||||
|
||||
@@ -125,7 +127,8 @@ ModuleChannelRange::ModuleChannelRange(Window* parent, uint8_t moduleIdx) :
|
||||
update();
|
||||
|
||||
// add callback to be notified when channel count changes
|
||||
lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed, LV_EVENT_VALUE_CHANGED, (void *)this);
|
||||
lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed,
|
||||
LV_EVENT_VALUE_CHANGED, (void*)this);
|
||||
}
|
||||
|
||||
void ModuleChannelRange::update()
|
||||
@@ -136,8 +139,7 @@ void ModuleChannelRange::update()
|
||||
auto max_mod_ch = maxModuleChannels(moduleIdx);
|
||||
chEnd->enable(min_mod_ch < max_mod_ch);
|
||||
|
||||
if (chEnd->getValue() > chEnd->getMax())
|
||||
chEnd->setValue(chEnd->getMax());
|
||||
if (chEnd->getValue() > chEnd->getMax()) chEnd->setValue(chEnd->getMax());
|
||||
|
||||
if (!isModulePXX2(moduleIdx)) {
|
||||
chEnd->setAvailableHandler(nullptr);
|
||||
@@ -165,7 +167,7 @@ void ModuleChannelRange::setChannelsStart(uint8_t val)
|
||||
int8_t ModuleChannelRange::getChannelsCount()
|
||||
{
|
||||
ModuleData* md = &g_model.moduleData[moduleIdx];
|
||||
return md->channelsCount;
|
||||
return md->channelsCount;
|
||||
}
|
||||
|
||||
void ModuleChannelRange::setChannelsCount(int8_t val)
|
||||
@@ -189,14 +191,14 @@ uint8_t ModuleChannelRange::getChannelsMax()
|
||||
return maxModuleChannels(moduleIdx);
|
||||
}
|
||||
|
||||
TrainerChannelRange::TrainerChannelRange(Window* parent) :
|
||||
ChannelRange(parent)
|
||||
TrainerChannelRange::TrainerChannelRange(Window* parent) : ChannelRange(parent)
|
||||
{
|
||||
build();
|
||||
update();
|
||||
|
||||
// add callback to be notified when channel count changes
|
||||
lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed, LV_EVENT_VALUE_CHANGED, (void *)this);
|
||||
lv_obj_add_event_cb(chEnd->getLvObj(), cb_value_changed,
|
||||
LV_EVENT_VALUE_CHANGED, (void*)this);
|
||||
}
|
||||
|
||||
uint8_t TrainerChannelRange::getChannelsStart()
|
||||
@@ -224,12 +226,6 @@ uint8_t TrainerChannelRange::getChannelsUsed()
|
||||
return 8 + getChannelsCount();
|
||||
}
|
||||
|
||||
uint8_t TrainerChannelRange::getChannelsMin()
|
||||
{
|
||||
return MIN_TRAINER_CHANNELS;
|
||||
}
|
||||
uint8_t TrainerChannelRange::getChannelsMin() { return MIN_TRAINER_CHANNELS; }
|
||||
|
||||
uint8_t TrainerChannelRange::getChannelsMax()
|
||||
{
|
||||
return MAX_TRAINER_CHANNELS;
|
||||
}
|
||||
uint8_t TrainerChannelRange::getChannelsMax() { return MAX_TRAINER_CHANNELS; }
|
||||
|
||||
@@ -21,10 +21,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
#include "numberedit.h"
|
||||
#include "window.h"
|
||||
|
||||
class ChannelRange : public FormWindow
|
||||
class NumberEdit;
|
||||
|
||||
class ChannelRange : public Window
|
||||
{
|
||||
public:
|
||||
ChannelRange(Window* parent);
|
||||
@@ -46,7 +47,7 @@ class ChannelRange : public FormWindow
|
||||
NumberEdit* ppmFrameLenEditObject = nullptr;
|
||||
|
||||
void build();
|
||||
|
||||
|
||||
virtual uint8_t getChannelsStart() = 0;
|
||||
virtual void setChannelsStart(uint8_t val) = 0;
|
||||
|
||||
|
||||
@@ -19,163 +19,254 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include "color_editor.h"
|
||||
#include "font.h"
|
||||
|
||||
#include "button.h"
|
||||
#include "themes/etx_lv_theme.h"
|
||||
|
||||
constexpr int BAR_MARGIN = 5;
|
||||
|
||||
constexpr int BAR_TOP_MARGIN = 5;
|
||||
constexpr int BAR_HEIGHT_OFFSET = BAR_TOP_MARGIN + 25;
|
||||
|
||||
static const char * const RGBChars[MAX_BARS] = { "R", "G", "B" };
|
||||
static const char * const HSVChars[MAX_BARS] = { "H", "S", "V" };
|
||||
static const char* const RGBChars[MAX_BARS] = {"R", "G", "B"};
|
||||
static const char* const HSVChars[MAX_BARS] = {"H", "S", "V"};
|
||||
|
||||
void ColorBar::pressing(lv_event_t* e)
|
||||
typedef std::function<uint32_t(int pos)> getRGBFromPos;
|
||||
|
||||
class ColorBar : public Window
|
||||
{
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
lv_indev_t* click_source = (lv_indev_t*)lv_event_get_param(e);
|
||||
if (!click_source ||
|
||||
(lv_indev_get_type(click_source) != LV_INDEV_TYPE_POINTER))
|
||||
return;
|
||||
public:
|
||||
ColorBar(Window* parent, const rect_t& r, uint32_t value = 0,
|
||||
uint32_t maxValue = 0, bool invert = false) :
|
||||
Window(parent, r)
|
||||
{
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL);
|
||||
|
||||
lv_area_t obj_coords;
|
||||
lv_obj_get_coords(target, &obj_coords);
|
||||
lv_group_add_obj((lv_group_t*)lv_group_get_default(), lvobj);
|
||||
lv_obj_add_event_cb(lvobj, ColorBar::pressing, LV_EVENT_PRESSING, nullptr);
|
||||
lv_obj_add_event_cb(lvobj, ColorBar::on_key, LV_EVENT_KEY, nullptr);
|
||||
lv_obj_add_event_cb(lvobj, ColorBar::draw_end, LV_EVENT_DRAW_PART_END,
|
||||
nullptr);
|
||||
|
||||
lv_point_t point_act;
|
||||
lv_indev_get_point(click_source, &point_act);
|
||||
|
||||
lv_point_t rel_pos;
|
||||
rel_pos.x = point_act.x - obj_coords.x1;
|
||||
rel_pos.y = point_act.y - obj_coords.y1;
|
||||
|
||||
TRACE("PRESSING [%d,%d]", rel_pos.x, rel_pos.y);
|
||||
|
||||
ColorBar* bar = (ColorBar*)lv_obj_get_user_data(target);
|
||||
if (!bar) return;
|
||||
|
||||
bar->value = bar->screenToValue(rel_pos.y);
|
||||
lv_event_send(target->parent, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
void ColorBar::on_key(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t* obj = lv_event_get_target(e);
|
||||
ColorBar* bar = (ColorBar*)lv_obj_get_user_data(obj);
|
||||
if (!bar) return;
|
||||
|
||||
uint32_t key = *(uint32_t*)lv_event_get_param(e);
|
||||
if (key == LV_KEY_LEFT) {
|
||||
if (bar->value > 0) {
|
||||
uint32_t accel = rotaryEncoderGetAccel();
|
||||
bar->value--;
|
||||
if (accel > 0) {
|
||||
if (accel > bar->value) bar->value = 0;
|
||||
else bar->value -= accel;
|
||||
}
|
||||
lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
} else if (key == LV_KEY_RIGHT) {
|
||||
if (bar->value < bar->maxValue) {
|
||||
uint32_t accel = rotaryEncoderGetAccel();
|
||||
bar->value++;
|
||||
if (accel > 0) {
|
||||
if (accel < bar->maxValue - bar->value) bar->value += accel;
|
||||
else bar->value = bar->maxValue;
|
||||
}
|
||||
lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ColorBar::draw_end(lv_event_t* e)
|
||||
{
|
||||
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
|
||||
if (dsc->type != LV_OBJ_DRAW_PART_RECTANGLE) return;
|
||||
|
||||
lv_obj_t* obj = lv_event_get_target(e);
|
||||
ColorBar* bar = (ColorBar*)lv_obj_get_user_data(obj);
|
||||
if (!bar) return;
|
||||
|
||||
lv_draw_line_dsc_t line_dsc;
|
||||
lv_draw_line_dsc_init(&line_dsc);
|
||||
|
||||
line_dsc.width = 1;
|
||||
line_dsc.opa = LV_OPA_100;
|
||||
|
||||
auto area = dsc->draw_area;
|
||||
lv_point_t p1, p2;
|
||||
p1.x = area->x1;
|
||||
p2.x = area->x2 + 1;
|
||||
|
||||
// draw background gradient
|
||||
for (auto y = area->y1; y <= area->y2; y++) {
|
||||
p1.y = y;
|
||||
p2.y = y;
|
||||
auto c = bar->getRGB(bar->screenToValue(y - area->y1));
|
||||
line_dsc.color = lv_color_make(GET_RED(c), GET_GREEN(c), GET_BLUE(c));
|
||||
lv_draw_line(dsc->draw_ctx, &line_dsc, &p1, &p2);
|
||||
etx_std_style(lvobj, LV_PART_MAIN, PAD_ZERO);
|
||||
}
|
||||
|
||||
// draw cursor
|
||||
lv_area_t cursor_area;
|
||||
cursor_area.x1 = area->x1 + (lv_area_get_width(area) / 2) - 5;
|
||||
cursor_area.x2 = cursor_area.x1 + 10 - 1;
|
||||
int valueToScreen(int val)
|
||||
{
|
||||
auto h = height() - 4; // exclude border
|
||||
|
||||
auto pos = bar->valueToScreen(bar->value);
|
||||
cursor_area.y1 = area->y1 + pos - 5;
|
||||
cursor_area.y2 = cursor_area.y1 + 10 - 1;
|
||||
int scaledValue = (val * h + maxValue / 2) / maxValue;
|
||||
if (invert) scaledValue = h - scaledValue;
|
||||
return scaledValue;
|
||||
}
|
||||
|
||||
lv_draw_rect_dsc_t cursor_dsc;
|
||||
lv_draw_rect_dsc_init(&cursor_dsc);
|
||||
uint32_t screenToValue(int pos)
|
||||
{
|
||||
auto h = height() - 4; // exclude border
|
||||
|
||||
cursor_dsc.radius = LV_RADIUS_CIRCLE;
|
||||
cursor_dsc.bg_opa = LV_OPA_100;
|
||||
cursor_dsc.bg_color = makeLvColor(COLOR_THEME_PRIMARY2);
|
||||
cursor_dsc.border_opa = LV_OPA_100;
|
||||
cursor_dsc.border_color = makeLvColor(COLOR_THEME_PRIMARY1);
|
||||
cursor_dsc.border_width = 1;
|
||||
// range check
|
||||
pos = min<int>(pos, h);
|
||||
pos = max<int>(pos, 0);
|
||||
|
||||
lv_draw_rect(dsc->draw_ctx, &cursor_dsc, &cursor_area);
|
||||
}
|
||||
|
||||
ColorBar::ColorBar(Window* parent, const rect_t& r, uint32_t value,
|
||||
uint32_t maxValue, bool invert) :
|
||||
FormField(parent, r)
|
||||
uint32_t scaledValue = ((pos * maxValue + h / 2) / h);
|
||||
if (invert) scaledValue = maxValue - scaledValue;
|
||||
return scaledValue;
|
||||
}
|
||||
|
||||
static void pressing(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
lv_indev_t* click_source = (lv_indev_t*)lv_event_get_param(e);
|
||||
if (!click_source ||
|
||||
(lv_indev_get_type(click_source) != LV_INDEV_TYPE_POINTER))
|
||||
return;
|
||||
|
||||
ColorBar* bar = (ColorBar*)lv_obj_get_user_data(target);
|
||||
if (!bar) return;
|
||||
|
||||
lv_area_t obj_coords;
|
||||
lv_obj_get_coords(target, &obj_coords);
|
||||
|
||||
lv_point_t point_act;
|
||||
lv_indev_get_point(click_source, &point_act);
|
||||
|
||||
lv_point_t rel_pos;
|
||||
rel_pos.x = point_act.x - obj_coords.x1;
|
||||
rel_pos.y = point_act.y - obj_coords.y1;
|
||||
|
||||
TRACE("PRESSING [%d,%d]", rel_pos.x, rel_pos.y);
|
||||
|
||||
bar->value = bar->screenToValue(rel_pos.y);
|
||||
lv_event_send(target->parent, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
|
||||
static void on_key(lv_event_t* e)
|
||||
{
|
||||
lv_obj_t* obj = lv_event_get_target(e);
|
||||
ColorBar* bar = (ColorBar*)lv_obj_get_user_data(obj);
|
||||
if (!bar) return;
|
||||
|
||||
uint32_t key = *(uint32_t*)lv_event_get_param(e);
|
||||
if (key == LV_KEY_LEFT) {
|
||||
if (bar->value > 0) {
|
||||
uint32_t accel = rotaryEncoderGetAccel();
|
||||
bar->value--;
|
||||
if (accel > 0) {
|
||||
if (accel > bar->value)
|
||||
bar->value = 0;
|
||||
else
|
||||
bar->value -= accel;
|
||||
}
|
||||
lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
} else if (key == LV_KEY_RIGHT) {
|
||||
if (bar->value < bar->maxValue) {
|
||||
uint32_t accel = rotaryEncoderGetAccel();
|
||||
bar->value++;
|
||||
if (accel > 0) {
|
||||
if (accel < bar->maxValue - bar->value)
|
||||
bar->value += accel;
|
||||
else
|
||||
bar->value = bar->maxValue;
|
||||
}
|
||||
lv_event_send(obj->parent, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_end(lv_event_t* e)
|
||||
{
|
||||
lv_obj_draw_part_dsc_t* dsc = lv_event_get_draw_part_dsc(e);
|
||||
if (dsc->type != LV_OBJ_DRAW_PART_RECTANGLE) return;
|
||||
|
||||
lv_obj_t* obj = lv_event_get_target(e);
|
||||
ColorBar* bar = (ColorBar*)lv_obj_get_user_data(obj);
|
||||
if (!bar) return;
|
||||
|
||||
lv_draw_line_dsc_t line_dsc;
|
||||
lv_draw_line_dsc_init(&line_dsc);
|
||||
|
||||
line_dsc.width = 1;
|
||||
line_dsc.opa = LV_OPA_100;
|
||||
|
||||
auto area = dsc->draw_area;
|
||||
lv_point_t p1, p2;
|
||||
int h = area->y2 - area->y1 - 4;
|
||||
|
||||
// draw background gradient
|
||||
for (int i = 0; i <= h; i += 1) {
|
||||
p1.y = p2.y = i + area->y1 + 2;
|
||||
if (i == 0 || i == h) {
|
||||
p1.x = area->x1 + 3;
|
||||
p2.x = area->x2 - 2;
|
||||
} else {
|
||||
p1.x = area->x1 + 2;
|
||||
p2.x = area->x2 - 1;
|
||||
}
|
||||
auto c = bar->getRGB(bar->screenToValue(i));
|
||||
line_dsc.color = lv_color_make(GET_RED(c), GET_GREEN(c), GET_BLUE(c));
|
||||
lv_draw_line(dsc->draw_ctx, &line_dsc, &p1, &p2);
|
||||
}
|
||||
|
||||
// draw cursor
|
||||
lv_area_t cursor_area;
|
||||
cursor_area.x1 = area->x1 + (lv_area_get_width(area) / 2) - 5;
|
||||
cursor_area.x2 = cursor_area.x1 + 10 - 1;
|
||||
|
||||
auto pos = bar->valueToScreen(bar->value);
|
||||
cursor_area.y1 = area->y1 + pos - 3;
|
||||
cursor_area.y2 = cursor_area.y1 + 10 - 1;
|
||||
|
||||
lv_draw_rect_dsc_t cursor_dsc;
|
||||
lv_draw_rect_dsc_init(&cursor_dsc);
|
||||
|
||||
cursor_dsc.radius = LV_RADIUS_CIRCLE;
|
||||
cursor_dsc.bg_opa = LV_OPA_100;
|
||||
cursor_dsc.bg_color = makeLvColor(COLOR_THEME_PRIMARY2);
|
||||
cursor_dsc.border_opa = LV_OPA_100;
|
||||
cursor_dsc.border_color = makeLvColor(COLOR_THEME_PRIMARY1);
|
||||
cursor_dsc.border_width = 1;
|
||||
|
||||
lv_draw_rect(dsc->draw_ctx, &cursor_dsc, &cursor_area);
|
||||
}
|
||||
|
||||
uint32_t maxValue = 0;
|
||||
uint32_t value = 0;
|
||||
bool invert = false;
|
||||
getRGBFromPos getRGB = nullptr;
|
||||
};
|
||||
|
||||
// ColorTypes()
|
||||
// A ColorType implements an editor for selecting a color. Currently we support
|
||||
// HSV, RGB and SYS (choose from system defined colors)
|
||||
class ColorType
|
||||
{
|
||||
lv_obj_add_flag(lvobj, LV_OBJ_FLAG_ENCODER_ACCEL);
|
||||
|
||||
lv_group_add_obj((lv_group_t*)lv_group_get_default(), lvobj);
|
||||
lv_obj_add_event_cb(lvobj, ColorBar::pressing, LV_EVENT_PRESSING, nullptr);
|
||||
lv_obj_add_event_cb(lvobj, ColorBar::on_key, LV_EVENT_KEY, nullptr);
|
||||
lv_obj_add_event_cb(lvobj, ColorBar::draw_end, LV_EVENT_DRAW_PART_END, nullptr);
|
||||
public:
|
||||
ColorType() {}
|
||||
virtual ~ColorType() {}
|
||||
|
||||
// normal
|
||||
lv_obj_set_style_border_width(lvobj, 1, 0);
|
||||
lv_obj_set_style_border_color(lvobj, makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
lv_obj_set_style_border_opa(lvobj, LV_OPA_100, 0);
|
||||
lv_obj_set_style_border_post(lvobj, true, 0);
|
||||
virtual void setText(){};
|
||||
virtual uint32_t getRGB() { return 0; };
|
||||
|
||||
// focused
|
||||
lv_obj_set_style_border_width(lvobj, 2, LV_STATE_FOCUSED);
|
||||
lv_obj_set_style_border_color(lvobj, makeLvColor(COLOR_THEME_FOCUS), LV_STATE_FOCUSED);
|
||||
}
|
||||
protected:
|
||||
};
|
||||
|
||||
int ColorBar::valueToScreen(int val)
|
||||
// Color editor with three bars for selecting color value. Base class for HSV
|
||||
// and RGB color types.
|
||||
class BarColorType : public ColorType
|
||||
{
|
||||
int scaledValue = (((float)val / maxValue) * height());
|
||||
if (invert) scaledValue = height() - scaledValue;
|
||||
return scaledValue;
|
||||
}
|
||||
public:
|
||||
BarColorType(Window* parent);
|
||||
~BarColorType() override;
|
||||
|
||||
uint32_t ColorBar::screenToValue(int pos)
|
||||
void setText() override;
|
||||
|
||||
protected:
|
||||
ColorBar* bars[MAX_BARS];
|
||||
lv_obj_t* barLabels[MAX_BARS];
|
||||
lv_obj_t* barValLabels[MAX_BARS];
|
||||
|
||||
virtual const char* const* getLabelChars() { return nullptr; };
|
||||
|
||||
lv_obj_t* create_bar_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y);
|
||||
lv_obj_t* create_bar_value_label(lv_obj_t* parent, lv_coord_t x,
|
||||
lv_coord_t y);
|
||||
};
|
||||
|
||||
// Color editor for HSV color input
|
||||
class HSVColorType : public BarColorType
|
||||
{
|
||||
// range check
|
||||
pos = min<int>(pos, height());
|
||||
pos = max<int>(pos, 0);
|
||||
public:
|
||||
HSVColorType(Window* parent, uint32_t color);
|
||||
uint32_t getRGB() override;
|
||||
|
||||
uint32_t scaledValue = (((float)pos / height()) * maxValue);
|
||||
if (invert) scaledValue = maxValue - scaledValue;
|
||||
return scaledValue;
|
||||
}
|
||||
protected:
|
||||
const char* const* getLabelChars() override;
|
||||
};
|
||||
|
||||
// Color editor for RGB color input
|
||||
class RGBColorType : public BarColorType
|
||||
{
|
||||
public:
|
||||
RGBColorType(Window* parent, uint32_t color);
|
||||
uint32_t getRGB() override;
|
||||
|
||||
protected:
|
||||
const char* const* getLabelChars() override;
|
||||
};
|
||||
|
||||
// Color editor that shows the system theme colors as buttons
|
||||
class ThemeColorType : public ColorType
|
||||
{
|
||||
public:
|
||||
ThemeColorType(Window* parent, uint32_t color);
|
||||
uint32_t getRGB() override;
|
||||
|
||||
protected:
|
||||
uint32_t m_color;
|
||||
void makeButton(Window* parent, uint16_t color);
|
||||
void makeButtonsRow(Window* parent, uint16_t c1, uint16_t c2, uint16_t c3);
|
||||
};
|
||||
|
||||
BarColorType::BarColorType(Window* parent)
|
||||
{
|
||||
@@ -187,7 +278,7 @@ BarColorType::BarColorType(Window* parent)
|
||||
r.w = spacePerBar - BAR_MARGIN - 5;
|
||||
r.h = parent->height() - BAR_HEIGHT_OFFSET;
|
||||
|
||||
for ( int i=0; i < MAX_BARS; i++){
|
||||
for (int i = 0; i < MAX_BARS; i++) {
|
||||
r.x = leftPos + BAR_MARGIN;
|
||||
|
||||
bars[i] = new ColorBar(parent, r);
|
||||
@@ -205,25 +296,27 @@ BarColorType::BarColorType(Window* parent)
|
||||
|
||||
BarColorType::~BarColorType()
|
||||
{
|
||||
for ( int i=0; i < MAX_BARS; i++) {
|
||||
for (int i = 0; i < MAX_BARS; i++) {
|
||||
bars[i]->deleteLater();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
lv_obj_t* BarColorType::create_bar_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y)
|
||||
lv_obj_t* BarColorType::create_bar_label(lv_obj_t* parent, lv_coord_t x,
|
||||
lv_coord_t y)
|
||||
{
|
||||
lv_obj_t* obj = lv_label_create(parent);
|
||||
lv_obj_set_pos(obj, x, y);
|
||||
lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
lv_obj_set_style_text_font(obj, getFont(FONT(XXS)), 0);
|
||||
etx_txt_color(obj, COLOR_THEME_PRIMARY1_INDEX);
|
||||
etx_font(obj, FONT_XXS_INDEX);
|
||||
return obj;
|
||||
}
|
||||
|
||||
lv_obj_t* BarColorType::create_bar_value_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y)
|
||||
lv_obj_t* BarColorType::create_bar_value_label(lv_obj_t* parent, lv_coord_t x,
|
||||
lv_coord_t y)
|
||||
{
|
||||
lv_obj_t* obj = lv_label_create(parent);
|
||||
lv_obj_set_pos(obj, x, y);
|
||||
lv_obj_set_style_text_color(obj, makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
etx_txt_color(obj, COLOR_THEME_PRIMARY1_INDEX);
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -238,12 +331,12 @@ void BarColorType::setText()
|
||||
}
|
||||
|
||||
HSVColorType::HSVColorType(Window* parent, uint32_t color) :
|
||||
BarColorType(parent)
|
||||
BarColorType(parent)
|
||||
{
|
||||
auto r = GET_RED(color), g = GET_GREEN(color), b = GET_BLUE(color);
|
||||
float values[MAX_BARS];
|
||||
RGBtoHSV(r, g, b, values[0], values[1], values[2]);
|
||||
values[1] *= MAX_SATURATION; // convert the proper base
|
||||
values[1] *= MAX_SATURATION; // convert the proper base
|
||||
values[2] *= MAX_BRIGHTNESS;
|
||||
|
||||
for (auto i = 0; i < MAX_BARS; i++) {
|
||||
@@ -253,19 +346,19 @@ HSVColorType::HSVColorType(Window* parent, uint32_t color) :
|
||||
}
|
||||
|
||||
// hue
|
||||
bars[0]->getRGB = [=] (int pos) {
|
||||
bars[0]->getRGB = [=](int pos) {
|
||||
auto rgb = HSVtoRGB(pos, bars[1]->value, bars[2]->value);
|
||||
return rgb;
|
||||
};
|
||||
|
||||
// saturation
|
||||
bars[1]->getRGB = [=] (int pos) {
|
||||
bars[1]->getRGB = [=](int pos) {
|
||||
auto rgb = HSVtoRGB(bars[0]->value, pos, bars[2]->value);
|
||||
return rgb;
|
||||
};
|
||||
|
||||
// brightness
|
||||
bars[2]->getRGB = [=] (int pos) {
|
||||
bars[2]->getRGB = [=](int pos) {
|
||||
auto rgb = HSVtoRGB(bars[0]->value, bars[1]->value, pos);
|
||||
return rgb;
|
||||
};
|
||||
@@ -276,10 +369,7 @@ uint32_t HSVColorType::getRGB()
|
||||
return HSVtoRGB(bars[0]->value, bars[1]->value, bars[2]->value);
|
||||
}
|
||||
|
||||
const char* const* HSVColorType::getLabelChars()
|
||||
{
|
||||
return HSVChars;
|
||||
}
|
||||
const char* const* HSVColorType::getLabelChars() { return HSVChars; }
|
||||
|
||||
RGBColorType::RGBColorType(Window* parent, uint32_t color) :
|
||||
BarColorType(parent)
|
||||
@@ -306,74 +396,65 @@ uint32_t RGBColorType::getRGB()
|
||||
return RGB(bars[0]->value, bars[1]->value, bars[2]->value);
|
||||
}
|
||||
|
||||
const char* const* RGBColorType::getLabelChars()
|
||||
{
|
||||
return RGBChars;
|
||||
}
|
||||
const char* const* RGBColorType::getLabelChars() { return RGBChars; }
|
||||
|
||||
void ThemeColorType::makeButton(Window* parent, uint32_t color)
|
||||
void ThemeColorType::makeButton(Window* parent, uint16_t color)
|
||||
{
|
||||
auto btn = new TextButton(parent, rect_t{}, " ");
|
||||
etx_bg_color(btn->getLvObj(), (LcdColorIndex)color);
|
||||
btn->setPressHandler([=]() {
|
||||
auto cv = COLOR_VAL(color);
|
||||
auto cv = lcdColorTable[color];
|
||||
m_color = RGB(GET_RED(cv), GET_GREEN(cv), GET_BLUE(cv));
|
||||
lv_event_send(parent->getParent()->getParent()->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
lv_event_send(parent->getParent()->getParent()->getLvObj(),
|
||||
LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
return 0;
|
||||
});
|
||||
btn->padAll(lv_dpx(7));
|
||||
lv_obj_set_style_bg_color(btn->getLvObj(), makeLvColor(color), LV_PART_MAIN);
|
||||
lv_obj_add_style(btn->getLvObj(), &style, 0);
|
||||
}
|
||||
|
||||
void ThemeColorType::makeButtonsRow(Window* parent, uint32_t c1, uint32_t c2, uint32_t c3)
|
||||
void ThemeColorType::makeButtonsRow(Window* parent, uint16_t c1, uint16_t c2,
|
||||
uint16_t c3)
|
||||
{
|
||||
auto hbox = new FormWindow(parent, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
auto hbox = new Window(parent, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM);
|
||||
lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER,
|
||||
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
|
||||
makeButton(hbox, c1);
|
||||
makeButton(hbox, c2);
|
||||
if (c3 != c2)
|
||||
makeButton(hbox, c3);
|
||||
if (c3 != c2) makeButton(hbox, c3);
|
||||
}
|
||||
|
||||
ThemeColorType::ThemeColorType(Window* parent, uint32_t color) :
|
||||
ColorType()
|
||||
ThemeColorType::ThemeColorType(Window* parent, uint32_t color) : ColorType()
|
||||
{
|
||||
m_color = color;
|
||||
|
||||
lv_style_init(&style);
|
||||
lv_style_set_border_opa(&style, LV_OPA_100);
|
||||
lv_style_set_border_width(&style, 2);
|
||||
lv_style_set_border_color(&style, lv_palette_main(LV_PALETTE_GREY));
|
||||
auto vbox = new Window(parent, rect_t{});
|
||||
vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_MEDIUM);
|
||||
|
||||
auto vbox = new FormWindow(parent, rect_t{});
|
||||
vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, lv_dpx(8));
|
||||
|
||||
makeButtonsRow(vbox, COLOR_THEME_PRIMARY1, COLOR_THEME_PRIMARY2, COLOR_THEME_PRIMARY3);
|
||||
makeButtonsRow(vbox, COLOR_THEME_SECONDARY1, COLOR_THEME_SECONDARY2, COLOR_THEME_SECONDARY3);
|
||||
makeButtonsRow(vbox, COLOR_THEME_FOCUS, COLOR_THEME_EDIT, COLOR_THEME_ACTIVE);
|
||||
makeButtonsRow(vbox, COLOR_THEME_WARNING, COLOR_THEME_DISABLED, COLOR_THEME_DISABLED);
|
||||
makeButtonsRow(vbox, COLOR_THEME_PRIMARY1_INDEX, COLOR_THEME_PRIMARY2_INDEX,
|
||||
COLOR_THEME_PRIMARY3_INDEX);
|
||||
makeButtonsRow(vbox, COLOR_THEME_SECONDARY1_INDEX,
|
||||
COLOR_THEME_SECONDARY2_INDEX, COLOR_THEME_SECONDARY3_INDEX);
|
||||
makeButtonsRow(vbox, COLOR_THEME_FOCUS_INDEX, COLOR_THEME_EDIT_INDEX,
|
||||
COLOR_THEME_ACTIVE_INDEX);
|
||||
makeButtonsRow(vbox, COLOR_THEME_WARNING_INDEX, COLOR_THEME_DISABLED_INDEX,
|
||||
COLOR_THEME_DISABLED_INDEX);
|
||||
}
|
||||
|
||||
uint32_t ThemeColorType::getRGB()
|
||||
{
|
||||
return m_color;
|
||||
}
|
||||
uint32_t ThemeColorType::getRGB() { return m_color; }
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
////// ColorEditor Base class
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
ColorEditor::ColorEditor(Window *parent, const rect_t& rect, uint32_t color,
|
||||
std::function<void (uint32_t rgb)> setValue) :
|
||||
FormWindow(parent, rect),
|
||||
_setValue(std::move(setValue)),
|
||||
_color(color)
|
||||
ColorEditor::ColorEditor(Window* parent, const rect_t& rect, uint32_t color,
|
||||
std::function<void(uint32_t rgb)> setValue) :
|
||||
Window(parent, rect), _setValue(std::move(setValue)), _color(color)
|
||||
{
|
||||
_colorType = new HSVColorType(this, color);
|
||||
_colorType->setText();
|
||||
|
||||
lv_obj_add_event_cb(lvobj, ColorEditor::value_changed, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
lv_obj_add_event_cb(lvobj, ColorEditor::value_changed, LV_EVENT_VALUE_CHANGED,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void ColorEditor::setColorEditorType(COLOR_EDITOR_TYPE colorType)
|
||||
@@ -392,6 +473,7 @@ void ColorEditor::setColorEditorType(COLOR_EDITOR_TYPE colorType)
|
||||
_colorType = new ThemeColorType(this, _color);
|
||||
setText();
|
||||
}
|
||||
// Update color bars
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@@ -420,4 +502,3 @@ void ColorEditor::value_changed(lv_event_t* e)
|
||||
ColorEditor* edit = (ColorEditor*)lv_obj_get_user_data(target);
|
||||
if (edit) edit->setRGB();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,110 +19,21 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include "bitmapbuffer.h"
|
||||
#include "libopenui.h"
|
||||
#include "theme_manager.h"
|
||||
#include "listbox.h"
|
||||
|
||||
#include "window.h"
|
||||
|
||||
class ColorType;
|
||||
|
||||
constexpr int MAX_BARS = 3;
|
||||
typedef std::function<uint32_t (int pos)> getRGBFromPos;
|
||||
|
||||
struct ColorBar : public FormField {
|
||||
uint32_t maxValue = 0;
|
||||
uint32_t value = 0;
|
||||
bool invert = false;
|
||||
getRGBFromPos getRGB = nullptr;
|
||||
|
||||
ColorBar(Window* parent, const rect_t& r, uint32_t value = 0,
|
||||
uint32_t maxValue = 0, bool invert = false);
|
||||
|
||||
int valueToScreen(int value);
|
||||
uint32_t screenToValue(int pos);
|
||||
|
||||
static void pressing(lv_event_t* e);
|
||||
static void on_key(lv_event_t* e);
|
||||
static void draw_end(lv_event_t* e);
|
||||
};
|
||||
|
||||
// ColorTypes()
|
||||
// A ColorType implements an editor for selecting a color. Currently we support HSV, RGB and SYS (choose from system defined colors)
|
||||
class ColorType
|
||||
{
|
||||
public:
|
||||
ColorType() {}
|
||||
virtual ~ColorType() {}
|
||||
|
||||
virtual void setText() {};
|
||||
virtual uint32_t getRGB() { return 0; };
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
// Color editor with three bars for selecting color value. Base class for HSV and RGB color types.
|
||||
class BarColorType : public ColorType
|
||||
{
|
||||
public:
|
||||
BarColorType(Window* parent);
|
||||
~BarColorType() override;
|
||||
|
||||
void setText() override;
|
||||
|
||||
protected:
|
||||
ColorBar* bars[MAX_BARS];
|
||||
lv_obj_t* barLabels[MAX_BARS];
|
||||
lv_obj_t* barValLabels[MAX_BARS];
|
||||
|
||||
virtual const char* const* getLabelChars() { return nullptr; };
|
||||
|
||||
lv_obj_t* create_bar_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y);
|
||||
lv_obj_t* create_bar_value_label(lv_obj_t* parent, lv_coord_t x, lv_coord_t y);
|
||||
};
|
||||
|
||||
// Color editor for HSV color input
|
||||
class HSVColorType : public BarColorType {
|
||||
public:
|
||||
HSVColorType(Window* parent, uint32_t color);
|
||||
uint32_t getRGB() override;
|
||||
|
||||
protected:
|
||||
const char* const* getLabelChars() override;
|
||||
};
|
||||
|
||||
// Color editor for RGB color input
|
||||
class RGBColorType : public BarColorType {
|
||||
public:
|
||||
RGBColorType(Window* parent, uint32_t color);
|
||||
uint32_t getRGB() override;
|
||||
|
||||
protected:
|
||||
const char* const* getLabelChars() override;
|
||||
};
|
||||
|
||||
// Color editor that shows the system theme colors as buttons
|
||||
class ThemeColorType : public ColorType {
|
||||
public:
|
||||
ThemeColorType(Window* parent, uint32_t color);
|
||||
uint32_t getRGB() override;
|
||||
|
||||
protected:
|
||||
uint32_t m_color;
|
||||
void makeButton(Window* parent, uint32_t color);
|
||||
void makeButtonsRow(Window* parent, uint32_t c1, uint32_t c2, uint32_t c3);
|
||||
lv_style_t style;
|
||||
};
|
||||
|
||||
enum COLOR_EDITOR_TYPE
|
||||
{
|
||||
enum COLOR_EDITOR_TYPE {
|
||||
RGB_COLOR_EDITOR = 0,
|
||||
HSV_COLOR_EDITOR,
|
||||
THM_COLOR_EDITOR
|
||||
};
|
||||
|
||||
// the ColorEditor() control is a group of other controls
|
||||
class ColorEditor : public FormWindow
|
||||
class ColorEditor : public Window
|
||||
{
|
||||
public:
|
||||
ColorEditor(Window* parent, const rect_t& rect, uint32_t color,
|
||||
|
||||
@@ -18,32 +18,33 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
#include "color_list.h"
|
||||
#include "color_editor.h"
|
||||
#include "color_editor.h"
|
||||
|
||||
ColorList::ColorList(
|
||||
Window *parent, const rect_t &rect, std::vector<ColorEntry> colors,
|
||||
WindowFlags windowFlag, LcdFlags lcdFlags) :
|
||||
ListBase(parent, rect, getColorListNames(colors)),
|
||||
_colorList(colors),
|
||||
_tp(ThemePersistance::instance())
|
||||
#include "color_list.h"
|
||||
|
||||
#include "color_editor.h"
|
||||
#include "themes/etx_lv_theme.h"
|
||||
|
||||
ColorList::ColorList(Window *parent, const rect_t &rect,
|
||||
std::vector<ColorEntry> colors, LcdFlags lcdFlags) :
|
||||
ListBox(parent, rect, getColorListNames(colors)), _colorList(colors)
|
||||
{
|
||||
setSelected(0);
|
||||
}
|
||||
|
||||
std::vector<std::string> ColorList::getColorListNames(std::vector<ColorEntry> colors)
|
||||
std::vector<std::string> ColorList::getColorListNames(
|
||||
std::vector<ColorEntry> colors)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
char **colorNames = ThemePersistance::getColorNames();
|
||||
for (auto color : colors) {
|
||||
names.emplace_back(colorNames[color.colorNumber]);
|
||||
}
|
||||
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
void ColorList::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc)
|
||||
void ColorList::onDrawEnd(uint16_t row, uint16_t col,
|
||||
lv_obj_draw_part_dsc_t *dsc)
|
||||
{
|
||||
lv_draw_rect_dsc_t rect_dsc;
|
||||
lv_draw_rect_dsc_init(&rect_dsc);
|
||||
@@ -65,8 +66,53 @@ void ColorList::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* ds
|
||||
rect_dsc.border_width = lv_dpx(1);
|
||||
|
||||
uint16_t color = _colorList[row].colorValue;
|
||||
rect_dsc.bg_color = lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color));
|
||||
rect_dsc.bg_color =
|
||||
lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color));
|
||||
rect_dsc.bg_opa = LV_OPA_100;
|
||||
|
||||
lv_draw_rect(dsc->draw_ctx, &rect_dsc, &coords);
|
||||
}
|
||||
|
||||
static void color_swatch_constructor(const lv_obj_class_t *class_p,
|
||||
lv_obj_t *obj)
|
||||
{
|
||||
etx_obj_add_style(obj, styles->bg_opacity_cover, LV_PART_MAIN);
|
||||
etx_obj_add_style(obj, styles->border_thin, LV_PART_MAIN);
|
||||
etx_obj_add_style(obj, styles->border_color_black, LV_PART_MAIN);
|
||||
}
|
||||
|
||||
static const lv_obj_class_t color_swatch_class = {
|
||||
.base_class = &lv_obj_class,
|
||||
.constructor_cb = color_swatch_constructor,
|
||||
.destructor_cb = nullptr,
|
||||
.user_data = nullptr,
|
||||
.event_cb = nullptr,
|
||||
.width_def = LV_SIZE_CONTENT,
|
||||
.height_def = LV_SIZE_CONTENT,
|
||||
.editable = LV_OBJ_CLASS_EDITABLE_INHERIT,
|
||||
.group_def = LV_OBJ_CLASS_GROUP_DEF_INHERIT,
|
||||
.instance_size = sizeof(lv_obj_t),
|
||||
};
|
||||
|
||||
static lv_obj_t *color_swatch_create(lv_obj_t *parent)
|
||||
{
|
||||
return etx_create(&color_swatch_class, parent);
|
||||
}
|
||||
|
||||
ColorSwatch::ColorSwatch(Window *window, const rect_t &rect, uint32_t color) :
|
||||
Window(window, rect, color_swatch_create)
|
||||
{
|
||||
setWindowFlag(NO_FOCUS);
|
||||
setColor(color);
|
||||
}
|
||||
|
||||
void ColorSwatch::setColor(uint32_t colorEntry)
|
||||
{
|
||||
lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR2FLAGS(colorEntry)),
|
||||
LV_PART_MAIN);
|
||||
}
|
||||
|
||||
void ColorSwatch::setColor(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
lv_obj_set_style_bg_color(lvobj, lv_color_make(r, g, b), LV_PART_MAIN);
|
||||
}
|
||||
|
||||
@@ -18,21 +18,20 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include "bitmapbuffer.h"
|
||||
#include "libopenui.h"
|
||||
#include "theme_manager.h"
|
||||
|
||||
#include "listbox.h"
|
||||
#include "theme_manager.h"
|
||||
|
||||
// a list of color theme names with their color to the right
|
||||
class ColorList : public ListBase
|
||||
class ColorList : public ListBox
|
||||
{
|
||||
public:
|
||||
ColorList(Window *parent, const rect_t &rect, std::vector<ColorEntry> colors,
|
||||
WindowFlags windowFlags = 0, LcdFlags lcdFlags = 0);
|
||||
ColorList(Window* parent, const rect_t& rect, std::vector<ColorEntry> colors,
|
||||
LcdFlags lcdFlags = 0);
|
||||
|
||||
inline ColorEntry getSelectedColor()
|
||||
{
|
||||
@@ -46,14 +45,22 @@ class ColorList : public ListBase
|
||||
inline void setColorList(std::vector<ColorEntry> colorList)
|
||||
{
|
||||
this->_colorList = colorList;
|
||||
ListBase::setNames(getColorListNames(colorList));
|
||||
invalidate();
|
||||
ListBox::setNames(getColorListNames(colorList));
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<ColorEntry> _colorList;
|
||||
ThemePersistance *_tp;
|
||||
|
||||
void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc);
|
||||
};
|
||||
|
||||
class ColorSwatch : public Window
|
||||
{
|
||||
public:
|
||||
ColorSwatch(Window* window, const rect_t& rect, uint32_t color);
|
||||
|
||||
void setColor(uint32_t colorEntry);
|
||||
void setColor(uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
@@ -20,81 +20,88 @@
|
||||
*/
|
||||
|
||||
#include "color_picker.h"
|
||||
|
||||
#include "color_editor.h"
|
||||
#include "color_list.h"
|
||||
#include "themes/etx_lv_theme.h"
|
||||
|
||||
// based on LVGL default switch size
|
||||
constexpr lv_coord_t COLOR_PAD_WIDTH = (4 * LV_DPI_DEF) / 10;
|
||||
constexpr lv_coord_t COLOR_PAD_HEIGHT = (4 * LV_DPI_DEF) / 17;
|
||||
constexpr lv_coord_t COLOR_PAD_HEIGHT = 32;
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
// Landscape
|
||||
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
#define COLOR_EDIT_WIDTH LCD_W * 0.8
|
||||
|
||||
#else
|
||||
// Portrait
|
||||
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT,
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
#define COLOR_EDIT_WIDTH LCD_W * 0.7
|
||||
|
||||
#endif
|
||||
|
||||
class ColorEditorPopup : public Dialog
|
||||
class ColorEditorPopup : public BaseDialog
|
||||
{
|
||||
lv_obj_t* colorPad = nullptr;
|
||||
lv_obj_t* hexStr = nullptr;
|
||||
ColorSwatch* colorPad = nullptr;
|
||||
StaticText* hexStr = nullptr;
|
||||
uint32_t m_color;
|
||||
|
||||
void updateColor(uint32_t c)
|
||||
{
|
||||
m_color = c;
|
||||
auto r = GET_RED(c), g = GET_GREEN(c), b = GET_BLUE(c);
|
||||
uint8_t r = GET_RED(c), g = GET_GREEN(c), b = GET_BLUE(c);
|
||||
|
||||
auto lvcolor = lv_color_make(r, g, b);
|
||||
lv_obj_set_style_bg_color(colorPad, lvcolor, LV_PART_MAIN);
|
||||
lv_label_set_text_fmt(hexStr, "%02X%02X%02X",
|
||||
(uint16_t)r, (uint16_t)g, (uint16_t)b);
|
||||
colorPad->setColor(r, g, b);
|
||||
|
||||
char s[10];
|
||||
sprintf(s, "%02X%02X%02X", r, g, b);
|
||||
hexStr->setText(s);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
ColorEditorPopup(Window* parent, uint32_t color,
|
||||
std::function<void(uint32_t)> _setValue) :
|
||||
Dialog(parent, STR_COLOR_PICKER, rect_t{})
|
||||
BaseDialog(parent, STR_COLOR_PICKER, false, COLOR_EDIT_WIDTH,
|
||||
LV_SIZE_CONTENT)
|
||||
{
|
||||
lv_obj_set_style_bg_color(content->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0);
|
||||
|
||||
auto form = &content->form;
|
||||
|
||||
FlexGridLayout grid(col_dsc, row_dsc);
|
||||
auto line = form->newLine(&grid);
|
||||
auto line = form->newLine(grid);
|
||||
|
||||
rect_t r{ 0, 0, 7 * LV_DPI_DEF / 5, 7 * LV_DPI_DEF / 5 };
|
||||
auto cedit = new ColorEditor(line, r, color, [=](uint32_t c) { updateColor(c); });
|
||||
lv_obj_set_style_grid_cell_x_align(cedit->getLvObj(), LV_GRID_ALIGN_CENTER, 0);
|
||||
rect_t r{0, 0, 7 * LV_DPI_DEF / 5, 7 * LV_DPI_DEF / 5};
|
||||
auto cedit =
|
||||
new ColorEditor(line, r, color, [=](uint32_t c) { updateColor(c); });
|
||||
lv_obj_set_style_grid_cell_x_align(cedit->getLvObj(), LV_GRID_ALIGN_CENTER,
|
||||
0);
|
||||
|
||||
auto vbox = new FormWindow(line, rect_t{});
|
||||
lv_obj_set_style_grid_cell_x_align(vbox->getLvObj(), LV_GRID_ALIGN_CENTER, 0);
|
||||
vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, lv_dpx(8));
|
||||
vbox->setWidth(r.w);
|
||||
vbox->setHeight(r.h);
|
||||
auto vbox = new Window(line, rect_t{});
|
||||
lv_obj_set_style_grid_cell_x_align(vbox->getLvObj(), LV_GRID_ALIGN_CENTER,
|
||||
0);
|
||||
vbox->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_MEDIUM, r.w, r.h);
|
||||
|
||||
auto hbox = new FormWindow(vbox, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
auto hbox = new Window(vbox, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM);
|
||||
auto hbox_obj = hbox->getLvObj();
|
||||
lv_obj_set_flex_align(hbox_obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
lv_obj_set_flex_align(hbox_obj, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START,
|
||||
LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
|
||||
colorPad = window_create(hbox_obj);
|
||||
lv_obj_set_style_bg_opa(colorPad, LV_OPA_100, LV_PART_MAIN);
|
||||
lv_obj_set_size(colorPad, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT);
|
||||
colorPad = new ColorSwatch(hbox, {0, 0, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT},
|
||||
COLOR_THEME_PRIMARY1);
|
||||
|
||||
hexStr = lv_label_create(hbox_obj);
|
||||
lv_obj_set_style_text_font(hexStr, getFont(FONT(L)), LV_PART_MAIN);
|
||||
lv_obj_set_style_text_color(hexStr, makeLvColor(COLOR_THEME_PRIMARY1), LV_PART_MAIN);
|
||||
hexStr = new StaticText(hbox, {0, 0, 100, 0}, "", COLOR_THEME_PRIMARY1 | FONT(L));
|
||||
|
||||
updateColor(color);
|
||||
|
||||
hbox = new FormWindow(vbox, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
|
||||
hbox = new Window(vbox, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM);
|
||||
lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER,
|
||||
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
|
||||
auto rgbBtn = new TextButton(hbox, rect_t{}, "RGB");
|
||||
auto hsvBtn = new TextButton(hbox, rect_t{}, "HSV");
|
||||
@@ -106,7 +113,7 @@ class ColorEditorPopup : public Dialog
|
||||
thmBtn->check(false);
|
||||
return 1;
|
||||
});
|
||||
rgbBtn->padAll(lv_dpx(8));
|
||||
rgbBtn->padAll(PAD_MEDIUM);
|
||||
|
||||
hsvBtn->setPressHandler([=]() {
|
||||
cedit->setColorEditorType(HSV_COLOR_EDITOR);
|
||||
@@ -114,7 +121,7 @@ class ColorEditorPopup : public Dialog
|
||||
thmBtn->check(false);
|
||||
return 1;
|
||||
});
|
||||
hsvBtn->padAll(lv_dpx(8));
|
||||
hsvBtn->padAll(PAD_MEDIUM);
|
||||
|
||||
thmBtn->setPressHandler([=]() {
|
||||
cedit->setColorEditorType(THM_COLOR_EDITOR);
|
||||
@@ -122,66 +129,45 @@ class ColorEditorPopup : public Dialog
|
||||
hsvBtn->check(false);
|
||||
return 1;
|
||||
});
|
||||
thmBtn->padAll(lv_dpx(8));
|
||||
thmBtn->padAll(PAD_MEDIUM);
|
||||
|
||||
// color editor defaults to HSV
|
||||
hsvBtn->check(true);
|
||||
|
||||
hbox = new FormWindow(vbox, rect_t{});
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_END, LV_FLEX_ALIGN_SPACE_BETWEEN);
|
||||
|
||||
hbox = new Window(vbox, rect_t{});
|
||||
hbox->padTop(60);
|
||||
hbox->setFlexLayout(LV_FLEX_FLOW_ROW, 20);
|
||||
lv_obj_set_flex_align(hbox->getLvObj(), LV_FLEX_ALIGN_CENTER,
|
||||
LV_FLEX_ALIGN_END, LV_FLEX_ALIGN_SPACE_BETWEEN);
|
||||
lv_obj_set_flex_grow(hbox->getLvObj(), 1);
|
||||
|
||||
auto cancelBtn = new TextButton(hbox, rect_t{}, STR_CANCEL, [=]() -> int8_t {
|
||||
new TextButton(hbox, rect_t{0, 0, 80, 0}, STR_CANCEL, [=]() -> int8_t {
|
||||
this->deleteLater();
|
||||
return 0;
|
||||
});
|
||||
cancelBtn->padTop(lv_dpx(12));
|
||||
cancelBtn->padBottom(lv_dpx(12));
|
||||
lv_obj_set_flex_grow(cancelBtn->getLvObj(), 1);
|
||||
|
||||
auto okBtn = new TextButton(hbox, rect_t{}, STR_SAVE, [=]() -> int8_t {
|
||||
new TextButton(hbox, rect_t{0, 0, 80, 0}, STR_SAVE, [=]() -> int8_t {
|
||||
if (_setValue) _setValue(m_color);
|
||||
this->deleteLater();
|
||||
return 0;
|
||||
});
|
||||
okBtn->padTop(lv_dpx(12));
|
||||
okBtn->padBottom(lv_dpx(12));
|
||||
lv_obj_set_flex_grow(okBtn->getLvObj(), 1);
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
content->setWidth(LCD_W * 0.9);
|
||||
#else
|
||||
content->setWidth(LCD_W * 0.8);
|
||||
#endif
|
||||
content->updateSize();
|
||||
}
|
||||
};
|
||||
|
||||
static void color_editor_popup(lv_event_t* e)
|
||||
{
|
||||
auto picker = (ColorPicker*)lv_event_get_user_data(e);
|
||||
if (picker) {
|
||||
new ColorEditorPopup(picker, picker->getColor(),
|
||||
[=](uint32_t c) { picker->setColor(c); });
|
||||
}
|
||||
}
|
||||
|
||||
ColorPicker::ColorPicker(Window* parent, const rect_t& rect,
|
||||
std::function<uint16_t()> getValue,
|
||||
std::function<void(uint16_t)> setValue) :
|
||||
FormField(parent, rect, 0, 0, etx_button_create),
|
||||
Button(parent, {0, 0, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT}),
|
||||
setValue(std::move(setValue))
|
||||
{
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_opa(lvobj, LV_OPA_100, LV_STATE_FOCUS_KEY);
|
||||
|
||||
lv_obj_set_size(lvobj, COLOR_PAD_WIDTH, COLOR_PAD_HEIGHT);
|
||||
lv_obj_add_event_cb(lvobj, color_editor_popup, LV_EVENT_CLICKED, this);
|
||||
|
||||
updateColor(getValue());
|
||||
}
|
||||
|
||||
void ColorPicker::onClicked()
|
||||
{
|
||||
new ColorEditorPopup(this, getColor(), [=](uint32_t c) { setColor(c); });
|
||||
}
|
||||
|
||||
void ColorPicker::setColor(uint32_t c)
|
||||
{
|
||||
setValue(c);
|
||||
@@ -192,7 +178,7 @@ void ColorPicker::updateColor(uint32_t c)
|
||||
{
|
||||
color = c;
|
||||
|
||||
auto lvcolor = lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color));
|
||||
auto lvcolor =
|
||||
lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color));
|
||||
lv_obj_set_style_bg_color(lvobj, lvcolor, LV_PART_MAIN);
|
||||
lv_obj_set_style_bg_color(lvobj, lvcolor, LV_STATE_FOCUS_KEY);
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
#include "button.h"
|
||||
|
||||
class ColorPicker : public FormField
|
||||
class ColorPicker : public Button
|
||||
{
|
||||
uint32_t color;
|
||||
std::function<void(uint16_t)> setValue;
|
||||
@@ -37,4 +37,6 @@ public:
|
||||
|
||||
void setColor(uint32_t c);
|
||||
uint32_t getColor() const { return color; }
|
||||
|
||||
void onClicked() override;
|
||||
};
|
||||
|
||||
@@ -20,86 +20,135 @@
|
||||
*/
|
||||
|
||||
#include "colors.h"
|
||||
#include <algorithm>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
uint16_t lcdColorTable[LCD_COLOR_COUNT];
|
||||
#include <algorithm>
|
||||
|
||||
const uint16_t defaultColors[] = {
|
||||
RGB(0, 0, 0), // PRIMARY1
|
||||
RGB(255, 255, 255), // PRIMARY2
|
||||
RGB(12, 63, 102), // PRIMARY3
|
||||
RGB(18, 94, 153), // SECONDARY1
|
||||
RGB(182, 224, 242), // SECONDARY2
|
||||
RGB(228, 238, 242), // SECONDARY3
|
||||
RGB(20, 161, 229), // FOCUS
|
||||
RGB(0, 153, 9), // EDIT
|
||||
RGB(255, 222, 0), // ACTIVE
|
||||
RGB(224, 0, 0), // WARNING
|
||||
RGB(140, 140, 140), // DISABLED
|
||||
RGB(170, 85, 0), // CUSTOM
|
||||
RGB(0, 0, 0), // FIXED BLACK
|
||||
RGB(255, 255, 255), // FIXED WHITE
|
||||
RGB(128, 128, 128), // FIXED GREY
|
||||
};
|
||||
|
||||
// Needs to be initialised at compile time so widget color options work
|
||||
uint16_t lcdColorTable[] = {
|
||||
RGB(0, 0, 0), // PRIMARY1
|
||||
RGB(255, 255, 255), // PRIMARY2
|
||||
RGB(12, 63, 102), // PRIMARY3
|
||||
RGB(18, 94, 153), // SECONDARY1
|
||||
RGB(182, 224, 242), // SECONDARY2
|
||||
RGB(228, 238, 242), // SECONDARY3
|
||||
RGB(20, 161, 229), // FOCUS
|
||||
RGB(0, 153, 9), // EDIT
|
||||
RGB(255, 222, 0), // ACTIVE
|
||||
RGB(224, 0, 0), // WARNING
|
||||
RGB(140, 140, 140), // DISABLED
|
||||
RGB(170, 85, 0), // CUSTOM
|
||||
RGB(0, 0, 0), // FIXED BLACK
|
||||
RGB(255, 255, 255), // FIXED WHITE
|
||||
RGB(128, 128, 128), // FIXED GREY
|
||||
};
|
||||
|
||||
uint32_t HSVtoRGB(float H, float S, float V)
|
||||
{
|
||||
if (H > 360 || H < 0 || S > 100 || S < 0 || V > 100 || V < 0) {
|
||||
return 0;
|
||||
}
|
||||
if (H > 360 || H < 0 || S > 100 || S < 0 || V > 100 || V < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float s = S / 100;
|
||||
float v = V / 100;
|
||||
float C = s * v;
|
||||
float X = C * (1 - abs(fmod(H / 60.0, 2) - 1));
|
||||
float m = v - C;
|
||||
float r, g, b;
|
||||
float s = S / 100;
|
||||
float v = V / 100;
|
||||
float C = s * v;
|
||||
float X = C * (1 - abs(fmod(H / 60.0, 2) - 1));
|
||||
float m = v - C;
|
||||
float r, g, b;
|
||||
|
||||
if (H >= 0 && H < 60) {
|
||||
r = C, g = X, b = 0;
|
||||
}
|
||||
else if (H >= 60 && H < 120) {
|
||||
r = X, g = C, b = 0;
|
||||
}
|
||||
else if (H >= 120 && H < 180) {
|
||||
r = 0, g = C, b = X;
|
||||
}
|
||||
else if (H >= 180 && H < 240) {
|
||||
r = 0, g = X, b = C;
|
||||
}
|
||||
else if (H >= 240 && H < 300) {
|
||||
r = X, g = 0, b = C;
|
||||
}
|
||||
else {
|
||||
r = C, g = 0, b = X;
|
||||
}
|
||||
int R = (r + m) * 255;
|
||||
int G = (g + m) * 255;
|
||||
int B = (b + m) * 255;
|
||||
if (H >= 0 && H < 60) {
|
||||
r = C, g = X, b = 0;
|
||||
} else if (H >= 60 && H < 120) {
|
||||
r = X, g = C, b = 0;
|
||||
} else if (H >= 120 && H < 180) {
|
||||
r = 0, g = C, b = X;
|
||||
} else if (H >= 180 && H < 240) {
|
||||
r = 0, g = X, b = C;
|
||||
} else if (H >= 240 && H < 300) {
|
||||
r = X, g = 0, b = C;
|
||||
} else {
|
||||
r = C, g = 0, b = X;
|
||||
}
|
||||
int R = (r + m) * 255;
|
||||
int G = (g + m) * 255;
|
||||
int B = (b + m) * 255;
|
||||
|
||||
return RGB(R, G, B);
|
||||
return RGB(R, G, B);
|
||||
}
|
||||
|
||||
void RGBtoHSV(uint8_t R, uint8_t G, uint8_t B, float& fH, float& fS, float& fV)
|
||||
void RGBtoHSV(uint8_t R, uint8_t G, uint8_t B, float &fH, float &fS, float &fV)
|
||||
{
|
||||
float fR = (float)R / 255;
|
||||
float fG = (float)G / 255;
|
||||
float fB = (float)B / 255;
|
||||
float fCMax = std::max(std::max(fR, fG), fB);
|
||||
float fCMin = std::min(std::min(fR, fG), fB);
|
||||
float fDelta = fCMax - fCMin;
|
||||
float fR = (float)R / 255;
|
||||
float fG = (float)G / 255;
|
||||
float fB = (float)B / 255;
|
||||
float fCMax = std::max(std::max(fR, fG), fB);
|
||||
float fCMin = std::min(std::min(fR, fG), fB);
|
||||
float fDelta = fCMax - fCMin;
|
||||
|
||||
if (fDelta > 0) {
|
||||
if (fCMax == fR) {
|
||||
fH = 60 * (fmod(((fG - fB) / fDelta), 6));
|
||||
}
|
||||
else if (fCMax == fG) {
|
||||
fH = 60 * (((fB - fR) / fDelta) + 2);
|
||||
}
|
||||
else if (fCMax == fB) {
|
||||
fH = 60 * (((fR - fG) / fDelta) + 4);
|
||||
}
|
||||
|
||||
if (fCMax > 0) {
|
||||
fS = fDelta / fCMax;
|
||||
}
|
||||
else {
|
||||
fS = 0;
|
||||
}
|
||||
|
||||
fV = fCMax;
|
||||
}
|
||||
else {
|
||||
fH = 0;
|
||||
fS = 0;
|
||||
fV = fCMax;
|
||||
if (fDelta > 0) {
|
||||
if (fCMax == fR) {
|
||||
fH = 60 * (fmod(((fG - fB) / fDelta), 6));
|
||||
} else if (fCMax == fG) {
|
||||
fH = 60 * (((fB - fR) / fDelta) + 2);
|
||||
} else if (fCMax == fB) {
|
||||
fH = 60 * (((fR - fG) / fDelta) + 4);
|
||||
}
|
||||
|
||||
if (fH < 0) {
|
||||
fH = 360 + fH;
|
||||
if (fCMax > 0) {
|
||||
fS = fDelta / fCMax;
|
||||
} else {
|
||||
fS = 0;
|
||||
}
|
||||
|
||||
fV = fCMax;
|
||||
} else {
|
||||
fH = 0;
|
||||
fS = 0;
|
||||
fV = fCMax;
|
||||
}
|
||||
|
||||
if (fH < 0) {
|
||||
fH = 360 + fH;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: work out how to remove this function
|
||||
LcdColorIndex indexFromColor(uint32_t lcdFlags)
|
||||
{
|
||||
uint16_t color = COLOR_VAL(lcdFlags);
|
||||
|
||||
for (uint8_t i = 0; i < TOTAL_COLOR_COUNT; i += 1)
|
||||
if (lcdColorTable[i] == color) return (LcdColorIndex)i;
|
||||
|
||||
return CUSTOM_COLOR_INDEX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to translate a colorFlags value to a lv_color_t suitable
|
||||
* for passing to an lv_obj function
|
||||
* @param colorFlags a textFlags value. This value will contain the color shifted by 16 bits.
|
||||
*/
|
||||
lv_color_t makeLvColor(uint32_t colorFlags)
|
||||
{
|
||||
auto color = COLOR_VAL(colorFlags);
|
||||
return lv_color_make(GET_RED(color), GET_GREEN(color), GET_BLUE(color));
|
||||
}
|
||||
|
||||
@@ -19,16 +19,15 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _COLORS_H_
|
||||
#define _COLORS_H_
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include "libopenui_defines.h"
|
||||
|
||||
// TODO common code, not in target
|
||||
enum LcdColorIndex {
|
||||
// this one first for when colour is not set
|
||||
DEFAULT_COLOR_INDEX,
|
||||
|
||||
// Variable colors
|
||||
COLOR_THEME_PRIMARY1_INDEX,
|
||||
COLOR_THEME_PRIMARY2_INDEX,
|
||||
COLOR_THEME_PRIMARY3_INDEX,
|
||||
@@ -42,52 +41,51 @@ enum LcdColorIndex {
|
||||
COLOR_THEME_DISABLED_INDEX,
|
||||
CUSTOM_COLOR_INDEX,
|
||||
|
||||
// this one MUST be last
|
||||
// Variable count
|
||||
LCD_COLOR_COUNT,
|
||||
|
||||
// Fixed Colors
|
||||
COLOR_BLACK_INDEX = LCD_COLOR_COUNT,
|
||||
COLOR_WHITE_INDEX,
|
||||
COLOR_GREY_INDEX,
|
||||
|
||||
TOTAL_COLOR_COUNT,
|
||||
};
|
||||
|
||||
#define ARGB_SPLIT(color, a, r, g, b) \
|
||||
uint16_t a = ((color) & 0xF000) >> 12; \
|
||||
uint16_t r = ((color) & 0x0F00) >> 8; \
|
||||
uint16_t g = ((color) & 0x00F0) >> 4; \
|
||||
uint16_t b = ((color) & 0x000F)
|
||||
#define ARGB_SPLIT(color, a, r, g, b) \
|
||||
uint16_t a = ((color >> 12) & 0xF); \
|
||||
uint16_t r = ((color >> 8) & 0xF); \
|
||||
uint16_t g = ((color >> 4) & 0xF); \
|
||||
uint16_t b = ((color) & 0xF)
|
||||
|
||||
#define RGB_SPLIT(color, r, g, b) \
|
||||
uint16_t r = ((color) & 0xF800) >> 11; \
|
||||
uint16_t g = ((color) & 0x07E0) >> 5; \
|
||||
uint16_t b = ((color) & 0x001F)
|
||||
#define RGB_SPLIT(color, r, g, b) \
|
||||
uint16_t r = ((color >> 11) & 0x1F); \
|
||||
uint16_t g = ((color >> 5) & 0x3F); \
|
||||
uint16_t b = ((color) & 0x1F)
|
||||
|
||||
#define ARGB_JOIN(a, r, g, b) \
|
||||
(((a&0xF) << 12) + ((r&0xF) << 8) + ((g&0xF) << 4) + (b&0xF))
|
||||
(((a & 0xF) << 12) + ((r & 0xF) << 8) + ((g & 0xF) << 4) + (b & 0xF))
|
||||
|
||||
#define RGB_JOIN(r, g, b) \
|
||||
(((r) << 11) + ((g) << 5) + (b))
|
||||
#define RGB_JOIN(r, g, b) (((r) << 11) + ((g) << 5) + (b))
|
||||
|
||||
#define GET_RED(color) \
|
||||
(((color) & 0xF800) >> 8)
|
||||
#define GET_RED(color) (((color) & 0xF800) >> 8)
|
||||
|
||||
#define GET_GREEN(color) \
|
||||
(((color) & 0x07E0) >> 3)
|
||||
#define GET_GREEN(color) (((color) & 0x07E0) >> 3)
|
||||
|
||||
#define GET_BLUE(color) \
|
||||
(((color) & 0x001F) << 3)
|
||||
#define GET_BLUE(color) (((color) & 0x001F) << 3)
|
||||
|
||||
#define OPACITY_MAX 0x0Fu
|
||||
#define OPACITY(value) ((value) & OPACITY_MAX)
|
||||
#define OPACITY_MAX 0x0Fu
|
||||
#define OPACITY(value) ((value) & OPACITY_MAX)
|
||||
|
||||
#define RGB(r, g, b) (uint16_t)((((r) & 0xF8) << 8) + (((g) & 0xFC) << 3) + (((b) & 0xF8) >> 3))
|
||||
#define ARGB(a, r, g, b) (uint16_t)((((a) & 0xF0) << 8) + (((r) & 0xF0) << 4) + (((g) & 0xF0) << 0) + (((b) & 0xF0) >> 4))
|
||||
#define RGB(r, g, b) \
|
||||
(uint16_t)((((r) & 0xF8) << 8) + (((g) & 0xFC) << 3) + (((b) & 0xF8) >> 3))
|
||||
#define ARGB(a, r, g, b) \
|
||||
(uint16_t)((((a) & 0xF0) << 8) + (((r) & 0xF0) << 4) + (((g) & 0xF0) << 0) + \
|
||||
(((b) & 0xF0) >> 4))
|
||||
|
||||
#define COLOR2FLAGS(color) LcdFlags(unsigned(color) << 16u)
|
||||
#define COLOR_VAL(flags) ((flags) >> 16u)
|
||||
#define COLOR_MASK(flags) ((flags) & 0xFFFF0000u)
|
||||
|
||||
//
|
||||
// Basic color definitions
|
||||
//
|
||||
|
||||
#define WHITE RGB(0xFF, 0xFF, 0xFF)
|
||||
#define BLACK RGB(0, 0, 0)
|
||||
#define COLOR2FLAGS(color) LcdFlags(unsigned(color) << 16u)
|
||||
#define COLOR_VAL(flags) ((flags) >> 16u)
|
||||
#define COLOR_MASK(flags) ((flags) & 0xFFFF0000u)
|
||||
|
||||
#define RGB_FLAG 0x8000u
|
||||
#define RGB2FLAGS(r, g, b) (COLOR2FLAGS(RGB(r, g, b)) | RGB_FLAG)
|
||||
@@ -95,33 +93,39 @@ enum LcdColorIndex {
|
||||
//
|
||||
// Indexed colors
|
||||
//
|
||||
extern uint16_t lcdColorTable[LCD_COLOR_COUNT];
|
||||
extern uint16_t lcdColorTable[];
|
||||
extern const uint16_t defaultColors[];
|
||||
|
||||
inline void lcdSetColor(uint16_t color)
|
||||
{
|
||||
lcdColorTable[CUSTOM_COLOR_INDEX] = color;
|
||||
}
|
||||
|
||||
#define COLOR(index) \
|
||||
((uint32_t) \
|
||||
lcdColorTable[unsigned(index & 0xFF) >= LCD_COLOR_COUNT \
|
||||
? DEFAULT_COLOR_INDEX \
|
||||
: ((index & 0xFF) == 0 ? COLOR_THEME_PRIMARY1_INDEX \
|
||||
: unsigned(index & 0xFF))] \
|
||||
LcdColorIndex indexFromColor(uint32_t lcdFlags);
|
||||
|
||||
#define COLOR(index) \
|
||||
((uint32_t) \
|
||||
lcdColorTable[unsigned(index & 0xFF) >= TOTAL_COLOR_COUNT \
|
||||
? COLOR_WHITE_INDEX \
|
||||
: unsigned(index & 0xFF)] \
|
||||
<< 16u)
|
||||
|
||||
#define COLOR_THEME_PRIMARY1 COLOR(COLOR_THEME_PRIMARY1_INDEX)
|
||||
#define COLOR_THEME_PRIMARY2 COLOR(COLOR_THEME_PRIMARY2_INDEX)
|
||||
#define COLOR_THEME_PRIMARY3 COLOR(COLOR_THEME_PRIMARY3_INDEX)
|
||||
#define COLOR_THEME_SECONDARY1 COLOR(COLOR_THEME_SECONDARY1_INDEX)
|
||||
#define COLOR_THEME_SECONDARY2 COLOR(COLOR_THEME_SECONDARY2_INDEX)
|
||||
#define COLOR_THEME_SECONDARY3 COLOR(COLOR_THEME_SECONDARY3_INDEX)
|
||||
#define COLOR_THEME_FOCUS COLOR(COLOR_THEME_FOCUS_INDEX)
|
||||
#define COLOR_THEME_EDIT COLOR(COLOR_THEME_EDIT_INDEX)
|
||||
#define COLOR_THEME_ACTIVE COLOR(COLOR_THEME_ACTIVE_INDEX)
|
||||
#define COLOR_THEME_WARNING COLOR(COLOR_THEME_WARNING_INDEX)
|
||||
#define COLOR_THEME_DISABLED COLOR(COLOR_THEME_DISABLED_INDEX)
|
||||
#define CUSTOM_COLOR COLOR(CUSTOM_COLOR_INDEX)
|
||||
#define COLOR_BLACK COLOR(COLOR_BLACK_INDEX)
|
||||
#define COLOR_WHITE COLOR(COLOR_WHITE_INDEX)
|
||||
#define COLOR_GREY COLOR(COLOR_GREY_INDEX)
|
||||
|
||||
#define COLOR_THEME_PRIMARY1 COLOR(COLOR_THEME_PRIMARY1_INDEX)
|
||||
#define COLOR_THEME_PRIMARY2 COLOR(COLOR_THEME_PRIMARY2_INDEX)
|
||||
#define COLOR_THEME_PRIMARY3 COLOR(COLOR_THEME_PRIMARY3_INDEX)
|
||||
#define COLOR_THEME_SECONDARY1 COLOR(COLOR_THEME_SECONDARY1_INDEX)
|
||||
#define COLOR_THEME_SECONDARY2 COLOR(COLOR_THEME_SECONDARY2_INDEX)
|
||||
#define COLOR_THEME_SECONDARY3 COLOR(COLOR_THEME_SECONDARY3_INDEX)
|
||||
#define COLOR_THEME_FOCUS COLOR(COLOR_THEME_FOCUS_INDEX)
|
||||
#define COLOR_THEME_EDIT COLOR(COLOR_THEME_EDIT_INDEX)
|
||||
#define COLOR_THEME_ACTIVE COLOR(COLOR_THEME_ACTIVE_INDEX)
|
||||
#define COLOR_THEME_WARNING COLOR(COLOR_THEME_WARNING_INDEX)
|
||||
#define COLOR_THEME_DISABLED COLOR(COLOR_THEME_DISABLED_INDEX)
|
||||
#define CUSTOM_COLOR COLOR(CUSTOM_COLOR_INDEX)
|
||||
|
||||
#if defined(WINDOWS_INSPECT_BORDERS)
|
||||
#define WINDOWS_INSPECT_BORDER_COLOR COLOR_THEME_PRIMARY3
|
||||
@@ -135,4 +139,4 @@ extern uint32_t HSVtoRGB(float H, float S, float V);
|
||||
extern void RGBtoHSV(uint8_t R, uint8_t G, uint8_t B, float& fH, float& fS,
|
||||
float& fV);
|
||||
|
||||
#endif // _COLORS_H_
|
||||
lv_color_t makeLvColor(uint32_t colorFlags);
|
||||
|
||||
@@ -1,74 +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 "opentx.h"
|
||||
#include "confirm_dialog.h"
|
||||
#include "static.h"
|
||||
|
||||
ConfirmDialog::ConfirmDialog(Window* parent, const char* title,
|
||||
const char* message,
|
||||
std::function<void(void)> confirmHandler,
|
||||
std::function<void(void)> cancelHandler) :
|
||||
Dialog(parent, title, rect_t{}),
|
||||
confirmHandler(std::move(confirmHandler)),
|
||||
cancelHandler(std::move(cancelHandler))
|
||||
{
|
||||
auto form = &content->form;
|
||||
auto msg = new StaticText(form, rect_t{}, message);
|
||||
msg->padAll(lv_dpx(16));
|
||||
|
||||
lv_obj_set_style_bg_color(content->getLvObj(),
|
||||
makeLvColor(COLOR_THEME_SECONDARY3), 0);
|
||||
|
||||
auto box = new FormWindow(form, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_flex_main_place(box->getLvObj(), LV_FLEX_ALIGN_SPACE_EVENLY, 0);
|
||||
|
||||
auto btn = new TextButton(box, rect_t{}, STR_NO, [=]() -> int8_t {
|
||||
onCancel();
|
||||
return 0;
|
||||
});
|
||||
#if LCD_W > LCD_H
|
||||
btn->setWidth(LV_DPI_DEF);
|
||||
#else
|
||||
btn->setWidth(LV_DPI_DEF * 3 / 4);
|
||||
#endif
|
||||
|
||||
btn = new TextButton(box, rect_t{}, STR_YES, [=]() -> int8_t {
|
||||
this->deleteLater();
|
||||
this->confirmHandler();
|
||||
return 0;
|
||||
});
|
||||
#if LCD_W > LCD_H
|
||||
btn->setWidth(LV_DPI_DEF);
|
||||
#else
|
||||
btn->setWidth(LV_DPI_DEF * 3 / 4);
|
||||
#endif
|
||||
|
||||
content->setWidth(LCD_W * 0.8);
|
||||
content->updateSize();
|
||||
}
|
||||
|
||||
void ConfirmDialog::onCancel()
|
||||
{
|
||||
deleteLater();
|
||||
if (cancelHandler) cancelHandler();
|
||||
}
|
||||
@@ -1,41 +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.
|
||||
*/
|
||||
|
||||
#ifndef _CONFIRM_DIALOG_H_
|
||||
#define _CONFIRM_DIALOG_H_
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
class ConfirmDialog : public Dialog
|
||||
{
|
||||
public:
|
||||
ConfirmDialog(Window* parent, const char* title, const char* message,
|
||||
std::function<void(void)> confirmHandler,
|
||||
std::function<void(void)> cancelHandler = nullptr);
|
||||
|
||||
protected:
|
||||
std::function<void(void)> confirmHandler;
|
||||
std::function<void(void)> cancelHandler;
|
||||
|
||||
void onCancel() override;
|
||||
};
|
||||
|
||||
#endif // _CONFIRM_DIALOG_H_
|
||||
@@ -30,14 +30,14 @@
|
||||
|
||||
CrossfireSettings::CrossfireSettings(Window* parent, const FlexGridLayout& g,
|
||||
uint8_t moduleIdx) :
|
||||
FormWindow(parent, rect_t{}), md(&g_model.moduleData[moduleIdx])
|
||||
Window(parent, rect_t{}), md(&g_model.moduleData[moduleIdx])
|
||||
{
|
||||
FlexGridLayout grid(g);
|
||||
setFlexLayout();
|
||||
|
||||
if (moduleIdx == EXTERNAL_MODULE) {
|
||||
auto line = newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_BAUDRATE, 0, COLOR_THEME_PRIMARY1);
|
||||
auto line = newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_BAUDRATE);
|
||||
new Choice(
|
||||
line, rect_t{}, STR_CRSF_BAUDRATE, 0, CROSSFIRE_MAX_INTERNAL_BAUDRATE,
|
||||
[=]() -> int {
|
||||
@@ -57,8 +57,8 @@ CrossfireSettings::CrossfireSettings(Window* parent, const FlexGridLayout& g,
|
||||
// 0, COLOR_THEME_PRIMARY1);
|
||||
}
|
||||
|
||||
auto line = newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_STATUS, 0, COLOR_THEME_PRIMARY1);
|
||||
auto line = newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_STATUS);
|
||||
new DynamicText(line, rect_t{}, [=] {
|
||||
char msg[64] = "";
|
||||
// sprintf(msg, "%d Hz %" PRIu32 " Err", 1000000 / getMixerSchedulerPeriod(),
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
#include "window.h"
|
||||
#include "module_setup.h"
|
||||
|
||||
struct ModuleData;
|
||||
|
||||
class CrossfireSettings : public FormWindow, public ModuleOptions
|
||||
class CrossfireSettings : public Window, public ModuleOptions
|
||||
{
|
||||
ModuleData* md;
|
||||
|
||||
|
||||
@@ -19,231 +19,240 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "opentx.h"
|
||||
#include "curve.h"
|
||||
#include "lcd.h"
|
||||
|
||||
#include "bitmaps.h"
|
||||
#include "opentx.h"
|
||||
#include "strhelpers.h"
|
||||
#include "font.h"
|
||||
#include "theme.h"
|
||||
|
||||
const uint8_t _LBM_CURVE_POINT[] = {
|
||||
#include "mask_cvpoint.lbm"
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const uint8_t _LBM_CURVE_POINT_CENTER[] = {
|
||||
#include "mask_cvpoint_center.lbm"
|
||||
};
|
||||
|
||||
const uint8_t _LBM_CURVE_COORD_SHADOW[] = {
|
||||
#include "mask_coord_shadow.lbm"
|
||||
};
|
||||
|
||||
IMPL_LZ4_BITMAP(LBM_CURVE_POINT);
|
||||
IMPL_LZ4_BITMAP(LBM_CURVE_POINT_CENTER);
|
||||
IMPL_LZ4_BITMAP(LBM_CURVE_COORD_SHADOW);
|
||||
|
||||
// Base curve rendering class to 'paint' the background and curve.
|
||||
CurveRenderer::CurveRenderer(const rect_t & rect, std::function<int(int)> function):
|
||||
rect(rect),
|
||||
function(std::move(function))
|
||||
// Base curve rendering class to draw the background and curve.
|
||||
CurveRenderer::CurveRenderer(Window* parent, const rect_t& rect,
|
||||
std::function<int(int)> function) :
|
||||
valueFunc(std::move(function))
|
||||
{
|
||||
dx = rect.x;
|
||||
dy = rect.y;
|
||||
dw = rect.w;
|
||||
dh = rect.h;
|
||||
|
||||
lv_obj_t* bgBox = lv_line_create(parent->getLvObj());
|
||||
etx_obj_add_style(bgBox, styles->graph_border, LV_PART_MAIN);
|
||||
|
||||
lv_obj_t* axis1 = lv_line_create(parent->getLvObj());
|
||||
etx_obj_add_style(axis1, styles->graph_border, LV_PART_MAIN);
|
||||
lv_obj_t* axis2 = lv_line_create(parent->getLvObj());
|
||||
etx_obj_add_style(axis2, styles->graph_border, LV_PART_MAIN);
|
||||
|
||||
lv_obj_t* extra1 = lv_line_create(parent->getLvObj());
|
||||
etx_obj_add_style(extra1, styles->graph_dashed, LV_PART_MAIN);
|
||||
lv_obj_t* extra2 = lv_line_create(parent->getLvObj());
|
||||
etx_obj_add_style(extra2, styles->graph_dashed, LV_PART_MAIN);
|
||||
lv_obj_t* extra3 = lv_line_create(parent->getLvObj());
|
||||
etx_obj_add_style(extra3, styles->graph_dashed, LV_PART_MAIN);
|
||||
lv_obj_t* extra4 = lv_line_create(parent->getLvObj());
|
||||
etx_obj_add_style(extra4, styles->graph_dashed, LV_PART_MAIN);
|
||||
|
||||
// Outer box
|
||||
bgPoints[0] = {dx, dy};
|
||||
bgPoints[1] = {(lv_coord_t)(dx + dw - 1), dy};
|
||||
bgPoints[2] = {(lv_coord_t)(dx + dw - 1), (lv_coord_t)(dy + dh - 1)};
|
||||
bgPoints[3] = {dx, (lv_coord_t)(dy + dh - 1)};
|
||||
bgPoints[4] = {dx, dy};
|
||||
|
||||
lv_line_set_points(bgBox, bgPoints, 5);
|
||||
|
||||
// Axis lines
|
||||
bgPoints[5] = {(lv_coord_t)(dx + dw / 2), dy};
|
||||
bgPoints[6] = {(lv_coord_t)(dx + dw / 2), (lv_coord_t)(dy + dh - 1)};
|
||||
bgPoints[7] = {dx, (lv_coord_t)(dy + dh / 2)};
|
||||
bgPoints[8] = {(lv_coord_t)(dx + dw - 1), (lv_coord_t)(dy + dh / 2)};
|
||||
|
||||
lv_line_set_points(axis1, &bgPoints[5], 2);
|
||||
lv_line_set_points(axis2, &bgPoints[7], 2);
|
||||
|
||||
// Extra lines
|
||||
bgPoints[9] = {(lv_coord_t)(dx + dw / 4), dy};
|
||||
bgPoints[10] = {(lv_coord_t)(dx + dw / 4), (lv_coord_t)(dy + dh - 1)};
|
||||
bgPoints[11] = {(lv_coord_t)(dx + dw * 3 / 4), dy};
|
||||
bgPoints[12] = {(lv_coord_t)(dx + dw * 3 / 4), (lv_coord_t)(dy + dh - 1)};
|
||||
bgPoints[13] = {dx, (lv_coord_t)(dy + dh / 4)};
|
||||
bgPoints[14] = {(lv_coord_t)(dx + dw - 1), (lv_coord_t)(dy + dh / 4)};
|
||||
bgPoints[15] = {dx, (lv_coord_t)(dy + dh * 3 / 4)};
|
||||
bgPoints[16] = {(lv_coord_t)(dx + dw - 1), (lv_coord_t)(dy + dh * 3 / 4)};
|
||||
|
||||
lv_line_set_points(extra1, &bgPoints[9], 2);
|
||||
lv_line_set_points(extra2, &bgPoints[11], 2);
|
||||
lv_line_set_points(extra3, &bgPoints[13], 2);
|
||||
lv_line_set_points(extra4, &bgPoints[15], 2);
|
||||
|
||||
// Curve points
|
||||
lnPoints = new lv_point_t[dw];
|
||||
|
||||
ptLine = lv_line_create(parent->getLvObj());
|
||||
etx_obj_add_style(ptLine, styles->graph_line, LV_PART_MAIN);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
CurveRenderer::~CurveRenderer()
|
||||
{
|
||||
if (lnPoints) delete lnPoints;
|
||||
}
|
||||
|
||||
void CurveRenderer::update()
|
||||
{
|
||||
for (lv_coord_t x = 0; x < dw; x += 1) {
|
||||
lv_coord_t y =
|
||||
getPointY(valueFunc(divRoundClosest((x - dw / 2) * RESX, dw / 2)));
|
||||
lnPoints[x] = {(lv_coord_t)(x + dx), y};
|
||||
}
|
||||
|
||||
lv_line_set_points(ptLine, lnPoints, dw);
|
||||
}
|
||||
|
||||
coord_t CurveRenderer::getPointY(int y) const
|
||||
{
|
||||
return dy + limit<coord_t>(0,
|
||||
dh / 2 - divRoundClosest(y * dh / 2, RESX),
|
||||
dh - 1);
|
||||
return dy +
|
||||
limit<coord_t>(0, dh / 2 - divRoundClosest(y * dh / 2, RESX), dh - 1);
|
||||
}
|
||||
|
||||
void CurveRenderer::drawBackground(BitmapBuffer * dc)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
Curve::Curve(Window* parent, const rect_t& rect,
|
||||
std::function<int(int)> function, std::function<int()> position) :
|
||||
Window(parent, rect),
|
||||
base(this,
|
||||
rect_t{(position ? 4 : 2), (position ? 4 : 2),
|
||||
rect.w - (position ? 8 : 4), rect.h - (position ? 8 : 4)},
|
||||
function),
|
||||
valueFunc(std::move(function)),
|
||||
positionFunc(std::move(position))
|
||||
{
|
||||
dc->drawSolidFilledRect(rect.x, rect.y, rect.w, rect.h, COLOR_THEME_PRIMARY2);
|
||||
setWindowFlag(NO_FOCUS);
|
||||
|
||||
// Axis
|
||||
dc->drawSolidHorizontalLine(dx, dy+dh/2, dw, COLOR_THEME_SECONDARY2);
|
||||
dc->drawSolidVerticalLine(dx+dw/2, dy, dh, COLOR_THEME_SECONDARY2);
|
||||
lv_obj_clear_flag(lvobj, LV_OBJ_FLAG_CLICKABLE);
|
||||
|
||||
// Extra lines
|
||||
dc->drawVerticalLine(dx+dw/4, dy, dh, STASHED, COLOR_THEME_SECONDARY2);
|
||||
dc->drawVerticalLine(dx+dw*3/4, dy, dh, STASHED, COLOR_THEME_SECONDARY2);
|
||||
dc->drawHorizontalLine(dx, dy+dh/4, dw, STASHED, COLOR_THEME_SECONDARY2);
|
||||
dc->drawHorizontalLine(dx, dy+dh*3/4, dw, STASHED, COLOR_THEME_SECONDARY2);
|
||||
etx_solid_bg(lvobj, COLOR_THEME_PRIMARY2_INDEX);
|
||||
|
||||
// Outside border
|
||||
dc->drawSolidRect(dx, dy, dw, dh, 1, COLOR_THEME_SECONDARY2);
|
||||
}
|
||||
|
||||
void CurveRenderer::drawCurve(BitmapBuffer * dc)
|
||||
{
|
||||
auto prev = (coord_t) -1;
|
||||
|
||||
for (int x = 0; x < dw; x++) {
|
||||
coord_t y = getPointY(function(divRoundClosest((x - dw / 2) * RESX, dw / 2)));
|
||||
if (prev >= 0) {
|
||||
if (prev < y) {
|
||||
for (int tmp = prev; tmp <= y; tmp++) {
|
||||
dc->drawBitmapPattern(dx + x - 2, tmp - 2, LBM_POINT, COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int tmp = y; tmp <= prev; tmp++) {
|
||||
dc->drawBitmapPattern(dx + x - 2, tmp - 2, LBM_POINT, COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = y;
|
||||
}
|
||||
}
|
||||
|
||||
void CurveRenderer::paint(BitmapBuffer * dc, uint8_t ofst)
|
||||
{
|
||||
dx = rect.x + 2 + ofst;
|
||||
dy = rect.y + 2 + ofst;
|
||||
dw = rect.w - 4 - ofst * 2;
|
||||
dh = rect.h - 4 - ofst * 2;
|
||||
|
||||
drawBackground(dc);
|
||||
drawCurve(dc);
|
||||
}
|
||||
|
||||
Curve::Curve(Window * parent, const rect_t & rect, std::function<int(int)> function, std::function<int()> position):
|
||||
Window(parent, rect, OPAQUE),
|
||||
base(rect_t{0, 0, rect.w, rect.h}, function),
|
||||
function(std::move(function)),
|
||||
position(std::move(position))
|
||||
{
|
||||
}
|
||||
|
||||
coord_t Curve::getPointX(int x) const
|
||||
{
|
||||
return dx + limit<coord_t>(0,
|
||||
dw / 2 + divRoundClosest(x * dw / 2, RESX),
|
||||
dw - 1);
|
||||
}
|
||||
|
||||
coord_t Curve::getPointY(int y) const
|
||||
{
|
||||
return dy + limit<coord_t>(0,
|
||||
dh / 2 - divRoundClosest(y * dh / 2, RESX),
|
||||
dh - 1);
|
||||
}
|
||||
|
||||
void Curve::drawBackground(BitmapBuffer * dc)
|
||||
{
|
||||
dc->clear(COLOR_THEME_PRIMARY2);
|
||||
|
||||
// Axis
|
||||
dc->drawSolidHorizontalLine(dx, dy+dh/2, dw, COLOR_THEME_SECONDARY2);
|
||||
dc->drawSolidVerticalLine(dx+dw/2, dy, dh, COLOR_THEME_SECONDARY2);
|
||||
|
||||
// Extra lines
|
||||
dc->drawVerticalLine(dx+dw/4, dy, dh, STASHED, COLOR_THEME_SECONDARY2);
|
||||
dc->drawVerticalLine(dx+dw*3/4, dy, dh, STASHED, COLOR_THEME_SECONDARY2);
|
||||
dc->drawHorizontalLine(dx, dy+dh/4, dw, STASHED, COLOR_THEME_SECONDARY2);
|
||||
dc->drawHorizontalLine(dx, dy+dh*3/4, dw, STASHED, COLOR_THEME_SECONDARY2);
|
||||
|
||||
// Outside border
|
||||
dc->drawSolidRect(dx, dy, dw, dh, 1, COLOR_THEME_SECONDARY2);
|
||||
}
|
||||
|
||||
void Curve::drawCurve(BitmapBuffer * dc)
|
||||
{
|
||||
auto prev = (coord_t) -1;
|
||||
|
||||
for (int x = 0; x < dw; x++) {
|
||||
coord_t y = getPointY(function(divRoundClosest((x - dw / 2) * RESX, dw / 2)));
|
||||
if (prev >= 0) {
|
||||
if (prev < y) {
|
||||
for (int tmp = prev; tmp <= y; tmp++) {
|
||||
dc->drawBitmapPattern(dx + x - 2, tmp - 2, LBM_POINT, COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int tmp = y; tmp <= prev; tmp++) {
|
||||
dc->drawBitmapPattern(dx + x - 2, tmp - 2, LBM_POINT, COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = y;
|
||||
}
|
||||
}
|
||||
|
||||
void Curve::drawPosition(BitmapBuffer * dc)
|
||||
{
|
||||
int valueX = position();
|
||||
int valueY = function(valueX);
|
||||
|
||||
coord_t x = getPointX(valueX);
|
||||
coord_t y = getPointY(valueY);
|
||||
|
||||
// the 2 lines
|
||||
dc->drawSolidHorizontalLine(dx, y, dw, COLOR_THEME_ACTIVE);
|
||||
dc->drawSolidVerticalLine(x, dy, dh, COLOR_THEME_ACTIVE);
|
||||
|
||||
// the point (white inside)
|
||||
dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT, COLOR_THEME_ACTIVE);
|
||||
dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT_CENTER, COLOR_THEME_PRIMARY2);
|
||||
|
||||
char coords[16];
|
||||
strAppendSigned(strAppend(strAppendSigned(coords, calcRESXto100(valueX)), ","), calcRESXto100(valueY));
|
||||
dc->drawSolidFilledRect(10, 11, 2 + getTextWidth(coords, 0, FONT(XS)), 17, COLOR_THEME_ACTIVE);
|
||||
dc->drawText(11, 10, coords, FONT(XS) | COLOR_THEME_PRIMARY1);
|
||||
}
|
||||
|
||||
void Curve::drawPoint(BitmapBuffer * dc, const CurvePoint & point)
|
||||
{
|
||||
coord_t x = getPointX(point.coords.x);
|
||||
coord_t y = getPointY(point.coords.y);
|
||||
|
||||
dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT, point.flags);
|
||||
dc->drawBitmapPattern(x-4, y-4, LBM_CURVE_POINT_CENTER, COLOR_THEME_SECONDARY3);
|
||||
}
|
||||
|
||||
void Curve::paint(BitmapBuffer * dc)
|
||||
{
|
||||
// Adjust border - if drawing points leave more space to prevent clipping of end points.
|
||||
if (points.size() > 0) {
|
||||
// Adjust border - if drawing points leave more space to prevent clipping of
|
||||
// end points.
|
||||
if (positionFunc) {
|
||||
dx = 4;
|
||||
dy = 4;
|
||||
} else {
|
||||
dx = 2;
|
||||
dy = 2;
|
||||
}
|
||||
dw = width() - dx * 2;
|
||||
dh = height() - dy * 2;
|
||||
dw = rect.w - dx * 2;
|
||||
dh = rect.h - dy * 2;
|
||||
|
||||
base.paint(dc, dx-2);
|
||||
|
||||
for (auto point: points) {
|
||||
drawPoint(dc, point);
|
||||
for (int i = 0; i < 17; i += 1) {
|
||||
auto p = lv_obj_create(lvobj);
|
||||
etx_solid_bg(p, COLOR_THEME_PRIMARY2_INDEX);
|
||||
etx_obj_add_style(p, styles->circle, LV_PART_MAIN);
|
||||
etx_obj_add_style(p, styles->border, LV_PART_MAIN);
|
||||
etx_obj_add_style(p, styles->border_color_dark, LV_PART_MAIN);
|
||||
lv_obj_set_size(p, 9, 9);
|
||||
lv_obj_add_flag(p, LV_OBJ_FLAG_HIDDEN);
|
||||
pointDots[i] = p;
|
||||
}
|
||||
if (position) {
|
||||
drawPosition(dc);
|
||||
|
||||
if (positionFunc) {
|
||||
posVLine = lv_line_create(lvobj);
|
||||
etx_obj_add_style(posVLine, styles->graph_position_line, LV_PART_MAIN);
|
||||
posHLine = lv_line_create(lvobj);
|
||||
etx_obj_add_style(posHLine, styles->graph_position_line, LV_PART_MAIN);
|
||||
|
||||
positionValue = new StaticText(this, {10, 10, LV_SIZE_CONTENT, 17}, "", COLOR_THEME_PRIMARY1 | FONT(XS));
|
||||
positionValue->padLeft(PAD_TINY);
|
||||
positionValue->padRight(PAD_TINY);
|
||||
etx_solid_bg(positionValue->getLvObj(), COLOR_THEME_ACTIVE_INDEX);
|
||||
|
||||
posPoint = lv_obj_create(lvobj);
|
||||
etx_solid_bg(posPoint, COLOR_THEME_PRIMARY2_INDEX);
|
||||
etx_obj_add_style(posPoint, styles->circle, LV_PART_MAIN);
|
||||
etx_obj_add_style(posPoint, styles->border, LV_PART_MAIN);
|
||||
etx_obj_add_style(posPoint, styles->border_color_active, LV_PART_MAIN);
|
||||
lv_obj_set_size(posPoint, 9, 9);
|
||||
|
||||
updatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
void Curve::addPoint(const point_t & point, LcdFlags flags)
|
||||
coord_t Curve::getPointX(int x) const
|
||||
{
|
||||
points.push_back({point, flags});
|
||||
invalidate();
|
||||
return dx +
|
||||
limit<coord_t>(0, dw / 2 + divRoundClosest(x * dw / 2, RESX), dw - 1);
|
||||
}
|
||||
|
||||
coord_t Curve::getPointY(int y) const
|
||||
{
|
||||
return dy +
|
||||
limit<coord_t>(0, dh / 2 - divRoundClosest(y * dh / 2, RESX), dh - 1);
|
||||
}
|
||||
|
||||
void Curve::updatePosition()
|
||||
{
|
||||
if (positionFunc) {
|
||||
int valueX = positionFunc();
|
||||
int valueY = valueFunc(valueX);
|
||||
|
||||
char coords[16];
|
||||
strAppendSigned(
|
||||
strAppend(strAppendSigned(coords, calcRESXto100(valueX)), ","),
|
||||
calcRESXto100(valueY));
|
||||
|
||||
positionValue->setText(coords);
|
||||
|
||||
lv_coord_t x = getPointX(valueX);
|
||||
lv_coord_t y = getPointY(valueY);
|
||||
|
||||
lv_obj_set_pos(posPoint, x - 4, y - 4);
|
||||
|
||||
posLinePoints[0] = {x, dy};
|
||||
posLinePoints[1] = {x, (lv_coord_t)(dy + dh - 1)};
|
||||
posLinePoints[2] = {dx, y};
|
||||
posLinePoints[3] = {(lv_coord_t)(dx + dw - 1), y};
|
||||
|
||||
lv_line_set_points(posVLine, &posLinePoints[0], 2);
|
||||
lv_line_set_points(posHLine, &posLinePoints[2], 2);
|
||||
}
|
||||
}
|
||||
|
||||
void Curve::addPoint(const point_t& point)
|
||||
{
|
||||
int i = points.size();
|
||||
coord_t x = getPointX(point.x);
|
||||
coord_t y = getPointY(point.y);
|
||||
lv_obj_set_pos(pointDots[i], x - 4, y - 4);
|
||||
lv_obj_clear_flag(pointDots[i], LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
points.push_back(point);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void Curve::clearPoints()
|
||||
{
|
||||
points.clear();
|
||||
invalidate();
|
||||
for (int i = 0; i < 17; i += 1)
|
||||
lv_obj_add_flag(pointDots[i], LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void Curve::update() { base.update(); }
|
||||
|
||||
void Curve::checkEvents()
|
||||
{
|
||||
// Redraw if crosshair position has changed
|
||||
if (position) {
|
||||
int pos = position();
|
||||
if (positionFunc) {
|
||||
int pos = positionFunc();
|
||||
if (pos != lastPos) {
|
||||
lastPos = pos;
|
||||
invalidate();
|
||||
updatePosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,66 +23,66 @@
|
||||
|
||||
#include "window.h"
|
||||
|
||||
struct CurvePoint {
|
||||
point_t coords;
|
||||
LcdFlags flags;
|
||||
};
|
||||
class StaticText;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CurveRenderer
|
||||
{
|
||||
public:
|
||||
CurveRenderer(const rect_t & rect, std::function<int(int)> function);
|
||||
public:
|
||||
CurveRenderer(Window* parent, const rect_t& rect,
|
||||
std::function<int(int)> function);
|
||||
~CurveRenderer();
|
||||
|
||||
void paint(BitmapBuffer * dc, uint8_t ofst = 0);
|
||||
void update();
|
||||
|
||||
protected:
|
||||
// Drawing rectangle position & size
|
||||
uint8_t dx, dy, dw, dh;
|
||||
rect_t rect;
|
||||
std::function<int(int)> function;
|
||||
void drawBackground(BitmapBuffer * dc);
|
||||
void drawCurve(BitmapBuffer * dc);
|
||||
coord_t getPointY(int y) const;
|
||||
protected:
|
||||
// Drawing rectangle position & size
|
||||
lv_coord_t dx, dy, dw, dh;
|
||||
std::function<int(int)> valueFunc;
|
||||
lv_point_t bgPoints[17];
|
||||
lv_point_t* lnPoints = nullptr;
|
||||
lv_obj_t* ptLine = nullptr;
|
||||
|
||||
coord_t getPointY(int y) const;
|
||||
};
|
||||
|
||||
class Curve: public Window
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class Curve : public Window
|
||||
{
|
||||
public:
|
||||
Curve(Window * parent, const rect_t & rect, std::function<int(int)> function, std::function<int()> position=nullptr);
|
||||
public:
|
||||
Curve(Window* parent, const rect_t& rect, std::function<int(int)> function,
|
||||
std::function<int()> position = nullptr);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override
|
||||
{
|
||||
return "Curve";
|
||||
}
|
||||
std::string getName() const override { return "Curve"; }
|
||||
#endif
|
||||
|
||||
void checkEvents() override;
|
||||
void addPoint(const point_t& point);
|
||||
void clearPoints();
|
||||
|
||||
void addPoint(const point_t & point, LcdFlags flags);
|
||||
void update();
|
||||
|
||||
void clearPoints();
|
||||
protected:
|
||||
CurveRenderer base;
|
||||
// Drawing rectangle position & size
|
||||
uint8_t dx, dy, dw, dh;
|
||||
int lastPos = 0;
|
||||
std::function<int(int)> valueFunc;
|
||||
std::function<int()> positionFunc;
|
||||
std::list<point_t> points;
|
||||
StaticText* positionValue = nullptr;
|
||||
lv_point_t posLinePoints[4];
|
||||
lv_obj_t* posVLine = nullptr;
|
||||
lv_obj_t* posHLine = nullptr;
|
||||
lv_obj_t* posPoint = nullptr;
|
||||
lv_obj_t* pointDots[17] = { nullptr };
|
||||
|
||||
void paint(BitmapBuffer * dc) override;
|
||||
void updatePosition();
|
||||
|
||||
protected:
|
||||
CurveRenderer base;
|
||||
// Drawing rectangle position & size
|
||||
uint8_t dx, dy, dw, dh;
|
||||
int lastPos = 0;
|
||||
std::function<int(int)> function;
|
||||
std::function<int()> position;
|
||||
std::list<CurvePoint> points;
|
||||
void drawBackground(BitmapBuffer * dc);
|
||||
void drawCurve(BitmapBuffer * dc);
|
||||
void drawPosition(BitmapBuffer * dc);
|
||||
void drawPoint(BitmapBuffer * dc, const CurvePoint & point);
|
||||
coord_t getPointX(int x) const;
|
||||
coord_t getPointY(int y) const;
|
||||
coord_t getPointX(int x) const;
|
||||
coord_t getPointY(int y) const;
|
||||
|
||||
void checkEvents() override;
|
||||
};
|
||||
|
||||
#include "lz4_bitmaps.h"
|
||||
|
||||
DEFINE_LZ4_BITMAP(LBM_CURVE_POINT);
|
||||
DEFINE_LZ4_BITMAP(LBM_CURVE_POINT_CENTER);
|
||||
DEFINE_LZ4_BITMAP(LBM_CURVE_COORD_SHADOW);
|
||||
|
||||
@@ -50,8 +50,8 @@ CurveParam::CurveParam(Window* parent, const rect_t& rect, CurveRef* ref,
|
||||
std::function<void(int32_t)> setRefValue) :
|
||||
Window(parent, rect), ref(ref), setRefValue(setRefValue)
|
||||
{
|
||||
padAll(PAD_TINY);
|
||||
lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW_WRAP);
|
||||
lv_obj_set_style_pad_column(lvobj, lv_dpx(4), 0);
|
||||
lv_obj_set_style_flex_cross_place(lvobj, LV_FLEX_ALIGN_CENTER, 0);
|
||||
lv_obj_set_size(lvobj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
|
||||
@@ -87,28 +87,21 @@ void CurveParam::update()
|
||||
{
|
||||
bool has_focus = act_field && act_field->hasFocus();
|
||||
|
||||
auto value_obj = value_edit->getLvObj();
|
||||
auto func_obj = func_choice->getLvObj();
|
||||
auto cust_obj = cust_choice->getLvObj();
|
||||
|
||||
lv_obj_add_flag(value_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(func_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(cust_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
value_edit->hide();
|
||||
func_choice->hide();
|
||||
cust_choice->hide();
|
||||
|
||||
switch (ref->type) {
|
||||
case CURVE_REF_DIFF:
|
||||
case CURVE_REF_EXPO:
|
||||
lv_obj_clear_flag(value_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
act_field = value_edit;
|
||||
break;
|
||||
|
||||
case CURVE_REF_FUNC:
|
||||
lv_obj_clear_flag(func_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
act_field = func_choice;
|
||||
break;
|
||||
|
||||
case CURVE_REF_CUSTOM:
|
||||
lv_obj_clear_flag(cust_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
act_field = cust_choice;
|
||||
break;
|
||||
|
||||
@@ -116,6 +109,8 @@ void CurveParam::update()
|
||||
return;
|
||||
}
|
||||
|
||||
act_field->show();
|
||||
|
||||
auto act_obj = act_field->getLvObj();
|
||||
if (has_focus) {
|
||||
lv_group_focus_obj(act_obj);
|
||||
|
||||
@@ -20,58 +20,72 @@
|
||||
*/
|
||||
|
||||
#include "curveedit.h"
|
||||
#include "opentx.h" // TODO for applyCustomCurve
|
||||
|
||||
#include "libopenui.h"
|
||||
#include "opentx.h" // TODO for applyCustomCurve
|
||||
#include "themes/etx_lv_theme.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
static const lv_coord_t default_col_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t default_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t default_col_dsc[] = {LV_GRID_CONTENT,
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t default_row_dsc[] = {LV_GRID_CONTENT,
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
CurveDataEdit::CurveDataEdit(Window * parent, const rect_t & rect, uint8_t index) :
|
||||
Window(parent, rect),
|
||||
index(index)
|
||||
CurveDataEdit::CurveDataEdit(Window* parent, const rect_t& rect,
|
||||
uint8_t index) :
|
||||
Window(parent, rect), index(index)
|
||||
{
|
||||
lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_SECONDARY3), 0);
|
||||
lv_obj_set_scrollbar_mode(lvobj, LV_SCROLLBAR_MODE_AUTO);
|
||||
etx_scrollbar(lvobj);
|
||||
}
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
#define NUM_BTN_WIDTH 44
|
||||
#define NUM_BTN_WIDTH 44
|
||||
#else
|
||||
#define NUM_BTN_WIDTH 48
|
||||
#define NUM_BTN_WIDTH 48
|
||||
#endif
|
||||
|
||||
void CurveDataEdit::curvePointsRow(FormWindow::Line* parent, int start, int count, int curvePointsCount, bool isCustom)
|
||||
void CurveDataEdit::curvePointsRow(FormLine* parent, int start, int count,
|
||||
int curvePointsCount, bool isCustom)
|
||||
{
|
||||
static const lv_coord_t points_col_dsc[] = {11, LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t points_col_dsc[] = {11,
|
||||
LV_GRID_FR(1),
|
||||
LV_GRID_FR(1),
|
||||
LV_GRID_FR(1),
|
||||
LV_GRID_FR(1),
|
||||
LV_GRID_FR(1),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
auto form = new FormWindow(parent, rect_t{});
|
||||
form->padAll(0);
|
||||
auto form = new Window(parent, rect_t{});
|
||||
form->padAll(PAD_ZERO);
|
||||
form->setFlexLayout();
|
||||
|
||||
FlexGridLayout grid(points_col_dsc, default_row_dsc, 4);
|
||||
|
||||
auto line = form->newLine(&grid);
|
||||
line->padAll(0);
|
||||
FlexGridLayout grid(points_col_dsc, default_row_dsc);
|
||||
|
||||
auto line = form->newLine(grid);
|
||||
line->padTop(-4);
|
||||
line->padBottom(0);
|
||||
line->padLeft(4);
|
||||
line->padRight(4);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
line->setHeight(12);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN,
|
||||
LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
|
||||
new StaticText(line, rect_t{}, "", CENTERED|COLOR_THEME_PRIMARY1);
|
||||
|
||||
// Point number
|
||||
grid.nextCell();
|
||||
for (int i = 0; i < count; i++) {
|
||||
new StaticText(line, rect_t{}, std::to_string(i + start + 1), 0, FONT(XS) | CENTERED | COLOR_THEME_PRIMARY1);
|
||||
(new StaticText(line, rect_t{}, std::to_string(i + start + 1),
|
||||
FONT(XS) | CENTERED | COLOR_THEME_PRIMARY1))
|
||||
->setHeight(10);
|
||||
}
|
||||
|
||||
line = form->newLine(&grid);
|
||||
line->padAll(2);
|
||||
line->padLeft(4);
|
||||
line->padRight(4);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
line = form->newLine(grid);
|
||||
line->padAll(PAD_TINY);
|
||||
line->setHeight(36);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN,
|
||||
LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
|
||||
new StaticText(line, rect_t{}, "X", 0, CENTERED|COLOR_THEME_PRIMARY1);
|
||||
new StaticText(line, rect_t{}, "X", CENTERED | COLOR_THEME_PRIMARY1);
|
||||
|
||||
int8_t* points = curveAddress(index);
|
||||
|
||||
@@ -80,7 +94,9 @@ void CurveDataEdit::curvePointsRow(FormWindow::Line* parent, int start, int coun
|
||||
uint8_t i = 0;
|
||||
uint8_t c = count;
|
||||
if (start == 0) {
|
||||
new StaticText(line, rect_t{}, "-100", 0, CENTERED | COLOR_THEME_SECONDARY1);
|
||||
(new StaticText(line, rect_t{}, "-100",
|
||||
CENTERED | COLOR_THEME_SECONDARY1))
|
||||
->padTop(1);
|
||||
i += 1;
|
||||
}
|
||||
if ((start + count) == curvePointsCount) {
|
||||
@@ -90,56 +106,61 @@ void CurveDataEdit::curvePointsRow(FormWindow::Line* parent, int start, int coun
|
||||
for (; i < c; i++) {
|
||||
uint8_t px = i + start - 1;
|
||||
numEditX[px] = new NumberEdit(
|
||||
line, rect_t{ 0, 0, NUM_BTN_WIDTH, 0 },
|
||||
line, rect_t{0, 0, NUM_BTN_WIDTH, 0},
|
||||
(px == 0) ? -100 : points[curvePointsCount + px - 1],
|
||||
(px == curvePointsCount - 3) ? 100 : points[curvePointsCount + px + 1],
|
||||
(px == curvePointsCount - 3) ? 100
|
||||
: points[curvePointsCount + px + 1],
|
||||
GET_VALUE(points[curvePointsCount + px]),
|
||||
[=](int32_t newValue) {
|
||||
points[curvePointsCount + px] = newValue;
|
||||
points[curvePointsCount + px] = newValue;
|
||||
if (px > 0) {
|
||||
numEditX[px-1]->setMax(newValue);
|
||||
numEditX[px - 1]->setMax(newValue);
|
||||
}
|
||||
if (px < curvePointsCount - 3) {
|
||||
numEditX[px+1]->setMin(newValue);
|
||||
numEditX[px + 1]->setMin(newValue);
|
||||
}
|
||||
SET_DIRTY();
|
||||
curveEdit->updatePreview();
|
||||
},
|
||||
0, RIGHT);
|
||||
lv_obj_set_grid_cell(numEditX[px]->getLvObj(), LV_GRID_ALIGN_CENTER, i+1, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
lv_textarea_set_align(numEditX[px]->getLvObj(), LV_TEXT_ALIGN_CENTER);
|
||||
});
|
||||
lv_obj_set_grid_cell(numEditX[px]->getLvObj(), LV_GRID_ALIGN_CENTER,
|
||||
i + 1, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
lv_textarea_set_align(numEditX[px]->getLvObj(), LV_TEXT_ALIGN_CENTER);
|
||||
}
|
||||
if ((start + count) == curvePointsCount) {
|
||||
new StaticText(line, rect_t{}, "100", 0, CENTERED | COLOR_THEME_SECONDARY1);
|
||||
(new StaticText(line, rect_t{}, "100",
|
||||
CENTERED | COLOR_THEME_SECONDARY1))
|
||||
->padTop(1);
|
||||
}
|
||||
} else {
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
new StaticText(line, rect_t{},
|
||||
std::to_string(-100 + (200 * (i + start)) / (curvePointsCount - 1)),
|
||||
0, CENTERED | COLOR_THEME_SECONDARY1);
|
||||
(new StaticText(
|
||||
line, rect_t{0, 1, 0, 0},
|
||||
std::to_string(-100 + (200 * (i + start)) / (curvePointsCount - 1)),
|
||||
CENTERED | COLOR_THEME_SECONDARY1))
|
||||
->padTop(1);
|
||||
}
|
||||
}
|
||||
|
||||
line = form->newLine(&grid);
|
||||
line->padAll(2);
|
||||
line->padLeft(4);
|
||||
line->padRight(4);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
line = form->newLine(grid);
|
||||
line->padAll(PAD_TINY);
|
||||
line->setHeight(36);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN,
|
||||
LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
|
||||
new StaticText(line, rect_t{}, "Y", 0, CENTERED|COLOR_THEME_PRIMARY1);
|
||||
new StaticText(line, rect_t{}, "Y", CENTERED | COLOR_THEME_PRIMARY1);
|
||||
|
||||
// y value
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
auto numedit = new NumberEdit(
|
||||
line, rect_t{ 0, 0, NUM_BTN_WIDTH, 0 },
|
||||
-100, 100, GET_VALUE(points[i+start]),
|
||||
line, rect_t{0, 0, NUM_BTN_WIDTH, 0}, -100, 100,
|
||||
GET_VALUE(points[i + start]),
|
||||
[=](int32_t newValue) {
|
||||
points[i+start] = newValue;
|
||||
points[i + start] = newValue;
|
||||
SET_DIRTY();
|
||||
curveEdit->updatePreview();
|
||||
},
|
||||
0, RIGHT);
|
||||
lv_obj_set_grid_cell(numedit->getLvObj(), LV_GRID_ALIGN_CENTER, i+1, 1, LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
});
|
||||
lv_obj_set_grid_cell(numedit->getLvObj(), LV_GRID_ALIGN_CENTER, i + 1, 1,
|
||||
LV_GRID_ALIGN_CENTER, 0, 1);
|
||||
lv_textarea_set_align(numedit->getLvObj(), LV_TEXT_ALIGN_CENTER);
|
||||
}
|
||||
}
|
||||
@@ -150,23 +171,25 @@ void CurveDataEdit::update()
|
||||
|
||||
memset(numEditX, 0, sizeof(numEditX));
|
||||
|
||||
auto form = new FormWindow(this, rect_t{});
|
||||
form->padAll(0);
|
||||
auto form = new Window(this, rect_t{});
|
||||
form->padAll(PAD_ZERO);
|
||||
form->padBottom(4);
|
||||
form->setFlexLayout();
|
||||
|
||||
FlexGridLayout grid(default_col_dsc, default_row_dsc, 4);
|
||||
FlexGridLayout grid(default_col_dsc, default_row_dsc);
|
||||
|
||||
CurveHeader & curve = g_model.curves[index];
|
||||
CurveHeader& curve = g_model.curves[index];
|
||||
uint8_t curvePointsCount = 5 + curve.points;
|
||||
|
||||
for (int i = 0; i < curvePointsCount; i += 5) {
|
||||
int count = 5;
|
||||
if (i + count > curvePointsCount) count = curvePointsCount - i;
|
||||
auto line = form->newLine(&grid);
|
||||
line->padAll(0);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
curvePointsRow(line, i, count, curvePointsCount, curve.type == CURVE_TYPE_CUSTOM);
|
||||
auto line = form->newLine(grid);
|
||||
line->padAll(PAD_ZERO);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN,
|
||||
LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
curvePointsRow(line, i, count, curvePointsCount,
|
||||
curve.type == CURVE_TYPE_CUSTOM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,16 +206,16 @@ mixsrc_t CurveEdit::currentSource = 0;
|
||||
bool CurveEdit::lockSource = false;
|
||||
|
||||
CurveEdit::CurveEdit(Window* parent, const rect_t& rect, uint8_t index) :
|
||||
FormField(parent, rect, NO_FOCUS),
|
||||
Window(parent, rect),
|
||||
preview(
|
||||
this, {0, 0, width(), height()},
|
||||
[=](int x) -> int { return applyCustomCurve(x, index); },
|
||||
[=]()->int {
|
||||
return getValue(CurveEdit::currentSource);
|
||||
}),
|
||||
[=]() -> int { return getValue(CurveEdit::currentSource); }),
|
||||
index(index),
|
||||
current(0)
|
||||
{
|
||||
setWindowFlag(NO_FOCUS);
|
||||
|
||||
TRACE("CurveEdit::currentSource=%d\tCurveEdit::lockSource=%d",
|
||||
CurveEdit::currentSource, CurveEdit::lockSource);
|
||||
updatePreview();
|
||||
@@ -201,11 +224,10 @@ CurveEdit::CurveEdit(Window* parent, const rect_t& rect, uint8_t index) :
|
||||
void CurveEdit::updatePreview()
|
||||
{
|
||||
preview.clearPoints();
|
||||
CurveHeader & curve = g_model.curves[index];
|
||||
CurveHeader& curve = g_model.curves[index];
|
||||
for (uint8_t i = 0; i < 5 + curve.points; i++) {
|
||||
preview.addPoint(getPoint(index, i), COLOR_THEME_SECONDARY1);
|
||||
preview.addPoint(getPoint(index, i));
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void CurveEdit::checkEvents()
|
||||
@@ -223,48 +245,46 @@ void CurveEdit::checkEvents()
|
||||
TRACE("Applied source=%d", CurveEdit::currentSource);
|
||||
}
|
||||
}
|
||||
FormField::checkEvents();
|
||||
Window::checkEvents();
|
||||
}
|
||||
|
||||
CurveEditWindow::CurveEditWindow(uint8_t index):
|
||||
Page(ICON_MODEL_CURVES),
|
||||
index(index)
|
||||
CurveEditWindow::CurveEditWindow(uint8_t index) :
|
||||
Page(ICON_MODEL_CURVES, PAD_ZERO), index(index)
|
||||
{
|
||||
buildBody(&body);
|
||||
buildHeader(&header);
|
||||
buildBody(body);
|
||||
buildHeader(header);
|
||||
}
|
||||
|
||||
void CurveEditWindow::buildHeader(Window * window)
|
||||
void CurveEditWindow::buildHeader(Window* window)
|
||||
{
|
||||
header.setTitle(STR_MENUCURVES);
|
||||
header->setTitle(STR_MENUCURVES);
|
||||
char s[16];
|
||||
strAppendStringWithIndex(s, STR_CV, index + 1);
|
||||
header.setTitle2(s);
|
||||
header->setTitle2(s);
|
||||
}
|
||||
|
||||
void CurveEditWindow::buildBody(FormWindow * window)
|
||||
void CurveEditWindow::buildBody(Window* window)
|
||||
{
|
||||
CurveHeader & curve = g_model.curves[index];
|
||||
int8_t * points = curveAddress(index);
|
||||
CurveHeader& curve = g_model.curves[index];
|
||||
int8_t* points = curveAddress(index);
|
||||
|
||||
auto form = new FormWindow(window, rect_t{});
|
||||
form->padAll(0);
|
||||
form->setFlexLayout();
|
||||
window->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO);
|
||||
|
||||
FlexGridLayout grid(default_col_dsc, default_row_dsc, 0);
|
||||
|
||||
auto line = form->newLine(&grid);
|
||||
line->padAll(0);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
FlexGridLayout grid(default_col_dsc, default_row_dsc, PAD_ZERO);
|
||||
|
||||
#if LCD_H > LCD_W // portrait
|
||||
auto line = window->newLine(grid);
|
||||
line->padAll(PAD_ZERO);
|
||||
lv_obj_set_grid_align(line->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN,
|
||||
LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
|
||||
#if LCD_H > LCD_W // portrait
|
||||
lv_obj_set_flex_flow(line->getLvObj(), LV_FLEX_FLOW_COLUMN);
|
||||
coord_t curveWidth = window->width() - 88;
|
||||
coord_t boxWidth = window->width();
|
||||
coord_t boxHeight = window->height() - curveWidth;
|
||||
#else
|
||||
lv_obj_set_flex_flow(line->getLvObj(), LV_FLEX_FLOW_ROW);
|
||||
coord_t curveWidth = window->height() - 2 * PAGE_PADDING;
|
||||
coord_t curveWidth = window->height() - 2 * PAD_MEDIUM;
|
||||
coord_t boxWidth = window->width() - curveWidth;
|
||||
coord_t boxHeight = window->height();
|
||||
#endif
|
||||
@@ -272,24 +292,26 @@ void CurveEditWindow::buildBody(FormWindow * window)
|
||||
auto box = new Window(line, rect_t{});
|
||||
box->setWidth(boxWidth);
|
||||
box->setHeight(boxHeight);
|
||||
box->padAll(0);
|
||||
box->padAll(PAD_ZERO);
|
||||
|
||||
static const lv_coord_t controls_col_dsc[] = {LV_GRID_FR(5), LV_GRID_FR(8), LV_GRID_FR(5), LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t controls_col_dsc[] = {
|
||||
LV_GRID_FR(5), LV_GRID_FR(8), LV_GRID_FR(5), LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
form = new FormWindow(box, rect_t{});
|
||||
form->padAll(0);
|
||||
form->setFlexLayout();
|
||||
auto form = new Window(box, rect_t{});
|
||||
form->padAll(PAD_ZERO);
|
||||
form->setFlexLayout(LV_FLEX_FLOW_COLUMN, PAD_ZERO);
|
||||
|
||||
FlexGridLayout iGrid(controls_col_dsc, default_row_dsc, 0);
|
||||
|
||||
auto iLine = form->newLine(&iGrid);
|
||||
iLine->padAll(4);
|
||||
iLine->padBottom(0);
|
||||
lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
FlexGridLayout iGrid(controls_col_dsc, default_row_dsc, PAD_ZERO);
|
||||
|
||||
auto iLine = form->newLine(iGrid);
|
||||
iLine->padAll(PAD_TINY);
|
||||
lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN,
|
||||
LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
|
||||
// Name
|
||||
new StaticText(iLine, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1);
|
||||
new ModelTextEdit(iLine, rect_t{0, 0, 100, 0}, curve.name, sizeof(curve.name));
|
||||
new StaticText(iLine, rect_t{}, STR_NAME);
|
||||
new ModelTextEdit(iLine, rect_t{0, 0, 100, 0}, curve.name,
|
||||
sizeof(curve.name));
|
||||
|
||||
// Smooth
|
||||
auto smooth = new TextButton(iLine, rect_t{0, 0, 70, 0}, STR_SMOOTH, [=]() {
|
||||
@@ -298,71 +320,83 @@ void CurveEditWindow::buildBody(FormWindow * window)
|
||||
return g_model.curves[index].smooth;
|
||||
});
|
||||
smooth->check(g_model.curves[index].smooth);
|
||||
|
||||
iLine = form->newLine(&iGrid);
|
||||
iLine->padAll(4);
|
||||
iLine->padBottom(0);
|
||||
lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
|
||||
iLine = form->newLine(iGrid);
|
||||
iLine->padAll(PAD_TINY);
|
||||
lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN,
|
||||
LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
|
||||
// Type
|
||||
new StaticText(iLine, rect_t{}, STR_TYPE, 0, COLOR_THEME_PRIMARY1);
|
||||
new Choice(iLine, rect_t{0, 0, 100, 0}, STR_CURVE_TYPES, 0, 1, GET_DEFAULT(g_model.curves[index].type),
|
||||
[=](int32_t newValue) {
|
||||
CurveHeader &curve = g_model.curves[index];
|
||||
if (newValue != curve.type) {
|
||||
for (int i = 1; i < 4 + curve.points; i++) {
|
||||
points[i] = calcRESXto100(applyCustomCurve(calc100toRESX(-100 + i * 200 / (4 + curve.points)), index));
|
||||
}
|
||||
if (moveCurve(index, newValue == CURVE_TYPE_CUSTOM ? 3 + curve.points : -3 - curve.points)) {
|
||||
if (newValue == CURVE_TYPE_CUSTOM) {
|
||||
resetCustomCurveX(points, 5 + curve.points);
|
||||
}
|
||||
curve.type = newValue;
|
||||
}
|
||||
SET_DIRTY();
|
||||
curveEdit->updatePreview();
|
||||
if (curveDataEdit) {
|
||||
curveDataEdit->update();
|
||||
}
|
||||
}
|
||||
});
|
||||
new StaticText(iLine, rect_t{}, STR_TYPE);
|
||||
new Choice(
|
||||
iLine, rect_t{0, 0, 100, 0}, STR_CURVE_TYPES, 0, 1,
|
||||
GET_DEFAULT(g_model.curves[index].type), [=](int32_t newValue) {
|
||||
CurveHeader& curve = g_model.curves[index];
|
||||
if (newValue != curve.type) {
|
||||
for (int i = 1; i < 4 + curve.points; i++) {
|
||||
points[i] = calcRESXto100(applyCustomCurve(
|
||||
calc100toRESX(-100 + i * 200 / (4 + curve.points)), index));
|
||||
}
|
||||
if (moveCurve(index, newValue == CURVE_TYPE_CUSTOM
|
||||
? 3 + curve.points
|
||||
: -3 - curve.points)) {
|
||||
if (newValue == CURVE_TYPE_CUSTOM) {
|
||||
resetCustomCurveX(points, 5 + curve.points);
|
||||
}
|
||||
curve.type = newValue;
|
||||
}
|
||||
SET_DIRTY();
|
||||
curveEdit->updatePreview();
|
||||
if (curveDataEdit) {
|
||||
curveDataEdit->update();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Points count
|
||||
auto edit = new NumberEdit(iLine, rect_t{0, 0, 70, 0}, 2, 17, GET_DEFAULT(g_model.curves[index].points + 5),
|
||||
[=](int32_t newValue) {
|
||||
newValue -= 5;
|
||||
CurveHeader &curve = g_model.curves[index];
|
||||
int newPoints[MAX_POINTS_PER_CURVE];
|
||||
newPoints[0] = points[0];
|
||||
newPoints[4 + newValue] = points[4 + curve.points];
|
||||
for (int i = 1; i < 4 + newValue; i++)
|
||||
newPoints[i] = calcRESXto100(applyCustomCurve(-RESX + (i * 2 * RESX) / (4 + newValue), index));
|
||||
if (moveCurve(index, (newValue - curve.points) * (curve.type == CURVE_TYPE_CUSTOM ? 2 : 1))) {
|
||||
for (int i = 0; i < 5 + newValue; i++) {
|
||||
points[i] = newPoints[i];
|
||||
if (curve.type == CURVE_TYPE_CUSTOM && i != 0 && i != 4 + newValue)
|
||||
points[5 + newValue + i - 1] = -100 + (i * 200) / (4 + newValue);
|
||||
}
|
||||
curve.points = newValue;
|
||||
SET_DIRTY();
|
||||
curveEdit->updatePreview();
|
||||
if (curveDataEdit) {
|
||||
curveDataEdit->update();
|
||||
}
|
||||
}
|
||||
});
|
||||
auto edit = new NumberEdit(
|
||||
iLine, rect_t{0, 0, 70, 0}, 2, 17,
|
||||
GET_DEFAULT(g_model.curves[index].points + 5), [=](int32_t newValue) {
|
||||
newValue -= 5;
|
||||
CurveHeader& curve = g_model.curves[index];
|
||||
int newPoints[MAX_POINTS_PER_CURVE];
|
||||
newPoints[0] = points[0];
|
||||
newPoints[4 + newValue] = points[4 + curve.points];
|
||||
for (int i = 1; i < 4 + newValue; i++)
|
||||
newPoints[i] = calcRESXto100(
|
||||
applyCustomCurve(-RESX + (i * 2 * RESX) / (4 + newValue), index));
|
||||
if (moveCurve(index, (newValue - curve.points) *
|
||||
(curve.type == CURVE_TYPE_CUSTOM ? 2 : 1))) {
|
||||
for (int i = 0; i < 5 + newValue; i++) {
|
||||
points[i] = newPoints[i];
|
||||
if (curve.type == CURVE_TYPE_CUSTOM && i != 0 && i != 4 + newValue)
|
||||
points[5 + newValue + i - 1] = -100 + (i * 200) / (4 + newValue);
|
||||
}
|
||||
curve.points = newValue;
|
||||
SET_DIRTY();
|
||||
curveEdit->updatePreview();
|
||||
if (curveDataEdit) {
|
||||
curveDataEdit->update();
|
||||
}
|
||||
}
|
||||
});
|
||||
edit->setSuffix(STR_PTS);
|
||||
edit->setDefault(5);
|
||||
|
||||
iLine = form->newLine(&iGrid);
|
||||
iLine->padAll(0);
|
||||
lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN, LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
iLine = form->newLine(iGrid);
|
||||
iLine->padAll(PAD_ZERO);
|
||||
iLine->padTop(PAD_SMALL);
|
||||
iLine->padBottom(PAD_SMALL);
|
||||
lv_obj_set_grid_align(iLine->getLvObj(), LV_GRID_ALIGN_SPACE_BETWEEN,
|
||||
LV_GRID_ALIGN_SPACE_BETWEEN);
|
||||
|
||||
curveDataEdit = new CurveDataEdit(iLine, rect_t{ 0, 0, box->width(), box->height() - 72 }, index);
|
||||
curveDataEdit = new CurveDataEdit(
|
||||
iLine, rect_t{0, 0, box->width(), box->height() - 82}, index);
|
||||
|
||||
// Curve editor
|
||||
lv_obj_set_flex_align(line->getLvObj(), LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
curveEdit = new CurveEdit(line, { 0, 0, curveWidth, curveWidth }, index);
|
||||
|
||||
lv_obj_set_flex_align(line->getLvObj(), LV_FLEX_ALIGN_CENTER,
|
||||
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_SPACE_AROUND);
|
||||
curveEdit = new CurveEdit(line, {0, 0, curveWidth, curveWidth}, index);
|
||||
|
||||
curveDataEdit->setCurveEdit(curveEdit);
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "page.h"
|
||||
#include "form.h"
|
||||
#include "window.h"
|
||||
#include "curve.h"
|
||||
|
||||
class NumberEdit;
|
||||
|
||||
class CurveEdit: public FormField
|
||||
class CurveEdit: public Window
|
||||
{
|
||||
public:
|
||||
CurveEdit(Window * parent, const rect_t & rect, uint8_t index);
|
||||
@@ -40,7 +40,7 @@ class CurveEdit: public FormField
|
||||
|
||||
preview.deleteLater(true, false);
|
||||
|
||||
FormField::deleteLater(detach, trash);
|
||||
Window::deleteLater(detach, trash);
|
||||
}
|
||||
|
||||
void updatePreview();
|
||||
@@ -73,7 +73,7 @@ class CurveDataEdit : public Window
|
||||
CurveEdit * curveEdit;
|
||||
NumberEdit* numEditX[16];
|
||||
|
||||
void curvePointsRow(FormWindow::Line* parent, int start, int count, int curvePointsCount, bool isCustom);
|
||||
void curvePointsRow(FormLine* parent, int start, int count, int curvePointsCount, bool isCustom);
|
||||
};
|
||||
|
||||
class CurveEditWindow : public Page
|
||||
@@ -87,5 +87,5 @@ class CurveEditWindow : public Page
|
||||
CurveDataEdit * curveDataEdit = nullptr;
|
||||
|
||||
void buildHeader(Window * window);
|
||||
void buildBody(FormWindow * window);
|
||||
void buildBody(Window * window);
|
||||
};
|
||||
|
||||
@@ -1,98 +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 "opentx.h"
|
||||
#include "font.h"
|
||||
|
||||
coord_t getCurveYCoord(FnFuncP fn, int x, int width)
|
||||
{
|
||||
return limit(-width, -divRoundClosest(fn(divRoundClosest(x * RESX, width)) * width, RESX), +width);
|
||||
}
|
||||
|
||||
void drawFunction(BitmapBuffer * dc, FnFuncP fn, int x, int y, int width)
|
||||
{
|
||||
int left = x - width;
|
||||
int right = x + width;
|
||||
|
||||
// Axis
|
||||
dc->drawSolidHorizontalLine(left, y, width*2+1, COLOR_THEME_DISABLED);
|
||||
dc->drawSolidVerticalLine(x, y-width, width*2, COLOR_THEME_DISABLED);
|
||||
|
||||
// Extra lines
|
||||
dc->drawVerticalLine(left+width/2, y-width, width*2, STASHED, COLOR_THEME_DISABLED);
|
||||
dc->drawVerticalLine(right-width/2, y-width, width*2, STASHED, COLOR_THEME_DISABLED);
|
||||
dc->drawHorizontalLine(left, y-width/2, width*2+1, STASHED, COLOR_THEME_DISABLED);
|
||||
dc->drawHorizontalLine(left, y+width/2, width*2+1, STASHED, COLOR_THEME_DISABLED);
|
||||
|
||||
// Outside border
|
||||
dc->drawSolidVerticalLine(left, y-width, width*2, COLOR_THEME_SECONDARY1);
|
||||
dc->drawSolidVerticalLine(right, y-width, width*2, COLOR_THEME_SECONDARY1);
|
||||
dc->drawSolidHorizontalLine(left, y-width, width*2+1, COLOR_THEME_SECONDARY1);
|
||||
dc->drawSolidHorizontalLine(left, y+width, width*2+1, COLOR_THEME_SECONDARY1);
|
||||
|
||||
coord_t prev_yv = (coord_t)-1;
|
||||
|
||||
for (int xv=-width; xv<=width; xv+=1) {
|
||||
coord_t yv = y + getCurveYCoord(fn, xv, width);
|
||||
if (prev_yv != (coord_t)-1) {
|
||||
if (prev_yv < yv) {
|
||||
for (int y=prev_yv; y<=yv; y+=1) {
|
||||
dc->drawBitmapPattern(x+xv-2, y-2, LBM_POINT, COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int y=yv; y<=prev_yv; y+=1) {
|
||||
dc->drawBitmapPattern(x+xv-2, y-2, LBM_POINT, COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_yv = yv;
|
||||
}
|
||||
}
|
||||
|
||||
void drawCurveVerticalScale(BitmapBuffer * dc, int x)
|
||||
{
|
||||
for (int i=0; i<=20; i++) {
|
||||
dc->drawSolidHorizontalLine(x, CURVE_CENTER_Y-CURVE_SIDE_WIDTH+i*CURVE_SIDE_WIDTH/10, 10, COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
|
||||
void drawCurveHorizontalScale(BitmapBuffer * dc)
|
||||
{
|
||||
for (int i=0; i<=20; i++) {
|
||||
dc->drawSolidVerticalLine(CURVE_CENTER_X-CURVE_SIDE_WIDTH+i*CURVE_SIDE_WIDTH/10, CURVE_CENTER_Y+CURVE_SIDE_WIDTH+5, 10, COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
|
||||
void drawCurveCoord(BitmapBuffer * dc, int x, int y, const char * text, bool active)
|
||||
{
|
||||
dc->drawSolidFilledRect(x, y, CURVE_COORD_WIDTH, CURVE_COORD_HEIGHT, COLOR_THEME_WARNING);
|
||||
dc->drawText(x+3+(CURVE_COORD_WIDTH - 1 - getTextWidth(text, 0, FONT(XS))) / 2, y + 1, text, LEFT|FONT(XS)|COLOR_THEME_SECONDARY3);
|
||||
if (active) {
|
||||
dc->drawBitmapPattern(x, y, LBM_CURVE_COORD_SHADOW, COLOR_THEME_SECONDARY1);
|
||||
}
|
||||
}
|
||||
|
||||
void drawCurvePoint(BitmapBuffer * dc, int x, int y, LcdFlags color)
|
||||
{
|
||||
dc->drawBitmapPattern(x, y, LBM_CURVE_POINT, color);
|
||||
dc->drawBitmapPattern(x, y, LBM_CURVE_POINT_CENTER, COLOR_THEME_SECONDARY3);
|
||||
}
|
||||
@@ -20,62 +20,51 @@
|
||||
*/
|
||||
|
||||
#include "custom_failsafe.h"
|
||||
#include "opentx.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
#include "channel_bar.h"
|
||||
#include "opentx.h"
|
||||
#include "themes/etx_lv_theme.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
class ChannelFailsafeBargraph : public Window
|
||||
{
|
||||
public:
|
||||
ChannelFailsafeBargraph(Window* parent, const rect_t& rect, uint8_t moduleIdx,
|
||||
uint8_t channel) :
|
||||
Window(parent, rect), moduleIdx(moduleIdx), channel(channel)
|
||||
ChannelFailsafeBargraph(Window* parent, const rect_t& rect, uint8_t channel) :
|
||||
Window(parent, rect), channel(channel)
|
||||
{
|
||||
etx_obj_add_style(lvobj, styles->border_thin, LV_PART_MAIN);
|
||||
etx_obj_add_style(lvobj, styles->border_color_black, LV_PART_MAIN);
|
||||
|
||||
outputsBar = new OutputChannelBar(this, {0, 1, width() - 2, BAR_HEIGHT},
|
||||
channel, false, false);
|
||||
outputsBar->hide();
|
||||
|
||||
failsafeBar = new ChannelBar(
|
||||
this, {0, BAR_HEIGHT + 3, width() - 2, BAR_HEIGHT},
|
||||
[=] { return calcRESXto100(g_model.failsafeChannels[channel]); },
|
||||
COLOR_THEME_WARNING, COLOR_THEME_WARNING);
|
||||
failsafeBar->hide();
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
invalidate();
|
||||
Window::checkEvents();
|
||||
}
|
||||
|
||||
void paint(BitmapBuffer* dc) override
|
||||
{
|
||||
int32_t failsafeValue = g_model.failsafeChannels[channel];
|
||||
int32_t channelValue = channelOutputs[channel];
|
||||
outputsBar->show(
|
||||
g_model.failsafeChannels[channel] != FAILSAFE_CHANNEL_HOLD &&
|
||||
g_model.failsafeChannels[channel] != FAILSAFE_CHANNEL_NOPULSE);
|
||||
|
||||
const int lim = g_model.extendedLimits ? 1024 * LIMIT_EXT_PERCENT / 100 : 1024;
|
||||
|
||||
coord_t x = 0;
|
||||
dc->drawRect(x, 0, width(), height());
|
||||
|
||||
if (failsafeValue == FAILSAFE_CHANNEL_HOLD ||
|
||||
failsafeValue == FAILSAFE_CHANNEL_NOPULSE)
|
||||
return;
|
||||
|
||||
const coord_t lenChannel = limit(
|
||||
(uint8_t)1, uint8_t((abs(channelValue) * width() / 2 + lim / 2) / lim),
|
||||
uint8_t(width() / 2));
|
||||
|
||||
const coord_t lenFailsafe = limit(
|
||||
(uint8_t)1, uint8_t((abs(failsafeValue) * width() / 2 + lim / 2) / lim),
|
||||
uint8_t(width() / 2));
|
||||
|
||||
x += width() / 2;
|
||||
|
||||
const coord_t xChannel = (channelValue > 0) ? x : x + 1 - lenChannel;
|
||||
const coord_t xFailsafe = (failsafeValue > 0) ? x : x + 1 - lenFailsafe;
|
||||
|
||||
dc->drawSolidFilledRect(xChannel, +2, lenChannel, (height() / 2) - 3,
|
||||
COLOR_THEME_SECONDARY1);
|
||||
|
||||
dc->drawSolidFilledRect(xFailsafe, (height() / 2) + 1, lenFailsafe,
|
||||
(height() / 2) - 3, COLOR_THEME_WARNING);
|
||||
failsafeBar->show(
|
||||
g_model.failsafeChannels[channel] != FAILSAFE_CHANNEL_HOLD &&
|
||||
g_model.failsafeChannels[channel] != FAILSAFE_CHANNEL_NOPULSE);
|
||||
}
|
||||
|
||||
protected:
|
||||
uint8_t moduleIdx;
|
||||
uint8_t channel;
|
||||
|
||||
OutputChannelBar* outputsBar = nullptr;
|
||||
ChannelBar* failsafeBar = nullptr;
|
||||
};
|
||||
|
||||
class ChannelFailsafeEdit : public NumberEdit
|
||||
@@ -94,12 +83,13 @@ class ChannelFailsafeEdit : public NumberEdit
|
||||
return formatNumberAsString(value, PREC1, 0, "", "%");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
ChannelFailsafeEdit(Window* parent, uint8_t ch, int vmin, int vmax) :
|
||||
NumberEdit(parent, rect_t{}, vmin, vmax, nullptr), channel(ch)
|
||||
NumberEdit(parent, rect_t{}, vmin, vmax, nullptr), channel(ch)
|
||||
{
|
||||
setGetValueHandler([=]() { return calcRESXto1000(g_model.failsafeChannels[ch]); });
|
||||
setGetValueHandler(
|
||||
[=]() { return calcRESXto1000(g_model.failsafeChannels[ch]); });
|
||||
setDisplayHandler([=](int) -> std::string { return getString(); });
|
||||
update();
|
||||
}
|
||||
@@ -112,11 +102,11 @@ public:
|
||||
g_model.failsafeChannels[channel] = calc1000toRESX(value);
|
||||
SET_DIRTY();
|
||||
});
|
||||
lv_obj_clear_state(lvobj, LV_STATE_DISABLED);
|
||||
enable();
|
||||
} else {
|
||||
// disable setter to avoid overwritting the value limited by vmin/vmax
|
||||
setSetValueHandler(nullptr);
|
||||
lv_obj_add_state(lvobj, LV_STATE_DISABLED);
|
||||
disable();
|
||||
}
|
||||
SET_DIRTY();
|
||||
NumberEdit::update();
|
||||
@@ -154,17 +144,16 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class ChannelFSCombo : public FormWindow
|
||||
class ChannelFSCombo : public Window
|
||||
{
|
||||
ChannelFailsafeEdit* edit = nullptr;
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
ChannelFSCombo(Window* parent, uint8_t ch, int vmin, int vmax) :
|
||||
FormWindow(parent, rect_t{})
|
||||
Window(parent, rect_t{})
|
||||
{
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_width(lvobj, LV_SIZE_CONTENT);
|
||||
|
||||
setFlexLayout(LV_FLEX_FLOW_ROW, PAD_TINY, LV_SIZE_CONTENT);
|
||||
|
||||
lv_obj_set_style_pad_column(lvobj, lv_dpx(4), 0);
|
||||
lv_obj_set_style_flex_cross_place(lvobj, LV_FLEX_ALIGN_CENTER, 0);
|
||||
|
||||
@@ -187,9 +176,8 @@ public:
|
||||
void update() { edit->update(); }
|
||||
};
|
||||
|
||||
|
||||
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3), LV_GRID_FR(3),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(3),
|
||||
LV_GRID_FR(3), LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT,
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
@@ -200,27 +188,22 @@ static void set_failsafe(lv_event_t* e)
|
||||
}
|
||||
|
||||
#if LCD_H > LCD_W
|
||||
#define FS_BARGRAPH_WIDTH (LV_DPI_DEF / 2)
|
||||
#else
|
||||
#define FS_BARGRAPH_WIDTH (LV_DPI_DEF)
|
||||
#define FS_BARGRAPH_WIDTH (LV_DPI_DEF / 2)
|
||||
#else
|
||||
#define FS_BARGRAPH_WIDTH (LV_DPI_DEF)
|
||||
#endif
|
||||
|
||||
|
||||
FailSafePage::FailSafePage(uint8_t moduleIdx) :
|
||||
Page(ICON_STATS_ANALOGS)
|
||||
FailSafePage::FailSafePage(uint8_t moduleIdx) : Page(ICON_STATS_ANALOGS)
|
||||
{
|
||||
header.setTitle(STR_FAILSAFESET);
|
||||
header->setTitle(STR_FAILSAFESET);
|
||||
|
||||
auto form = new FormWindow(&body, rect_t{});
|
||||
form->setFlexLayout();
|
||||
form->padAll(lv_dpx(8));
|
||||
form->padRow(lv_dpx(8));
|
||||
body->setFlexLayout();
|
||||
|
||||
FlexGridLayout grid(line_col_dsc, line_row_dsc, 0);
|
||||
FlexGridLayout grid(line_col_dsc, line_row_dsc, PAD_TINY);
|
||||
|
||||
auto btn = new TextButton(form, rect_t{}, STR_CHANNELS2FAILSAFE);
|
||||
auto btn = new TextButton(body, rect_t{}, STR_CHANNELS2FAILSAFE);
|
||||
lv_obj_set_width(btn->getLvObj(), lv_pct(100));
|
||||
|
||||
|
||||
btn->setPressHandler([=]() {
|
||||
setCustomFailsafe(moduleIdx);
|
||||
AUDIO_WARNING1();
|
||||
@@ -236,20 +219,18 @@ FailSafePage::FailSafePage(uint8_t moduleIdx) :
|
||||
g_model.extendedLimits ? 1024 * LIMIT_EXT_PERCENT / 100 : 1024);
|
||||
|
||||
for (int ch = start_ch; ch < end_ch; ch++) {
|
||||
|
||||
// Channel name
|
||||
auto line = form->newLine(&grid);
|
||||
auto line = body->newLine(grid);
|
||||
const char* ch_label = getSourceString(MIXSRC_FIRST_CH + ch);
|
||||
new StaticText(line, rect_t{}, ch_label, 0, COLOR_THEME_PRIMARY1);
|
||||
new StaticText(line, rect_t{}, ch_label);
|
||||
|
||||
// Channel value
|
||||
auto combo = new ChannelFSCombo(line, ch, -lim, lim);
|
||||
lv_obj_add_event_cb(btn->getLvObj(), set_failsafe, LV_EVENT_CLICKED, combo);
|
||||
|
||||
|
||||
// Channel bargraph
|
||||
auto bar = new ChannelFailsafeBargraph(line, rect_t{}, moduleIdx, ch);
|
||||
bar->setWidth(FS_BARGRAPH_WIDTH);
|
||||
bar->setHeight(LV_DPI_DEF / 5);
|
||||
auto bar = new ChannelFailsafeBargraph(
|
||||
line, rect_t{0, 0, FS_BARGRAPH_WIDTH, 32}, ch);
|
||||
lv_obj_set_style_grid_cell_x_align(bar->getLvObj(), LV_GRID_ALIGN_END, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,544 +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 "opentx.h"
|
||||
#include "lcd.h"
|
||||
#include "theme_manager.h"
|
||||
#include "libopenui.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include "hal/watchdog_driver.h"
|
||||
|
||||
coord_t drawStringWithIndex(BitmapBuffer * dc, coord_t x, coord_t y, const char * str, int idx, LcdFlags flags, const char * prefix, const char * suffix)
|
||||
{
|
||||
char s[64];
|
||||
char * tmp = (prefix ? strAppend(s, prefix) : s);
|
||||
tmp = strAppend(tmp, str);
|
||||
tmp = strAppendUnsigned(tmp, abs(idx));
|
||||
if (suffix)
|
||||
strAppend(tmp, suffix);
|
||||
return dc->drawText(x, y, s, flags);
|
||||
}
|
||||
|
||||
void drawStatusText(BitmapBuffer * dc, const char * text)
|
||||
{
|
||||
dc->drawText(MENUS_MARGIN_LEFT, MENU_FOOTER_TOP, text, COLOR_THEME_PRIMARY2);
|
||||
}
|
||||
|
||||
void drawVerticalScrollbar(BitmapBuffer * dc, coord_t x, coord_t y, coord_t h, uint16_t offset, uint16_t count, uint8_t visible)
|
||||
{
|
||||
if (visible < count) {
|
||||
dc->drawSolidVerticalLine(x, y, h, COLOR_THEME_PRIMARY3);
|
||||
coord_t yofs = (h*offset + count/2) / count;
|
||||
coord_t yhgt = (h*visible + count/2) / count;
|
||||
if (yhgt + yofs > h)
|
||||
yhgt = h - yofs;
|
||||
dc->drawSolidFilledRect(x-1, y + yofs, 3, yhgt, COLOR_THEME_FOCUS);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t _LBM_TRIM_SHADOW[] = {
|
||||
#include "mask_trim_shadow.lbm"
|
||||
};
|
||||
STATIC_LZ4_BITMAP(LBM_TRIM_SHADOW);
|
||||
|
||||
void drawTrimSquare(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags color)
|
||||
{
|
||||
dc->drawSolidFilledRect(x, y, 15, 15, color);
|
||||
dc->drawBitmapPattern(x, y, LBM_TRIM_SHADOW, COLOR_THEME_PRIMARY1);
|
||||
}
|
||||
|
||||
void drawGVarValue(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t gvar, gvar_t value, LcdFlags flags)
|
||||
{
|
||||
uint8_t prec = g_model.gvars[gvar].prec;
|
||||
if (prec > 0) {
|
||||
flags |= (prec == 1 ? PREC1 : PREC2);
|
||||
}
|
||||
drawValueWithUnit(dc, x, y, value, g_model.gvars[gvar].unit ? UNIT_PERCENT : UNIT_RAW, flags);
|
||||
}
|
||||
|
||||
void drawValueOrGVar(BitmapBuffer* dc, coord_t x, coord_t y, gvar_t value,
|
||||
gvar_t vmin, gvar_t vmax, LcdFlags flags,
|
||||
const char* suffix, gvar_t offset)
|
||||
{
|
||||
if (GV_IS_GV_VALUE(value, vmin, vmax)) {
|
||||
int index = GV_INDEX_CALC_DELTA(value, GV_GET_GV1_VALUE(vmin, vmax));
|
||||
dc->drawText(x, y, getGVarString(index), flags);
|
||||
} else {
|
||||
dc->drawNumber(x, y, value + offset, flags, 0, nullptr, suffix);
|
||||
}
|
||||
}
|
||||
|
||||
void drawSleepBitmap()
|
||||
{
|
||||
LcdFlags fgColor;
|
||||
LcdFlags bgColor;
|
||||
|
||||
if (ThemePersistance::instance()->isDefaultTheme()) {
|
||||
fgColor = COLOR2FLAGS(WHITE);
|
||||
bgColor = COLOR2FLAGS(BLACK);
|
||||
} else {
|
||||
fgColor = COLOR_THEME_PRIMARY2;
|
||||
bgColor = COLOR_THEME_SECONDARY1;
|
||||
}
|
||||
|
||||
lcdInitDirectDrawing();
|
||||
lcd->clear(bgColor);
|
||||
|
||||
const BitmapBuffer* bitmap = EdgeTxTheme::instance()->shutdown;
|
||||
if (bitmap) {
|
||||
lcd->drawMask((LCD_W - bitmap->width()) / 2, (LCD_H - bitmap->height()) / 2,
|
||||
bitmap, fgColor);
|
||||
}
|
||||
|
||||
lcdRefresh();
|
||||
}
|
||||
|
||||
#define SHUTDOWN_CIRCLE_RADIUS 75
|
||||
|
||||
const uint8_t _LBM_SHUTDOWN_CIRCLE[] = {
|
||||
#include "mask_shutdown_circle.lbm"
|
||||
};
|
||||
STATIC_LZ4_BITMAP(LBM_SHUTDOWN_CIRCLE);
|
||||
|
||||
const int8_t bmp_shutdown_xo[] = {
|
||||
0, 0, -SHUTDOWN_CIRCLE_RADIUS, -SHUTDOWN_CIRCLE_RADIUS
|
||||
};
|
||||
const int8_t bmp_shutdown_yo[] = {
|
||||
-SHUTDOWN_CIRCLE_RADIUS, 0, 0, -SHUTDOWN_CIRCLE_RADIUS
|
||||
};
|
||||
|
||||
void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration,
|
||||
const char* message)
|
||||
{
|
||||
static BitmapBuffer* shutdownSplashImg = nullptr;
|
||||
if (totalDuration == 0) return;
|
||||
|
||||
LcdFlags fgColor;
|
||||
LcdFlags bgColor;
|
||||
|
||||
if (ThemePersistance::instance()->isDefaultTheme()) {
|
||||
fgColor = COLOR2FLAGS(WHITE);
|
||||
bgColor = COLOR2FLAGS(BLACK);
|
||||
} else {
|
||||
fgColor = COLOR_THEME_PRIMARY2;
|
||||
bgColor = COLOR_THEME_SECONDARY1;
|
||||
}
|
||||
|
||||
static const BitmapBuffer* shutdown = EdgeTxTheme::instance()->shutdown;
|
||||
|
||||
lcdInitDirectDrawing();
|
||||
lcd->clear(bgColor);
|
||||
|
||||
int quarter = duration / (totalDuration / 5);
|
||||
|
||||
if (shutdown) {
|
||||
if (!sdMounted()) sdInit();
|
||||
shutdownSplashImg = BitmapBuffer::loadBitmap(
|
||||
BITMAPS_PATH "/" SHUTDOWN_SPLASH_FILE, BMP_RGB565);
|
||||
|
||||
if (shutdownSplashImg) {
|
||||
lcd->drawBitmap(0, 0, shutdownSplashImg);
|
||||
} else {
|
||||
lcd->drawMask((LCD_W - shutdown->width()) / 2,
|
||||
(LCD_H - shutdown->height()) / 2, shutdown, fgColor);
|
||||
|
||||
for (int i = 0; i <= 3 - quarter; i += 1) {
|
||||
lcd->drawBitmapPattern(
|
||||
LCD_W / 2 + bmp_shutdown_xo[i], LCD_H / 2 + bmp_shutdown_yo[i],
|
||||
LBM_SHUTDOWN_CIRCLE, fgColor, i * SHUTDOWN_CIRCLE_RADIUS,
|
||||
SHUTDOWN_CIRCLE_RADIUS);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
if (quarter >= i) {
|
||||
lcd->drawSolidFilledRect(LCD_W / 2 - 70 + 24 * i, LCD_H / 2 - 10, 20,
|
||||
20, fgColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
lcdRefresh();
|
||||
|
||||
// invalidate screen to enable quick return
|
||||
// to normal display routine
|
||||
lv_obj_invalidate(lv_scr_act());
|
||||
}
|
||||
|
||||
void drawFatalErrorScreen(const char * message)
|
||||
{
|
||||
backlightEnable(BACKLIGHT_LEVEL_MAX);
|
||||
lcdInitDirectDrawing();
|
||||
lcd->clear(COLOR2FLAGS(BLACK));
|
||||
lcd->drawText(LCD_W/2, LCD_H/2-20, message, FONT(XL)|CENTERED|COLOR2FLAGS(WHITE));
|
||||
lcdRefresh();
|
||||
|
||||
// invalidate screen to enable quick return
|
||||
// to normal display routine
|
||||
lv_obj_invalidate(lv_scr_act());
|
||||
}
|
||||
|
||||
void runFatalErrorScreen(const char * message)
|
||||
{
|
||||
lcdInitDisplayDriver();
|
||||
|
||||
while (true) {
|
||||
drawFatalErrorScreen(message);
|
||||
WDG_RESET();
|
||||
|
||||
// loop as long as PWR button is pressed
|
||||
while (true) {
|
||||
uint32_t pwr_check = pwrCheck();
|
||||
if (pwr_check == e_power_off) {
|
||||
boardOff();
|
||||
return; // only happens in SIMU, required for proper shutdown
|
||||
}
|
||||
else if (pwr_check == e_power_on) {
|
||||
break;
|
||||
}
|
||||
WDG_RESET();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawCurveRef(BitmapBuffer * dc, coord_t x, coord_t y, const CurveRef & curve, LcdFlags flags)
|
||||
{
|
||||
if (curve.value != 0) {
|
||||
switch (curve.type) {
|
||||
case CURVE_REF_DIFF:
|
||||
x = dc->drawText(x, y, "D", flags);
|
||||
drawValueOrGVar(dc, x, y, curve.value, -100, 100, LEFT | flags);
|
||||
break;
|
||||
|
||||
case CURVE_REF_EXPO:
|
||||
x = dc->drawText(x, y, "E", flags);
|
||||
drawValueOrGVar(dc, x, y, curve.value, -100, 100, LEFT | flags);
|
||||
break;
|
||||
|
||||
case CURVE_REF_FUNC:
|
||||
dc->drawText(x, y, STR_VCURVEFUNC[curve.value], flags);
|
||||
break;
|
||||
|
||||
case CURVE_REF_CUSTOM:
|
||||
dc->drawText(x, y, getCurveString(curve.value), flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawModelName(BitmapBuffer * dc, coord_t x, coord_t y, char * name, uint8_t id, LcdFlags att)
|
||||
{
|
||||
uint8_t len = sizeof(g_model.header.name);
|
||||
while (len>0 && !name[len-1]) --len;
|
||||
if (len==0) {
|
||||
drawStringWithIndex(dc, x, y, STR_MODEL, id+1, att|LEADING0);
|
||||
}
|
||||
else {
|
||||
dc->drawSizedText(x, y, name, sizeof(g_model.header.name), att);
|
||||
}
|
||||
}
|
||||
|
||||
void drawCurveName(BitmapBuffer * dc, coord_t x, coord_t y, int8_t idx, LcdFlags flags)
|
||||
{
|
||||
char s[8];
|
||||
getCurveString(s, idx);
|
||||
dc->drawText(x, y, s, flags);
|
||||
}
|
||||
|
||||
void drawSource(BitmapBuffer * dc, coord_t x, coord_t y, mixsrc_t idx, LcdFlags flags)
|
||||
{
|
||||
char s[16];
|
||||
getSourceString(s, idx);
|
||||
dc->drawText(x, y, s, flags);
|
||||
}
|
||||
|
||||
coord_t drawSwitch(BitmapBuffer * dc, coord_t x, coord_t y, int32_t idx, LcdFlags flags)
|
||||
{
|
||||
return dc->drawText(x, y, getSwitchPositionName(idx), flags);
|
||||
}
|
||||
|
||||
void drawTrimMode(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t phase, uint8_t idx, LcdFlags att)
|
||||
{
|
||||
trim_t v = getRawTrimValue(phase, idx);
|
||||
unsigned int mode = v.mode;
|
||||
unsigned int p = mode >> 1;
|
||||
|
||||
if (mode == TRIM_MODE_NONE) {
|
||||
dc->drawText(x, y, "--", att);
|
||||
} else if (mode == TRIM_MODE_3POS) {
|
||||
dc->drawText(x, y, "3P", att);
|
||||
} else {
|
||||
char s[2];
|
||||
s[0] = (mode % 2 == 0) ? ':' : '+';
|
||||
s[1] = '0'+p;
|
||||
dc->drawSizedText(x, y, s, 2, att);
|
||||
}
|
||||
}
|
||||
|
||||
void drawDate(BitmapBuffer * dc, coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags att)
|
||||
{
|
||||
bool doTwoLines = false;
|
||||
coord_t ox = x;
|
||||
|
||||
if (att & FONT(XL)) {
|
||||
att &= ~FONT_MASK;
|
||||
doTwoLines = true;
|
||||
}
|
||||
|
||||
LcdFlags fl = att|LEADING0|LEFT;
|
||||
|
||||
x = dc->drawNumber(x, y, telemetryItem.datetime.year, fl,4);
|
||||
x = dc->drawText(x, y, "-", att);
|
||||
x = dc->drawNumber(x, y, telemetryItem.datetime.month, fl, 2);
|
||||
x = dc->drawText(x, y, "-", att);
|
||||
x = dc->drawNumber(x, y, telemetryItem.datetime.day, fl, 2);
|
||||
|
||||
if (doTwoLines) {
|
||||
y += FH; x = ox;
|
||||
} else {
|
||||
x += 11;
|
||||
}
|
||||
|
||||
x = dc->drawNumber(x, y, telemetryItem.datetime.hour, fl, 2);
|
||||
x = dc->drawText(x, y, ":", att);
|
||||
x = dc->drawNumber(x, y, telemetryItem.datetime.min, fl, 2);
|
||||
x = dc->drawText(x, y, ":", att);
|
||||
dc->drawNumber(x, y, telemetryItem.datetime.sec, fl, 2);
|
||||
}
|
||||
|
||||
coord_t drawGPSCoord(BitmapBuffer * dc, coord_t x, coord_t y, int32_t value, const char * direction, LcdFlags flags, bool seconds=true)
|
||||
{
|
||||
char s[32] = {};
|
||||
uint32_t absvalue = abs(value);
|
||||
char * tmp = strAppendUnsigned(s, absvalue / 1000000);
|
||||
tmp = strAppend(tmp, "°");
|
||||
absvalue = absvalue % 1000000;
|
||||
absvalue *= 60;
|
||||
if (g_eeGeneral.gpsFormat == 0 || !seconds) {
|
||||
tmp = strAppendUnsigned(tmp, absvalue / 1000000, 2);
|
||||
*tmp++ = '\'';
|
||||
if (seconds) {
|
||||
absvalue %= 1000000;
|
||||
absvalue *= 60;
|
||||
absvalue /= 100000;
|
||||
tmp = strAppendUnsigned(tmp, absvalue / 10);
|
||||
*tmp++ = '.';
|
||||
tmp = strAppendUnsigned(tmp, absvalue % 10);
|
||||
*tmp++ = '"';
|
||||
}
|
||||
}
|
||||
else {
|
||||
tmp = strAppendUnsigned(tmp, absvalue / 1000000, 2);
|
||||
*tmp++ = '.';
|
||||
absvalue /= 1000;
|
||||
tmp = strAppendUnsigned(tmp, absvalue, 3);
|
||||
}
|
||||
*tmp++ = direction[value>=0 ? 0 : 1];
|
||||
*tmp = '\0';
|
||||
x = dc->drawText(x, y, s, flags);
|
||||
return x;
|
||||
}
|
||||
|
||||
void drawGPSPosition(BitmapBuffer * dc, coord_t x, coord_t y, int32_t longitude, int32_t latitude, LcdFlags flags)
|
||||
{
|
||||
if (flags & PREC1) {
|
||||
drawGPSCoord(dc, x, y, latitude, "NS", flags, true);
|
||||
drawGPSCoord(dc, x, y + FH, longitude, "EW", flags, true);
|
||||
} else {
|
||||
if (flags & RIGHT) {
|
||||
x = drawGPSCoord(dc, x, y, longitude, "EW", flags, true);
|
||||
drawGPSCoord(dc, x - 5, y, latitude, "NS", flags, true);
|
||||
} else {
|
||||
x = drawGPSCoord(dc, x, y, latitude, "NS", flags, true);
|
||||
drawGPSCoord(dc, x + 5, y, longitude, "EW", flags, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawGPSSensorValue(BitmapBuffer * dc, coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags flags)
|
||||
{
|
||||
drawGPSPosition(dc, x, y, telemetryItem.gps.longitude, telemetryItem.gps.latitude, flags);
|
||||
}
|
||||
|
||||
void drawSensorCustomValue(BitmapBuffer* dc, coord_t x, coord_t y,
|
||||
uint8_t sensor, int32_t value, LcdFlags flags)
|
||||
{
|
||||
if (sensor >= MAX_TELEMETRY_SENSORS) {
|
||||
// Lua luaLcdDrawChannel() can call us with a bad value
|
||||
return;
|
||||
}
|
||||
|
||||
TelemetryItem & telemetryItem = telemetryItems[sensor];
|
||||
TelemetrySensor & telemetrySensor = g_model.telemetrySensors[sensor];
|
||||
|
||||
if (telemetrySensor.unit == UNIT_DATETIME) {
|
||||
drawDate(dc, x, y, telemetryItem, flags);
|
||||
}
|
||||
else if (telemetrySensor.unit == UNIT_GPS) {
|
||||
drawGPSSensorValue(dc, x, y, telemetryItem, flags);
|
||||
}
|
||||
else if (telemetrySensor.unit == UNIT_TEXT) {
|
||||
dc->drawSizedText(x, flags & FONT(XL) ? y + 1 : y, telemetryItem.text,
|
||||
sizeof(telemetryItem.text), flags & ~FONT(XL));
|
||||
} else {
|
||||
if (telemetrySensor.prec > 0) {
|
||||
flags |= (telemetrySensor.prec==1 ? PREC1 : PREC2);
|
||||
}
|
||||
drawValueWithUnit(dc, x, y, value,
|
||||
telemetrySensor.unit == UNIT_CELLS ? UNIT_VOLTS : telemetrySensor.unit,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
|
||||
void drawTimer(BitmapBuffer * dc, coord_t x, coord_t y, int32_t tme, LcdFlags flags)
|
||||
{
|
||||
char str[LEN_TIMER_STRING];
|
||||
TimerOptions timerOptions;
|
||||
timerOptions.options = (flags & TIMEHOUR) != 0 ? SHOW_TIME : SHOW_TIMER;
|
||||
getTimerString(str, tme, timerOptions);
|
||||
dc->drawText(x, y, str, flags);
|
||||
}
|
||||
|
||||
void drawSourceValue(BitmapBuffer * dc, coord_t x, coord_t y, source_t source, LcdFlags flags)
|
||||
{
|
||||
getvalue_t value = getValue(source);
|
||||
drawSourceCustomValue(dc, x, y, source, value, flags);
|
||||
}
|
||||
|
||||
void drawSourceCustomValue(BitmapBuffer * dc, coord_t x, coord_t y, source_t source, int32_t value, LcdFlags flags)
|
||||
{
|
||||
if (source >= MIXSRC_FIRST_TELEM) {
|
||||
source = (source-MIXSRC_FIRST_TELEM) / 3;
|
||||
drawSensorCustomValue(dc, x, y, source, value, flags);
|
||||
}
|
||||
else if (source >= MIXSRC_FIRST_TIMER || source == MIXSRC_TX_TIME) {
|
||||
// TODO if (value < 0) flags |= BLINK|INVERS;
|
||||
if (source == MIXSRC_TX_TIME) flags |= TIMEHOUR;
|
||||
drawTimer(dc, x, y, value, flags);
|
||||
}
|
||||
else if (source == MIXSRC_TX_VOLTAGE) {
|
||||
dc->drawNumber(x, y, value, flags|PREC1);
|
||||
}
|
||||
#if defined(INTERNAL_GPS)
|
||||
else if (source == MIXSRC_TX_GPS) {
|
||||
if (gpsData.fix) {
|
||||
drawGPSPosition(dc, x, y, gpsData.longitude, gpsData.latitude, flags);
|
||||
}
|
||||
else {
|
||||
x = dc->drawText(x, y, "sats: ", flags);
|
||||
dc->drawNumber(x, y, gpsData.numSat, flags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(GVARS)
|
||||
else if (source >= MIXSRC_FIRST_GVAR && source <= MIXSRC_LAST_GVAR) {
|
||||
drawGVarValue(dc, x, y, source - MIXSRC_FIRST_GVAR, value, flags);
|
||||
}
|
||||
#endif
|
||||
#if defined(LUA_INPUTS)
|
||||
else if (source >= MIXSRC_FIRST_LUA && source <= MIXSRC_LAST_LUA) {
|
||||
dc->drawNumber(x, y, value, flags);
|
||||
}
|
||||
#endif
|
||||
else if (source < MIXSRC_FIRST_CH) {
|
||||
dc->drawNumber(x, y, calcRESXto100(value), flags);
|
||||
}
|
||||
else if (source <= MIXSRC_LAST_CH) {
|
||||
if (g_eeGeneral.ppmunit == PPM_PERCENT_PREC1) {
|
||||
dc->drawNumber(x, y, calcRESXto1000(value), flags|PREC1);
|
||||
} else {
|
||||
dc->drawNumber(x, y, calcRESXto100(value), flags);
|
||||
}
|
||||
}
|
||||
else {
|
||||
dc->drawNumber(x, y, value, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void drawValueWithUnit(BitmapBuffer * dc, coord_t x, coord_t y, int val, uint8_t unit, LcdFlags flags)
|
||||
{
|
||||
if ((flags & NO_UNIT) || unit == UNIT_RAW) {
|
||||
dc->drawNumber(x, y, val, flags & (~NO_UNIT));
|
||||
}
|
||||
else {
|
||||
dc->drawNumber(x, y, val, flags & (~NO_UNIT), 0, nullptr, TEXT_AT_INDEX(STR_VTELEMUNIT, unit).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void drawHexNumber(BitmapBuffer * dc, coord_t x, coord_t y, uint32_t val, LcdFlags flags)
|
||||
{
|
||||
for (int i = 12; i >= 0; i -= 4) {
|
||||
char c = (val >> i) & 0x0F;
|
||||
c += (c >= 10 ? 'A' - 10 : '0');
|
||||
x = dc->drawSizedText(x, y, &c, 1, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, coord_t height, const char * str, LcdFlags flags)
|
||||
{
|
||||
coord_t x = left;
|
||||
coord_t y = top;
|
||||
coord_t line = getFontHeightCondensed(flags & 0xFFFF);
|
||||
coord_t space = getTextWidth(" ", 1, flags);
|
||||
coord_t word;
|
||||
const char * nxt = str;
|
||||
flags &= ~(VCENTERED | CENTERED | RIGHT);
|
||||
|
||||
while (true) {
|
||||
for (bool done = false; !done; nxt++) {
|
||||
switch (nxt[0]) {
|
||||
case '-':
|
||||
case '/':
|
||||
case ':':
|
||||
case '(':
|
||||
case '{':
|
||||
case '[':
|
||||
nxt++;
|
||||
case ' ':
|
||||
case '\n':
|
||||
case '\0':
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
nxt--;
|
||||
word = getTextWidth(str, nxt - str, flags);
|
||||
if (x + word > left + width && x > left) {
|
||||
x = left;
|
||||
y += line;
|
||||
}
|
||||
if (y + line > top + height) return;
|
||||
dc->drawSizedText(x, y, str, nxt - str, flags);
|
||||
x += word;
|
||||
switch (nxt[0]) {
|
||||
case '\0':
|
||||
return;
|
||||
case '\n':
|
||||
x = left;
|
||||
y += line;
|
||||
nxt++;
|
||||
break;
|
||||
case ' ':
|
||||
x += space;
|
||||
nxt++;
|
||||
}
|
||||
str = nxt;
|
||||
}
|
||||
}
|
||||
@@ -1,97 +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.
|
||||
*/
|
||||
|
||||
#ifndef _DRAW_FUNCTIONS_H_
|
||||
#define _DRAW_FUNCTIONS_H_
|
||||
|
||||
#include "dataconstants.h"
|
||||
#include "telemetry/telemetry_sensors.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// libopenui defines TIMOUR as zero
|
||||
#if !TIMEHOUR
|
||||
#undef TIMEHOUR
|
||||
#endif
|
||||
|
||||
#if !defined(TIMEHOUR)
|
||||
#define TIMEHOUR 0x2000
|
||||
#endif
|
||||
|
||||
#define OPTION_MENU_NO_FOOTER 0x01
|
||||
#define OPTION_MENU_TITLE_BAR 0x02
|
||||
#define OPTION_MENU_NO_SCROLLBAR 0x04
|
||||
|
||||
#define OPTION_SLIDER_INVERS INVERS
|
||||
#define OPTION_SLIDER_BLINK BLINK
|
||||
#define OPTION_SLIDER_VERTICAL 0x04
|
||||
#define OPTION_SLIDER_EMPTY_BAR 0x08
|
||||
#define OPTION_SLIDER_DBL_COLOR 0x10
|
||||
#define OPTION_SLIDER_TICKS 0x20
|
||||
#define OPTION_SLIDER_BIG_TICKS 0x40
|
||||
#define OPTION_SLIDER_TRIM_BUTTON 0x80
|
||||
#define OPTION_SLIDER_NUMBER_BUTTON 0x100
|
||||
#define OPTION_SLIDER_SQUARE_BUTTON 0x200
|
||||
|
||||
coord_t drawStringWithIndex(BitmapBuffer * dc, coord_t x, coord_t y, const char * str, int idx, LcdFlags flags = 0, const char * prefix = nullptr, const char * suffix = nullptr);
|
||||
void drawFatalErrorScreen(const char * message);
|
||||
void clearFatalErrorScreen();
|
||||
void runFatalErrorScreen(const char * message);
|
||||
void drawPower(coord_t x, coord_t y, int8_t dBm, LcdFlags att);
|
||||
void drawSource(BitmapBuffer * dc, coord_t x, coord_t y, mixsrc_t idx, LcdFlags flags=0);
|
||||
coord_t drawSwitch(BitmapBuffer * dc, coord_t x, coord_t y, int32_t idx, LcdFlags flags=0);
|
||||
void drawTrimMode(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t phase, uint8_t idx, LcdFlags flags = 0);
|
||||
void drawCurveRef(BitmapBuffer * dc, coord_t x, coord_t y, const CurveRef & curve, LcdFlags flags = 0);
|
||||
|
||||
#if defined(FLIGHT_MODES)
|
||||
void drawFlightMode(coord_t x, coord_t y, int8_t idx, LcdFlags att);
|
||||
#endif
|
||||
|
||||
void drawStatusText(BitmapBuffer * dc, const char * text);
|
||||
void drawVerticalScrollbar(BitmapBuffer * dc, coord_t x, coord_t y, coord_t h, uint16_t offset, uint16_t count, uint8_t visible);
|
||||
void drawProgressScreen(BitmapBuffer * dc, const char * title, const char * message, int num, int den);
|
||||
void drawTrimSquare(BitmapBuffer * dc, coord_t x, coord_t y, LcdFlags color = COLOR_THEME_FOCUS);
|
||||
void drawValueOrGVar(BitmapBuffer * dc, coord_t x, coord_t y, gvar_t value, gvar_t vmin, gvar_t vmax, LcdFlags flags = 0, const char* suffix = "%", gvar_t offset = 0);
|
||||
void drawGVarValue(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t gvar, gvar_t value, LcdFlags flags = 0);
|
||||
void drawTimer(BitmapBuffer * dc, coord_t x, coord_t y, int32_t tme, LcdFlags flags = 0);
|
||||
void drawSourceValue(BitmapBuffer * dc, coord_t x, coord_t y, source_t source, LcdFlags flags = 0);
|
||||
void drawSourceCustomValue(BitmapBuffer * dc, coord_t x, coord_t y, source_t source, int32_t value, LcdFlags flags);
|
||||
void drawSensorCustomValue(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t sensor, int32_t value, LcdFlags flags = 0);
|
||||
void drawGPSPosition(BitmapBuffer * dc, coord_t x, coord_t y, int32_t longitude, int32_t latitude, LcdFlags flags = 0);
|
||||
void drawDate(BitmapBuffer * dc, coord_t x, coord_t y, TelemetryItem & telemetryItem, LcdFlags flags = 0);
|
||||
void drawValueWithUnit(BitmapBuffer * dc, coord_t x, coord_t y, int val, uint8_t unit, LcdFlags flags = 0);
|
||||
void drawHexNumber(BitmapBuffer * dc, coord_t x, coord_t y, uint32_t val, LcdFlags flags = 0);
|
||||
void drawTextLines(BitmapBuffer * dc, coord_t left, coord_t top, coord_t width, coord_t height, const char * str, LcdFlags flags);
|
||||
inline void drawChn(BitmapBuffer * dc, coord_t x, coord_t y, uint8_t idx, LcdFlags flags)
|
||||
{
|
||||
drawSource(dc, x, y, MIXSRC_FIRST_CH + idx - 1, flags);
|
||||
}
|
||||
|
||||
// Screen templates
|
||||
void drawSplash();
|
||||
void drawSleepBitmap();
|
||||
void drawShutdownAnimation(uint32_t duration, uint32_t totalDuration, const char * message);
|
||||
void clearShutdownAnimation();
|
||||
|
||||
// Main view standard widgets
|
||||
void drawMainPots();
|
||||
void drawTrims(uint8_t flightMode);
|
||||
|
||||
#endif // _DRAW_FUNCTIONS_H_
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "file_browser.h"
|
||||
#include "libopenui_file.h"
|
||||
#include "font.h"
|
||||
#include "fonts.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
@@ -166,8 +166,6 @@ FileBrowser::FileBrowser(Window* parent, const rect_t& rect, const char* dir) :
|
||||
{
|
||||
lv_obj_add_event_cb(lvobj, fb_event, LV_EVENT_ALL, nullptr);
|
||||
|
||||
setColumnCount(1);
|
||||
|
||||
f_chdir(dir);
|
||||
|
||||
if (lv_obj_has_state(lvobj, LV_STATE_FOCUSED)) {
|
||||
|
||||
@@ -36,16 +36,19 @@ class FileBrowser : public TableField
|
||||
void refresh();
|
||||
|
||||
void adjustWidth();
|
||||
|
||||
protected:
|
||||
void onSelected(const char* name, bool is_dir);
|
||||
void onPress(const char* name, bool is_dir);
|
||||
|
||||
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;
|
||||
|
||||
// TableField methods
|
||||
void onSelected(uint16_t row, uint16_t col) override;
|
||||
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;
|
||||
|
||||
protected:
|
||||
void onSelected(const char* name, bool is_dir);
|
||||
void onPress(const char* name, bool is_dir);
|
||||
|
||||
private:
|
||||
const char* selected = nullptr;
|
||||
|
||||
@@ -18,8 +18,11 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "file_carosell.h"
|
||||
|
||||
#include "translations.h"
|
||||
|
||||
extern inline tmr10ms_t getTicks()
|
||||
{
|
||||
return g_tmr10ms;
|
||||
@@ -27,13 +30,14 @@ extern inline tmr10ms_t getTicks()
|
||||
|
||||
FileCarosell::FileCarosell(Window *parent, const rect_t &rect,
|
||||
std::vector<std::string> fileNames) :
|
||||
FormWindow(parent, rect, NO_FOCUS),
|
||||
_fileNames(fileNames),
|
||||
fp(new FilePreview(this, {0, 0, rect.w, rect.h}, false))
|
||||
Window(parent, rect),
|
||||
fp(new FilePreview(this, {0, 0, rect.w, rect.h}))
|
||||
{
|
||||
timer = getTicks();
|
||||
message = new StaticText(this, {0, rect.h/2, rect.w, PAGE_LINE_HEIGHT}, "", 0, CENTERED | FONT(L) | COLOR_THEME_PRIMARY1);
|
||||
setSelected(0);
|
||||
setWindowFlag(NO_FOCUS);
|
||||
|
||||
message = new StaticText(this, {0, rect.h/2, rect.w, PAGE_LINE_HEIGHT}, "", CENTERED | FONT(L) | COLOR_THEME_PRIMARY1);
|
||||
|
||||
setFileNames(fileNames);
|
||||
}
|
||||
|
||||
void FileCarosell::setFileNames(std::vector<std::string> fileNames)
|
||||
@@ -65,7 +69,7 @@ void FileCarosell::setSelected(int n)
|
||||
|
||||
void FileCarosell::checkEvents()
|
||||
{
|
||||
FormWindow::checkEvents();
|
||||
Window::checkEvents();
|
||||
|
||||
uint32_t newTicks = getTicks();
|
||||
|
||||
|
||||
@@ -18,16 +18,16 @@
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "color_editor.h"
|
||||
|
||||
#include "file_preview.h"
|
||||
#include "file_carosell.h"
|
||||
#include "tabsgroup.h"
|
||||
|
||||
#define PAGE_INTERVAL ((1000 / 10) * 2)
|
||||
#define SHORT_PAGE_INTERVAL ((1000 / 20)) // 500 MS
|
||||
|
||||
class FileCarosell : public FormWindow
|
||||
class FileCarosell : public Window
|
||||
{
|
||||
public:
|
||||
FileCarosell(Window *parent, const rect_t &rect,
|
||||
|
||||
@@ -20,61 +20,15 @@
|
||||
*/
|
||||
|
||||
#include "file_preview.h"
|
||||
#include "sdcard.h"
|
||||
|
||||
FilePreview::FilePreview(Window *parent, const rect_t &rect,
|
||||
bool drawCentered) :
|
||||
Window(parent, rect), _drawCentered(drawCentered)
|
||||
FilePreview::FilePreview(Window *parent, const rect_t &rect) :
|
||||
StaticImage(parent, rect)
|
||||
{
|
||||
}
|
||||
|
||||
FilePreview::~FilePreview()
|
||||
{
|
||||
if (bitmap != nullptr) delete bitmap;
|
||||
hide();
|
||||
}
|
||||
|
||||
void FilePreview::setFile(const char *filename)
|
||||
{
|
||||
if (bitmap != nullptr) delete bitmap;
|
||||
bitmap = nullptr;
|
||||
|
||||
if (filename) {
|
||||
const char *ext = getFileExtension(filename);
|
||||
if (ext && isExtensionMatching(ext, BITMAPS_EXT)) {
|
||||
bitmap = BitmapBuffer::loadBitmap(filename);
|
||||
} else {
|
||||
bitmap = nullptr;
|
||||
}
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
coord_t FilePreview::getBitmapWidth() const
|
||||
{
|
||||
if (bitmap) return bitmap->width();
|
||||
return 0;
|
||||
}
|
||||
|
||||
coord_t FilePreview::getBitmapHeight() const
|
||||
{
|
||||
if (bitmap) return bitmap->height();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FilePreview::paint(BitmapBuffer *dc)
|
||||
{
|
||||
if (!bitmap) return;
|
||||
|
||||
coord_t w = lv_obj_get_content_width(lvobj);
|
||||
coord_t h = lv_obj_get_content_height(lvobj);
|
||||
|
||||
coord_t bm_w = min<coord_t>(w, bitmap->width());
|
||||
coord_t bm_h = min<coord_t>(h, bitmap->height());
|
||||
|
||||
coord_t border_w = lv_obj_get_style_border_width(lvobj, 0);
|
||||
coord_t x = border_w + lv_obj_get_style_pad_left(lvobj, 0);
|
||||
coord_t y = border_w + lv_obj_get_style_pad_top(lvobj, 0);
|
||||
|
||||
dc->setFormat(BMP_RGB565);
|
||||
dc->drawScaledBitmap(bitmap, x + (w - bm_w) / 2, y + (h - bm_h) / 2, bm_w, bm_h);
|
||||
setSource(filename ? filename : "");
|
||||
show(hasImage());
|
||||
}
|
||||
|
||||
@@ -20,25 +20,17 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "libopenui.h"
|
||||
|
||||
class FilePreview : public Window
|
||||
class FilePreview : public StaticImage
|
||||
{
|
||||
public:
|
||||
FilePreview(Window *parent, const rect_t &rect, bool drawCentered = true);
|
||||
~FilePreview();
|
||||
FilePreview(Window *parent, const rect_t &rect);
|
||||
|
||||
#if defined(DEBUG_WINDOWS)
|
||||
std::string getName() const override { return "FilePreview"; }
|
||||
#endif
|
||||
|
||||
void setFile(const char *filename);
|
||||
coord_t getBitmapWidth() const;
|
||||
coord_t getBitmapHeight() const;
|
||||
|
||||
void paint(BitmapBuffer *dc) override;
|
||||
|
||||
protected:
|
||||
BitmapBuffer *bitmap = nullptr;
|
||||
bool _drawCentered = true;
|
||||
};
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "fm_matrix.h"
|
||||
|
||||
#include "opentx.h"
|
||||
#include "themes/etx_lv_theme.h"
|
||||
|
||||
template <class T>
|
||||
FMMatrix<T>::FMMatrix(Window* parent, const rect_t& r, T* input) :
|
||||
@@ -47,9 +48,7 @@ FMMatrix<T>::FMMatrix(Window* parent, const rect_t& r, T* input) :
|
||||
lv_obj_set_height(lvobj, 108);
|
||||
#endif
|
||||
|
||||
lv_obj_set_style_pad_all(lvobj, lv_dpx(4), LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_row(lvobj, lv_dpx(4), LV_PART_MAIN);
|
||||
lv_obj_set_style_pad_column(lvobj, lv_dpx(4), LV_PART_MAIN);
|
||||
padAll(PAD_SMALL);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "font.h"
|
||||
#include "fonts.h"
|
||||
#include "libopenui/thirdparty/lz4/lz4.h"
|
||||
#include "libopenui_defines.h"
|
||||
#include "lz4_fonts.h"
|
||||
|
||||
@@ -19,10 +19,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#include "opentx_types.h"
|
||||
|
||||
enum FontIndex {
|
||||
FONT_STD_INDEX,
|
||||
FONT_BOLD_INDEX,
|
||||
FONT_XXS_INDEX,
|
||||
FONT_XS_INDEX,
|
||||
FONT_L_INDEX,
|
||||
FONT_XL_INDEX,
|
||||
FONT_XXL_INDEX,
|
||||
|
||||
// this one MUST be last
|
||||
FONTS_COUNT
|
||||
};
|
||||
|
||||
#define FONT_MASK 0x0F00u
|
||||
#define FONT_INDEX(flags) ((FontIndex)(((flags) & FONT_MASK) >> 8u))
|
||||
#define FONT(xx) (unsigned(FONT_##xx##_INDEX) << 8u)
|
||||
|
||||
const lv_font_t* getFont(LcdFlags flags);
|
||||
uint8_t getFontHeight(LcdFlags flags);
|
||||
uint8_t getFontHeightCondensed(LcdFlags flags);
|
||||
int getTextWidth(const char * s, int len = 0, LcdFlags flags = 0);
|
||||
|
||||
int getTextWidth(const char* s, int len = 0, LcdFlags flags = 0);
|
||||
@@ -20,59 +20,64 @@
|
||||
*/
|
||||
|
||||
#include "fullscreen_dialog.h"
|
||||
|
||||
#include "LvglWrapper.h"
|
||||
#include "libopenui.h"
|
||||
#include "mainwindow.h"
|
||||
#include "opentx.h"
|
||||
#include "libopenui.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include "themes/etx_lv_theme.h"
|
||||
#include "view_main.h"
|
||||
#include "hal/watchdog_driver.h"
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
constexpr uint32_t ALERT_FRAME_TOP = 50;
|
||||
constexpr uint32_t ALERT_FRAME_HEIGHT = (LCD_H - 120);
|
||||
constexpr uint32_t ALERT_BITMAP_TOP = ALERT_FRAME_TOP + 25;
|
||||
constexpr uint32_t ALERT_BITMAP_LEFT = 20;
|
||||
constexpr uint32_t ALERT_TITLE_TOP = ALERT_FRAME_TOP + 5;
|
||||
constexpr uint32_t ALERT_TITLE_LEFT = 146;
|
||||
constexpr uint32_t ALERT_MESSAGE_TOP = ALERT_TITLE_TOP + 85;
|
||||
constexpr uint32_t ALERT_MESSAGE_LEFT = ALERT_TITLE_LEFT;
|
||||
constexpr uint32_t ALERT_FRAME_TOP = 50;
|
||||
constexpr uint32_t ALERT_FRAME_HEIGHT = (LCD_H - 120);
|
||||
constexpr uint32_t ALERT_BITMAP_TOP = ALERT_FRAME_TOP + 25;
|
||||
constexpr uint32_t ALERT_BITMAP_LEFT = 20;
|
||||
constexpr uint32_t ALERT_TITLE_TOP = ALERT_FRAME_TOP + 5;
|
||||
constexpr uint32_t ALERT_TITLE_LEFT = 146;
|
||||
constexpr uint32_t ALERT_MESSAGE_TOP = ALERT_TITLE_TOP + 85;
|
||||
constexpr uint32_t ALERT_MESSAGE_LEFT = ALERT_TITLE_LEFT;
|
||||
#else
|
||||
constexpr uint32_t ALERT_FRAME_TOP = 70;
|
||||
constexpr uint32_t ALERT_FRAME_HEIGHT = (LCD_H - 2 * ALERT_FRAME_TOP);
|
||||
constexpr uint32_t ALERT_BITMAP_TOP = ALERT_FRAME_TOP + 15;
|
||||
constexpr uint32_t ALERT_BITMAP_LEFT = 15;
|
||||
constexpr uint32_t ALERT_TITLE_TOP = ALERT_FRAME_TOP + 10;
|
||||
constexpr uint32_t ALERT_TITLE_LEFT = 140;
|
||||
constexpr uint32_t ALERT_MESSAGE_TOP = ALERT_TITLE_TOP + 130;
|
||||
constexpr uint32_t ALERT_MESSAGE_LEFT = 15;
|
||||
constexpr uint32_t ALERT_FRAME_TOP = 70;
|
||||
constexpr uint32_t ALERT_FRAME_HEIGHT = (LCD_H - 2 * ALERT_FRAME_TOP);
|
||||
constexpr uint32_t ALERT_BITMAP_TOP = ALERT_FRAME_TOP + 15;
|
||||
constexpr uint32_t ALERT_BITMAP_LEFT = 15;
|
||||
constexpr uint32_t ALERT_TITLE_TOP = ALERT_FRAME_TOP + 10;
|
||||
constexpr uint32_t ALERT_TITLE_LEFT = 140;
|
||||
constexpr uint32_t ALERT_MESSAGE_TOP = ALERT_TITLE_TOP + 130;
|
||||
constexpr uint32_t ALERT_MESSAGE_LEFT = 15;
|
||||
#endif
|
||||
|
||||
static Window* _get_parent()
|
||||
{
|
||||
Window* p = Layer::back();
|
||||
if (!p) p = MainWindow::instance();
|
||||
return p;
|
||||
}
|
||||
|
||||
FullScreenDialog::FullScreenDialog(
|
||||
uint8_t type, std::string title, std::string message, std::string action,
|
||||
const std::function<void(void)>& confirmHandler) :
|
||||
Window(_get_parent(), {0, 0, LCD_W, LCD_H}, OPAQUE),
|
||||
Window(MainWindow::instance(), {0, 0, LCD_W, LCD_H}),
|
||||
type(type),
|
||||
title(std::move(title)),
|
||||
message(std::move(message)),
|
||||
action(std::move(action)),
|
||||
confirmHandler(confirmHandler)
|
||||
{
|
||||
setWindowFlag(OPAQUE);
|
||||
|
||||
// In case alert raised while splash screen is showing.
|
||||
cancelSplash();
|
||||
|
||||
Window* p = Layer::back();
|
||||
if (p) p->hide();
|
||||
|
||||
Layer::push(this);
|
||||
|
||||
bringToTop();
|
||||
|
||||
build();
|
||||
|
||||
lv_obj_add_event_cb(lvobj, FullScreenDialog::long_pressed, LV_EVENT_LONG_PRESSED, nullptr);
|
||||
lv_obj_add_event_cb(lvobj, FullScreenDialog::on_draw, LV_EVENT_DRAW_MAIN_BEGIN, nullptr);
|
||||
lv_obj_add_event_cb(lvobj, FullScreenDialog::long_pressed,
|
||||
LV_EVENT_LONG_PRESSED, nullptr);
|
||||
lv_obj_add_event_cb(lvobj, FullScreenDialog::on_draw,
|
||||
LV_EVENT_DRAW_MAIN_BEGIN, nullptr);
|
||||
}
|
||||
|
||||
void FullScreenDialog::on_draw(lv_event_t* e)
|
||||
@@ -88,9 +93,20 @@ void FullScreenDialog::on_draw(lv_event_t* e)
|
||||
|
||||
void FullScreenDialog::build()
|
||||
{
|
||||
auto div = new Window(this, {0, ALERT_FRAME_TOP, LCD_W, ALERT_FRAME_HEIGHT});
|
||||
div->setWindowFlag(NO_FOCUS);
|
||||
etx_bg_color(div->getLvObj(), COLOR_THEME_PRIMARY2_INDEX);
|
||||
etx_obj_add_style(div->getLvObj(), styles->bg_opacity_50, LV_PART_MAIN);
|
||||
|
||||
new StaticIcon(
|
||||
this, ALERT_BITMAP_LEFT, ALERT_BITMAP_TOP,
|
||||
(type == WARNING_TYPE_INFO) ? ICON_BUSY : ICON_ERROR,
|
||||
COLOR_THEME_WARNING);
|
||||
|
||||
std::string t;
|
||||
if (type == WARNING_TYPE_ALERT) {
|
||||
#if defined(TRANSLATIONS_FR) || defined(TRANSLATIONS_IT) || defined(TRANSLATIONS_CZ)
|
||||
#if defined(TRANSLATIONS_FR) || defined(TRANSLATIONS_IT) || \
|
||||
defined(TRANSLATIONS_CZ)
|
||||
t = std::string(STR_WARNING) + "\n" + title;
|
||||
#else
|
||||
t = title + "\n" + STR_WARNING;
|
||||
@@ -98,69 +114,54 @@ void FullScreenDialog::build()
|
||||
} else if (!title.empty()) {
|
||||
t = title;
|
||||
}
|
||||
new StaticText(this,
|
||||
rect_t{ALERT_TITLE_LEFT, ALERT_TITLE_TOP, LCD_W - ALERT_TITLE_LEFT - PAGE_PADDING, LCD_H - ALERT_TITLE_TOP - PAGE_PADDING},
|
||||
t.c_str(), 0, COLOR_THEME_WARNING | FONT(XL));
|
||||
new StaticText(this,
|
||||
rect_t{ALERT_TITLE_LEFT, ALERT_TITLE_TOP,
|
||||
LCD_W - ALERT_TITLE_LEFT - PAD_MEDIUM,
|
||||
LCD_H - ALERT_TITLE_TOP - PAD_MEDIUM},
|
||||
t.c_str(), COLOR_THEME_WARNING | FONT(XL));
|
||||
|
||||
messageLabel = new StaticText(this,
|
||||
rect_t{ALERT_MESSAGE_LEFT, ALERT_MESSAGE_TOP, LCD_W - ALERT_MESSAGE_LEFT - PAGE_PADDING, LCD_H - ALERT_MESSAGE_TOP - PAGE_PADDING},
|
||||
message.c_str(), 0, COLOR_THEME_PRIMARY1 | FONT(BOLD));
|
||||
messageLabel =
|
||||
new StaticText(this,
|
||||
rect_t{ALERT_MESSAGE_LEFT, ALERT_MESSAGE_TOP,
|
||||
LCD_W - ALERT_MESSAGE_LEFT - PAD_MEDIUM,
|
||||
LCD_H - ALERT_MESSAGE_TOP - PAD_MEDIUM},
|
||||
message.c_str(), COLOR_THEME_PRIMARY1 | FONT(BOLD));
|
||||
|
||||
if (!action.empty()) {
|
||||
auto btn = new TextButton(this, { (LCD_W - 280) / 2, LCD_H - 48, 280, 40 }, action.c_str(),
|
||||
[=]() {
|
||||
closeDialog();
|
||||
return 0;
|
||||
}, COLOR_THEME_PRIMARY1 | FONT(BOLD));
|
||||
lv_obj_set_style_bg_color(btn->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0);
|
||||
lv_obj_set_style_bg_opa(btn->getLvObj(), LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_text_color(btn->getLvObj(), makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
auto btn = new TextButton(
|
||||
this, {(LCD_W - 280) / 2, LCD_H - 48, 280, 40}, action.c_str(),
|
||||
[=]() {
|
||||
closeDialog();
|
||||
return 0;
|
||||
});
|
||||
etx_bg_color(btn->getLvObj(), COLOR_THEME_SECONDARY3_INDEX);
|
||||
etx_txt_color(btn->getLvObj(), COLOR_THEME_PRIMARY1_INDEX);
|
||||
} else {
|
||||
if (type == WARNING_TYPE_CONFIRM) {
|
||||
auto btn = new TextButton(this, { LCD_W / 3 - 50, LCD_H - 48, 100, 40 }, STR_EXIT,
|
||||
[=]() {
|
||||
deleteLater();
|
||||
return 0;
|
||||
}, COLOR_THEME_PRIMARY1 | FONT(BOLD));
|
||||
lv_obj_set_style_bg_color(btn->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0);
|
||||
lv_obj_set_style_bg_opa(btn->getLvObj(), LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_text_color(btn->getLvObj(), makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
btn = new TextButton(this, { LCD_W * 2 / 3 - 50, LCD_H - 48, 100, 40 }, STR_OK,
|
||||
[=]() {
|
||||
closeDialog();
|
||||
return 0;
|
||||
}, COLOR_THEME_PRIMARY1 | FONT(BOLD));
|
||||
lv_obj_set_style_bg_color(btn->getLvObj(), makeLvColor(COLOR_THEME_SECONDARY3), 0);
|
||||
lv_obj_set_style_bg_opa(btn->getLvObj(), LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_text_color(btn->getLvObj(), makeLvColor(COLOR_THEME_PRIMARY1), 0);
|
||||
auto btn = new TextButton(
|
||||
this, {LCD_W / 3 - 50, LCD_H - 48, 100, 40}, STR_EXIT,
|
||||
[=]() {
|
||||
deleteLater();
|
||||
return 0;
|
||||
});
|
||||
etx_bg_color(btn->getLvObj(), COLOR_THEME_SECONDARY3_INDEX);
|
||||
etx_txt_color(btn->getLvObj(), COLOR_THEME_PRIMARY1_INDEX);
|
||||
btn = new TextButton(
|
||||
this, {LCD_W * 2 / 3 - 50, LCD_H - 48, 100, 40}, STR_OK,
|
||||
[=]() {
|
||||
closeDialog();
|
||||
return 0;
|
||||
});
|
||||
etx_bg_color(btn->getLvObj(), COLOR_THEME_SECONDARY3_INDEX);
|
||||
etx_txt_color(btn->getLvObj(), COLOR_THEME_PRIMARY1_INDEX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FullScreenDialog::paint(BitmapBuffer * dc)
|
||||
{
|
||||
EdgeTxTheme::instance()->drawBackground(dc);
|
||||
|
||||
dc->drawFilledRect(0, ALERT_FRAME_TOP, LCD_W, ALERT_FRAME_HEIGHT, SOLID,
|
||||
COLOR_THEME_PRIMARY2, OPACITY(8));
|
||||
|
||||
if (type == WARNING_TYPE_ALERT || type == WARNING_TYPE_ASTERISK) {
|
||||
dc->drawMask(ALERT_BITMAP_LEFT, ALERT_BITMAP_TOP,
|
||||
EdgeTxTheme::instance()->error, COLOR_THEME_WARNING);
|
||||
} else if (type == WARNING_TYPE_INFO) {
|
||||
dc->drawMask(ALERT_BITMAP_LEFT, ALERT_BITMAP_TOP,
|
||||
EdgeTxTheme::instance()->busy, COLOR_THEME_WARNING);
|
||||
} else { // confirmation
|
||||
dc->drawMask(ALERT_BITMAP_LEFT, ALERT_BITMAP_TOP,
|
||||
EdgeTxTheme::instance()->error, COLOR_THEME_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
void FullScreenDialog::closeDialog()
|
||||
{
|
||||
if (confirmHandler)
|
||||
confirmHandler();
|
||||
deleteLater();
|
||||
if (confirmHandler) confirmHandler();
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void FullScreenDialog::long_pressed(lv_event_t* e)
|
||||
@@ -183,10 +184,7 @@ void FullScreenDialog::onEvent(event_t event)
|
||||
}
|
||||
}
|
||||
|
||||
void FullScreenDialog::onCancel()
|
||||
{
|
||||
deleteLater();
|
||||
}
|
||||
void FullScreenDialog::onCancel() { deleteLater(); }
|
||||
|
||||
void FullScreenDialog::checkEvents()
|
||||
{
|
||||
@@ -200,11 +198,12 @@ void FullScreenDialog::deleteLater(bool detach, bool trash)
|
||||
{
|
||||
if (running) {
|
||||
running = false;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Layer::pop(this);
|
||||
Window::deleteLater(detach, trash);
|
||||
}
|
||||
Window* p = Layer::back();
|
||||
if (p) p->show();
|
||||
}
|
||||
|
||||
void FullScreenDialog::setMessage(std::string text)
|
||||
@@ -229,7 +228,7 @@ void FullScreenDialog::runForever(bool checkPwr)
|
||||
// reset input devices to avoid
|
||||
// RELEASED/CLICKED to be called in a loop
|
||||
lv_indev_reset(nullptr, nullptr);
|
||||
|
||||
|
||||
while (running) {
|
||||
resetBacklightTimeout();
|
||||
|
||||
@@ -253,7 +252,8 @@ void FullScreenDialog::runForever(bool checkPwr)
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void raiseAlert(const char * title, const char * msg, const char * action, uint8_t sound)
|
||||
void raiseAlert(const char* title, const char* msg, const char* action,
|
||||
uint8_t sound)
|
||||
{
|
||||
TRACE("raiseAlert('%s')", msg);
|
||||
AUDIO_ERROR_MESSAGE(sound);
|
||||
|
||||
@@ -19,19 +19,10 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _FULLSCREEN_DIALOG_H_
|
||||
#define _FULLSCREEN_DIALOG_H_
|
||||
#pragma once
|
||||
|
||||
#include "dialog.h"
|
||||
|
||||
enum DialogType {
|
||||
WARNING_TYPE_ALERT,
|
||||
WARNING_TYPE_ASTERISK,
|
||||
WARNING_TYPE_CONFIRM,
|
||||
WARNING_TYPE_INPUT,
|
||||
WARNING_TYPE_INFO
|
||||
};
|
||||
|
||||
class StaticText;
|
||||
|
||||
class FullScreenDialog : public Window
|
||||
@@ -50,8 +41,6 @@ class FullScreenDialog : public Window
|
||||
|
||||
void setMessage(std::string text);
|
||||
|
||||
void paint(BitmapBuffer * dc) override;
|
||||
|
||||
void onEvent(event_t event) override;
|
||||
void onCancel() override;
|
||||
|
||||
@@ -85,5 +74,3 @@ class FullScreenDialog : public Window
|
||||
static void long_pressed(lv_event_t* e);
|
||||
static void on_draw(lv_event_t* e);
|
||||
};
|
||||
|
||||
#endif // _FULLSCREEN_DIALOG_H_
|
||||
|
||||
@@ -19,26 +19,19 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _GETSET_HELPERS_H_
|
||||
#define _GETSET_HELPERS_H_
|
||||
#pragma once
|
||||
|
||||
#define GET_VALUE(value) [=] { return value; }
|
||||
#define GET_DEFAULT(value) [=] { return value; }
|
||||
#define GET_INVERTED(value) [=] { return !value; }
|
||||
#define GET_VALUE_WITH_OFFSET(value, offset) [=] { return value + offset; }
|
||||
#define GET_VALUE_WITH_BF(value, offset, bits) [=] { return bfGet(value, offset, bits); }
|
||||
|
||||
#define SET_VALUE(value, _newValue) [=](int32_t newValue) { value = _newValue; SET_DIRTY(); }
|
||||
#define SET_DEFAULT(value) [=](int32_t newValue) { value = newValue; SET_DIRTY(); }
|
||||
#define SET_INVERTED(value) [=](uint8_t newValue) { value = !newValue; SET_DIRTY(); }
|
||||
#define SET_VALUE_WITH_OFFSET(value, offset) [=](int32_t newValue) { value = newValue - offset; SET_DIRTY(); }
|
||||
#define SET_VALUE_WITH_BF(value, offset, bits) [=](uint16_t newValue) { bfSet<uint16_t>(value, newValue, offset, bits); SET_DIRTY(); }
|
||||
|
||||
#define GET_SET_DEFAULT(value) GET_DEFAULT(value), SET_DEFAULT(value)
|
||||
#define GET_SET_INVERTED(value) GET_INVERTED(value), SET_INVERTED(value)
|
||||
#define GET_SET_VALUE_WITH_OFFSET(value, offset) GET_VALUE_WITH_OFFSET(value, offset), SET_VALUE_WITH_OFFSET(value, offset)
|
||||
#define GET_SET_WITH_OFFSET(value, offset) GET_VALUE_WITH_OFFSET(value, offset), SET_VALUE_WITH_OFFSET(value, offset)
|
||||
#define GET_SET_BF(value, offset, bits) GET_VALUE_WITH_BF(value, offset, bits), SET_VALUE_WITH_BF(value, offset, bits)
|
||||
|
||||
#endif // _GETSET_HELPERS_H_
|
||||
|
||||
|
||||
@@ -1,58 +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.
|
||||
*/
|
||||
|
||||
#ifndef _GUI_H_
|
||||
#define _GUI_H_
|
||||
|
||||
#include "gui_common.h"
|
||||
#include "lcd.h"
|
||||
#include "menus.h"
|
||||
#include "popups.h"
|
||||
#include "draw_functions.h"
|
||||
#include "bitmaps.h"
|
||||
|
||||
#define LOAD_MODEL_BITMAP()
|
||||
|
||||
#if defined(FLIGHT_MODES)
|
||||
void displayFlightModes(coord_t x, coord_t y, FlightModesType value, uint8_t attr);
|
||||
FlightModesType editFlightModes(coord_t x, coord_t y, event_t event, FlightModesType value, uint8_t attr);
|
||||
#else
|
||||
#define displayFlightModes(...)
|
||||
#endif
|
||||
|
||||
// Curve functions
|
||||
coord_t getCurveYCoord(FnFuncP fn, int x, int width);
|
||||
void drawFunction(FnFuncP fn, int offset);
|
||||
void drawCurveVerticalScale(int x);
|
||||
void drawCurveHorizontalScale();
|
||||
void drawCurveCoord(int x, int y, const char * text, bool active=false);
|
||||
void drawCurvePoint(int x, int y, LcdFlags color);
|
||||
|
||||
extern WidgetsContainer * customScreens[MAX_CUSTOM_SCREENS];
|
||||
|
||||
void drawAlertBox(const char * title, const char * text, const char * action);
|
||||
void showAlertBox(const char * title, const char * text, const char * action, uint8_t sound);
|
||||
|
||||
#define IS_MAIN_VIEW_DISPLAYED() menuHandlers[0] == menuMainView
|
||||
#define IS_TELEMETRY_VIEW_DISPLAYED() false
|
||||
#define IS_OTHER_VIEW_DISPLAYED() false
|
||||
|
||||
#endif // _GUI_H_
|
||||
@@ -43,8 +43,8 @@ GVarNumberEdit::GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin,
|
||||
textFlags(textFlags),
|
||||
voffset(voffset)
|
||||
{
|
||||
padAll(PAD_TINY);
|
||||
lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_ROW_WRAP);
|
||||
lv_obj_set_style_pad_column(lvobj, lv_dpx(4), 0);
|
||||
lv_obj_set_style_flex_cross_place(lvobj, LV_FLEX_ALIGN_CENTER, 0);
|
||||
lv_obj_set_size(lvobj, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
|
||||
@@ -68,7 +68,8 @@ GVarNumberEdit::GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin,
|
||||
|
||||
num_field = new NumberEdit(
|
||||
this, rect_t{}, vmin, vmax, [=]() { return getValue() + voffset; },
|
||||
nullptr, windowFlags, textFlags);
|
||||
nullptr);
|
||||
num_field->setTextFlag(textFlags);
|
||||
num_field->setWidth(70);
|
||||
num_field->setDefault(vdefault);
|
||||
|
||||
@@ -80,7 +81,6 @@ GVarNumberEdit::GVarNumberEdit(Window* parent, const rect_t& rect, int32_t vmin,
|
||||
return GV_IS_GV_VALUE(getValue(), vmin, vmax);
|
||||
});
|
||||
m_gvBtn->check(GV_IS_GV_VALUE(getValue(), vmin, vmax));
|
||||
lv_obj_set_height(m_gvBtn->getLvObj(), lv_obj_get_height(gvar_field->getLvObj()));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -131,26 +131,23 @@ void GVarNumberEdit::update()
|
||||
{
|
||||
bool has_focus = act_field && act_field->hasFocus();
|
||||
|
||||
auto gvar_obj = gvar_field->getLvObj();
|
||||
auto num_obj = num_field->getLvObj();
|
||||
|
||||
lv_obj_add_flag(gvar_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(num_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
gvar_field->hide();
|
||||
num_field->hide();
|
||||
|
||||
int32_t value = getValue();
|
||||
if (GV_IS_GV_VALUE(value, vmin, vmax)) {
|
||||
// GVAR mode
|
||||
act_field = gvar_field;
|
||||
num_field->setSetValueHandler(nullptr);
|
||||
lv_obj_clear_flag(gvar_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_event_send(gvar_obj, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
gvar_field->show();
|
||||
lv_event_send(gvar_field->getLvObj(), LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
} else {
|
||||
// number edit mode
|
||||
act_field = num_field;
|
||||
num_field->setSetValueHandler(
|
||||
[=](int32_t newValue) { return setValue(newValue - voffset); });
|
||||
num_field->setValue(value + voffset);
|
||||
lv_obj_clear_flag(num_obj, LV_OBJ_FLAG_HIDDEN);
|
||||
num_field->show();
|
||||
}
|
||||
|
||||
if (has_focus) {
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _GVAR_NUMBEREDIT_H_
|
||||
#define _GVAR_NUMBEREDIT_H_
|
||||
#pragma once
|
||||
|
||||
#include "form.h"
|
||||
#include "choice.h"
|
||||
@@ -65,5 +64,3 @@ class GVarNumberEdit : public Window
|
||||
|
||||
static void value_changed(lv_event_t* e);
|
||||
};
|
||||
|
||||
#endif // _GVAR_NUMBEREDIT_H_
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "hw_bluetooth.h"
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_GENERAL)
|
||||
@@ -29,108 +30,79 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(3),
|
||||
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
class BTDetailsDialog : public Dialog
|
||||
class BTDetailsDialog : public BaseDialog
|
||||
{
|
||||
StaticText* l_addr;
|
||||
StaticText* r_addr;
|
||||
|
||||
void setAddr(StaticText* label, const char* addr)
|
||||
public:
|
||||
BTDetailsDialog(Window* parent) : BaseDialog(parent, STR_BLUETOOTH, true)
|
||||
{
|
||||
if (addr[0] == '\0') {
|
||||
label->setText("---");
|
||||
} else {
|
||||
label->setText(addr);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
BTDetailsDialog(Window *parent) :
|
||||
Dialog(parent, STR_BLUETOOTH, rect_t{})
|
||||
{
|
||||
setCloseWhenClickOutside(true);
|
||||
|
||||
auto form = &content->form;
|
||||
form->setFlexLayout();
|
||||
|
||||
FlexGridLayout grid(col_dsc, row_dsc);
|
||||
|
||||
if (g_eeGeneral.bluetoothMode == BLUETOOTH_TELEMETRY) {
|
||||
auto line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_BLUETOOTH_PIN_CODE, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
new StaticText(line, rect_t{}, "000000", 0, COLOR_THEME_PRIMARY1);
|
||||
auto line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_BLUETOOTH_PIN_CODE);
|
||||
new StaticText(line, rect_t{}, "000000");
|
||||
}
|
||||
|
||||
// Local MAC
|
||||
auto line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_BLUETOOTH_LOCAL_ADDR, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
l_addr = new StaticText(line, rect_t{}, "", 0, COLOR_THEME_PRIMARY1);
|
||||
auto line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_BLUETOOTH_LOCAL_ADDR);
|
||||
new DynamicText(
|
||||
line, rect_t{},
|
||||
[=]() {
|
||||
return std::string(bluetooth.localAddr[0] ? bluetooth.localAddr
|
||||
: "---");
|
||||
},
|
||||
COLOR_THEME_PRIMARY1);
|
||||
|
||||
// Remote MAC
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_BLUETOOTH_DIST_ADDR, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
r_addr = new StaticText(line, rect_t{}, "", 0, COLOR_THEME_PRIMARY1);
|
||||
|
||||
content->setWidth(LCD_W * 0.8);
|
||||
content->updateSize();
|
||||
}
|
||||
|
||||
void checkEvents() override
|
||||
{
|
||||
setAddr(l_addr, bluetooth.localAddr);
|
||||
setAddr(r_addr, bluetooth.distantAddr);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_BLUETOOTH_DIST_ADDR);
|
||||
new DynamicText(
|
||||
line, rect_t{},
|
||||
[=]() {
|
||||
return std::string(bluetooth.distantAddr[0] ? bluetooth.distantAddr
|
||||
: "---");
|
||||
},
|
||||
COLOR_THEME_PRIMARY1);
|
||||
}
|
||||
};
|
||||
|
||||
static void bt_mode_changed(lv_event_t* e)
|
||||
BluetoothConfigWindow::BluetoothConfigWindow(Window* parent, FlexGridLayout& grid)
|
||||
{
|
||||
lv_obj_t* target = lv_event_get_target(e);
|
||||
auto obj = (lv_obj_t*)lv_event_get_user_data(e);
|
||||
auto choice = (Choice*)lv_obj_get_user_data(target);
|
||||
if (!obj || !choice) return;
|
||||
auto line = parent->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_MODE);
|
||||
|
||||
if (choice->getIntValue() != BLUETOOTH_OFF) {
|
||||
lv_obj_clear_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
||||
} else {
|
||||
lv_obj_add_flag(obj, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
}
|
||||
|
||||
BluetoothConfigWindow::BluetoothConfigWindow(Window *parent) :
|
||||
FormWindow(parent, rect_t{})
|
||||
{
|
||||
setFlexLayout();
|
||||
FlexGridLayout grid(col_dsc, row_dsc, 2);
|
||||
|
||||
auto line = newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_MODE, 0, COLOR_THEME_PRIMARY1);
|
||||
|
||||
auto box = new FormWindow(line, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, lv_dpx(8));
|
||||
auto box = new Window(line, rect_t{});
|
||||
box->padAll(PAD_TINY);
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_SMALL);
|
||||
lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
|
||||
lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0);
|
||||
|
||||
auto mode = new Choice(box, rect_t{}, STR_BLUETOOTH_MODES, BLUETOOTH_OFF,
|
||||
BLUETOOTH_TRAINER, GET_SET_DEFAULT(g_eeGeneral.bluetoothMode));
|
||||
auto mode = new Choice(
|
||||
box, rect_t{}, STR_BLUETOOTH_MODES, BLUETOOTH_OFF, BLUETOOTH_TRAINER,
|
||||
GET_DEFAULT(g_eeGeneral.bluetoothMode), [=](int value) {
|
||||
g_eeGeneral.bluetoothMode = value;
|
||||
settingsBtn->show(g_eeGeneral.bluetoothMode != BLUETOOTH_OFF);
|
||||
nameEdit->show(g_eeGeneral.bluetoothMode != BLUETOOTH_OFF);
|
||||
});
|
||||
|
||||
auto btn =
|
||||
settingsBtn =
|
||||
new TextButton(box, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t {
|
||||
new BTDetailsDialog(Layer::back());
|
||||
new BTDetailsDialog(parent);
|
||||
return 0;
|
||||
});
|
||||
btn->padAll(lv_dpx(4));
|
||||
btn->setWidth(LV_DPI_DEF / 2);
|
||||
settingsBtn->show(g_eeGeneral.bluetoothMode != BLUETOOTH_OFF);
|
||||
|
||||
lv_obj_add_event_cb(mode->getLvObj(), bt_mode_changed,
|
||||
LV_EVENT_VALUE_CHANGED, btn->getLvObj());
|
||||
|
||||
// BT radio name
|
||||
line = newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_NAME, 0, COLOR_THEME_PRIMARY1);
|
||||
new RadioTextEdit(line, rect_t{}, g_eeGeneral.bluetoothName, LEN_BLUETOOTH_NAME);
|
||||
nameEdit = parent->newLine(grid);
|
||||
new StaticText(nameEdit, rect_t{}, STR_NAME);
|
||||
|
||||
lv_obj_add_event_cb(mode->getLvObj(), bt_mode_changed,
|
||||
LV_EVENT_VALUE_CHANGED, line->getLvObj());
|
||||
box = new Window(nameEdit, rect_t{});
|
||||
box->padAll(PAD_TINY);
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW_WRAP, PAD_SMALL);
|
||||
lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
|
||||
lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0);
|
||||
new RadioTextEdit(box, rect_t{}, g_eeGeneral.bluetoothName,
|
||||
LEN_BLUETOOTH_NAME);
|
||||
nameEdit->show(g_eeGeneral.bluetoothMode != BLUETOOTH_OFF);
|
||||
}
|
||||
|
||||
@@ -23,8 +23,12 @@
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class BluetoothConfigWindow : public FormWindow
|
||||
class BluetoothConfigWindow
|
||||
{
|
||||
public:
|
||||
BluetoothConfigWindow(Window* parent);
|
||||
BluetoothConfigWindow(Window* parent, FlexGridLayout& grid);
|
||||
|
||||
protected:
|
||||
Window* settingsBtn = nullptr;
|
||||
Window* nameEdit = nullptr;
|
||||
};
|
||||
|
||||
@@ -25,32 +25,16 @@
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_GENERAL)
|
||||
|
||||
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(3),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
ExternalModuleWindow::ExternalModuleWindow(Window *parent) :
|
||||
FormWindow::Line(parent), lastModule(g_eeGeneral.internalModule)
|
||||
ExternalModuleWindow::ExternalModuleWindow(Window *parent, FlexGridLayout& grid)
|
||||
{
|
||||
FlexGridLayout grid(col_dsc, row_dsc, 2);
|
||||
setLayout(&grid);
|
||||
auto line = parent->newLine(grid);
|
||||
|
||||
new StaticText(this, rect_t{}, STR_SAMPLE_MODE, 0, COLOR_THEME_PRIMARY1);
|
||||
new StaticText(line, rect_t{}, STR_SAMPLE_MODE);
|
||||
|
||||
auto box = new FormWindow(this, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
|
||||
|
||||
new Choice(box, rect_t{}, STR_SAMPLE_MODES, 0, UART_SAMPLE_MODE_MAX,
|
||||
getSampleMode, setSampleMode);
|
||||
}
|
||||
|
||||
int ExternalModuleWindow::getSampleMode() { return g_eeGeneral.uartSampleMode; }
|
||||
|
||||
void ExternalModuleWindow::setSampleMode(int modeValue)
|
||||
{
|
||||
g_eeGeneral.uartSampleMode = modeValue;
|
||||
SET_DIRTY();
|
||||
restartModule(EXTERNAL_MODULE);
|
||||
new Choice(line, rect_t{}, STR_SAMPLE_MODES, 0, UART_SAMPLE_MODE_MAX,
|
||||
GET_DEFAULT(g_eeGeneral.uartSampleMode), [=](int modeValue) {
|
||||
g_eeGeneral.uartSampleMode = modeValue;
|
||||
SET_DIRTY();
|
||||
restartModule(EXTERNAL_MODULE);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -23,15 +23,8 @@
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class ExternalModuleWindow : public FormWindow::Line
|
||||
class ExternalModuleWindow
|
||||
{
|
||||
public:
|
||||
ExternalModuleWindow(Window* parent);
|
||||
|
||||
protected:
|
||||
uint8_t lastModule = 0;
|
||||
lv_obj_t* br_box = nullptr;
|
||||
|
||||
static int getSampleMode();
|
||||
static void setSampleMode(int modeValue);
|
||||
ExternalModuleWindow(Window* parent, FlexGridLayout& grid);
|
||||
};
|
||||
|
||||
@@ -30,45 +30,45 @@
|
||||
#define SET_DIRTY() storageDirty(EE_GENERAL)
|
||||
|
||||
struct HWInputEdit : public RadioTextEdit {
|
||||
HWInputEdit(Window* parent, char* name, size_t len) :
|
||||
RadioTextEdit(parent, rect_t{}, name, len)
|
||||
HWInputEdit(Window* parent, char* name, size_t len, coord_t x = 0,
|
||||
coord_t y = 0) :
|
||||
RadioTextEdit(parent, rect_t{x, y, 64, 32}, name, len)
|
||||
{
|
||||
setWidth(LV_DPI_DEF / 2);
|
||||
}
|
||||
};
|
||||
|
||||
static const lv_coord_t col_two_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t col_three_dsc[] = {LV_GRID_FR(8), LV_GRID_FR(12), LV_GRID_FR(20),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t col_three_dsc[] = {
|
||||
LV_GRID_FR(8), LV_GRID_FR(12), LV_GRID_FR(20), LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
static const lv_coord_t pots_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(2), LV_GRID_FR(5),
|
||||
LV_GRID_FR(2), LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t pots_col_dsc[] = {LV_GRID_FR(2), LV_GRID_FR(2),
|
||||
LV_GRID_FR(5), LV_GRID_FR(2),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
#else
|
||||
static const lv_coord_t pots_col_dsc[] = {LV_GRID_FR(22), LV_GRID_FR(48), LV_GRID_FR(16),
|
||||
static const lv_coord_t pots_col_dsc[] = {LV_GRID_FR(13), LV_GRID_FR(7),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
#endif
|
||||
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
HWSticks::HWSticks(Window* parent) : FormWindow(parent, rect_t{})
|
||||
HWSticks::HWSticks(Window* parent) : Window(parent, rect_t{})
|
||||
{
|
||||
FlexGridLayout grid(col_two_dsc, row_dsc, 2);
|
||||
FlexGridLayout grid(col_two_dsc, row_dsc, PAD_TINY);
|
||||
setFlexLayout();
|
||||
|
||||
auto max_sticks = adcGetMaxInputs(ADC_INPUT_MAIN);
|
||||
for (int i = 0; i < max_sticks; i++) {
|
||||
auto line = newLine(&grid);
|
||||
new StaticText(line, rect_t{}, analogGetCanonicalName(ADC_INPUT_MAIN, i), 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
auto line = newLine(grid);
|
||||
new StaticText(line, rect_t{}, analogGetCanonicalName(ADC_INPUT_MAIN, i));
|
||||
new HWInputEdit(line, (char*)analogGetCustomLabel(ADC_INPUT_MAIN, i),
|
||||
LEN_ANA_NAME);
|
||||
}
|
||||
|
||||
#if defined(STICK_DEAD_ZONE)
|
||||
auto line = newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_DEAD_ZONE, 0, COLOR_THEME_PRIMARY1);
|
||||
auto line = newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_DEAD_ZONE);
|
||||
auto dz = new Choice(line, rect_t{}, 0, 7,
|
||||
GET_SET_DEFAULT(g_eeGeneral.stickDeadZone));
|
||||
dz->setTextHandler([](uint8_t value) {
|
||||
@@ -77,17 +77,39 @@ HWSticks::HWSticks(Window* parent) : FormWindow(parent, rect_t{})
|
||||
#endif
|
||||
}
|
||||
|
||||
HWPots::HWPots(Window* parent) : FormWindow(parent, rect_t{})
|
||||
{
|
||||
FlexGridLayout grid(pots_col_dsc, row_dsc, 2);
|
||||
setFlexLayout();
|
||||
// Absolute layout for Pots popup - due to performance issues with lv_textarea
|
||||
// in a flex layout
|
||||
#if LCD_W > LCD_H
|
||||
#define P_LBL_X 0
|
||||
#define P_LBL_W ((coord_t)((DIALOG_DEFAULT_WIDTH - 30) * 2 / 11))
|
||||
#define P_NM_X (P_LBL_X + P_LBL_W + 6)
|
||||
#define P_TYP_X (P_NM_X + 70)
|
||||
#define P_TYP_W 160
|
||||
#define P_INV_X (P_TYP_X + P_TYP_W + 6)
|
||||
#define P_INV_W 52
|
||||
#define P_Y(i) (i * 36 + 2)
|
||||
#define P_OFST_Y 0
|
||||
#else
|
||||
#define P_LBL_X 0
|
||||
#define P_LBL_W ((coord_t)((DIALOG_DEFAULT_WIDTH - 18) * 13 / 21))
|
||||
#define P_NM_X (P_LBL_X + P_LBL_W + 6)
|
||||
#define P_TYP_X 0
|
||||
#define P_TYP_W P_LBL_W
|
||||
#define P_INV_X (P_TYP_X + P_TYP_W + 6)
|
||||
#define P_INV_W 52
|
||||
#define P_Y(i) (i * 72 + 2)
|
||||
#define P_OFST_Y 36
|
||||
#endif
|
||||
|
||||
HWPots::HWPots(Window* parent) :
|
||||
Window(parent, rect_t{0, 0, DIALOG_DEFAULT_WIDTH - 12, LV_SIZE_CONTENT})
|
||||
{
|
||||
potsChanged = false;
|
||||
|
||||
setCloseHandler([=]() {
|
||||
if (potsChanged) {
|
||||
deleteCustomScreens();
|
||||
loadCustomScreens();
|
||||
LayoutFactory::deleteCustomScreens();
|
||||
LayoutFactory::loadCustomScreens();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -100,19 +122,15 @@ HWPots::HWPots(Window* parent) : FormWindow(parent, rect_t{})
|
||||
// #if !defined(SIMU) && defined(RADIO_FAMILY_T16)
|
||||
// if (!globalData.flyskygimbals && (i >= (NUM_POTS - 2))) continue;
|
||||
// #endif
|
||||
auto line = newLine(&grid);
|
||||
new StaticText(line, rect_t{}, adcGetInputLabel(ADC_INPUT_FLEX, i), 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
new StaticText(this, rect_t{P_LBL_X, P_Y(i) + 6, P_LBL_W, 32},
|
||||
adcGetInputLabel(ADC_INPUT_FLEX, i));
|
||||
|
||||
#if LCD_H > LCD_W
|
||||
line = newLine(&grid);
|
||||
#endif
|
||||
new HWInputEdit(this, (char*)analogGetCustomLabel(ADC_INPUT_FLEX, i),
|
||||
LEN_ANA_NAME, P_NM_X, P_Y(i));
|
||||
|
||||
new HWInputEdit(line, (char*)analogGetCustomLabel(ADC_INPUT_FLEX, i),
|
||||
LEN_ANA_NAME);
|
||||
auto pot = new Choice(
|
||||
line, rect_t{}, STR_POTTYPES, FLEX_NONE, FLEX_SWITCH,
|
||||
[=]() -> int { return getPotType(i); },
|
||||
this, rect_t{P_TYP_X, P_Y(i) + P_OFST_Y, P_TYP_W, 32}, STR_POTTYPES,
|
||||
FLEX_NONE, FLEX_SWITCH, [=]() -> int { return getPotType(i); },
|
||||
[=](int newValue) {
|
||||
setPotType(i, newValue);
|
||||
switchFixFlexConfig();
|
||||
@@ -122,7 +140,8 @@ HWPots::HWPots(Window* parent) : FormWindow(parent, rect_t{})
|
||||
pot->setAvailableHandler([=](int val) { return isPotTypeAvailable(val); });
|
||||
|
||||
new ToggleSwitch(
|
||||
line, rect_t{}, [=]() -> uint8_t { return (uint8_t)getPotInversion(i); },
|
||||
this, rect_t{P_INV_X, P_Y(i) + P_OFST_Y, P_INV_W, 32},
|
||||
[=]() -> uint8_t { return (uint8_t)getPotInversion(i); },
|
||||
[=](int8_t newValue) {
|
||||
setPotInversion(i, newValue);
|
||||
SET_DIRTY();
|
||||
@@ -130,11 +149,20 @@ HWPots::HWPots(Window* parent) : FormWindow(parent, rect_t{})
|
||||
}
|
||||
}
|
||||
|
||||
// Absolute layout for Switches popup - due to performance issues with
|
||||
// lv_textarea in a flex layout
|
||||
#if LCD_W > LCD_H
|
||||
#define SW_CTRL_W 86
|
||||
#else
|
||||
#define SW_CTRL_W 75
|
||||
#endif
|
||||
|
||||
class SwitchDynamicLabel : public StaticText
|
||||
{
|
||||
public:
|
||||
SwitchDynamicLabel(Window* parent, uint8_t index) :
|
||||
StaticText(parent, rect_t{}, "", 0, COLOR_THEME_PRIMARY1), index(index)
|
||||
SwitchDynamicLabel(Window* parent, uint8_t index, coord_t x, coord_t y) :
|
||||
StaticText(parent, rect_t{x, y, SW_CTRL_W, 32}, ""),
|
||||
index(index)
|
||||
{
|
||||
checkEvents();
|
||||
}
|
||||
@@ -186,38 +214,36 @@ static void flex_channel_changed(lv_event_t* e)
|
||||
}
|
||||
}
|
||||
|
||||
HWSwitches::HWSwitches(Window* parent) : FormWindow(parent, rect_t{})
|
||||
HWSwitches::HWSwitches(Window* parent) :
|
||||
Window(parent, rect_t{0, 0, DIALOG_DEFAULT_WIDTH - 12, LV_SIZE_CONTENT})
|
||||
{
|
||||
FlexGridLayout grid(col_three_dsc, row_dsc, 2);
|
||||
setFlexLayout();
|
||||
|
||||
auto max_switches = switchGetMaxSwitches();
|
||||
for (int i = 0; i < max_switches; i++) {
|
||||
auto line = newLine(&grid);
|
||||
new SwitchDynamicLabel(line, i);
|
||||
new HWInputEdit(line, (char*)switchGetCustomName(i), LEN_SWITCH_NAME);
|
||||
|
||||
auto box = new FormWindow(line, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(4));
|
||||
box->setWidth(lv_pct(45));
|
||||
new SwitchDynamicLabel(this, i, 2, i * 36 + 2);
|
||||
new HWInputEdit(this, (char*)switchGetCustomName(i), LEN_SWITCH_NAME,
|
||||
SW_CTRL_W + 8, i * 36 + 2);
|
||||
|
||||
coord_t x = SW_CTRL_W * 2 + 14;
|
||||
Choice* channel = nullptr;
|
||||
if (switchIsFlex(i)) {
|
||||
channel = new Choice(
|
||||
box, rect_t{}, -1, adcGetMaxInputs(ADC_INPUT_FLEX) - 1,
|
||||
this, rect_t{x, i * 36 + 2, SW_CTRL_W, 32}, -1,
|
||||
adcGetMaxInputs(ADC_INPUT_FLEX) - 1,
|
||||
[=]() -> int { return switchGetFlexConfig(i); },
|
||||
[=](int newValue) { switchConfigFlex(i, newValue); });
|
||||
channel->setAvailableHandler(
|
||||
[=](int val) { return val < 0 || switchIsFlexInputAvailable(i, val); });
|
||||
channel->setAvailableHandler([=](int val) {
|
||||
return val < 0 || switchIsFlexInputAvailable(i, val);
|
||||
});
|
||||
channel->setTextHandler([=](int val) -> std::string {
|
||||
if (val < 0) return STR_NONE;
|
||||
return adcGetInputLabel(ADC_INPUT_FLEX, val);
|
||||
});
|
||||
x += SW_CTRL_W + 6;
|
||||
}
|
||||
|
||||
auto sw_cfg = new Choice(
|
||||
box, rect_t{}, STR_SWTYPES, SWITCH_NONE, switchGetMaxType(i),
|
||||
[=]() -> int { return SWITCH_CONFIG(i); },
|
||||
this, rect_t{x, i * 36 + 2, SW_CTRL_W, 32}, STR_SWTYPES, SWITCH_NONE,
|
||||
switchGetMaxType(i), [=]() -> int { return SWITCH_CONFIG(i); },
|
||||
[=](int newValue) {
|
||||
swconfig_t mask = (swconfig_t)SWITCH_CONFIG_MASK(i);
|
||||
g_eeGeneral.switchConfig =
|
||||
@@ -228,7 +254,8 @@ HWSwitches::HWSwitches(Window* parent) : FormWindow(parent, rect_t{})
|
||||
|
||||
if (channel) {
|
||||
lv_obj_t* obj = channel->getLvObj();
|
||||
lv_obj_add_event_cb(obj, flex_channel_changed, LV_EVENT_VALUE_CHANGED, sw_cfg);
|
||||
lv_obj_add_event_cb(obj, flex_channel_changed, LV_EVENT_VALUE_CHANGED,
|
||||
sw_cfg);
|
||||
lv_event_send(obj, LV_EVENT_VALUE_CHANGED, NULL);
|
||||
}
|
||||
}
|
||||
@@ -236,17 +263,9 @@ HWSwitches::HWSwitches(Window* parent) : FormWindow(parent, rect_t{})
|
||||
|
||||
template <class T>
|
||||
HWInputDialog<T>::HWInputDialog(const char* title) :
|
||||
Dialog(Layer::back(), std::string(), rect_t{})
|
||||
BaseDialog(Layer::back(), title, true)
|
||||
{
|
||||
setCloseWhenClickOutside(true);
|
||||
if (title) content->setTitle(title);
|
||||
new T(&content->form);
|
||||
#if LCD_W > LCD_H
|
||||
content->setWidth(LCD_W * 0.8);
|
||||
#else
|
||||
content->setWidth(LCD_W * 0.95);
|
||||
#endif
|
||||
content->updateSize();
|
||||
new T(form);
|
||||
}
|
||||
|
||||
template struct HWInputDialog<HWSticks>;
|
||||
|
||||
@@ -25,28 +25,28 @@
|
||||
#include "dialog.h"
|
||||
#include "form.h"
|
||||
|
||||
struct HWSticks : public FormWindow {
|
||||
struct HWSticks : public Window {
|
||||
HWSticks(Window* parent);
|
||||
};
|
||||
|
||||
struct HWPots : public FormWindow {
|
||||
struct HWPots : public Window {
|
||||
HWPots(Window* parent);
|
||||
bool potsChanged;
|
||||
};
|
||||
|
||||
struct HWSwitches : public FormWindow {
|
||||
struct HWSwitches : public Window {
|
||||
HWSwitches(Window* parent);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct HWInputDialog : public Dialog {
|
||||
struct HWInputDialog : public BaseDialog {
|
||||
HWInputDialog(const char* title = nullptr);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
TextButton* makeHWInputButton(Window* parent, const char* title)
|
||||
{
|
||||
return new TextButton(parent, rect_t{}, title, [=]() {
|
||||
return new TextButton(parent, rect_t{0, 0, 100, 0}, title, [=]() {
|
||||
new HWInputDialog<T>(title);
|
||||
return 0;
|
||||
});
|
||||
|
||||
@@ -20,51 +20,32 @@
|
||||
*/
|
||||
|
||||
#include "hw_intmodule.h"
|
||||
|
||||
#include "opentx.h"
|
||||
|
||||
#if defined(CROSSFIRE)
|
||||
#include "telemetry/crossfire.h"
|
||||
#include "telemetry/crossfire.h"
|
||||
#endif
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_GENERAL)
|
||||
|
||||
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(3),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
InternalModuleWindow::InternalModuleWindow(Window *parent) :
|
||||
FormWindow::Line(parent),
|
||||
lastModule(g_eeGeneral.internalModule)
|
||||
InternalModuleWindow::InternalModuleWindow(Window *parent, FlexGridLayout& grid)
|
||||
{
|
||||
FlexGridLayout grid(col_dsc, row_dsc, 2);
|
||||
setLayout(&grid);
|
||||
|
||||
new StaticText(this, rect_t{}, STR_TYPE, 0, COLOR_THEME_PRIMARY1);
|
||||
|
||||
auto box = new FormWindow(this, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
|
||||
|
||||
auto internalModule = new Choice(
|
||||
box, rect_t{}, STR_MODULE_PROTOCOLS, MODULE_TYPE_NONE,
|
||||
MODULE_TYPE_COUNT - 1, GET_DEFAULT(g_eeGeneral.internalModule),
|
||||
[=](int type) { return setModuleType(type); });
|
||||
auto line = parent->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_TYPE);
|
||||
auto internalModule =
|
||||
new Choice(line, rect_t{}, STR_MODULE_PROTOCOLS, MODULE_TYPE_NONE,
|
||||
MODULE_TYPE_COUNT - 1, GET_DEFAULT(g_eeGeneral.internalModule),
|
||||
[=](int type) { return setModuleType(type); });
|
||||
|
||||
internalModule->setAvailableHandler(
|
||||
[](int module) { return isInternalModuleSupported(module); });
|
||||
|
||||
#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
|
||||
auto pxx1_box = new FormWindow(box, rect_t{});
|
||||
pxx1_box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
|
||||
ant_box = pxx1_box->getLvObj();
|
||||
lv_obj_set_width(ant_box, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_flex_cross_place(ant_box, LV_FLEX_ALIGN_CENTER, 0);
|
||||
|
||||
new StaticText(pxx1_box, rect_t{}, STR_ANTENNA, 0, COLOR_THEME_PRIMARY1);
|
||||
ant_box = parent->newLine(grid);
|
||||
new StaticText(ant_box, rect_t{}, STR_ANTENNA);
|
||||
new Choice(
|
||||
pxx1_box, rect_t{}, STR_ANTENNA_MODES, ANTENNA_MODE_INTERNAL,
|
||||
ant_box, rect_t{}, STR_ANTENNA_MODES, ANTENNA_MODE_INTERNAL,
|
||||
ANTENNA_MODE_EXTERNAL, GET_DEFAULT(g_eeGeneral.antennaMode),
|
||||
[](int antenna) {
|
||||
if (!isExternalAntennaEnabled() &&
|
||||
@@ -87,16 +68,18 @@ InternalModuleWindow::InternalModuleWindow(Window *parent) :
|
||||
#endif
|
||||
|
||||
#if defined(CROSSFIRE)
|
||||
auto crsf_box = new FormWindow(box, rect_t{});
|
||||
crsf_box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
|
||||
br_box = crsf_box->getLvObj();
|
||||
lv_obj_set_width(br_box, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_flex_cross_place(br_box, LV_FLEX_ALIGN_CENTER, 0);
|
||||
|
||||
new StaticText(crsf_box, rect_t{}, STR_BAUDRATE, 0, COLOR_THEME_PRIMARY1);
|
||||
new Choice(crsf_box, rect_t{}, STR_CRSF_BAUDRATE, 0,
|
||||
CROSSFIRE_MAX_INTERNAL_BAUDRATE, getBaudrate, setBaudrate);
|
||||
br_box = parent->newLine(grid);
|
||||
new StaticText(br_box, rect_t{}, STR_BAUDRATE);
|
||||
new Choice(
|
||||
br_box, rect_t{}, STR_CRSF_BAUDRATE, 0, CROSSFIRE_MAX_INTERNAL_BAUDRATE,
|
||||
[=]() {
|
||||
return CROSSFIRE_STORE_TO_INDEX(g_eeGeneral.internalModuleBaudrate);
|
||||
},
|
||||
[=](int val) {
|
||||
g_eeGeneral.internalModuleBaudrate = CROSSFIRE_INDEX_TO_STORE(val);
|
||||
restartModule(INTERNAL_MODULE);
|
||||
SET_DIRTY();
|
||||
});
|
||||
|
||||
updateBaudrateLine();
|
||||
#endif
|
||||
@@ -114,38 +97,16 @@ void InternalModuleWindow::setModuleType(int moduleType)
|
||||
SET_DIRTY();
|
||||
}
|
||||
|
||||
#if defined(CROSSFIRE)
|
||||
int InternalModuleWindow::getBaudrate()
|
||||
{
|
||||
return CROSSFIRE_STORE_TO_INDEX(g_eeGeneral.internalModuleBaudrate);
|
||||
}
|
||||
|
||||
void InternalModuleWindow::setBaudrate(int val)
|
||||
{
|
||||
g_eeGeneral.internalModuleBaudrate = CROSSFIRE_INDEX_TO_STORE(val);
|
||||
restartModule(INTERNAL_MODULE);
|
||||
SET_DIRTY();
|
||||
}
|
||||
#endif
|
||||
|
||||
void InternalModuleWindow::updateBaudrateLine()
|
||||
{
|
||||
#if defined(CROSSFIRE)
|
||||
if (isInternalModuleCrossfire()) {
|
||||
lv_obj_clear_flag(br_box, LV_OBJ_FLAG_HIDDEN);
|
||||
} else {
|
||||
lv_obj_add_flag(br_box, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
br_box->show(isInternalModuleCrossfire());
|
||||
#endif
|
||||
}
|
||||
|
||||
void InternalModuleWindow::updateAntennaLine()
|
||||
{
|
||||
#if defined(INTERNAL_MODULE_PXX1) && defined(EXTERNAL_ANTENNA)
|
||||
if (isInternalModuleAvailable(MODULE_TYPE_XJT_PXX1)) {
|
||||
lv_obj_clear_flag(ant_box, LV_OBJ_FLAG_HIDDEN);
|
||||
} else {
|
||||
lv_obj_add_flag(ant_box, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
ant_box->show(isInternalModuleAvailable(MODULE_TYPE_XJT_PXX1));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -23,20 +23,14 @@
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class InternalModuleWindow : public FormWindow::Line
|
||||
class InternalModuleWindow
|
||||
{
|
||||
public:
|
||||
InternalModuleWindow(Window *parent);
|
||||
InternalModuleWindow(Window *parent, FlexGridLayout& grid);
|
||||
|
||||
protected:
|
||||
uint8_t lastModule = 0;
|
||||
lv_obj_t* br_box = nullptr;
|
||||
lv_obj_t* ant_box = nullptr;
|
||||
|
||||
#if defined(CROSSFIRE)
|
||||
static int getBaudrate();
|
||||
static void setBaudrate(int val);
|
||||
#endif
|
||||
Window* br_box = nullptr;
|
||||
Window* ant_box = nullptr;
|
||||
|
||||
void setModuleType(int moduleType);
|
||||
void updateBaudrateLine();
|
||||
|
||||
@@ -24,26 +24,18 @@
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_GENERAL)
|
||||
|
||||
static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(3),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
SerialConfigWindow::SerialConfigWindow(Window *parent, const rect_t &rect) :
|
||||
FormWindow(parent, rect)
|
||||
SerialConfigWindow::SerialConfigWindow(Window *parent, FlexGridLayout& grid)
|
||||
{
|
||||
setFlexLayout();
|
||||
FlexGridLayout grid(col_dsc, row_dsc, 2);
|
||||
|
||||
for (uint8_t port_nr = 0; port_nr < MAX_SERIAL_PORTS; port_nr++) {
|
||||
auto port = serialGetPort(port_nr);
|
||||
if (!port || !port->name) continue;
|
||||
|
||||
auto line = newLine(&grid);
|
||||
new StaticText(line, rect_t{}, port->name, 0, COLOR_THEME_PRIMARY1);
|
||||
auto line = parent->newLine(grid);
|
||||
(new StaticText(line, rect_t{}, port->name))->padLeft(PAD_SMALL);
|
||||
|
||||
auto box = new FormWindow(line, rect_t{});
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW, lv_dpx(8));
|
||||
auto box = new Window(line, rect_t{});
|
||||
box->padAll(PAD_TINY);
|
||||
box->setFlexLayout(LV_FLEX_FLOW_ROW, PAD_MEDIUM);
|
||||
lv_obj_set_style_grid_cell_x_align(box->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
|
||||
lv_obj_set_style_flex_cross_place(box->getLvObj(), LV_FLEX_ALIGN_CENTER, 0);
|
||||
|
||||
@@ -59,8 +51,7 @@ SerialConfigWindow::SerialConfigWindow(Window *parent, const rect_t &rect) :
|
||||
[=](int value) { return isSerialModeAvailable(port_nr, value); });
|
||||
|
||||
if (port->set_pwr != nullptr) {
|
||||
new StaticText(box, rect_t{}, STR_AUX_SERIAL_PORT_POWER, 0,
|
||||
COLOR_THEME_PRIMARY1);
|
||||
new StaticText(box, rect_t{}, STR_AUX_SERIAL_PORT_POWER);
|
||||
new ToggleSwitch(
|
||||
box, rect_t{}, [=] { return serialGetPower(port_nr); },
|
||||
[=](int8_t newValue) {
|
||||
@@ -68,14 +59,14 @@ SerialConfigWindow::SerialConfigWindow(Window *parent, const rect_t &rect) :
|
||||
SET_DIRTY();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (port_nr != SP_VCP) {
|
||||
grid.setColSpan(2);
|
||||
auto line = newLine(&grid);
|
||||
line->padLeft(20);
|
||||
line->padBottom(6);
|
||||
new StaticText(line, rect_t{}, STR_TTL_WARNING, 0, COLOR_THEME_WARNING);
|
||||
grid.setColSpan(1);
|
||||
grid.setColSpan(2);
|
||||
auto line = parent->newLine(grid);
|
||||
line->padLeft(20);
|
||||
line->padBottom(6);
|
||||
new StaticText(line, rect_t{}, STR_TTL_WARNING, COLOR_THEME_WARNING);
|
||||
grid.setColSpan(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
#include "form.h"
|
||||
|
||||
class SerialConfigWindow : public FormWindow
|
||||
class SerialConfigWindow
|
||||
{
|
||||
public:
|
||||
SerialConfigWindow(Window *parent, const rect_t &rect);
|
||||
SerialConfigWindow(Window *parent, FlexGridLayout& grid);
|
||||
};
|
||||
|
||||
@@ -20,57 +20,57 @@
|
||||
*/
|
||||
|
||||
#include "input_edit.h"
|
||||
#include "input_edit_adv.h"
|
||||
|
||||
#include "curve_param.h"
|
||||
#include "gvar_numberedit.h"
|
||||
#include "input_source.h"
|
||||
#include "curveedit.h"
|
||||
|
||||
#include "gvar_numberedit.h"
|
||||
#include "input_edit_adv.h"
|
||||
#include "input_source.h"
|
||||
#include "opentx.h"
|
||||
#include "themes/etx_lv_theme.h"
|
||||
#include "switchchoice.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
#if LCD_W > LCD_H
|
||||
constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 140;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = INPUT_EDIT_CURVE_WIDTH;
|
||||
#else
|
||||
constexpr coord_t INPUT_EDIT_CURVE_WIDTH = 176;
|
||||
constexpr coord_t INPUT_EDIT_CURVE_HEIGHT = 132;
|
||||
#endif
|
||||
|
||||
InputEditWindow::InputEditWindow(int8_t input, uint8_t index) :
|
||||
Page(ICON_MODEL_INPUTS),
|
||||
input(input),
|
||||
index(index)
|
||||
Page(ICON_MODEL_INPUTS), input(input), index(index)
|
||||
{
|
||||
std::string title2(getSourceString(MIXSRC_FIRST_INPUT + input));
|
||||
header.setTitle(STR_MENUINPUTS);
|
||||
header.setTitle2(title2);
|
||||
header->setTitle(STR_MENUINPUTS);
|
||||
header->setTitle2(title2);
|
||||
|
||||
auto body_obj = body.getLvObj();
|
||||
#if LCD_H > LCD_W // portrait
|
||||
auto body_obj = body->getLvObj();
|
||||
#if LCD_H > LCD_W // portrait
|
||||
lv_obj_set_flex_flow(body_obj, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_row(body_obj, lv_dpx(8), 0);
|
||||
#else // landscape
|
||||
#else // landscape
|
||||
lv_obj_set_flex_flow(body_obj, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_column(body_obj, lv_dpx(8), 0);
|
||||
#endif
|
||||
lv_obj_set_style_flex_cross_place(body_obj, LV_FLEX_ALIGN_CENTER, 0);
|
||||
|
||||
// TODO: would be better to set the padding on the preview window...
|
||||
// ...but it doesn't support it yet.
|
||||
lv_obj_set_style_pad_all(body_obj, lv_dpx(8), 0);
|
||||
|
||||
auto box = new Window(&body, rect_t{});
|
||||
auto box = new Window(body, rect_t{});
|
||||
auto box_obj = box->getLvObj();
|
||||
lv_obj_set_flex_grow(box_obj, 2);
|
||||
lv_obj_set_scrollbar_mode(box->getLvObj(), LV_SCROLLBAR_MODE_AUTO);
|
||||
etx_scrollbar(box_obj);
|
||||
|
||||
#if LCD_H > LCD_W // portrait
|
||||
box->setWidth(body.width() - 2*lv_dpx(8));
|
||||
#else // landscape
|
||||
box->setHeight(body.height() - 2*lv_dpx(8));
|
||||
#if LCD_H > LCD_W // portrait
|
||||
box->setWidth(body->width() - 2 * lv_dpx(8));
|
||||
#else // landscape
|
||||
box->setHeight(body->height() - 2 * lv_dpx(8));
|
||||
#endif
|
||||
|
||||
auto form = new FormWindow(box, rect_t{});
|
||||
auto form_obj = form->getLvObj();
|
||||
lv_obj_set_style_pad_all(form_obj, lv_dpx(8), 0);
|
||||
auto form = new Window(box, rect_t{});
|
||||
buildBody(form);
|
||||
|
||||
preview = new Curve(&body, rect_t{0, 0, INPUT_EDIT_CURVE_WIDTH, INPUT_EDIT_CURVE_HEIGHT},
|
||||
preview = new Curve(
|
||||
body, rect_t{0, 0, INPUT_EDIT_CURVE_WIDTH, INPUT_EDIT_CURVE_HEIGHT},
|
||||
[=](int x) -> int {
|
||||
ExpoData* line = expoAddress(index);
|
||||
int16_t anas[MAX_INPUTS] = {0};
|
||||
@@ -86,77 +86,78 @@ static const lv_coord_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2),
|
||||
LV_GRID_TEMPLATE_LAST};
|
||||
static const lv_coord_t row_dsc[] = {LV_GRID_CONTENT, LV_GRID_TEMPLATE_LAST};
|
||||
|
||||
void InputEditWindow::buildBody(FormWindow* form)
|
||||
void InputEditWindow::buildBody(Window* form)
|
||||
{
|
||||
FlexGridLayout grid(col_dsc, row_dsc, 2);
|
||||
FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY);
|
||||
form->setFlexLayout();
|
||||
|
||||
ExpoData* input = expoAddress(index);
|
||||
|
||||
// Input Name
|
||||
auto line = form->newLine(&grid);
|
||||
auto line = form->newLine(grid);
|
||||
auto inputName = g_model.inputNames[input->chn];
|
||||
new StaticText(line, rect_t{}, STR_INPUTNAME, 0, COLOR_THEME_PRIMARY1);
|
||||
new StaticText(line, rect_t{}, STR_INPUTNAME);
|
||||
new ModelTextEdit(line, rect_t{}, inputName, LEN_INPUT_NAME);
|
||||
|
||||
// Line Name
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_EXPONAME, 0, COLOR_THEME_PRIMARY1);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_EXPONAME);
|
||||
new ModelTextEdit(line, rect_t{}, input->name, LEN_EXPOMIX_NAME);
|
||||
|
||||
// Source
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_SOURCE, 0, COLOR_THEME_PRIMARY1);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_SOURCE);
|
||||
auto src = new InputSource(line, input);
|
||||
lv_obj_set_style_grid_cell_x_align(src->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
|
||||
|
||||
// Weight
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_WEIGHT, 0, COLOR_THEME_PRIMARY1);
|
||||
auto gvar = new GVarNumberEdit(line, rect_t{}, -100, 100,
|
||||
GET_DEFAULT(input->weight),
|
||||
[=](int32_t newValue) {
|
||||
input->weight = newValue;
|
||||
preview->invalidate();
|
||||
SET_DIRTY();
|
||||
});
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_WEIGHT);
|
||||
auto gvar =
|
||||
new GVarNumberEdit(line, rect_t{}, -100, 100, GET_DEFAULT(input->weight),
|
||||
[=](int32_t newValue) {
|
||||
input->weight = newValue;
|
||||
preview->update();
|
||||
SET_DIRTY();
|
||||
});
|
||||
gvar->setSuffix("%");
|
||||
|
||||
// Offset
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_OFFSET, 0, COLOR_THEME_PRIMARY1);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_OFFSET);
|
||||
gvar = new GVarNumberEdit(line, rect_t{}, -100, 100,
|
||||
GET_DEFAULT(input->offset),
|
||||
[=](int32_t newValue) {
|
||||
GET_DEFAULT(input->offset), [=](int32_t newValue) {
|
||||
input->offset = newValue;
|
||||
preview->invalidate();
|
||||
preview->update();
|
||||
SET_DIRTY();
|
||||
});
|
||||
gvar->setSuffix("%");
|
||||
|
||||
// Switch
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_SWITCH, 0, COLOR_THEME_PRIMARY1);
|
||||
new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES,
|
||||
SWSRC_LAST_IN_MIXES, GET_SET_DEFAULT(input->swtch));
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_SWITCH);
|
||||
new SwitchChoice(line, rect_t{}, SWSRC_FIRST_IN_MIXES, SWSRC_LAST_IN_MIXES,
|
||||
GET_SET_DEFAULT(input->swtch));
|
||||
|
||||
// Curve
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_CURVE, 0, COLOR_THEME_PRIMARY1);
|
||||
auto param = new CurveParam(line, rect_t{}, &input->curve,
|
||||
[=](int32_t newValue) {
|
||||
input->curve.value = newValue;
|
||||
preview->invalidate();
|
||||
SET_DIRTY();
|
||||
});
|
||||
lv_obj_set_style_grid_cell_x_align(param->getLvObj(), LV_GRID_ALIGN_STRETCH, 0);
|
||||
line = form->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_CURVE);
|
||||
auto param =
|
||||
new CurveParam(line, rect_t{}, &input->curve, [=](int32_t newValue) {
|
||||
input->curve.value = newValue;
|
||||
preview->update();
|
||||
SET_DIRTY();
|
||||
});
|
||||
lv_obj_set_style_grid_cell_x_align(param->getLvObj(), LV_GRID_ALIGN_STRETCH,
|
||||
0);
|
||||
|
||||
line = form->newLine();
|
||||
lv_obj_set_style_pad_all(line->getLvObj(), lv_dpx(8), 0);
|
||||
auto btn = new TextButton(line, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t {
|
||||
new InputEditAdvanced(this->input, index);
|
||||
return 0;
|
||||
});
|
||||
line = form->newLine(grid);
|
||||
line->padAll(PAD_LARGE);
|
||||
auto btn =
|
||||
new TextButton(line, rect_t{}, LV_SYMBOL_SETTINGS, [=]() -> uint8_t {
|
||||
new InputEditAdvanced(this->input, index);
|
||||
return 0;
|
||||
});
|
||||
lv_obj_set_width(btn->getLvObj(), lv_pct(100));
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class InputEditWindow : public Page
|
||||
uint8_t index;
|
||||
Curve* preview;
|
||||
|
||||
void buildBody(FormWindow *window);
|
||||
void buildBody(Window *window);
|
||||
|
||||
void deleteLater(bool detach = true, bool trash = true) override;
|
||||
};
|
||||
|
||||
@@ -20,9 +20,10 @@
|
||||
*/
|
||||
|
||||
#include "input_edit_adv.h"
|
||||
#include "fm_matrix.h"
|
||||
|
||||
#include "fm_matrix.h"
|
||||
#include "opentx.h"
|
||||
#include "themes/etx_lv_theme.h"
|
||||
|
||||
#define SET_DIRTY() storageDirty(EE_MODEL)
|
||||
|
||||
@@ -34,20 +35,17 @@ InputEditAdvanced::InputEditAdvanced(uint8_t input_n, uint8_t index) :
|
||||
Page(ICON_MODEL_INPUTS)
|
||||
{
|
||||
std::string title2(getSourceString(MIXSRC_FIRST_INPUT + input_n));
|
||||
header.setTitle(STR_MENUINPUTS);
|
||||
header.setTitle2(title2);
|
||||
header->setTitle(STR_MENUINPUTS);
|
||||
header->setTitle2(title2);
|
||||
|
||||
rect_t r = rect_t{0, 0, body.width(), body.height()};
|
||||
auto form = new FormWindow(&body, r);
|
||||
|
||||
FlexGridLayout grid(col_dsc, row_dsc, 2);
|
||||
form->setFlexLayout();
|
||||
FlexGridLayout grid(col_dsc, row_dsc, PAD_TINY);
|
||||
body->setFlexLayout();
|
||||
|
||||
ExpoData* input = expoAddress(index);
|
||||
|
||||
// Side
|
||||
auto line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_SIDE, 0, COLOR_THEME_PRIMARY1);
|
||||
auto line = body->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_SIDE);
|
||||
new Choice(
|
||||
line, rect_t{}, STR_VCURVEFUNC, 1, 3,
|
||||
[=]() -> int16_t { return 4 - input->mode; },
|
||||
@@ -57,8 +55,8 @@ InputEditAdvanced::InputEditAdvanced(uint8_t input_n, uint8_t index) :
|
||||
});
|
||||
|
||||
// Trim
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_TRIM, 0, COLOR_THEME_PRIMARY1);
|
||||
line = body->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_TRIM);
|
||||
const auto trimLast = TRIM_OFF + keysGetMaxTrims() - 1;
|
||||
auto c = new Choice(line, rect_t{}, -TRIM_OFF, trimLast,
|
||||
GET_VALUE(-input->trimSource),
|
||||
@@ -74,8 +72,8 @@ InputEditAdvanced::InputEditAdvanced(uint8_t input_n, uint8_t index) :
|
||||
|
||||
// Flight modes
|
||||
if (modelFMEnabled()) {
|
||||
line = form->newLine(&grid);
|
||||
new StaticText(line, rect_t{}, STR_FLMODE, 0, COLOR_THEME_PRIMARY1);
|
||||
line = body->newLine(grid);
|
||||
new StaticText(line, rect_t{}, STR_FLMODE);
|
||||
new FMMatrix<ExpoData>(line, rect_t{}, input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,7 @@
|
||||
|
||||
#include "input_mix_button.h"
|
||||
#include "opentx.h"
|
||||
|
||||
// icon: 17 x 17
|
||||
static const uint8_t _mask_textline_fm[] = {
|
||||
#include "mask_textline_fm.lbm"
|
||||
};
|
||||
STATIC_LZ4_BITMAP(mask_textline_fm);
|
||||
#include "bitmaps.h"
|
||||
|
||||
// total: 92 x 17
|
||||
#define FM_CANVAS_HEIGHT 17
|
||||
@@ -129,13 +124,12 @@ void InputMixButton::setFlightModes(uint16_t modes)
|
||||
|
||||
lv_canvas_fill_bg(fm_canvas, lv_color_black(), LV_OPA_TRANSP);
|
||||
|
||||
auto mask = (const uint8_t*)mask_textline_fm;
|
||||
auto mask_hdr = (const uint16_t*)mask;
|
||||
lv_coord_t w = mask_hdr[0];
|
||||
lv_coord_t h = mask_hdr[1];
|
||||
const MaskBitmap* mask = getBuiltinIcon(ICON_TEXTLINE_FM);
|
||||
lv_coord_t w = mask->width;
|
||||
lv_coord_t h = mask->height;
|
||||
|
||||
coord_t x = 0;
|
||||
lv_canvas_copy_buf(fm_canvas, mask + 4, x, 0, w, h);
|
||||
lv_canvas_copy_buf(fm_canvas, mask->data, x, 0, w, h);
|
||||
x += 20;
|
||||
|
||||
lv_draw_label_dsc_t label_dsc;
|
||||
|
||||