From f81e140cf3a6e6ca10240ea1c3ebe26af72c3e84 Mon Sep 17 00:00:00 2001 From: philmoz Date: Mon, 27 Feb 2023 12:40:02 +1100 Subject: [PATCH] fix(color): LVGLify themes page and fix several possible string handling issues (#3135) * Convert theme select, theme edit and color edit pages to LVGL flex. Add 'Edit Color' string to language files (requires translations). Simplify theme edit 'onCancel' logic. Fix size of buttons in ConfirmDialog for portrait layout. Truncate item strings in ListBox to fit available space. Set window background color on Page and TabsGroup classes instead of using 'paint' function. Replace strncpy and strncat with strAppend - avoid possible unterminated strings and string overrun. Truncate display of long name and author strings in theme pages. * Revert code to truncate ListBox entry strings as it causes other issues. * Adjust layout for theme color editor to fit large hex string size. * Remove unnecessary copying of the ThemeFile object being edited. Refresh TabsGroup page background color when theme changes. * Set selected theme in list on long press as well as short press. Comment out unused 'title' in ListBox. * Handle default theme like custom themes on SD card: - show logo when selecting theme - support background_WxH.png names for background images Use f_stat( via isFileAvailable) instead of opening and closing files to check for existence. * Remove debug print. * Fix rebase. --- radio/src/gui/colorlcd/confirm_dialog.cpp | 8 + radio/src/gui/colorlcd/listbox.h | 4 +- radio/src/gui/colorlcd/page.cpp | 10 +- radio/src/gui/colorlcd/page.h | 3 - radio/src/gui/colorlcd/radio_theme.cpp | 640 ++++++++++++---------- radio/src/gui/colorlcd/radio_theme.h | 7 +- radio/src/gui/colorlcd/tabsgroup.cpp | 20 +- radio/src/gui/colorlcd/tabsgroup.h | 4 +- radio/src/gui/colorlcd/theme_manager.cpp | 102 ++-- radio/src/gui/colorlcd/theme_manager.h | 16 +- radio/src/translations.cpp | 1 + radio/src/translations.h | 1 + radio/src/translations/cn.h | 1 + radio/src/translations/cz.h | 1 + radio/src/translations/da.h | 1 + radio/src/translations/de.h | 1 + radio/src/translations/en.h | 1 + radio/src/translations/es.h | 1 + radio/src/translations/fi.h | 1 + radio/src/translations/fr.h | 1 + radio/src/translations/it.h | 1 + radio/src/translations/jp.h | 1 + radio/src/translations/nl.h | 1 + radio/src/translations/pl.h | 1 + radio/src/translations/pt.h | 1 + radio/src/translations/se.h | 1 + radio/src/translations/tw.h | 1 + 27 files changed, 435 insertions(+), 396 deletions(-) diff --git a/radio/src/gui/colorlcd/confirm_dialog.cpp b/radio/src/gui/colorlcd/confirm_dialog.cpp index 0508401da..0776f79c0 100644 --- a/radio/src/gui/colorlcd/confirm_dialog.cpp +++ b/radio/src/gui/colorlcd/confirm_dialog.cpp @@ -47,14 +47,22 @@ ConfirmDialog::ConfirmDialog(Window* parent, const char* title, 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(); diff --git a/radio/src/gui/colorlcd/listbox.h b/radio/src/gui/colorlcd/listbox.h index c4fc4c290..a2e468b8b 100644 --- a/radio/src/gui/colorlcd/listbox.h +++ b/radio/src/gui/colorlcd/listbox.h @@ -97,9 +97,9 @@ class ListBase : public TableField class ListBox : public ListBase { - std::string title; +// std::string title; public: using ListBase::ListBase; - inline void setTitle(std::string title) { this->title = title; } +// inline void setTitle(std::string title) { this->title = title; } }; diff --git a/radio/src/gui/colorlcd/page.cpp b/radio/src/gui/colorlcd/page.cpp index 7d682e3a9..2852f79d6 100644 --- a/radio/src/gui/colorlcd/page.cpp +++ b/radio/src/gui/colorlcd/page.cpp @@ -58,6 +58,8 @@ Page::Page(unsigned icon): body(this, _get_body_rect(), FORM_FORWARD_FOCUS) { Layer::push(this); + + lv_obj_set_style_bg_color(lvobj, makeLvColor(COLOR_THEME_SECONDARY3), 0); } void Page::deleteLater(bool detach, bool trash) @@ -69,15 +71,9 @@ void Page::deleteLater(bool detach, bool trash) Window::deleteLater(detach, trash); } -void Page::paint(BitmapBuffer * dc) -{ - dc->clear(COLOR_THEME_SECONDARY3); -} - void Page::onCancel() { - if (canCancel()) - deleteLater(); + deleteLater(); } void Page::onClicked() diff --git a/radio/src/gui/colorlcd/page.h b/radio/src/gui/colorlcd/page.h index 3a267f19a..e5aa8fe27 100644 --- a/radio/src/gui/colorlcd/page.h +++ b/radio/src/gui/colorlcd/page.h @@ -55,11 +55,8 @@ class Page : public Window void onCancel() override; void onClicked() override; - void paint(BitmapBuffer* dc) override; void deleteLater(bool detach = true, bool trash = true) override; - virtual bool canCancel() { return true; } - protected: PageHeader header; FormWindow body; diff --git a/radio/src/gui/colorlcd/radio_theme.cpp b/radio/src/gui/colorlcd/radio_theme.cpp index baeabb040..9919f321b 100644 --- a/radio/src/gui/colorlcd/radio_theme.cpp +++ b/radio/src/gui/colorlcd/radio_theme.cpp @@ -21,112 +21,98 @@ #include "radio_theme.h" #include -#include "bitmapbuffer.h" #include "libopenui.h" #include "opentx.h" #include "file_preview.h" #include "theme_manager.h" #include "view_main.h" -#include "widget_settings.h" -#include "sliders.h" #include "color_list.h" -#include "color_editor.h" #include "listbox.h" #include "preview_window.h" -#if (LCD_W > LCD_H) - #define COLOR_PREVIEW_WIDTH 18 - #define COLOR_PREVIEW_HEIGHT (LCD_H - TOPBAR_HEIGHT - 30) - #define LEFT_LIST_WIDTH (LCD_W / 2) - COLOR_PREVIEW_WIDTH - #define LEFT_LIST_HEIGHT (LCD_H - TOPBAR_HEIGHT - 37) - #define COLOR_LIST_WIDTH ((LCD_W * 3)/10) - #define COLOR_LIST_HEIGHT (LCD_H - TOPBAR_HEIGHT - 14) - #define TOP_LIST_OFFSET 4 - #define LEFT_LIST_OFFSET 3 +constexpr int COLOR_PREVIEW_SIZE = 18; + +#if LCD_W > LCD_H + constexpr int LIST_WIDTH = ((LCD_W - 12) / 2 - COLOR_PREVIEW_SIZE); + constexpr int COLOR_LIST_WIDTH = ((LCD_W * 3)/10); #else - #define COLOR_PREVIEW_WIDTH LCD_W - #define COLOR_PREVIEW_HEIGHT 18 - #define LEFT_LIST_WIDTH LCD_W - 6 - #define LEFT_LIST_HEIGHT (LCD_H / 2 - 38) - #define COLOR_LIST_WIDTH LCD_W - 6 - #define COLOR_LIST_HEIGHT (LCD_H / 2 - 24) - #define TOP_LIST_OFFSET 4 - #define LEFT_LIST_OFFSET 3 + constexpr int LIST_HEIGHT = (LCD_H / 2 - 38); + constexpr int COLOR_LIST_HEIGHT = (LCD_H / 2 - 24); #endif -#define MARGIN_WIDTH 5 - -#if (LCD_W > LCD_H) -constexpr int BUTTON_HEIGHT = 30; +#if LCD_W > LCD_H constexpr int BUTTON_WIDTH = 75; constexpr rect_t detailsDialogRect = {30, 30, LCD_W - 60, LCD_H - 60}; -constexpr int labelWidth = 150; -constexpr int COLOR_BOX_LEFT = 5; constexpr int COLOR_BOX_WIDTH = 45; -constexpr int COLOR_BOX_HEIGHT = 27; #else -constexpr int BUTTON_HEIGHT = 30; constexpr int BUTTON_WIDTH = 65; constexpr rect_t detailsDialogRect = {10, 50, LCD_W - 20, 220}; -constexpr int labelWidth = 120; -constexpr int COLOR_BOX_LEFT = 3; constexpr int COLOR_BOX_WIDTH = 55; -constexpr int COLOR_BOX_HEIGHT = 32; - -constexpr int COLOR_BUTTON_WIDTH = COLOR_BOX_WIDTH; -constexpr int COLOR_BUTTON_HEIGHT = 20; #endif +constexpr int BUTTON_HEIGHT = 30; +constexpr int COLOR_BOX_HEIGHT = 30; + constexpr int BOX_MARGIN = 2; constexpr int MAX_BOX_WIDTH = 15; -class ThemeColorPreview : public FormField +class ThemeColorPreview : public FormWindow { public: ThemeColorPreview(Window *parent, const rect_t &rect, std::vector colorList) : - FormField(parent, rect, NO_FOCUS), + FormWindow(parent, rect, NO_FOCUS), colorList(colorList) { - setBoxWidth(); + padAll(0); +#if LCD_W > LCD_H + setFlexLayout(LV_FLEX_FLOW_COLUMN, BOX_MARGIN); +#else + setFlexLayout(LV_FLEX_FLOW_ROW, BOX_MARGIN); +#endif + build(); } - ~ThemeColorPreview() + + void build() { + clear(); + setBoxWidth(); + int size = (boxWidth + BOX_MARGIN) * colorList.size() - BOX_MARGIN; +#if LCD_W > LCD_H + padTop((height() - size) / 2); +#else + padLeft((width() - size) / 2); +#endif + for (auto color: colorList) { + auto c = lv_obj_create(lvobj); + lv_obj_set_size(c, boxWidth, boxWidth); + lv_obj_set_style_border_width(c, 1, 0); + lv_obj_set_style_border_color(c, makeLvColor(COLOR2FLAGS(BLACK)), 0); + lv_obj_set_style_border_opa(c, LV_OPA_100, 0); + lv_obj_set_style_bg_color(c, makeLvColor(COLOR2FLAGS(color.colorValue)), 0); + lv_obj_set_style_bg_opa(c, LV_OPA_100, 0); + } } void setColorList(std::vector colorList) { - this->colorList.assign(colorList.begin(), colorList.end()); - setBoxWidth(); - invalidate(); - } - - void paint(BitmapBuffer *dc) override - { - int totalNessessarySpace = colorList.size() * (boxWidth + 2); - int axis = rect.w > rect.h ? rect.w : rect.h; - axis = (axis - totalNessessarySpace) / 2; - for (auto color: colorList) { - if (rect.w > rect.h) { - dc->drawSolidFilledRect(axis, 0, boxWidth, boxWidth, COLOR2FLAGS(color.colorValue)); - dc->drawSolidRect(axis, 0, boxWidth, boxWidth, 1, COLOR2FLAGS(BLACK)); - } else { - dc->drawSolidFilledRect(0, axis, boxWidth, boxWidth, COLOR2FLAGS(color.colorValue)); - dc->drawSolidRect(0, axis, boxWidth, boxWidth, 1, COLOR2FLAGS(BLACK)); - } - axis += boxWidth + BOX_MARGIN; - } + this->colorList = colorList; + build(); } protected: std::vector colorList; int boxWidth = MAX_BOX_WIDTH; + void setBoxWidth() { - auto winSize = rect.w > rect.h ? rect.w : rect.h; - boxWidth = winSize / (colorList.size() + BOX_MARGIN); +#if LCD_W > LCD_H + boxWidth = (height() - (colorList.size() - 1) * BOX_MARGIN) / colorList.size(); +#else + boxWidth = (width() - (colorList.size() - 1) * BOX_MARGIN) / colorList.size(); +#endif boxWidth = min(boxWidth, MAX_BOX_WIDTH); } }; @@ -198,169 +184,179 @@ class ThemeDetailsDialog: public Dialog std::function saveHandler = nullptr; }; -class ColorSquare : public FormField +class ColorSquare : public Window { public: - ColorSquare(Window *window, const rect_t &rect, uint32_t color, WindowFlags windowFlags = 0) - : FormField(window, rect, windowFlags | NO_FOCUS), + ColorSquare(Window *window, const rect_t &rect, uint32_t color, WindowFlags windowFlags = 0) : + Window(window, rect, windowFlags | NO_FOCUS), _color(color) { - } - - void paint (BitmapBuffer *dc) override - { - dc->drawSolidFilledRect(0, 0, rect.w, rect.h, COLOR2FLAGS(_color)); - dc->drawSolidRect(0, 0, rect.w, rect.h, 1, COLOR2FLAGS(BLACK)); + swatch = lv_obj_create(lvobj); + lv_obj_set_size(swatch, width(), height()); + lv_obj_set_style_border_width(swatch, 1, 0); + lv_obj_set_style_border_color(swatch, makeLvColor(COLOR2FLAGS(BLACK)), 0); + lv_obj_set_style_border_opa(swatch, LV_OPA_100, 0); + lv_obj_set_style_bg_color(swatch, makeLvColor(COLOR2FLAGS(_color)), 0); + lv_obj_set_style_bg_opa(swatch, LV_OPA_100, 0); } void setColorToEdit(uint32_t colorEntry) { _color = colorEntry; - - invalidate(); + lv_obj_set_style_bg_color(swatch, makeLvColor(COLOR2FLAGS(_color)), 0); } protected: uint32_t _color; + lv_obj_t *swatch; }; -void setHexStr(StaticText* hexBox, uint32_t rgb) -{ - auto r = GET_RED(rgb), g = GET_GREEN(rgb), b = GET_BLUE(rgb); - char hexstr[8]; - snprintf(hexstr, sizeof(hexstr), "%02X%02X%02X", - (uint16_t)r, (uint16_t)g, (uint16_t)b); - hexBox->setText(hexstr); -} - class ColorEditPage : public Page { -public: - ColorEditPage(ThemeFile theme, LcdColorIndex indexOfColor, - std::function setValue = nullptr) : - Page(ICON_RADIO_EDIT_THEME), - _setValue(std::move(setValue)), - _indexOfColor(indexOfColor), - _theme(theme) - { - buildBody(&body); - buildHead(&header); - } - - void setActiveColorBar(int activeTab) - { - if (activeTab >= 0 && _activeTab <= (int)_tabs.size()) { - _activeTab = activeTab; - for (auto i = 0; i < (int) _tabs.size(); i++) - _tabs[i]->check(i == _activeTab); - _colorEditor->setColorEditorType(_activeTab == 1 ? HSV_COLOR_EDITOR : RGB_COLOR_EDITOR); - } - } - -protected: - std::function _setValue; - LcdColorIndex _indexOfColor; - ThemeFile _theme; - TextButton *_cancelButton; - ColorEditor *_colorEditor; - PreviewWindow *_previewWindow = nullptr; - std::vector