feat(color): Main navigation menu styling (#4320)

This commit is contained in:
philmoz
2023-11-17 12:44:22 +10:00
committed by GitHub
parent f9b39a53d8
commit 86d4f65f74
13 changed files with 195 additions and 253 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

-1
View File
@@ -36,7 +36,6 @@ set(GUI_SRC
listbox.cpp
tabsgroup.cpp
page.cpp
fab_button.cpp
select_fab_button.cpp
select_fab_carousel.cpp
topbar.cpp
-65
View File
@@ -1,65 +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 "fab_button.h"
#include "font.h"
#include "theme.h"
const uint8_t __alpha_button_on[] {
#include "alpha_button_on.lbm"
};
LZ4Bitmap ALPHA_BUTTON_ON(BMP_ARGB4444, __alpha_button_on);
const uint8_t __alpha_button_off[] {
#include "alpha_button_off.lbm"
};
LZ4Bitmap ALPHA_BUTTON_OFF(BMP_ARGB4444, __alpha_button_off);
FabButton::FabButton(FormWindow* parent, coord_t x, coord_t y, uint8_t icon,
std::function<uint8_t(void)> pressHandler,
WindowFlags windowFlags) :
Button(parent,
{x, y, FAB_BUTTON_SIZE, FAB_BUTTON_SIZE},
pressHandler, windowFlags),
icon(icon)
{
}
FabButton::FabButton(FormWindow* parent, uint8_t icon,
std::function<uint8_t(void)> pressHandler,
WindowFlags windowFlags) :
Button(parent, {}, pressHandler, windowFlags), icon(icon)
{
}
void FabButton::paint(BitmapBuffer * dc)
{
const BitmapBuffer* bitmap = checked() ? &ALPHA_BUTTON_ON : &ALPHA_BUTTON_OFF;
dc->drawBitmap((width() - bitmap->width()) / 2,
(FAB_BUTTON_SIZE - bitmap->height()) / 2, bitmap);
const BitmapBuffer* mask = EdgeTxTheme::instance()->getIconMask(icon);
if (mask) {
dc->drawMask((width() - mask->width()) / 2,
(FAB_BUTTON_SIZE - mask->height()) / 2, mask, COLOR2FLAGS(WHITE));
}
}
-52
View File
@@ -1,52 +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 _FAB_ICON_BUTTON_H_
#define _FAB_ICON_BUTTON_H_
#include "button.h"
constexpr coord_t FAB_BUTTON_SIZE = 68;
class FabButton: public Button {
public:
FabButton(FormWindow * parent, coord_t x, coord_t y,
uint8_t icon, std::function<uint8_t(void)> pressHandler,
WindowFlags windowFlags = 0);
FabButton(FormWindow * parent, uint8_t icon,
std::function<uint8_t(void)> pressHandler,
WindowFlags windowFlags = 0);
#if defined(DEBUG_WINDOWS)
std::string getName() const override
{
return "FabButton";
}
#endif
void paint(BitmapBuffer * dc) override;
protected:
uint8_t icon;
};
#endif
-1
View File
@@ -29,7 +29,6 @@
#include "mainwindow.h"
#include "static.h"
#include "button.h"
#include "fab_button.h"
#include "toggleswitch.h"
#include "numberedit.h"
#include "timeedit.h"
+25 -16
View File
@@ -21,31 +21,40 @@
#include "select_fab_button.h"
SelectFabButton::SelectFabButton(FormWindow* parent,
uint8_t icon, const char* title,
#include "font.h"
#include "static.h"
#include "theme.h"
const uint8_t __alpha_button_off[]{
#include "alpha_button_off.lbm"
};
LZ4Bitmap ALPHA_BUTTON_OFF(BMP_ARGB4444, __alpha_button_off);
SelectFabButton::SelectFabButton(FormWindow* parent, uint8_t icon,
const char* title,
std::function<uint8_t(void)> pressHandler,
WindowFlags windowFlags) :
// FabButton uses center coordinates, we want top left corner:
FabButton(parent, icon, pressHandler, windowFlags),
Button(parent, {}, pressHandler, windowFlags, 0, etx_quick_button_create),
icon(icon),
title(title)
{
// Add some space on either side on the button
setWidth(FAB_BUTTON_SIZE + SELECT_BUTTON_BORDER);
// 2 Lines extra for the text + half border
setHeight(FAB_BUTTON_SIZE + 2 * PAGE_LINE_HEIGHT + SELECT_BUTTON_BORDER / 2);
padAll(0);
new StaticText(this, {1, FAB_BUTTON_SIZE - 14, FAB_BUTTON_SIZE - 4, 0}, title, 0,
COLOR2FLAGS(WHITE) | CENTERED);
}
void SelectFabButton::paint(BitmapBuffer* dc)
{
FabButton::paint(dc);
const BitmapBuffer* bitmap = &ALPHA_BUTTON_OFF;
dc->drawSizedText(width() / 2, FAB_BUTTON_SIZE,
title.c_str(), title.size(),
COLOR2FLAGS(WHITE) | CENTERED);
dc->drawBitmap((FAB_BUTTON_SIZE - bitmap->width()) / 2,
(FAB_BUTTON_SIZE - bitmap->height()) / 2 - 6, bitmap);
if (hasFocus()) {
dc->drawSolidRect(0, 0, width(), height(), 2, COLOR2FLAGS(WHITE));
const BitmapBuffer* mask = EdgeTxTheme::instance()->getIconMask(icon);
if (mask) {
dc->drawMask((FAB_BUTTON_SIZE - mask->width()) / 2,
(FAB_BUTTON_SIZE - mask->height()) / 2 - 6, mask,
COLOR2FLAGS(WHITE));
}
}
@@ -59,5 +68,5 @@ void SelectFabButton::onEvent(event_t event)
return;
}
#endif
FabButton::onEvent(event);
Button::onEvent(event);
}
+16 -11
View File
@@ -21,20 +21,25 @@
#pragma once
#include "fab_button.h"
#include "button.h"
constexpr coord_t SELECT_BUTTON_BORDER = 12;
constexpr coord_t FAB_BUTTON_SIZE = 80;
class SelectFabButton : public FabButton
class SelectFabButton : public Button
{
public:
SelectFabButton(FormWindow* parent, uint8_t icon, const char* title,
std::function<uint8_t(void)> pressHandler,
WindowFlags windowFlags = 0);
public:
SelectFabButton(FormWindow* parent, uint8_t icon, const char* title,
std::function<uint8_t(void)> pressHandler,
WindowFlags windowFlags = 0);
void paint(BitmapBuffer* dc) override;
void onEvent(event_t event) override;
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "SelectFabButton"; }
#endif
protected:
std::string title;
void paint(BitmapBuffer* dc) override;
void onEvent(event_t event) override;
protected:
uint8_t icon;
std::string title;
};
@@ -21,16 +21,10 @@
#include "select_fab_carousel.h"
SelectFabCarousel::SelectFabCarousel(Window* parent) :
FormWindow(parent, {})
SelectFabCarousel::SelectFabCarousel(Window* parent) : FormWindow(parent, {})
{
padAll(0);
setFlexLayout(LV_FLEX_FLOW_ROW_WRAP);
coord_t w = parent->width() * 0.8;
w -= w % (FAB_BUTTON_SIZE + SELECT_BUTTON_BORDER);
lv_obj_set_width(lvobj, w);
lv_obj_set_style_max_height(lvobj, lv_pct(85), 0);
}
void SelectFabCarousel::addButton(uint8_t icon, const char* title,
+8 -11
View File
@@ -25,17 +25,14 @@
class SelectFabCarousel : public FormWindow
{
public:
explicit SelectFabCarousel(Window* parent);
public:
explicit SelectFabCarousel(Window* parent);
// Maximum visible buttons (-> width of the carousel)
void setMaxButtons(uint8_t max);
#if defined(DEBUG_WINDOWS)
std::string getName() const override { return "SelectFabCarousel"; }
#endif
// Add a new button to the carousel
void addButton(uint8_t icon, const char* title,
std::function<uint8_t(void)> pressHandler);
protected:
uint8_t maxButtons = 0;
uint8_t buttons = 0;
// Add a new button to the carousel
void addButton(uint8_t icon, const char* title,
std::function<uint8_t(void)> pressHandler);
};
@@ -68,6 +68,7 @@ LV_STYLE_CONST_SINGLE_INIT(bg_opacity_transparent, LV_STYLE_BG_OPA,
LV_OPA_TRANSP);
LV_STYLE_CONST_SINGLE_INIT(bg_opacity_20, LV_STYLE_BG_OPA, LV_OPA_20);
LV_STYLE_CONST_SINGLE_INIT(bg_opacity_50, LV_STYLE_BG_OPA, LV_OPA_50);
LV_STYLE_CONST_SINGLE_INIT(bg_opacity_75, LV_STYLE_BG_OPA, 187);
LV_STYLE_CONST_SINGLE_INIT(bg_opacity_cover, LV_STYLE_BG_OPA, LV_OPA_COVER);
LV_STYLE_CONST_SINGLE_INIT(fg_opacity_transparent, LV_STYLE_OPA, LV_OPA_TRANSP);
LV_STYLE_CONST_SINGLE_INIT(fg_opacity_cover, LV_STYLE_OPA, LV_OPA_COVER);
@@ -140,6 +141,14 @@ const lv_style_const_prop_t border_props[] = {
};
LV_STYLE_CONST_MULTI_INIT(border, border_props);
// Border
const lv_style_const_prop_t border_transparent_props[] = {
LV_STYLE_CONST_BORDER_OPA(LV_OPA_TRANSP),
LV_STYLE_CONST_BORDER_WIDTH(BORDER_WIDTH),
LV_STYLE_PROP_INV,
};
LV_STYLE_CONST_MULTI_INIT(border_transparent, border_transparent_props);
// Button
const lv_style_const_prop_t btn_props[] = {
LV_STYLE_CONST_PAD_TOP(PAD_SMALL),
@@ -274,11 +283,13 @@ class EdgeTxStyles
lv_style_t border_color_secondary1;
lv_style_t border_color_secondary2;
lv_style_t border_color_black;
lv_style_t border_color_white;
lv_style_t border_color_focus;
lv_style_t bg_color_grey;
lv_style_t bg_color_white;
lv_style_t bg_color_black;
lv_style_t fg_color_black;
lv_style_t fg_color_white;
// Fonts
lv_style_t font_std;
@@ -308,8 +319,12 @@ class EdgeTxStyles
lv_style_set_bg_color(&bg_color_black, lv_color_black());
lv_style_init(&fg_color_black);
lv_style_set_text_color(&fg_color_black, lv_color_black());
lv_style_init(&fg_color_white);
lv_style_set_text_color(&fg_color_white, lv_color_white());
lv_style_init(&border_color_black);
lv_style_set_border_color(&border_color_black, lv_color_black());
lv_style_init(&border_color_white);
lv_style_set_border_color(&border_color_white, lv_color_white());
// Fonts
lv_style_init(&font_std);
@@ -636,6 +651,18 @@ void etx_button_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
LV_PART_MAIN | LV_STATE_DISABLED);
}
void etx_quick_button_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
{
lv_obj_add_style(obj, (lv_style_t*)&border_transparent, LV_PART_MAIN);
lv_obj_add_style(obj, (lv_style_t*)&rounded, LV_PART_MAIN);
lv_obj_add_style(obj, &styles->fg_color_white, LV_PART_MAIN);
lv_obj_add_style(obj, (lv_style_t*)&btn, LV_PART_MAIN);
lv_obj_add_style(obj, (lv_style_t*)&border, LV_PART_MAIN | LV_STATE_FOCUSED);
lv_obj_add_style(obj, &styles->border_color_white,
LV_PART_MAIN | LV_STATE_FOCUSED);
}
void etx_choice_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
{
etx_add_border_rounded(obj);
@@ -699,6 +726,14 @@ void modal_window_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
lv_obj_add_style(obj, &styles->bg_color_black, LV_PART_MAIN);
}
void modal_dialog_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
{
window_base_constructor(class_p, obj);
lv_obj_add_style(obj, (lv_style_t*)&rounded, LV_PART_MAIN);
lv_obj_add_style(obj, (lv_style_t*)&bg_opacity_75, LV_PART_MAIN);
lv_obj_add_style(obj, &styles->bg_color_black, LV_PART_MAIN);
}
void modal_content_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
{
window_base_constructor(class_p, obj);
@@ -868,6 +903,19 @@ const lv_obj_class_t etx_button_class = {
.instance_size = sizeof(lv_btn_t),
};
const lv_obj_class_t etx_quick_button_class = {
.base_class = &lv_btn_class,
.constructor_cb = etx_quick_button_constructor,
.destructor_cb = nullptr,
.user_data = nullptr,
.event_cb = nullptr,
.width_def = 80,
.height_def = 114,
.editable = LV_OBJ_CLASS_EDITABLE_INHERIT,
.group_def = LV_OBJ_CLASS_GROUP_DEF_TRUE,
.instance_size = sizeof(lv_btn_t),
};
const lv_obj_class_t etx_menu_button_class = {
.base_class = &lv_btn_class,
.constructor_cb = etx_button_constructor,
@@ -944,6 +992,18 @@ const lv_obj_class_t etx_modal_window_class = {
.group_def = LV_OBJ_CLASS_EDITABLE_INHERIT,
.instance_size = sizeof(lv_obj_t)};
const lv_obj_class_t etx_modal_dialog_class = {
.base_class = &window_base_class,
.constructor_cb = modal_dialog_constructor,
.destructor_cb = nullptr,
.user_data = nullptr,
.event_cb = nullptr,
.width_def = 0,
.height_def = 0,
.editable = LV_OBJ_CLASS_EDITABLE_INHERIT,
.group_def = LV_OBJ_CLASS_EDITABLE_INHERIT,
.instance_size = sizeof(lv_obj_t)};
const lv_obj_class_t etx_modal_content_class = {
.base_class = &window_base_class,
.constructor_cb = modal_content_constructor,
@@ -1073,6 +1133,11 @@ lv_obj_t* etx_button_create(lv_obj_t* parent)
return etx_create(&etx_button_class, parent);
}
lv_obj_t* etx_quick_button_create(lv_obj_t* parent)
{
return etx_create(&etx_quick_button_class, parent);
}
lv_obj_t* etx_menu_button_create(lv_obj_t* parent)
{
return etx_create(&etx_menu_button_class, parent);
@@ -1103,6 +1168,11 @@ lv_obj_t* etx_modal_create(lv_obj_t* parent)
return etx_create(&etx_modal_window_class, parent);
}
lv_obj_t* etx_modal_dialog_create(lv_obj_t* parent)
{
return etx_create(&etx_modal_dialog_class, parent);
}
lv_obj_t* etx_modal_content_create(lv_obj_t* parent)
{
return etx_create(&etx_modal_content_class, parent);
+72 -86
View File
@@ -20,80 +20,92 @@
*/
#include "view_main_menu.h"
#include "menu.h"
#include "audio.h"
#include "translations.h"
#include "model_select.h"
#include "menu_model.h"
#include "menu_radio.h"
#include "menu_screen.h"
#include "model_select.h"
#include "select_fab_carousel.h"
#include "view_about.h"
#include "view_channels.h"
#include "view_statistics.h"
#include "select_fab_carousel.h"
#include "view_text.h"
#if LCD_W > LCD_H
#define VM_W (FAB_BUTTON_SIZE * 4 + 16)
#define VM_H ((FAB_BUTTON_SIZE + 34) * 2 + 16)
#else
#define VM_W (FAB_BUTTON_SIZE * 3 + 16)
#define VM_H ((FAB_BUTTON_SIZE + 34) * 3 + 16)
#endif
ViewMainMenu::ViewMainMenu(Window* parent, std::function<void()> closeHandler) :
Window(parent->getFullScreenWindow(), rect_t{})
Window(parent->getFullScreenWindow(),
{(LCD_W - VM_W) / 2, (LCD_H - VM_H) / 2, VM_W, VM_H}, 0, 0,
etx_modal_dialog_create),
closeHandler(std::move(closeHandler))
{
this->closeHandler = std::move(closeHandler);
padAll(8);
// Save focus
Layer::push(this);
// Take over the screen
setWidth(parent->width());
setHeight(parent->height());
auto carousel = new SelectFabCarousel(this);
carousel->addButton(ICON_MODEL_SELECT,STR_MAIN_MENU_MANAGE_MODELS, [=]() -> uint8_t {
deleteLater();
new ModelLabelsWindow();
return 0;
});
carousel->addButton(ICON_MODEL_SELECT, STR_MAIN_MENU_MANAGE_MODELS,
[=]() -> uint8_t {
deleteLater();
new ModelLabelsWindow();
return 0;
});
if (modelHasNotes()) {
carousel->addButton(ICON_MODEL_NOTES, STR_MAIN_MENU_MODEL_NOTES, [=]() -> uint8_t {
deleteLater();
readModelNotes(true);
return 0;
});
carousel->addButton(ICON_MODEL_NOTES, STR_MAIN_MENU_MODEL_NOTES,
[=]() -> uint8_t {
deleteLater();
readModelNotes(true);
return 0;
});
}
carousel->addButton(ICON_MONITOR, STR_MAIN_MENU_CHANNEL_MONITOR, [=]() -> uint8_t {
deleteLater();
new ChannelsViewMenu();
return 0;
});
carousel->addButton(ICON_MONITOR, STR_MAIN_MENU_CHANNEL_MONITOR,
[=]() -> uint8_t {
deleteLater();
new ChannelsViewMenu();
return 0;
});
carousel->addButton(ICON_MODEL, STR_MAIN_MENU_MODEL_SETTINGS, [=]() -> uint8_t {
deleteLater();
new ModelMenu();
return 0;
});
carousel->addButton(ICON_MODEL, STR_MAIN_MENU_MODEL_SETTINGS,
[=]() -> uint8_t {
deleteLater();
new ModelMenu();
return 0;
});
carousel->addButton(ICON_RADIO, STR_MAIN_MENU_RADIO_SETTINGS, [=]() -> uint8_t {
deleteLater();
new RadioMenu();
return 0;
});
carousel->addButton(ICON_RADIO, STR_MAIN_MENU_RADIO_SETTINGS,
[=]() -> uint8_t {
deleteLater();
new RadioMenu();
return 0;
});
carousel->addButton(ICON_THEME, STR_MAIN_MENU_SCREEN_SETTINGS, [=]() -> uint8_t {
deleteLater();
new ScreenMenu();
return 0;
});
carousel->addButton(ICON_THEME, STR_MAIN_MENU_SCREEN_SETTINGS,
[=]() -> uint8_t {
deleteLater();
new ScreenMenu();
return 0;
});
carousel->addButton(ICON_MODEL_TELEMETRY, STR_MAIN_MENU_RESET_TELEMETRY, [=]() -> uint8_t {
deleteLater();
Menu* resetMenu = new Menu(parent);
resetMenu->addLine(STR_RESET_FLIGHT, []() { flightReset(); });
resetMenu->addLine(STR_RESET_TIMER1, []() { timerReset(0); });
resetMenu->addLine(STR_RESET_TIMER2, []() { timerReset(1); });
resetMenu->addLine(STR_RESET_TIMER3, []() { timerReset(2); });
resetMenu->addLine(STR_RESET_TELEMETRY, []() { telemetryReset(); });
return 0;
});
carousel->addButton(
ICON_MODEL_TELEMETRY, STR_MAIN_MENU_RESET_TELEMETRY, [=]() -> uint8_t {
deleteLater();
Menu* resetMenu = new Menu(parent);
resetMenu->addLine(STR_RESET_FLIGHT, []() { flightReset(); });
resetMenu->addLine(STR_RESET_TIMER1, []() { timerReset(0); });
resetMenu->addLine(STR_RESET_TIMER2, []() { timerReset(1); });
resetMenu->addLine(STR_RESET_TIMER3, []() { timerReset(2); });
resetMenu->addLine(STR_RESET_TELEMETRY, []() { telemetryReset(); });
return 0;
});
carousel->addButton(ICON_STATS, STR_MAIN_MENU_STATISTICS, [=]() -> uint8_t {
deleteLater();
@@ -101,34 +113,14 @@ ViewMainMenu::ViewMainMenu(Window* parent, std::function<void()> closeHandler) :
return 0;
});
carousel->addButton(ICON_EDGETX, STR_MAIN_MENU_ABOUT_EDGETX, [=]() -> uint8_t {
deleteLater();
new AboutUs();
return 0;
});
carousel->addButton(ICON_EDGETX, STR_MAIN_MENU_ABOUT_EDGETX,
[=]() -> uint8_t {
deleteLater();
new AboutUs();
return 0;
});
auto carousel_obj = carousel->getLvObj();
lv_obj_center(carousel_obj);
lv_obj_update_layout(carousel_obj);
carouselRect.x = lv_obj_get_x(carousel_obj);
carouselRect.y = lv_obj_get_y(carousel_obj);
carouselRect.w = lv_obj_get_width(carousel_obj);
carouselRect.h = lv_obj_get_height(carousel_obj);
// carousel->setCloseHandler([=]() { deleteLater(); });
// carousel->setFocus();
}
uint16_t* lcdGetBackupBuffer();
void ViewMainMenu::paint(BitmapBuffer* dc)
{
rect_t zone = carouselRect;
zone.x -= 8; zone.y -= 8;
zone.w += 16; zone.h += 16;
dc->drawFilledRect(zone.x, zone.y, zone.w, zone.h, SOLID, BLACK, OPACITY(4));
lv_obj_center(carousel->getLvObj());
}
void ViewMainMenu::deleteLater(bool detach, bool trash)
@@ -138,12 +130,6 @@ void ViewMainMenu::deleteLater(bool detach, bool trash)
Window::deleteLater(detach, trash);
}
void ViewMainMenu::onClicked()
{
deleteLater();
}
void ViewMainMenu::onClicked() { deleteLater(); }
void ViewMainMenu::onCancel()
{
deleteLater();
}
void ViewMainMenu::onCancel() { deleteLater(); }
-2
View File
@@ -30,10 +30,8 @@ class ViewMainMenu : public Window
void onCancel() override;
void onClicked() override;
void paint(BitmapBuffer* dc) override;
void deleteLater(bool detach = true, bool trash = true) override;
protected:
rect_t carouselRect;
std::function<void()> closeHandler = nullptr;
};
@@ -35,9 +35,11 @@ lv_obj_t* etx_switch_create(lv_obj_t* parent);
lv_obj_t* etx_slider_create(lv_obj_t* parent);
lv_obj_t* etx_btnmatrix_create(lv_obj_t* parent);
lv_obj_t* etx_button_create(lv_obj_t* parent);
lv_obj_t* etx_quick_button_create(lv_obj_t* parent);
lv_obj_t* etx_menu_button_create(lv_obj_t* parent);
lv_obj_t* etx_choice_create(lv_obj_t* parent);
lv_obj_t* etx_modal_create(lv_obj_t* parent);
lv_obj_t* etx_modal_dialog_create(lv_obj_t* parent);
lv_obj_t* etx_modal_content_create(lv_obj_t* parent);
lv_obj_t* etx_modal_title_create(lv_obj_t* parent);
lv_obj_t* etx_bar_create(lv_obj_t* parent);