refactor(color): use LVGL styles and objects for UI, legacy cleanup (#4407)

This commit is contained in:
philmoz
2024-04-05 17:33:14 +10:00
committed by GitHub
parent 5ff5c2ab8e
commit f28c1150ed
392 changed files with 18929 additions and 19492 deletions
-4
View File
@@ -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
)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 310 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 866 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 833 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 922 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1012 B

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

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
+1 -4
View File
@@ -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_
+84 -97
View File
@@ -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()
+3 -26
View File
@@ -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();
+1 -8
View File
@@ -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_
+225 -196
View File
@@ -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
+2 -60
View File
@@ -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();
};
};
+16 -16
View File
@@ -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()
+2 -3
View File
@@ -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;
+16 -20
View File
@@ -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);
+1 -1
View File
@@ -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;
+62 -60
View File
@@ -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()
+3 -3
View File
@@ -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;
+2 -2
View File
@@ -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();
});
}
+295 -111
View File
@@ -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
+130 -19
View File
@@ -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();
};
+204 -124
View File
@@ -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
+30 -113
View File
@@ -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
};
+47 -51
View File
@@ -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; }
+5 -4
View File
@@ -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;
+271 -190
View File
@@ -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();
}
+6 -95
View File
@@ -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,
+59 -13
View File
@@ -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 -11
View File
@@ -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:
};
+63 -77
View File
@@ -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);
}
+4 -2
View File
@@ -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;
};
+115 -66
View File
@@ -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));
}
+62 -58
View File
@@ -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);
-74
View File
@@ -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();
}
-41
View File
@@ -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(),
+2 -2
View File
@@ -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;
+194 -185
View File
@@ -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();
}
}
+46 -46
View File
@@ -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);
+6 -11
View File
@@ -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);
+195 -161
View File
@@ -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);
}
+5 -5
View File
@@ -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);
};
-98
View File
@@ -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);
}
+57 -76
View File
@@ -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);
}
}
-544
View File
@@ -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;
}
}
-97
View File
@@ -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_
+1 -3
View File
@@ -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)) {
+9 -6
View File
@@ -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;
+11 -7
View File
@@ -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();
+3 -3
View File
@@ -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,
+5 -51
View File
@@ -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());
}
+3 -11
View File
@@ -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;
};
+2 -3
View File
@@ -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>
+1 -1
View File
@@ -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);
+89 -89
View File
@@ -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);
+1 -14
View File
@@ -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_
+1 -8
View File
@@ -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_
-58
View File
@@ -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_
+8 -11
View File
@@ -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) {
+1 -4
View File
@@ -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_
+51 -79
View File
@@ -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);
}
+6 -2
View File
@@ -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;
};
+9 -25
View File
@@ -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);
});
}
+2 -9
View File
@@ -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);
};
+80 -61
View File
@@ -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>;
+5 -5
View File
@@ -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;
});
+26 -65
View File
@@ -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
}
+4 -10
View File
@@ -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();
+14 -23
View File
@@ -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);
}
}
}
+2 -2
View File
@@ -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);
};
+70 -69
View File
@@ -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));
}
+1 -1
View File
@@ -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;
};
+12 -14
View File
@@ -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);
}
}
+5 -11
View File
@@ -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;

Some files were not shown because too many files have changed in this diff Show More