diff --git a/radio/src/gui/colorlcd/CMakeLists.txt b/radio/src/gui/colorlcd/CMakeLists.txt index e9ebe5162..e1426717d 100644 --- a/radio/src/gui/colorlcd/CMakeLists.txt +++ b/radio/src/gui/colorlcd/CMakeLists.txt @@ -31,6 +31,7 @@ set(GUI_SRC color_editor.cpp color_list.cpp preview_window.cpp + file_preview.cpp file_carosell.cpp listbox.cpp tabsgroup.cpp @@ -85,6 +86,7 @@ set(GUI_SRC view_statistics.cpp view_text.cpp menu_screen.cpp + screen_user_interface.cpp screen_setup.cpp switch_warn_dialog.cpp LvglWrapper.cpp diff --git a/radio/src/gui/colorlcd/file_preview.cpp b/radio/src/gui/colorlcd/file_preview.cpp new file mode 100644 index 000000000..54f44adb4 --- /dev/null +++ b/radio/src/gui/colorlcd/file_preview.cpp @@ -0,0 +1,74 @@ +/* + * 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 "file_preview.h" +#include "sdcard.h" + +FilePreview::FilePreview(Window *parent, const rect_t &rect, + bool drawCentered) : + Window(parent, rect, NO_SCROLLBAR), _drawCentered(drawCentered) +{ +} + +FilePreview::~FilePreview() +{ + if (bitmap != nullptr) delete bitmap; +} + +void FilePreview::setFile(const char *filename) +{ + if (bitmap != nullptr) delete bitmap; + bitmap = nullptr; + + 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) +{ + dc->setFormat(BMP_RGB565); + coord_t y = _drawCentered ? parent->getScrollPositionY() + 2 : 2; + coord_t h = _drawCentered ? MENU_BODY_HEIGHT - 4 : rect.h; + if (bitmap != nullptr) { + coord_t bitmapHeight = min(h, bitmap->height()); + coord_t bitmapWidth = min(width(), bitmap->width()); + dc->drawScaledBitmap(bitmap, (width() - bitmapWidth) / 2, + _drawCentered ? y + (h - bitmapHeight) / 2 : 0, + bitmapWidth, bitmapHeight); + } +} diff --git a/radio/src/gui/colorlcd/file_preview.h b/radio/src/gui/colorlcd/file_preview.h index ede22777c..5a36d4263 100644 --- a/radio/src/gui/colorlcd/file_preview.h +++ b/radio/src/gui/colorlcd/file_preview.h @@ -24,56 +24,21 @@ class FilePreview : public Window { - public: - FilePreview(Window *parent, const rect_t &rect, bool drawCentered = true) : - Window(parent, rect, NO_SCROLLBAR), - _drawCentered(drawCentered) - { - } - - ~FilePreview() - { - if (bitmap != nullptr) - delete bitmap; - } + public: + FilePreview(Window *parent, const rect_t &rect, bool drawCentered = true); + ~FilePreview(); #if defined(DEBUG_WINDOWS) - std::string getName() const override - { - return "FilePreview"; - } + std::string getName() const override { return "FilePreview"; } #endif - void setFile(const char *filename) - { - if (bitmap != nullptr) - delete bitmap; - bitmap = nullptr; + void setFile(const char *filename); + coord_t getBitmapWidth() const; + coord_t getBitmapHeight() const; - const char *ext = getFileExtension(filename); - if (ext && isExtensionMatching(ext, BITMAPS_EXT)) { - bitmap = BitmapBuffer::loadBitmap(filename); - } else { - bitmap = nullptr; - } - invalidate(); - } + void paint(BitmapBuffer *dc) override; - void paint(BitmapBuffer *dc) override - { - dc->setFormat(BMP_RGB565); - coord_t y = _drawCentered ? parent->getScrollPositionY() + 2 : 2; - coord_t h = _drawCentered ? MENU_BODY_HEIGHT - 4 : rect.h; - if (bitmap != nullptr) { - coord_t bitmapHeight = min(h, bitmap->height()); - coord_t bitmapWidth = min(width(), bitmap->width()); - dc->drawScaledBitmap(bitmap, (width() - bitmapWidth) / 2, - _drawCentered ? y + (h - bitmapHeight) / 2 : 0, - bitmapWidth, bitmapHeight); - } - } - - protected: - BitmapBuffer *bitmap = nullptr; - bool _drawCentered = true; + protected: + BitmapBuffer *bitmap = nullptr; + bool _drawCentered = true; }; diff --git a/radio/src/gui/colorlcd/screen_setup.cpp b/radio/src/gui/colorlcd/screen_setup.cpp index efa5b0ef3..cde9a556f 100644 --- a/radio/src/gui/colorlcd/screen_setup.cpp +++ b/radio/src/gui/colorlcd/screen_setup.cpp @@ -26,8 +26,6 @@ #include "topbar.h" #include "libopenui.h" #include "layouts/layout_factory_impl.h" -#include "theme_manager.h" -#include "file_preview.h" #define SET_DIRTY() storageDirty(EE_MODEL) #define BUTTON_HEIGHT 30 @@ -254,98 +252,6 @@ class SetupWidgetsPage: public FormWindow // } }; -ScreenUserInterfacePage::ScreenUserInterfacePage(ScreenMenu* menu): - PageTab(STR_USER_INTERFACE, ICON_THEME_SETUP), - menu(menu) -{ -} - - -class MyFormGridLayout : public FormGridLayout -{ - public: - MyFormGridLayout(int width, int top) : - FormGridLayout(width, top) - { - } - - rect_t getFieldSlotEx(uint8_t count = 1, uint8_t index = 0, uint8_t number = 1) const - { - coord_t width = (this->width - labelWidth - lineMarginRight - (count - 1) * PAGE_LINE_SPACING) / count; - coord_t left = labelWidth + (width + PAGE_LINE_SPACING) * index; - return {left, currentY, width *number, PAGE_LINE_HEIGHT}; - } -}; - - -void ScreenUserInterfacePage::build(FormWindow * window) -{ - MyFormGridLayout grid(LCD_W, 10); - - // Top Bar - new StaticText(window, grid.getLabelSlot(), STR_TOP_BAR, 0, COLOR_THEME_PRIMARY1); - - auto menu = this->menu; - auto setupTopbarWidgets = new TextButton(window, grid.getFieldSlot(), STR_SETUP_WIDGETS); - setupTopbarWidgets->setPressHandler([menu]() -> uint8_t { - new SetupTopBarWidgetsPage(menu); - return 0; - }); - - grid.nextLine(); - grid.spacer(8); - - // Theme choice - new StaticText(window, grid.getLabelSlot(), STR_THEME, 0, COLOR_THEME_PRIMARY1); - auto tp = ThemePersistance::instance(); - tp->refresh(); - std::vector names = tp->getNames(); - new Choice(window, grid.getFieldSlotEx(), names, 0, names.size() - 1, - [=] () { - return tp->getThemeIndex(); - }, - [=] (int value) { - tp->setThemeIndex(value); - tp->applyTheme(value); - tp->setDefaultTheme(value); - - window->clear(); - build(window); - }); - - bool bNarrowScreen = LCD_W < LCD_H; - if (bNarrowScreen) - grid.setLabelWidth(LCD_W); - - grid.nextLine(); - auto theme = tp->getCurrentTheme(); - auto themeImage = theme->getThemeImageFileNames(); - - grid.spacer(8); - - new StaticText(window, grid.getLabelSlot(), "Author", 0, COLOR_THEME_PRIMARY1 | FONT(BOLD)); - grid.nextLine(); - new StaticText(window, grid.getLabelSlot(), theme->getAuthor(), 0, COLOR_THEME_PRIMARY1); - grid.nextLine(); - new StaticText(window, grid.getLabelSlot(), "Description", 0, COLOR_THEME_PRIMARY1 | FONT(BOLD)); - grid.nextLine(); - - int charBreak = bNarrowScreen ? 40 : 30; - auto info = wrap(theme->getInfo(), charBreak); - - rect_t r = grid.getLabelSlot(); - r.h += 50; - new StaticText(window, r, info, 0, COLOR_THEME_PRIMARY1); - - rect_t previewRect = bNarrowScreen ? - rect_t {0, r.h, LCD_W, window->height()} : - rect_t {LCD_W / 2 + 6, 30, LCD_W / 2 - 12, window->height()}; - auto preview = new FilePreview(window, previewRect); - preview->setFile(themeImage.size() > 0 ? themeImage[0].c_str() : ""); - - window->setInnerHeight(grid.getWindowHeight()); -} - ScreenAddPage::ScreenAddPage(ScreenMenu * menu, uint8_t pageIndex): PageTab(), menu(menu), diff --git a/radio/src/gui/colorlcd/screen_setup.h b/radio/src/gui/colorlcd/screen_setup.h index 64191fa1e..7aec7e8c2 100644 --- a/radio/src/gui/colorlcd/screen_setup.h +++ b/radio/src/gui/colorlcd/screen_setup.h @@ -20,19 +20,11 @@ */ #include "menu_screen.h" +#include "screen_user_interface.h" + #include "layout.h" #include "datastructs.h" -class ScreenUserInterfacePage: public PageTab { - public: - ScreenUserInterfacePage(ScreenMenu* menu); - - void build(FormWindow * window) override; - - protected: - ScreenMenu * menu; -}; - class ScreenAddPage: public PageTab { public: ScreenAddPage(ScreenMenu * menu, uint8_t pageIndex); diff --git a/radio/src/gui/colorlcd/screen_user_interface.cpp b/radio/src/gui/colorlcd/screen_user_interface.cpp new file mode 100644 index 000000000..ed2f6a8a4 --- /dev/null +++ b/radio/src/gui/colorlcd/screen_user_interface.cpp @@ -0,0 +1,156 @@ +/* + * 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 "screen_user_interface.h" +#include "theme_manager.h" +#include "file_preview.h" + +struct ThemeDetails : public Window { + ThemeDetails(Window* parent, ThemeFile* theme) : Window(parent, rect_t{}) + { + // vertical flow layout + lv_obj_set_flex_flow(lvobj, LV_FLEX_FLOW_COLUMN); + lv_obj_set_style_pad_row(lvobj, 2, LV_PART_MAIN); + + // make the object fill the grid cell + lv_obj_set_style_grid_cell_x_align(lvobj, LV_GRID_ALIGN_STRETCH, 0); + + // TODO: translation + new StaticText(this, rect_t{}, "Author", 0, + COLOR_THEME_PRIMARY1 | FONT(BOLD)); + auto txt = new StaticText(this, rect_t{}, theme->getAuthor(), 0, + COLOR_THEME_PRIMARY1); + + // labels default to LV_SIZE_CONTENT, + // which could overflow the width avail + auto obj = txt->getLvObj(); + lv_obj_set_width(obj, lv_pct(100)); + + // TODO: translation + new StaticText(this, rect_t{}, "Description", 0, + COLOR_THEME_PRIMARY1 | FONT(BOLD)); + txt = new StaticText(this, rect_t{}, theme->getInfo(), 0, + COLOR_THEME_PRIMARY1); + obj = txt->getLvObj(); + lv_obj_set_width(obj, lv_pct(100)); + } +}; + +#if LCD_W > LCD_H // landscape + +// form grid +static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; + +// theme details grid +static const lv_coord_t* theme_col_dsc = line_col_dsc; +static const lv_coord_t* theme_row_dsc = line_row_dsc; + +#else // portrait + +// form grid +static const lv_coord_t line_col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(2), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t line_row_dsc[] = {LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; + +// theme details grid +static const lv_coord_t theme_col_dsc[] = {LV_GRID_FR(1), + LV_GRID_TEMPLATE_LAST}; +static const lv_coord_t theme_row_dsc[] = {LV_GRID_CONTENT, LV_GRID_CONTENT, + LV_GRID_TEMPLATE_LAST}; +#endif + +constexpr coord_t MAX_PREVIEW_WIDTH = (100 * LV_DPI_DEF) / 57; +constexpr coord_t MAX_PREVIEW_HEIGHT = LV_DPI_DEF; + +ScreenUserInterfacePage::ScreenUserInterfacePage(ScreenMenu* menu): + PageTab(STR_USER_INTERFACE, ICON_THEME_SETUP), + menu(menu) +{ +} +void ScreenUserInterfacePage::build(FormWindow* form) +{ + FlexGridLayout grid(line_col_dsc, line_row_dsc); + form->setFlexLayout(); + + // Top Bar + auto line = form->newLine(&grid); + new StaticText(line, rect_t{}, STR_TOP_BAR, 0, COLOR_THEME_PRIMARY1); + + auto menu = this->menu; + auto setupTopbarWidgets = new TextButton(line, rect_t{}, STR_SETUP_WIDGETS); + setupTopbarWidgets->setPressHandler([menu]() -> uint8_t { + new SetupTopBarWidgetsPage(menu); + return 0; + }); + + // Theme choice + line = form->newLine(&grid); + new StaticText(line, rect_t{}, STR_THEME, 0, COLOR_THEME_PRIMARY1); + + auto tp = ThemePersistance::instance(); + tp->refresh(); + std::vector names = tp->getNames(); + + new Choice(line, rect_t{}, names, 0, names.size() - 1, + [=] () { + return tp->getThemeIndex(); + }, + [=] (int value) { + tp->setThemeIndex(value); + tp->applyTheme(value); + tp->setDefaultTheme(value); + + // TODO: shouldn't be necessary, would be better to send LV_EVENT_CHANGED + form->clear(); + build(form); + }); + + auto theme = tp->getCurrentTheme(); + FilePreview* preview = nullptr; + + if (theme) { + FlexGridLayout theme_grid(theme_col_dsc, theme_row_dsc); + line = form->newLine(&theme_grid); + + new ThemeDetails(line, theme); + + auto themeImage = theme->getThemeImageFileNames(); + if (themeImage.size() > 0) { + preview = new FilePreview(line, rect_t{}, false); + preview->setFile(themeImage[0].c_str()); + + // adjust width according to max + preview->setWidth(min(MAX_PREVIEW_WIDTH, preview->getBitmapWidth())); + preview->setHeight(min(MAX_PREVIEW_HEIGHT, preview->getBitmapHeight())); + + // center within cell + auto obj = preview->getLvObj(); + lv_obj_set_style_grid_cell_x_align(obj, LV_GRID_ALIGN_CENTER, 0); + } + } + + form->updateSize(); +} + diff --git a/radio/src/gui/colorlcd/screen_user_interface.h b/radio/src/gui/colorlcd/screen_user_interface.h new file mode 100644 index 000000000..6f90ee572 --- /dev/null +++ b/radio/src/gui/colorlcd/screen_user_interface.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#pragma once + +#include "tabsgroup.h" + +class ScreenMenu; + +class ScreenUserInterfacePage : public PageTab +{ + public: + ScreenUserInterfacePage(ScreenMenu* menu); + + void build(FormWindow* window) override; + + protected: + ScreenMenu* menu; +}; diff --git a/radio/src/thirdparty/libopenui b/radio/src/thirdparty/libopenui index f6a19ca00..4491bb075 160000 --- a/radio/src/thirdparty/libopenui +++ b/radio/src/thirdparty/libopenui @@ -1 +1 @@ -Subproject commit f6a19ca00b912f91f9a39269bde49ba52cf9bdd4 +Subproject commit 4491bb0755a3a72cb4d4ac4492d01cf3f6f31550