From f05230e8701ca4641aeac0691f0db3bc68bb50fa Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:03:51 +0000 Subject: [PATCH 1/5] initial work on theme v2 see #78 --- assets/romfs/themes/abyss_theme.ini | 15 +- assets/romfs/themes/base_black_theme.ini | 44 +++- assets/romfs/themes/base_white_theme.ini | 34 +++ assets/romfs/themes/black_theme.ini | 2 +- assets/romfs/themes/oled_black_theme.ini | 16 +- assets/romfs/themes/white_theme.ini | 5 + sphaira/CMakeLists.txt | 2 +- sphaira/include/app.hpp | 7 +- sphaira/include/ui/nvg_util.hpp | 76 +----- sphaira/include/ui/types.hpp | 50 +++- sphaira/source/app.cpp | 188 ++++++++++----- sphaira/source/ui/error_box.cpp | 16 +- sphaira/source/ui/menus/appstore.cpp | 38 +-- sphaira/source/ui/menus/filebrowser.cpp | 24 +- sphaira/source/ui/menus/ghdl.cpp | 13 +- sphaira/source/ui/menus/homebrew.cpp | 8 +- sphaira/source/ui/menus/menu_base.cpp | 14 +- sphaira/source/ui/menus/themezer.cpp | 15 +- sphaira/source/ui/notification.cpp | 10 +- sphaira/source/ui/nvg_util.cpp | 289 ++++------------------- sphaira/source/ui/option_box.cpp | 12 +- sphaira/source/ui/popup_list.cpp | 36 +-- sphaira/source/ui/progress_box.cpp | 16 +- sphaira/source/ui/scrollable_text.cpp | 10 +- sphaira/source/ui/sidebar.cpp | 42 ++-- sphaira/source/ui/widget.cpp | 2 +- 26 files changed, 452 insertions(+), 532 deletions(-) create mode 100644 assets/romfs/themes/base_white_theme.ini create mode 100644 assets/romfs/themes/white_theme.ini diff --git a/assets/romfs/themes/abyss_theme.ini b/assets/romfs/themes/abyss_theme.ini index 4d94280..acd1cff 100644 --- a/assets/romfs/themes/abyss_theme.ini +++ b/assets/romfs/themes/abyss_theme.ini @@ -1,13 +1,14 @@ [meta] name=Abyss author=TotalJustice -version=1.0.0 +version=1.1.0 inherit=romfs:/themes/base_black_theme.ini [theme] -background=0x0f111aff -grid=0x0f115c30 -selected=0x0f115cff -selected_overlay=0x529cffff -text=0xffbc41ff -text_selected=0x529cffff +background = 0x0f111a +grid = 0x0f115c30 +popup = 0x0f115c +text = 0xffbc41 +text_info = 0xffbc41 +text_selected = 0x529cff +selected_background = 0x0f115c diff --git a/assets/romfs/themes/base_black_theme.ini b/assets/romfs/themes/base_black_theme.ini index 674f454..3f61226 100644 --- a/assets/romfs/themes/base_black_theme.ini +++ b/assets/romfs/themes/base_black_theme.ini @@ -1,15 +1,33 @@ [theme] -background=0x2d2d2dff -grid=0x46464630 -selected=0x464646ff -selected_overlay=0x00ffc8ff -text=0xfbfbfbff -text_selected=0x00ffc8ff +background = 0x2d2d2d +grid = 0x46464630 +popup = 0x464646 +error = 0xfa5a3a -icon_audio=romfs:/theme/icon_audio.png -icon_video=romfs:/theme/icon_video.png -icon_image=romfs:/theme/icon_image.png -icon_file=romfs:/theme/icon_file.png -icon_folder=romfs:/theme/icon_folder.png -icon_zip=romfs:/theme/icon_zip.png -icon_nro=romfs:/theme/icon_nro.png +line = 0xfbfbfb +line_seperator = 0xd1d1d1 + +text = 0xfbfbfb +text_info = 0xd1d1d1 +text_selected = 0x00ffc8 +selected_background = 0x464646 + +sidebar = 0x000000dc + +scrollbar = 0x00ffc8 +scrollbar_background = ; hide the background +; scrollbar_background = 0x464646 + +progressbar = 0x00ffc8 +progressbar_background = 0x464646 + +highlight_1 = 0x1989c6 +highlight_2 = 0x89f0f2 + +icon_audio = romfs:/theme/icon_audio.png +icon_video = romfs:/theme/icon_video.png +icon_image = romfs:/theme/icon_image.png +icon_file = romfs:/theme/icon_file.png +icon_folder = romfs:/theme/icon_folder.png +icon_zip = romfs:/theme/icon_zip.png +icon_nro = romfs:/theme/icon_nro.png diff --git a/assets/romfs/themes/base_white_theme.ini b/assets/romfs/themes/base_white_theme.ini new file mode 100644 index 0000000..376598e --- /dev/null +++ b/assets/romfs/themes/base_white_theme.ini @@ -0,0 +1,34 @@ +[theme] +background = 0xececec +grid = 0xf1f1f1 +popup = 0xf1f1f1 +error = 0xfa5a3a + +line = 0x373737 +line_seperator = 0x373737 + +text = 0x373737 +text_info = 0x808080 +text_selected = 0x3250f0 +selected_background = 0xfdfdfd + +sidebar = 0xe2e2e2f5 + +scrollbar = 0x3250f0 +scrollbar_background = ; hide the background +; scrollbar_background = 0xababab + +progressbar = 0x3250f0 +progressbar_background = 0x808080 + +highlight_1 = 0x1989c6 +highlight_2 = 0x89f0f2 + +icon_colour = 0x6f7779 +icon_audio = romfs:/theme/icon_audio.png +icon_video = romfs:/theme/icon_video.png +icon_image = romfs:/theme/icon_image.png +icon_file = romfs:/theme/icon_file.png +icon_folder = romfs:/theme/icon_folder.png +icon_zip = romfs:/theme/icon_zip.png +icon_nro = romfs:/theme/icon_nro.png diff --git a/assets/romfs/themes/black_theme.ini b/assets/romfs/themes/black_theme.ini index f31fa27..d801962 100644 --- a/assets/romfs/themes/black_theme.ini +++ b/assets/romfs/themes/black_theme.ini @@ -1,5 +1,5 @@ [meta] name=Black author=TotalJustice -version=1.0.0 +version=1.1.0 inherit=romfs:/themes/base_black_theme.ini diff --git a/assets/romfs/themes/oled_black_theme.ini b/assets/romfs/themes/oled_black_theme.ini index 9d2c26a..35b04e5 100644 --- a/assets/romfs/themes/oled_black_theme.ini +++ b/assets/romfs/themes/oled_black_theme.ini @@ -1,13 +1,13 @@ [meta] name=OLED Black -author=iTotalJustice/Sanras -version=1.0.0 +author=TotalJustice/Sanras +version=1.1.0 inherit=romfs:/themes/base_black_theme.ini [theme] -background=0x000000ff -grid=0x46464640 -selected=0x323232ff -selected_overlay=0x00ffc8ff -text=0xfbfbfbff -text_selected=0x00ffc8ff +background = 0x000000 +grid = 0x46464640 +popup = 0x323232 +text = 0xfbfbfb +text_selected = 0x00ffc8 +selected_background = 0x323232 diff --git a/assets/romfs/themes/white_theme.ini b/assets/romfs/themes/white_theme.ini new file mode 100644 index 0000000..1d4208d --- /dev/null +++ b/assets/romfs/themes/white_theme.ini @@ -0,0 +1,5 @@ +[meta] +name=White +author=TotalJustice/Yorunokyujitsu +version=1.0.0 +inherit=romfs:/themes/base_white_theme.ini diff --git a/sphaira/CMakeLists.txt b/sphaira/CMakeLists.txt index dada051..2931c66 100644 --- a/sphaira/CMakeLists.txt +++ b/sphaira/CMakeLists.txt @@ -115,7 +115,7 @@ FetchContent_Declare(yyjson FetchContent_Declare(minIni GIT_REPOSITORY https://github.com/ITotalJustice/minIni-nx.git - GIT_TAG 63ec295 + GIT_TAG 11cac8b ) set(MININI_LIB_NAME minIni) diff --git a/sphaira/include/app.hpp b/sphaira/include/app.hpp index aa0810d..2ab1304 100644 --- a/sphaira/include/app.hpp +++ b/sphaira/include/app.hpp @@ -105,9 +105,9 @@ public: // void DrawElement(float x, float y, float w, float h, ui::ThemeEntryID id); auto LoadElementImage(std::string_view value) -> ElementEntry; auto LoadElementColour(std::string_view value) -> ElementEntry; - auto LoadElement(std::string_view data) -> ElementEntry; + auto LoadElement(std::string_view data, ElementType type) -> ElementEntry; - void LoadTheme(const ThemeMeta& meta); + void LoadTheme(ThemeMeta meta, int inherit_level = 0); void CloseTheme(); void ScanThemes(const std::string& path); void ScanThemeEntries(); @@ -165,6 +165,9 @@ public: PLSR_BFSAR m_qlaunch_bfsar{}; PLSR_PlayerSoundId m_sound_ids[SoundEffect_MAX]{}; +private: + void CloseMusic(); + private: // from nanovg decko3d example by adubbz static constexpr unsigned NumFramebuffers = 2; static constexpr unsigned StaticCmdSize = 0x1000; diff --git a/sphaira/include/ui/nvg_util.hpp b/sphaira/include/ui/nvg_util.hpp index c9c1c00..139aadf 100644 --- a/sphaira/include/ui/nvg_util.hpp +++ b/sphaira/include/ui/nvg_util.hpp @@ -5,87 +5,37 @@ namespace sphaira::ui::gfx { -enum class Colour { - BLACK, - LIGHT_BLACK, - SILVER, - DARK_GREY, - GREY, - WHITE, - CYAN, - TEAL, - BLUE, - LIGHT_BLUE, - YELLOW, - RED, -}; - void drawImage(NVGcontext*, float x, float y, float w, float h, int texture); -void drawImage(NVGcontext*, Vec4 v, int texture); +void drawImage(NVGcontext*, const Vec4& v, int texture); void drawImageRounded(NVGcontext*, float x, float y, float w, float h, int texture); -void drawImageRounded(NVGcontext*, Vec4 v, int texture); - -auto getColour(Colour c) -> NVGcolor; +void drawImageRounded(NVGcontext*, const Vec4& v, int texture); void dimBackground(NVGcontext*); -void drawRect(NVGcontext*, float x, float y, float w, float h, Colour c, bool rounded = false); -void drawRect(NVGcontext*, Vec4 vec, Colour c, bool rounded = false); void drawRect(NVGcontext*, float x, float y, float w, float h, const NVGcolor& c, bool rounded = false); -void drawRect(NVGcontext*, float x, float y, float w, float h, const NVGcolor&& c, bool rounded = false); -void drawRect(NVGcontext*, Vec4 vec, const NVGcolor& c, bool rounded = false); -void drawRect(NVGcontext*, Vec4 vec, const NVGcolor&& c, bool rounded = false); +void drawRect(NVGcontext*, const Vec4& v, const NVGcolor& c, bool rounded = false); void drawRect(NVGcontext*, float x, float y, float w, float h, const NVGpaint& p, bool rounded = false); -void drawRect(NVGcontext*, float x, float y, float w, float h, const NVGpaint&& p, bool rounded = false); -void drawRect(NVGcontext*, Vec4 vec, const NVGpaint& p, bool rounded = false); -void drawRect(NVGcontext*, Vec4 vec, const NVGpaint&& p, bool rounded = false); +void drawRect(NVGcontext*, const Vec4& v, const NVGpaint& p, bool rounded = false); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, float x, float y, float w, float h, Colour c); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, Vec4 vec, Colour c); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, float x, float y, float w, float h, const NVGcolor& c); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, float x, float y, float w, float h, const NVGcolor&& c); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, Vec4 vec, const NVGcolor& c); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, Vec4 vec, const NVGcolor&& c); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, float x, float y, float w, float h, const NVGpaint& p); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, float x, float y, float w, float h, const NVGpaint&& p); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, Vec4 vec, const NVGpaint& p); -void drawRectOutline(NVGcontext*, float size, const NVGcolor& out_col, Vec4 vec, const NVGpaint&& p); +void drawRectOutline(NVGcontext*, const Theme*, float size, float x, float y, float w, float h); +void drawRectOutline(NVGcontext*, const Theme*, float size, const Vec4& v); -void drawTriangle(NVGcontext*, float aX, float aY, float bX, float bY, float cX, float cY, Colour c); -void drawTriangle(NVGcontext*, float aX, float aY, float bX, float bY, float cX, float cY, const NVGcolor& c); -void drawTriangle(NVGcontext*, float aX, float aY, float bX, float bY, float cX, float cY, const NVGcolor&& c); -void drawTriangle(NVGcontext*, float aX, float aY, float bX, float bY, float cX, float cY, const NVGpaint& p); -void drawTriangle(NVGcontext*, float aX, float aY, float bX, float bY, float cX, float cY, const NVGpaint&& p); - -void drawText(NVGcontext*, float x, float y, float size, const char* str, const char* end, int align, Colour c); -void drawText(NVGcontext*, float x, float y, float size, Colour c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); -void drawText(NVGcontext*, Vec2 vec, float size, const char* str, const char* end, int align, Colour c); -void drawText(NVGcontext*, Vec2 vec, float size, Colour c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); void drawText(NVGcontext*, float x, float y, float size, const char* str, const char* end, int align, const NVGcolor& c); -void drawText(NVGcontext*, float x, float y, float size, const char* str, const char* end, int align, const NVGcolor&& c); void drawText(NVGcontext*, float x, float y, float size, const NVGcolor& c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); -void drawText(NVGcontext*, float x, float y, float size, const NVGcolor&& c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); -void drawText(NVGcontext*, Vec2 vec, float size, const char* str, const char* end, int align, const NVGcolor& c); -void drawText(NVGcontext*, Vec2 vec, float size, const char* str, const char* end, int align, const NVGcolor&& c); -void drawText(NVGcontext*, Vec2 vec, float size, const NVGcolor& c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); -void drawText(NVGcontext*, Vec2 vec, float size, const NVGcolor&& c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); -void drawTextArgs(NVGcontext*, float x, float y, float size, int align, Colour c, const char* str, ...) __attribute__ ((format (printf, 7, 8))); +void drawText(NVGcontext*, const Vec2& v, float size, const char* str, const char* end, int align, const NVGcolor& c); +void drawText(NVGcontext*, const Vec2& v, float size, const NVGcolor& c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); void drawTextArgs(NVGcontext*, float x, float y, float size, int align, const NVGcolor& c, const char* str, ...) __attribute__ ((format (printf, 7, 8))); -void drawTextBox(NVGcontext*, float x, float y, float size, float bound, NVGcolor& c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); -void drawTextBox(NVGcontext*, float x, float y, float size, float bound, NVGcolor&& c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); -void drawTextBox(NVGcontext*, float x, float y, float size, float bound, Colour c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); +void drawTextBox(NVGcontext*, float x, float y, float size, float bound, const NVGcolor& c, const char* str, int align = NVG_ALIGN_LEFT | NVG_ALIGN_TOP, const char* end = nullptr); void textBounds(NVGcontext*, float x, float y, float *bounds, const char* str, ...) __attribute__ ((format (printf, 5, 6))); -// void textBounds(NVGcontext*, float *bounds, const char* str, ...) __attribute__ ((format (printf, 5, 6))); -// void textBounds(NVGcontext*, float *bounds, const char* str); auto getButton(Button button) -> const char*; -void drawScrollbar(NVGcontext* vg, Theme* theme, u32 index_off, u32 count, u32 max_per_page); -void drawScrollbar(NVGcontext* vg, Theme* theme, float x, float y, float h, u32 index_off, u32 count, u32 max_per_page); +void drawScrollbar(NVGcontext*, const Theme*, u32 index_off, u32 count, u32 max_per_page); +void drawScrollbar(NVGcontext*, const Theme*, float x, float y, float h, u32 index_off, u32 count, u32 max_per_page); -void drawScrollbar2(NVGcontext* vg, Theme* theme, float x, float y, float h, s64 index_off, s64 count, s64 row, s64 page); -void drawScrollbar2(NVGcontext* vg, Theme* theme, s64 index_off, s64 count, s64 row, s64 page); +void drawScrollbar2(NVGcontext*, const Theme*, float x, float y, float h, s64 index_off, s64 count, s64 row, s64 page); +void drawScrollbar2(NVGcontext*, const Theme*, s64 index_off, s64 count, s64 row, s64 page); void updateHighlightAnimation(); void getHighlightAnimation(float* gradientX, float* gradientY, float* color); diff --git a/sphaira/include/ui/types.hpp b/sphaira/include/ui/types.hpp index 616fd32..a8b68d2 100644 --- a/sphaira/include/ui/types.hpp +++ b/sphaira/include/ui/types.hpp @@ -162,21 +162,55 @@ struct ElementEntry { }; enum ThemeEntryID { + // colour of the background, can be an image. ThemeEntryID_BACKGROUND, - + // colour of the grid background (homebrew, appstore), can be an image. ThemeEntryID_GRID, - ThemeEntryID_SELECTED, - ThemeEntryID_SELECTED_OVERLAY, - ThemeEntryID_TEXT, - ThemeEntryID_TEXT_SELECTED, + // background colour of a popup. + ThemeEntryID_POPUP, + // colour of the error text / button. + ThemeEntryID_ERROR, + // colour of all text. + ThemeEntryID_TEXT, + // colour of text info and subheaders. + ThemeEntryID_TEXT_INFO, + // colour of selected item text. + ThemeEntryID_TEXT_SELECTED, + // background colour of a selected item, can be an image (not recommended). + ThemeEntryID_SELECTED_BACKGROUND, + + // colour of line separators in a list. + ThemeEntryID_LINE, + ThemeEntryID_LINE_SEPERATOR, + + // colour of the sidebar backrgound. + ThemeEntryID_SIDEBAR, + + // colour of the scrollbar (full portion). + ThemeEntryID_SCROLLBAR, + // colour of the scrollbar background (empty portion). + ThemeEntryID_SCROLLBAR_BACKGROUND, + + // colour of the progressbar (full portion). + ThemeEntryID_PROGRESSBAR, + // colour of the progressbar background (empty portion). + ThemeEntryID_PROGRESSBAR_BACKGROUND, + + // the colours of the pulsing effect, from 1 -> 2. + ThemeEntryID_HIGHLIGHT_1, + ThemeEntryID_HIGHLIGHT_2, + + // changes the colours of the internal icons used below. + ThemeEntryID_ICON_COLOUR, + + // images used in the filebrowser. ThemeEntryID_ICON_AUDIO, ThemeEntryID_ICON_VIDEO, ThemeEntryID_ICON_IMAGE, ThemeEntryID_ICON_FILE, ThemeEntryID_ICON_FOLDER, ThemeEntryID_ICON_ZIP, - ThemeEntryID_ICON_GAME, ThemeEntryID_ICON_NRO, ThemeEntryID_MAX, @@ -194,6 +228,10 @@ struct Theme { ThemeMeta meta; PLSR_BFSTM music; ElementEntry elements[ThemeEntryID_MAX]; + + auto GetColour(ThemeEntryID id) const { + return elements[id].colour; + } }; // enum class TouchGesture { diff --git a/sphaira/source/app.cpp b/sphaira/source/app.cpp index b2348a6..a5857fa 100644 --- a/sphaira/source/app.cpp +++ b/sphaira/source/app.cpp @@ -747,6 +747,48 @@ void App::Poll() { hidGetTouchScreenStates(&state, 1); m_touch_info.is_clicked = false; +// todo: replace old touch code with gestures from below +#if 0 + static HidGestureState prev_gestures[17]{}; + HidGestureState gestures[17]{}; + const auto gesture_count = hidGetGestureStates(gestures, std::size(gestures)); + for (int i = (int)gesture_count - 1; i >= 0; i--) { + bool found = false; + for (int j = 0; j < gesture_count; j++) { + if (gestures[i].type == prev_gestures[j].type && gestures[i].sampling_number == prev_gestures[j].sampling_number) { + found = true; + break; + } + } + + if (found) { + continue; + } + + auto gesture = gestures[i]; + if (gesture_count && gesture.type == HidGestureType_Swipe) { + log_write("[SWIPE] got gesture type: %d direction: %d sampling_number: %d context_number: %d\n", gesture.type, gesture.direction, gesture.sampling_number, gesture.context_number); + } + else if (gesture_count && gesture.type == HidGestureType_Tap) { + log_write("[TAP] got gesture type: %d direction: %d sampling_number: %d context_number: %d\n", gesture.type, gesture.direction, gesture.sampling_number, gesture.context_number); + } + else if (gesture_count && gesture.type == HidGestureType_Press) { + log_write("[PRESS] got gesture type: %d direction: %d sampling_number: %d context_number: %d\n", gesture.type, gesture.direction, gesture.sampling_number, gesture.context_number); + } + else if (gesture_count && gesture.type == HidGestureType_Cancel) { + log_write("[CANCEL] got gesture type: %d direction: %d sampling_number: %d context_number: %d\n", gesture.type, gesture.direction, gesture.sampling_number, gesture.context_number); + } + else if (gesture_count && gesture.type == HidGestureType_Complete) { + log_write("[COMPLETE] got gesture type: %d direction: %d sampling_number: %d context_number: %d\n", gesture.type, gesture.direction, gesture.sampling_number, gesture.context_number); + } + else if (gesture_count && gesture.type == HidGestureType_Pan) { + log_write("[PAN] got gesture sampling_number: %d context_number: %d x: %d y: %d dx: %d dy: %d vx: %.2f vy: %.2f count: %d\n", gesture.sampling_number, gesture.context_number, gesture.x, gesture.y, gesture.delta_x, gesture.delta_y, gesture.velocity_x, gesture.velocity_y, gesture.point_count); + } + } + + memcpy(prev_gestures, gestures, sizeof(gestures)); +#endif + if (state.count == 1 && !m_touch_info.is_touching) { m_touch_info.initial = m_touch_info.cur = state.touches[0]; m_touch_info.is_touching = true; @@ -860,7 +902,13 @@ void DrawElement(const Vec4& v, ThemeEntryID id) { case ElementType::None: { } break; case ElementType::Texture: { - const auto paint = nvgImagePattern(g_app->vg, v.x, v.y, v.w, v.h, 0, e.texture, 1.f); + auto paint = nvgImagePattern(g_app->vg, v.x, v.y, v.w, v.h, 0, e.texture, 1.f); + // override the icon colours if set + if (id > ThemeEntryID_ICON_COLOUR && id < ThemeEntryID_MAX) { + if (g_app->m_theme.elements[ThemeEntryID_ICON_COLOUR].type != ElementType::None) { + paint.innerColor = g_app->m_theme.GetColour(ThemeEntryID_ICON_COLOUR); + } + } ui::gfx::drawRect(g_app->vg, v, paint); } break; case ElementType::Colour: { @@ -885,62 +933,113 @@ auto App::LoadElementColour(std::string_view value) -> ElementEntry { if (value.starts_with("0x")) { value = value.substr(2); - } else if (value.starts_with('#')) { - value = value.substr(1); + } else { + return {}; } - const u32 c = std::strtol(value.data(), nullptr, 16); - if (c) { - entry.colour = nvgRGBA((c >> 24) & 0xFF, (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF); - entry.type = ElementType::Colour; + char* end; + u32 c = std::strtoul(value.data(), &end, 16); + if (!c && value.data() == end) { + return {}; } + // force alpha bit if not already set. + if (value.length() <= 6) { + c <<= 8; + c |= 0xFF; + } + + entry.colour = nvgRGBA((c >> 24) & 0xFF, (c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF); + entry.type = ElementType::Colour; return entry; } -auto App::LoadElement(std::string_view value) -> ElementEntry { +auto App::LoadElement(std::string_view value, ElementType type) -> ElementEntry { if (value.size() <= 1) { return {}; } - if (auto e = LoadElementImage(value); e.type != ElementType::None) { - return e; + if (type == ElementType::None || type == ElementType::Colour) { + // most assets are colours, so prioritise this first + if (auto e = LoadElementColour(value); e.type != ElementType::None) { + return e; + } } - if (auto e = LoadElementColour(value); e.type != ElementType::None) { - return e; + if (type == ElementType::None || type == ElementType::Texture) { + if (auto e = LoadElementImage(value); e.type != ElementType::None) { + return e; + } } return {}; } -void App::CloseTheme() { - m_theme.meta.name.clear(); - m_theme.meta.author.clear(); - m_theme.meta.version.clear(); - m_theme.meta.ini_path.clear(); - +void App::CloseMusic() { if (m_sound_ids[SoundEffect_Music]) { plsrPlayerFree(m_sound_ids[SoundEffect_Music]); m_sound_ids[SoundEffect_Music] = nullptr; plsrBFSTMClose(&m_theme.music); } +} + +void App::CloseTheme() { + CloseMusic(); for (auto& e : m_theme.elements) { if (e.type == ElementType::Texture) { nvgDeleteImage(vg, e.texture); } - e.type = ElementType::None; } + + m_theme = {}; } -void App::LoadTheme(const ThemeMeta& meta) { +void App::LoadTheme(ThemeMeta meta, int inherit_level) { // reset theme CloseTheme(); + static constexpr struct ThemeIdPair{ + const char* label; + ThemeEntryID id; + ElementType type{ElementType::None}; + } theme_entries[] = { + { "background", ThemeEntryID_BACKGROUND }, + { "grid", ThemeEntryID_GRID }, + { "text", ThemeEntryID_TEXT, ElementType::Colour }, + { "text_info", ThemeEntryID_TEXT_INFO, ElementType::Colour }, + { "text_selected", ThemeEntryID_TEXT_SELECTED, ElementType::Colour }, + { "selected_background", ThemeEntryID_SELECTED_BACKGROUND, ElementType::Colour }, + { "popup", ThemeEntryID_POPUP, ElementType::Colour }, + { "line", ThemeEntryID_LINE, ElementType::Colour }, + { "line_seperator", ThemeEntryID_LINE_SEPERATOR, ElementType::Colour }, + { "sidebar", ThemeEntryID_SIDEBAR, ElementType::Colour }, + { "scrollbar", ThemeEntryID_SCROLLBAR, ElementType::Colour }, + { "scrollbar_background", ThemeEntryID_SCROLLBAR_BACKGROUND, ElementType::Colour }, + { "progressbar", ThemeEntryID_PROGRESSBAR, ElementType::Colour }, + { "progressbar_background", ThemeEntryID_PROGRESSBAR_BACKGROUND, ElementType::Colour }, + { "highlight_1", ThemeEntryID_HIGHLIGHT_1, ElementType::Colour }, + { "highlight_2", ThemeEntryID_HIGHLIGHT_2, ElementType::Colour }, + { "icon_colour", ThemeEntryID_ICON_COLOUR, ElementType::Colour }, + { "icon_audio", ThemeEntryID_ICON_AUDIO, ElementType::Texture }, + { "icon_video", ThemeEntryID_ICON_VIDEO, ElementType::Texture }, + { "icon_image", ThemeEntryID_ICON_IMAGE, ElementType::Texture }, + { "icon_file", ThemeEntryID_ICON_FILE, ElementType::Texture }, + { "icon_folder", ThemeEntryID_ICON_FOLDER, ElementType::Texture }, + { "icon_zip", ThemeEntryID_ICON_ZIP, ElementType::Texture }, + { "icon_nro", ThemeEntryID_ICON_NRO, ElementType::Texture }, + }; + + const auto inherit_level_max = 5; + + // all themes will inherit from black theme by default. + if (meta.inherit.empty() && !inherit_level) { + meta.inherit = "romfs:/themes/base_black_theme.ini"; + } + // check if the theme inherits from another, if so, load it. // block inheriting from itself. - if (!meta.inherit.empty() && meta.inherit != meta.ini_path) { + if (inherit_level < inherit_level_max && !meta.inherit.empty() && strcasecmp(meta.inherit, "none") && meta.inherit != meta.ini_path) { log_write("inherit is not empty: %s\n", meta.inherit.s); if (R_SUCCEEDED(romfsInit())) { ThemeMeta inherit_meta; @@ -952,7 +1051,7 @@ void App::LoadTheme(const ThemeMeta& meta) { inherit_meta.ini_path = meta.inherit; } - LoadTheme(inherit_meta); + LoadTheme(inherit_meta, inherit_level + 1); } } @@ -961,45 +1060,23 @@ void App::LoadTheme(const ThemeMeta& meta) { const auto cb = [](const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData) -> int { auto app = static_cast(UserData); auto& theme = app->m_theme; - std::string_view section{Section}; - std::string_view key{Key}; - std::string_view value{Value}; - if (section == "theme") { - if (key == "background") { - theme.elements[ThemeEntryID_BACKGROUND] = app->LoadElement(value); - } else if (key == "music") { + if (!std::strcmp(Section, "theme")) { + if (!std::strcmp(Key, "music")) { + app->CloseMusic(); if (R_SUCCEEDED(plsrBFSTMOpen(Value, &theme.music))) { if (R_SUCCEEDED(plsrPlayerLoadStream(&theme.music, &app->m_sound_ids[SoundEffect_Music]))) { app->PlaySoundEffect(SoundEffect_Music); } } - } else if (key == "grid") { - theme.elements[ThemeEntryID_GRID] = app->LoadElement(value); - } else if (key == "selected") { - theme.elements[ThemeEntryID_SELECTED] = app->LoadElement(value); - } else if (key == "selected_overlay") { - theme.elements[ThemeEntryID_SELECTED_OVERLAY] = app->LoadElement(value); - } else if (key == "text") { - theme.elements[ThemeEntryID_TEXT] = app->LoadElementColour(value); - } else if (key == "text_selected") { - theme.elements[ThemeEntryID_TEXT_SELECTED] = app->LoadElementColour(value); - } else if (key == "icon_audio") { - theme.elements[ThemeEntryID_ICON_AUDIO] = app->LoadElement(value); - } else if (key == "icon_video") { - theme.elements[ThemeEntryID_ICON_VIDEO] = app->LoadElement(value); - } else if (key == "icon_image") { - theme.elements[ThemeEntryID_ICON_IMAGE] = app->LoadElement(value); - } else if (key == "icon_file") { - theme.elements[ThemeEntryID_ICON_FILE] = app->LoadElement(value); - } else if (key == "icon_folder") { - theme.elements[ThemeEntryID_ICON_FOLDER] = app->LoadElement(value); - } else if (key == "icon_zip") { - theme.elements[ThemeEntryID_ICON_ZIP] = app->LoadElement(value); - } else if (key == "icon_game") { - theme.elements[ThemeEntryID_ICON_GAME] = app->LoadElement(value); - } else if (key == "icon_nro") { - theme.elements[ThemeEntryID_ICON_NRO] = app->LoadElement(value); + } else { + for (auto& e : theme_entries) { + if (!std::strcmp(Key, e.label)) { + // log_write("\tfound: %s value: %s\n", Key, Value); + theme.elements[e.id] = app->LoadElement(Value, e.type); + break; + } + } } } @@ -1207,6 +1284,7 @@ App::App(const char* argv0) { appletHook(&m_appletHookCookie, appplet_hook_calback, this); hidInitializeTouchScreen(); + hidInitializeGesture(); padConfigureInput(8, HidNpadStyleSet_NpadStandard); // padInitializeDefault(&m_pad); padInitializeAny(&m_pad); diff --git a/sphaira/source/ui/error_box.cpp b/sphaira/source/ui/error_box.cpp index 02f4f30..c35b61b 100644 --- a/sphaira/source/ui/error_box.cpp +++ b/sphaira/source/ui/error_box.cpp @@ -1136,18 +1136,18 @@ auto ErrorBox::Update(Controller* controller, TouchInfo* touch) -> void { auto ErrorBox::Draw(NVGcontext* vg, Theme* theme) -> void { gfx::dimBackground(vg); - gfx::drawRect(vg, m_pos, theme->elements[ThemeEntryID_SELECTED].colour); + gfx::drawRect(vg, m_pos, theme->GetColour(ThemeEntryID_POPUP)); const Vec4 box = { 455, 470, 365, 65 }; const auto center_x = m_pos.x + m_pos.w/2; - gfx::drawTextArgs(vg, center_x, 180, 63, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, gfx::Colour::RED, "\uE140"); - gfx::drawTextArgs(vg, center_x, 270, 25, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->elements[ThemeEntryID_TEXT].colour, "Error code: 0x%X Module: %s Description: %s", m_code, m_module_str.c_str(), m_description_str.c_str()); - gfx::drawTextArgs(vg, center_x, 325, 23, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->elements[ThemeEntryID_TEXT].colour, "%s", m_message.c_str()); - gfx::drawTextArgs(vg, center_x, 380, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, gfx::Colour::SILVER, "If this message appears repeatedly, please open an issue."_i18n.c_str()); - gfx::drawTextArgs(vg, center_x, 415, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, gfx::Colour::SILVER, "https://github.com/ITotalJustice/sphaira/issues"); - gfx::drawRectOutline(vg, 4.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour, box, theme->elements[ThemeEntryID_SELECTED].colour); - gfx::drawTextArgs(vg, center_x, box.y + box.h/2, 23, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, gfx::Colour::WHITE, "OK"_i18n.c_str()); + gfx::drawTextArgs(vg, center_x, 180, 63, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_ERROR), "\uE140"); + gfx::drawTextArgs(vg, center_x, 270, 25, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "Error code: 0x%X Module: %s Description: %s", m_code, m_module_str.c_str(), m_description_str.c_str()); + gfx::drawTextArgs(vg, center_x, 325, 23, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%s", m_message.c_str()); + gfx::drawTextArgs(vg, center_x, 380, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "If this message appears repeatedly, please open an issue."_i18n.c_str()); + gfx::drawTextArgs(vg, center_x, 415, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "https://github.com/ITotalJustice/sphaira/issues"); + gfx::drawRectOutline(vg, theme, 4.f, box); + gfx::drawTextArgs(vg, center_x, box.y + box.h/2, 23, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT), "OK"_i18n.c_str()); } } // namespace sphaira::ui diff --git a/sphaira/source/ui/menus/appstore.cpp b/sphaira/source/ui/menus/appstore.cpp index 21dfefe..c7ece08 100644 --- a/sphaira/source/ui/menus/appstore.cpp +++ b/sphaira/source/ui/menus/appstore.cpp @@ -271,11 +271,19 @@ void DrawIcon(NVGcontext* vg, const LazyImage& l, const LazyImage& d, float x, f rounded_image = false; gfx::drawRect(vg, x, y, w, h, nvgRGB(i.first_pixel[0], i.first_pixel[1], i.first_pixel[2]), rounded); } + if (iw > w || ih > h) { + crop = true; + nvgSave(vg); + nvgIntersectScissor(vg, x, y, w, h); + } if (rounded_image) { gfx::drawImageRounded(vg, ix, iy, iw, ih, i.image); } else { gfx::drawImage(vg, ix, iy, iw, ih, i.image); } + if (crop) { + nvgRestore(vg); + } } void DrawIcon(NVGcontext* vg, const LazyImage& l, const LazyImage& d, Vec4 vec, bool rounded = true, float scale = 1.0) { @@ -725,11 +733,13 @@ void EntryMenu::Draw(NVGcontext* vg, Theme* theme) { constexpr Vec4 line_vec(30, 86, 1220, 646); constexpr Vec4 banner_vec(70, line_vec.y + 20, 848.f, 208.f); constexpr Vec4 icon_vec(968, line_vec.y + 30, 256, 150); + constexpr Vec4 grid_vec(icon_vec.x - 50, line_vec.y + 1, line_vec.w, line_vec.h - line_vec.y - 1); // nvgSave(vg); // nvgScissor(vg, line_vec.x, line_vec.y, line_vec.w - line_vec.x, line_vec.h - line_vec.y); // clip // ON_SCOPE_EXIT(nvgRestore(vg)); + gfx::drawRect(vg, grid_vec, theme->GetColour(ThemeEntryID_GRID)); DrawIcon(vg, m_banner, m_entry.image.image ? m_entry.image : m_default_icon, banner_vec, false); DrawIcon(vg, m_entry.image, m_default_icon, icon_vec); @@ -738,19 +748,19 @@ void EntryMenu::Draw(NVGcontext* vg, Theme* theme) { const float text_inc_y = 32; const float font_size = 20; - gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->elements[ThemeEntryID_TEXT].colour, "version: %s"_i18n.c_str(), m_entry.version.c_str()); + gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "version: %s"_i18n.c_str(), m_entry.version.c_str()); text_start_y += text_inc_y; - gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->elements[ThemeEntryID_TEXT].colour, "updated: %s"_i18n.c_str(), m_entry.updated.c_str()); + gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "updated: %s"_i18n.c_str(), m_entry.updated.c_str()); text_start_y += text_inc_y; - gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->elements[ThemeEntryID_TEXT].colour, "category: %s"_i18n.c_str(), m_entry.category.c_str()); + gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "category: %s"_i18n.c_str(), m_entry.category.c_str()); text_start_y += text_inc_y; - gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->elements[ThemeEntryID_TEXT].colour, "extracted: %.2f MiB"_i18n.c_str(), (double)m_entry.extracted / 1024.0); + gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "extracted: %.2f MiB"_i18n.c_str(), (double)m_entry.extracted / 1024.0); text_start_y += text_inc_y; - gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->elements[ThemeEntryID_TEXT].colour, "app_dls: %s"_i18n.c_str(), AppDlToStr(m_entry.app_dls).c_str()); + gfx::drawTextArgs(vg, text_start_x, text_start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "app_dls: %s"_i18n.c_str(), AppDlToStr(m_entry.app_dls).c_str()); text_start_y += text_inc_y; // for (const auto& option : m_options) { - const auto& text_col = theme->elements[ThemeEntryID_TEXT].colour; + const auto& text_col = theme->GetColour(ThemeEntryID_TEXT); // todo: rewrite this mess and use list constexpr float mm = 0;//20; @@ -766,10 +776,10 @@ void EntryMenu::Draw(NVGcontext* vg, Theme* theme) { auto text_id = ThemeEntryID_TEXT; if (m_index == i) { text_id = ThemeEntryID_TEXT_SELECTED; - gfx::drawRectOutline(vg, 4.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour, x, y, w, h, theme->elements[ThemeEntryID_SELECTED].colour); + gfx::drawRectOutline(vg, theme, 4.f, Vec4{x, y, w, h}); } - gfx::drawTextArgs(vg, x + w / 2, y + h / 2, 22, NVG_ALIGN_MIDDLE | NVG_ALIGN_CENTER, theme->elements[ThemeEntryID_TEXT].colour, option.display_text.c_str()); + gfx::drawTextArgs(vg, x + w / 2, y + h / 2, 22, NVG_ALIGN_MIDDLE | NVG_ALIGN_CENTER, theme->GetColour(ThemeEntryID_TEXT), option.display_text.c_str()); y -= block.h + 18; } @@ -1022,12 +1032,12 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { MenuBase::Draw(vg, theme); if (m_entries.empty()) { - gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, gfx::Colour::YELLOW, "Loading..."_i18n.c_str()); + gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "Loading..."_i18n.c_str()); return; } if (m_entries_current.empty()) { - gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, gfx::Colour::YELLOW, "Empty!"_i18n.c_str()); + gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "Empty!"_i18n.c_str()); return; } @@ -1096,7 +1106,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { auto text_id = ThemeEntryID_TEXT; if (pos == m_index) { text_id = ThemeEntryID_TEXT_SELECTED; - gfx::drawRectOutline(vg, 4.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour, x, y, w, h, theme->elements[ThemeEntryID_SELECTED].colour); + gfx::drawRectOutline(vg, theme, 4.f, v); } else { DrawElement(x, y, w, h, ThemeEntryID_GRID); } @@ -1111,9 +1121,9 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { nvgIntersectScissor(vg, v.x, v.y, w - 30.f, h); // clip { const float font_size = 18; - gfx::drawTextArgs(vg, x + 148, y + 45, font_size, NVG_ALIGN_LEFT, theme->elements[text_id].colour, e.title.c_str()); - gfx::drawTextArgs(vg, x + 148, y + 80, font_size, NVG_ALIGN_LEFT, theme->elements[text_id].colour, e.author.c_str()); - gfx::drawTextArgs(vg, x + 148, y + 115, font_size, NVG_ALIGN_LEFT, theme->elements[text_id].colour, e.version.c_str()); + gfx::drawTextArgs(vg, x + 148, y + 45, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), e.title.c_str()); + gfx::drawTextArgs(vg, x + 148, y + 80, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), e.author.c_str()); + gfx::drawTextArgs(vg, x + 148, y + 115, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), e.version.c_str()); } nvgRestore(vg); diff --git a/sphaira/source/ui/menus/filebrowser.cpp b/sphaira/source/ui/menus/filebrowser.cpp index 7e1fb7f..3eb8f60 100644 --- a/sphaira/source/ui/menus/filebrowser.cpp +++ b/sphaira/source/ui/menus/filebrowser.cpp @@ -578,7 +578,7 @@ void Menu::Update(Controller* controller, TouchInfo* touch) { void Menu::Draw(NVGcontext* vg, Theme* theme) { MenuBase::Draw(vg, theme); - const auto& text_col = theme->elements[ThemeEntryID_TEXT].colour; + const auto& text_col = theme->GetColour(ThemeEntryID_TEXT); if (m_entries_current.empty()) { gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, text_col, "Empty..."_i18n.c_str()); @@ -605,19 +605,17 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { } if (e.IsSelected()) { - // gfx::drawText(vg, x - 60.f, y + (h / 2.f) - (48.f / 2), 48.f, "\uE14B", nullptr, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, gfx::Colour::CYAN); - gfx::drawText(vg, x, y + (h / 2.f) - (24.f / 2), 24.f, "\uE14B", nullptr, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, gfx::Colour::CYAN); + gfx::drawText(vg, Vec2{x, y + (h / 2.f) - (24.f / 2)}, 24.f, "\uE14B", nullptr, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_SELECTED)); } auto text_id = ThemeEntryID_TEXT; if (m_index == i) { text_id = ThemeEntryID_TEXT_SELECTED; - gfx::drawRectOutline(vg, 4.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour, x, y, w, h, theme->elements[ThemeEntryID_SELECTED].colour); + gfx::drawRectOutline(vg, theme, 4.f, v); } else { - if (i == m_index) { - gfx::drawRect(vg, x, y, w, 1.f, text_col); + if (i != m_entries_current.size() - 1) { + gfx::drawRect(vg, Vec4{x, y + h, w, 1.f}, theme->GetColour(ThemeEntryID_LINE_SEPERATOR)); } - gfx::drawRect(vg, x, y + h, w, 1.f, text_col); } if (e.IsDir()) { @@ -642,12 +640,12 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { nvgSave(vg); nvgIntersectScissor(vg, x + text_xoffset+65, y, w-(x+text_xoffset+65+50), h); - gfx::drawText(vg, x + text_xoffset+65, y + (h / 2.f), 20.f, e.name, NULL, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->elements[text_id].colour); + gfx::drawText(vg, x + text_xoffset+65, y + (h / 2.f), 20.f, e.name, NULL, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id)); nvgRestore(vg); if (e.IsDir()) { - gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->elements[text_id].colour, "%zd files"_i18n.c_str(), e.file_count); - gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->elements[text_id].colour, "%zd dirs"_i18n.c_str(), e.dir_count); + gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%zd files"_i18n.c_str(), e.file_count); + gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(text_id), "%zd dirs"_i18n.c_str(), e.dir_count); } else { if (!e.time_stamp.is_valid) { const auto path = GetNewPath(e); @@ -656,11 +654,11 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { const auto t = (time_t)(e.time_stamp.modified); struct tm tm{}; localtime_r(&t, &tm); - gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->elements[text_id].colour, "%02u/%02u/%u", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900); + gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) + 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(text_id), "%02u/%02u/%u", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900); if ((double)e.file_size / 1024.0 / 1024.0 <= 0.009) { - gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->elements[text_id].colour, "%.2f KiB", (double)e.file_size / 1024.0); + gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%.2f KiB", (double)e.file_size / 1024.0); } else { - gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->elements[text_id].colour, "%.2f MiB", (double)e.file_size / 1024.0 / 1024.0); + gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f) - 3, 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_BOTTOM, theme->GetColour(text_id), "%.2f MiB", (double)e.file_size / 1024.0 / 1024.0); } } }); diff --git a/sphaira/source/ui/menus/ghdl.cpp b/sphaira/source/ui/menus/ghdl.cpp index a19fcc1..2414b4a 100644 --- a/sphaira/source/ui/menus/ghdl.cpp +++ b/sphaira/source/ui/menus/ghdl.cpp @@ -386,7 +386,7 @@ void Menu::Update(Controller* controller, TouchInfo* touch) { void Menu::Draw(NVGcontext* vg, Theme* theme) { MenuBase::Draw(vg, theme); - const auto& text_col = theme->elements[ThemeEntryID_TEXT].colour; + const auto& text_col = theme->GetColour(ThemeEntryID_TEXT); if (m_entries.empty()) { gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, text_col, "Empty..."_i18n.c_str()); @@ -402,20 +402,19 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { auto text_id = ThemeEntryID_TEXT; if (m_index == i) { text_id = ThemeEntryID_TEXT_SELECTED; - gfx::drawRectOutline(vg, 4.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour, x, y, w, h, theme->elements[ThemeEntryID_SELECTED].colour); + gfx::drawRectOutline(vg, theme, 4.f, v); } else { - if (i == m_index) { - gfx::drawRect(vg, x, y, w, 1.f, text_col); + if (i != m_entries.size() - 1) { + gfx::drawRect(vg, x, y + h, w, 1.f, theme->GetColour(ThemeEntryID_LINE_SEPERATOR)); } - gfx::drawRect(vg, x, y + h, w, 1.f, text_col); } nvgSave(vg); nvgIntersectScissor(vg, x + text_xoffset, y, w-(x+text_xoffset+50), h); - gfx::drawTextArgs(vg, x + text_xoffset, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->elements[text_id].colour, "%s By %s", e.repo.c_str(), e.owner.c_str()); + gfx::drawTextArgs(vg, x + text_xoffset, y + (h / 2.f), 20.f, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "%s By %s", e.repo.c_str(), e.owner.c_str()); nvgRestore(vg); - gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->elements[text_id].colour, "version: %s", e.tag.c_str()); + gfx::drawTextArgs(vg, x + w - text_xoffset, y + (h / 2.f), 16.f, NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE, theme->GetColour(text_id), "version: %s", e.tag.c_str()); }); } diff --git a/sphaira/source/ui/menus/homebrew.cpp b/sphaira/source/ui/menus/homebrew.cpp index 2ed0907..53d5b2e 100644 --- a/sphaira/source/ui/menus/homebrew.cpp +++ b/sphaira/source/ui/menus/homebrew.cpp @@ -196,7 +196,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { auto text_id = ThemeEntryID_TEXT; if (pos == m_index) { text_id = ThemeEntryID_TEXT_SELECTED; - gfx::drawRectOutline(vg, 4.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour, v, theme->elements[ThemeEntryID_SELECTED].colour); + gfx::drawRectOutline(vg, theme, 4.f, v); } else { DrawElement(v, ThemeEntryID_GRID); } @@ -216,9 +216,9 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { } const float font_size = 18; - gfx::drawTextArgs(vg, x + 148, y + 45, font_size, NVG_ALIGN_LEFT, theme->elements[text_id].colour, "%s%s", has_star ? "\u2605 " : "", e.GetName()); - gfx::drawTextArgs(vg, x + 148, y + 80, font_size, NVG_ALIGN_LEFT, theme->elements[text_id].colour, e.GetAuthor()); - gfx::drawTextArgs(vg, x + 148, y + 115, font_size, NVG_ALIGN_LEFT, theme->elements[text_id].colour, e.GetDisplayVersion()); + gfx::drawTextArgs(vg, x + 148, y + 45, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), "%s%s", has_star ? "\u2605 " : "", e.GetName()); + gfx::drawTextArgs(vg, x + 148, y + 80, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), e.GetAuthor()); + gfx::drawTextArgs(vg, x + 148, y + 115, font_size, NVG_ALIGN_LEFT, theme->GetColour(text_id), e.GetDisplayVersion()); } nvgRestore(vg); }); diff --git a/sphaira/source/ui/menus/menu_base.cpp b/sphaira/source/ui/menus/menu_base.cpp index b9a1009..0be00f8 100644 --- a/sphaira/source/ui/menus/menu_base.cpp +++ b/sphaira/source/ui/menus/menu_base.cpp @@ -41,7 +41,7 @@ void MenuBase::Draw(NVGcontext* vg, Theme* theme) { #define draw(...) \ gfx::textBounds(vg, 0, 0, bounds, __VA_ARGS__); \ start_x -= bounds[2] - bounds[0]; \ - gfx::drawTextArgs(vg, start_x, start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->elements[ThemeEntryID_TEXT].colour, __VA_ARGS__); \ + gfx::drawTextArgs(vg, start_x, start_y, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT), __VA_ARGS__); \ start_x -= spacing; // draw("version %s", APP_VERSION); @@ -58,17 +58,15 @@ void MenuBase::Draw(NVGcontext* vg, Theme* theme) { #undef draw - gfx::drawRect(vg, 30.f, 86.f, 1220.f, 1.f, theme->elements[ThemeEntryID_TEXT].colour); - gfx::drawRect(vg, 30.f, 646.0f, 1220.f, 1.f, theme->elements[ThemeEntryID_TEXT].colour); + gfx::drawRect(vg, 30.f, 86.f, 1220.f, 1.f, theme->GetColour(ThemeEntryID_TEXT)); + gfx::drawRect(vg, 30.f, 646.0f, 1220.f, 1.f, theme->GetColour(ThemeEntryID_TEXT)); nvgFontSize(vg, 28); gfx::textBounds(vg, 0, 0, bounds, m_title.c_str()); - gfx::drawTextArgs(vg, 80, start_y, 28.f, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->elements[ThemeEntryID_TEXT].colour, m_title.c_str()); - gfx::drawTextArgs(vg, 80 + (bounds[2] - bounds[0]) + 10, start_y, 16, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->elements[ThemeEntryID_TEXT].colour, m_title_sub_heading.c_str()); + gfx::drawTextArgs(vg, 80, start_y, 28.f, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str()); + gfx::drawTextArgs(vg, 80 + (bounds[2] - bounds[0]) + 10, start_y, 16, NVG_ALIGN_LEFT | NVG_ALIGN_BOTTOM, theme->GetColour(ThemeEntryID_TEXT_INFO), m_title_sub_heading.c_str()); - // gfx::drawTextArgs(vg, 80, 65, 28.f, NVG_ALIGN_LEFT, theme->elements[ThemeEntryID_TEXT].colour, m_title.c_str()); - // gfx::drawTextArgs(vg, 80, 680.f, 18, NVG_ALIGN_LEFT, theme->elements[ThemeEntryID_TEXT].colour, "%s", m_sub_heading.c_str()); - gfx::drawTextArgs(vg, 80, 685.f, 18, NVG_ALIGN_LEFT, theme->elements[ThemeEntryID_TEXT].colour, "%s", m_sub_heading.c_str()); + gfx::drawTextArgs(vg, 80, 685.f, 18, NVG_ALIGN_LEFT, theme->GetColour(ThemeEntryID_TEXT), "%s", m_sub_heading.c_str()); } void MenuBase::SetTitle(std::string title) { diff --git a/sphaira/source/ui/menus/themezer.cpp b/sphaira/source/ui/menus/themezer.cpp index 4321d28..5f289f6 100644 --- a/sphaira/source/ui/menus/themezer.cpp +++ b/sphaira/source/ui/menus/themezer.cpp @@ -542,7 +542,6 @@ Menu::Menu() : MenuBase{"Themezer"_i18n} { }}) ); - const Vec4 v{75, 110, 350, 250}; const Vec2 pad{10, 10}; m_list = std::make_unique(3, 6, m_pos, v, pad); @@ -582,7 +581,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { MenuBase::Draw(vg, theme); if (m_pages.empty()) { - gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, gfx::Colour::YELLOW, "Empty!"_i18n.c_str()); + gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "Empty!"_i18n.c_str()); return; } @@ -590,15 +589,15 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { switch (page.m_ready) { case PageLoadState::None: - gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, gfx::Colour::YELLOW, "Not Ready..."_i18n.c_str()); + gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "Not Ready..."_i18n.c_str()); return; case PageLoadState::Loading: - gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, gfx::Colour::YELLOW, "Loading"_i18n.c_str()); + gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "Loading"_i18n.c_str()); return; case PageLoadState::Done: break; case PageLoadState::Error: - gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, gfx::Colour::YELLOW, "Error loading page!"_i18n.c_str()); + gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "Error loading page!"_i18n.c_str()); return; } @@ -613,7 +612,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { auto text_id = ThemeEntryID_TEXT; if (pos == m_index) { text_id = ThemeEntryID_TEXT_SELECTED; - gfx::drawRectOutline(vg, 4.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour, x, y, w, h, theme->elements[ThemeEntryID_SELECTED].colour); + gfx::drawRectOutline(vg, theme, 4.f, v); } else { DrawElement(x, y, w, h, ThemeEntryID_GRID); } @@ -684,8 +683,8 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { nvgSave(vg); nvgIntersectScissor(vg, x, y, w - 30.f, h); // clip { - gfx::drawTextArgs(vg, x + xoff, y + 180 + 20, 18, NVG_ALIGN_LEFT, theme->elements[text_id].colour, "%s", e.details.name.c_str()); - gfx::drawTextArgs(vg, x + xoff, y + 180 + 55, 18, NVG_ALIGN_LEFT, theme->elements[text_id].colour, "%s", e.creator.display_name.c_str()); + gfx::drawTextArgs(vg, x + xoff, y + 180 + 20, 18, NVG_ALIGN_LEFT, theme->GetColour(text_id), "%s", e.details.name.c_str()); + gfx::drawTextArgs(vg, x + xoff, y + 180 + 55, 18, NVG_ALIGN_LEFT, theme->GetColour(text_id), "%s", e.creator.display_name.c_str()); } nvgRestore(vg); }); diff --git a/sphaira/source/ui/notification.cpp b/sphaira/source/ui/notification.cpp index c2b6934..fcd64bb 100644 --- a/sphaira/source/ui/notification.cpp +++ b/sphaira/source/ui/notification.cpp @@ -19,15 +19,9 @@ auto NotifEntry::Draw(NVGcontext* vg, Theme* theme, float y) -> bool { } auto NotifEntry::Draw(NVGcontext* vg, Theme* theme) -> void { - auto overlay_col = theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour; - auto selected_col = theme->elements[ThemeEntryID_SELECTED].colour; - auto text_col = theme->elements[ThemeEntryID_TEXT].colour; + auto text_col = theme->GetColour(ThemeEntryID_TEXT); float font_size = 18.f; - // overlay_col.a = 0.2f; - // selected_col.a = 0.2f; - // text_col.a = 0.2f; - // auto vg = App::GetVg(); if (!m_bounds_measured) { m_bounds_measured = true; m_pos.w = 320.f; @@ -49,7 +43,7 @@ auto NotifEntry::Draw(NVGcontext* vg, Theme* theme) -> void { } } - gfx::drawRectOutline(vg, 4.f, overlay_col, m_pos, selected_col); + gfx::drawRectOutline(vg, theme, 4.f, m_pos); gfx::drawText(vg, Vec2{m_pos.x + (m_pos.w / 2.f), m_pos.y + (m_pos.h / 2.f)}, font_size, text_col, m_text.c_str(), NVG_ALIGN_MIDDLE | NVG_ALIGN_CENTER); } diff --git a/sphaira/source/ui/nvg_util.cpp b/sphaira/source/ui/nvg_util.cpp index fd531cd..6bf0d3f 100644 --- a/sphaira/source/ui/nvg_util.cpp +++ b/sphaira/source/ui/nvg_util.cpp @@ -33,76 +33,41 @@ static constexpr std::array buttons = { std::pair{Button::R3, "\uE105"}, }; -#define F(a) (a/255.f) // turn range 0-255 to 0.f-1.f range -constexpr std::array COLOURS = { - std::pair{Colour::BLACK, { F(45.f), F(45.f), F(45.f), F(255.f) }}, - std::pair{Colour::LIGHT_BLACK, { F(50.f), F(50.f), F(50.f), F(255.f) }}, - std::pair{Colour::SILVER, { F(128.f), F(128.f), F(128.f), F(255.f) }}, - std::pair{Colour::DARK_GREY, { F(70.f), F(70.f), F(70.f), F(255.f) }}, - std::pair{Colour::GREY, { F(77.f), F(77.f), F(77.f), F(255.f) }}, - std::pair{Colour::WHITE, { F(251.f), F(251.f), F(251.f), F(255.f) }}, - std::pair{Colour::CYAN, { F(0.f), F(255.f), F(200.f), F(255.f) }}, - std::pair{Colour::TEAL, { F(143.f), F(253.f), F(252.f), F(255.f) }}, - std::pair{Colour::BLUE, { F(36.f), F(141.f), F(199.f), F(255.f) }}, - std::pair{Colour::LIGHT_BLUE, { F(26.f), F(188.f), F(252.f), F(255.f) }}, - std::pair{Colour::YELLOW, { F(255.f), F(177.f), F(66.f), F(255.f) }}, - std::pair{Colour::RED, { F(250.f), F(90.f), F(58.f), F(255.f) }} -}; -#undef F - // NEW --------------------- -inline void drawRectIntenal(NVGcontext* vg, const Vec4& vec, const NVGcolor& c, bool rounded) { +void drawRectIntenal(NVGcontext* vg, const Vec4& v, const NVGcolor& c, bool rounded) { nvgBeginPath(vg); if (rounded) { - nvgRoundedRect(vg, vec.x, vec.y, vec.w, vec.h, 15); + nvgRoundedRect(vg, v.x, v.y, v.w, v.h, 15); } else { - nvgRect(vg, vec.x, vec.y, vec.w, vec.h); + nvgRect(vg, v.x, v.y, v.w, v.h); } nvgFillColor(vg, c); nvgFill(vg); } -inline void drawRectIntenal(NVGcontext* vg, const Vec4& vec, const NVGpaint& p, bool rounded) { +void drawRectIntenal(NVGcontext* vg, const Vec4& v, const NVGpaint& p, bool rounded) { nvgBeginPath(vg); if (rounded) { - nvgRoundedRect(vg, vec.x, vec.y, vec.w, vec.h, 15); + nvgRoundedRect(vg, v.x, v.y, v.w, v.h, 15); } else { - nvgRect(vg, vec.x, vec.y, vec.w, vec.h); + nvgRect(vg, v.x, v.y, v.w, v.h); } nvgFillPaint(vg, p); nvgFill(vg); } -inline void drawRectOutlineInternal(NVGcontext* vg, float size, const NVGcolor& out_col, Vec4 vec, const NVGcolor& c) { +void drawRectOutlineInternal(NVGcontext* vg, const Theme* theme, float size, const Vec4& v) { float gradientX, gradientY, color; getHighlightAnimation(&gradientX, &gradientY, &color); -#if 0 - // NVGcolor pulsationColor = nvgRGBAf((color * out_col.r) + (1 - color) * out_col.r, - // (color * out_col.g) + (1 - color) * out_col.g, - // (color * out_col.b) + (1 - color) * out_col.b, - // out_col.a); - NVGcolor pulsationColor = nvgRGBAf((color * out_col.r) + (1 - color) * out_col.r, - (color * out_col.g) + (1 - color) * out_col.g, - (color * out_col.b) + (1 - color) * out_col.b, - out_col.a); - - drawRectIntenal(vg, {vec.x-size,vec.y-size,vec.w+(size*2.f),vec.h+(size * 2.f)}, pulsationColor, false); - drawRectIntenal(vg, vec, c, false); -#else const auto strokeWidth = 5.0; - auto v2 = vec; + auto v2 = v; v2.x -= strokeWidth / 2.0; v2.y -= strokeWidth / 2.0; v2.w += strokeWidth; v2.h += strokeWidth; const auto corner_radius = 0.5; - // nvgSave(vg); - // nvgResetScissor(vg); - - // const auto stroke_width = 5.0f; - // const auto shadow_corner_radius = 6.0f; const auto shadow_width = 2.0f; const auto shadow_offset = 10.0f; const auto shadow_feather = 10.0f; @@ -123,8 +88,8 @@ inline void drawRectOutlineInternal(NVGcontext* vg, float size, const NVGcolor& nvgFillPaint(vg, shadowPaint); nvgFill(vg); - const auto color1 = nvgRGB(25, 138, 198); - const auto color2 = nvgRGB(137, 241, 242); + const auto color1 = theme->GetColour(ThemeEntryID_HIGHLIGHT_1); + const auto color2 = theme->GetColour(ThemeEntryID_HIGHLIGHT_2); const auto borderColor = nvgRGBAf(color2.r, color2.g, color2.b, 0.5); const auto transparent = nvgRGBA(0, 0, 0, 0); @@ -160,55 +125,32 @@ inline void drawRectOutlineInternal(NVGcontext* vg, float size, const NVGcolor& nvgStrokeWidth(vg, strokeWidth); nvgRoundedRect(vg, v2.x, v2.y, v2.w, v2.h, corner_radius); nvgStroke(vg); - - drawRectIntenal(vg, {vec.x-size,vec.y-size,vec.w+(size*2.f),vec.h+(size * 2.f)}, pulsationColor, false); - drawRectIntenal(vg, vec, c, true); - nvgBeginPath(vg); - nvgRoundedRect(vg, vec.x, vec.y, vec.w, vec.h, corner_radius); - nvgFillColor(vg, c); - nvgFill(vg); - - // nvgRestore(vg); -#endif } -inline void drawRectOutlineInternal(NVGcontext* vg, float size, const NVGcolor& out_col, Vec4 vec, const NVGpaint& p) { - float gradientX, gradientY, color; - getHighlightAnimation(&gradientX, &gradientY, &color); - - NVGcolor pulsationColor = nvgRGBAf((color * out_col.r) + (1 - color) * out_col.r, - (color * out_col.g) + (1 - color) * out_col.g, - (color * out_col.b) + (1 - color) * out_col.b, - out_col.a); - - drawRectIntenal(vg, {vec.x-size,vec.y-size,vec.w+(size*2.f),vec.h+(size * 2.f)}, pulsationColor, false); - drawRectIntenal(vg, vec, p, false); -} - -inline void drawTriangleInternal(NVGcontext* vg, float aX, float aY, float bX, float bY, float cX, float cY, const NVGcolor& c) { +void drawRectOutlineInternal(NVGcontext* vg, const Theme* theme, float size, const Vec4& v, const NVGcolor& c) { + const auto corner_radius = 0.5; + drawRectOutlineInternal(vg, theme, size, v); nvgBeginPath(vg); - nvgMoveTo(vg, aX, aY); - nvgLineTo(vg, bX, bY); - nvgLineTo(vg, cX, cY); + nvgRoundedRect(vg, v.x, v.y, v.w, v.h, corner_radius); nvgFillColor(vg, c); nvgFill(vg); } -inline void drawTriangleInternal(NVGcontext* vg, float aX, float aY, float bX, float bY, float cX, float cY, const NVGpaint& p) { +void drawRectOutlineInternal(NVGcontext* vg, const Theme* theme, float size, const Vec4& v, const NVGpaint& p) { + const auto corner_radius = 0.5; + drawRectOutlineInternal(vg, theme, size, v); nvgBeginPath(vg); - nvgMoveTo(vg, aX, aY); - nvgLineTo(vg, bX, bY); - nvgLineTo(vg, cX, cY); + nvgRoundedRect(vg, v.x, v.y, v.w, v.h, corner_radius); nvgFillPaint(vg, p); nvgFill(vg); } -inline void drawTextIntenal(NVGcontext* vg, Vec2 vec, float size, const char* str, const char* end, int align, const NVGcolor& c) { +void drawTextIntenal(NVGcontext* vg, const Vec2& v, float size, const char* str, const char* end, int align, const NVGcolor& c) { nvgBeginPath(vg); nvgFontSize(vg, size); nvgTextAlign(vg, align); nvgFillColor(vg, c); - nvgText(vg, vec.x, vec.y, str, end); + nvgText(vg, v.x, v.y, str, end); } } // namespace @@ -222,15 +164,6 @@ const char* getButton(const Button want) { std::unreachable(); } -NVGcolor getColour(Colour want) { - for (auto& [key, val] : COLOURS) { - if (key == want) { - return val; - } - } - std::unreachable(); -} - void drawTextArgs(NVGcontext* vg, float x, float y, float size, int align, const NVGcolor& c, const char* str, ...) { std::va_list v; va_start(v, str); @@ -240,7 +173,7 @@ void drawTextArgs(NVGcontext* vg, float x, float y, float size, int align, const drawText(vg, x, y, size, buffer, nullptr, align, c); } -static void drawImageInternal(NVGcontext* vg, Vec4 v, int texture, int rounded = 0) { +static void drawImageInternal(NVGcontext* vg, const Vec4& v, int texture, int rounded = 0) { const auto paint = nvgImagePattern(vg, v.x, v.y, v.w, v.h, 0, texture, 1.f); // drawRect(vg, x, y, w, h, paint); nvgBeginPath(vg); @@ -254,7 +187,7 @@ static void drawImageInternal(NVGcontext* vg, Vec4 v, int texture, int rounded = nvgFill(vg); } -void drawImage(NVGcontext* vg, Vec4 v, int texture) { +void drawImage(NVGcontext* vg, const Vec4& v, int texture) { const auto paint = nvgImagePattern(vg, v.x, v.y, v.w, v.h, 0, texture, 1.f); drawRect(vg, v, paint, false); } @@ -263,7 +196,7 @@ void drawImage(NVGcontext* vg, float x, float y, float w, float h, int texture) drawImage(vg, Vec4(x, y, w, h), texture); } -void drawImageRounded(NVGcontext* vg, Vec4 v, int texture) { +void drawImageRounded(NVGcontext* vg, const Vec4& v, int texture) { const auto paint = nvgImagePattern(vg, v.x, v.y, v.w, v.h, 0, texture, 1.f); nvgBeginPath(vg); nvgRoundedRect(vg, v.x, v.y, v.w, v.h, 15); @@ -275,7 +208,7 @@ void drawImageRounded(NVGcontext* vg, float x, float y, float w, float h, int te drawImageRounded(vg, Vec4(x, y, w, h), texture); } -void drawTextBox(NVGcontext* vg, float x, float y, float size, float bound, NVGcolor& c, const char* str, int align, const char* end) { +void drawTextBox(NVGcontext* vg, float x, float y, float size, float bound, const NVGcolor& c, const char* str, int align, const char* end) { nvgBeginPath(vg); nvgFontSize(vg, size); nvgTextAlign(vg, align); @@ -283,14 +216,6 @@ void drawTextBox(NVGcontext* vg, float x, float y, float size, float bound, NVGc nvgTextBox(vg, x, y, bound, str, end); } -void drawTextBox(NVGcontext* vg, float x, float y, float size, float bound, NVGcolor&& c, const char* str, int align, const char* end) { - drawTextBox(vg, x, y, size, bound, c, str, align, end); -} - -void drawTextBox(NVGcontext* vg, float x, float y, float size, float bound, Colour c, const char* str, int align, const char* end) { - drawTextBox(vg, x, y, size, bound, getColour(c), str, align, end); -} - void textBounds(NVGcontext* vg, float x, float y, float *bounds, const char* str, ...) { char buf[0x100]; va_list v; @@ -303,171 +228,50 @@ void textBounds(NVGcontext* vg, float x, float y, float *bounds, const char* str // NEW----------- void dimBackground(NVGcontext* vg) { - // drawRectIntenal(vg, {0.f,0.f,1280.f,720.f}, nvgRGBA(30,30,30,180)); - // drawRectIntenal(vg, {0.f,0.f,1920.f,1080.f}, nvgRGBA(20, 20, 20, 225), false); - drawRectIntenal(vg, {0.f,0.f,1920.f,1080.f}, nvgRGBA(0, 0, 0, 230), false); -} - -void drawRect(NVGcontext* vg, float x, float y, float w, float h, Colour c, bool rounded) { - drawRectIntenal(vg, {x,y,w,h}, getColour(c), rounded); -} - -void drawRect(NVGcontext* vg, Vec4 vec, Colour c, bool rounded) { - drawRectIntenal(vg, vec, getColour(c), rounded); + drawRectIntenal(vg, {0.f,0.f,SCREEN_WIDTH,SCREEN_HEIGHT}, nvgRGBA(0, 0, 0, 180), false); } void drawRect(NVGcontext* vg, float x, float y, float w, float h, const NVGcolor& c, bool rounded) { drawRectIntenal(vg, {x,y,w,h}, c, rounded); } -void drawRect(NVGcontext* vg, float x, float y, float w, float h, const NVGcolor&& c, bool rounded) { - drawRectIntenal(vg, {x,y,w,h}, c, rounded); -} - -void drawRect(NVGcontext* vg, Vec4 vec, const NVGcolor& c, bool rounded) { - drawRectIntenal(vg, vec, c, rounded); -} - -void drawRect(NVGcontext* vg, Vec4 vec, const NVGcolor&& c, bool rounded) { - drawRectIntenal(vg, vec, c, rounded); +void drawRect(NVGcontext* vg, const Vec4& v, const NVGcolor& c, bool rounded) { + drawRectIntenal(vg, v, c, rounded); } void drawRect(NVGcontext* vg, float x, float y, float w, float h, const NVGpaint& p, bool rounded) { drawRectIntenal(vg, {x,y,w,h}, p, rounded); } -void drawRect(NVGcontext* vg, float x, float y, float w, float h, const NVGpaint&& p, bool rounded) { - drawRectIntenal(vg, {x,y,w,h}, p, rounded); +void drawRect(NVGcontext* vg, const Vec4& v, const NVGpaint& p, bool rounded) { + drawRectIntenal(vg, v, p, rounded); } -void drawRect(NVGcontext* vg, Vec4 vec, const NVGpaint& p, bool rounded) { - drawRectIntenal(vg, vec, p, rounded); +void drawRectOutline(NVGcontext* vg, const Theme* theme, float size, float x, float y, float w, float h) { + drawRectOutlineInternal(vg, theme, size, {x,y,w,h}, theme->GetColour(ThemeEntryID_SELECTED_BACKGROUND)); } -void drawRect(NVGcontext* vg, Vec4 vec, const NVGpaint&& p, bool rounded) { - drawRectIntenal(vg, vec, p, rounded); -} - - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, float x, float y, float w, float h, Colour c) { - drawRectOutlineInternal(vg, size, out_col, {x,y,w,h}, getColour(c)); -} - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, Vec4 vec, Colour c) { - drawRectOutlineInternal(vg, size, out_col, vec, getColour(c)); -} - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, float x, float y, float w, float h, const NVGcolor& c) { - drawRectOutlineInternal(vg, size, out_col, {x,y,w,h}, c); -} - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, float x, float y, float w, float h, const NVGcolor&& c) { - drawRectOutlineInternal(vg, size, out_col, {x,y,w,h}, c); -} - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, Vec4 vec, const NVGcolor& c) { - drawRectOutlineInternal(vg, size, out_col, vec, c); -} - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, Vec4 vec, const NVGcolor&& c) { - drawRectOutlineInternal(vg, size, out_col, vec, c); -} - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, float x, float y, float w, float h, const NVGpaint& p) { - drawRectOutlineInternal(vg, size, out_col, {x,y,w,h}, p); -} - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, float x, float y, float w, float h, const NVGpaint&& p) { - drawRectOutlineInternal(vg, size, out_col, {x,y,w,h}, p); -} - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, Vec4 vec, const NVGpaint& p) { - drawRectOutlineInternal(vg, size, out_col, vec, p); -} - -void drawRectOutline(NVGcontext* vg, float size, const NVGcolor& out_col, Vec4 vec, const NVGpaint&& p) { - drawRectOutlineInternal(vg, size, out_col, vec, p); -} - - -void drawTriangle(NVGcontext* vg, float aX, float aY, float bX, float bY, float cX, float cY, Colour c) { - drawTriangleInternal(vg, aX, aY, bX, bY, cX, cY, getColour(c)); -} - -void drawTriangle(NVGcontext* vg, float aX, float aY, float bX, float bY, float cX, float cY, const NVGcolor& c) { - drawTriangleInternal(vg, aX, aY, bX, bY, cX, cY, c); -} - -void drawTriangle(NVGcontext* vg, float aX, float aY, float bX, float bY, float cX, float cY, const NVGcolor&& c) { - drawTriangleInternal(vg, aX, aY, bX, bY, cX, cY, c); -} - -void drawTriangle(NVGcontext* vg, float aX, float aY, float bX, float bY, float cX, float cY, const NVGpaint& p) { - drawTriangleInternal(vg, aX, aY, bX, bY, cX, cY, p); -} - -void drawTriangle(NVGcontext* vg, float aX, float aY, float bX, float bY, float cX, float cY, const NVGpaint&& p) { - drawTriangleInternal(vg, aX, aY, bX, bY, cX, cY, p); -} - -void drawText(NVGcontext* vg, float x, float y, float size, const char* str, const char* end, int align, Colour c) { - drawTextIntenal(vg, {x,y}, size, str, end, align, getColour(c)); -} - -void drawText(NVGcontext* vg, float x, float y, float size, Colour c, const char* str, int align, const char* end) { - drawTextIntenal(vg, {x,y}, size, str, end, align, getColour(c)); -} - -void drawText(NVGcontext* vg, Vec2 vec, float size, const char* str, const char* end, int align, Colour c) { - drawTextIntenal(vg, vec, size, str, end, align, getColour(c)); -} - -void drawText(NVGcontext* vg, Vec2 vec, float size, Colour c, const char* str, int align, const char* end) { - drawTextIntenal(vg, vec, size, str, end, align, getColour(c)); +void drawRectOutline(NVGcontext* vg, const Theme* theme, float size, const Vec4& v) { + drawRectOutlineInternal(vg, theme, size, v, theme->GetColour(ThemeEntryID_SELECTED_BACKGROUND)); } void drawText(NVGcontext* vg, float x, float y, float size, const char* str, const char* end, int align, const NVGcolor& c) { drawTextIntenal(vg, {x,y}, size, str, end, align, c); } -void drawText(NVGcontext* vg, float x, float y, float size, const char* str, const char* end, int align, const NVGcolor&& c) { - drawTextIntenal(vg, {x,y}, size, str, end, align, c); -} - void drawText(NVGcontext* vg, float x, float y, float size, const NVGcolor& c, const char* str, int align, const char* end) { drawTextIntenal(vg, {x,y}, size, str, end, align, c); } -void drawText(NVGcontext* vg, float x, float y, float size, const NVGcolor&& c, const char* str, int align, const char* end) { - drawTextIntenal(vg, {x,y}, size, str, end, align, c); +void drawText(NVGcontext* vg, const Vec2& v, float size, const char* str, const char* end, int align, const NVGcolor& c) { + drawTextIntenal(vg, v, size, str, end, align, c); } -void drawText(NVGcontext* vg, Vec2 vec, float size, const char* str, const char* end, int align, const NVGcolor& c) { - drawTextIntenal(vg, vec, size, str, end, align, c); +void drawText(NVGcontext* vg, const Vec2& v, float size, const NVGcolor& c, const char* str, int align, const char* end) { + drawTextIntenal(vg, v, size, str, end, align, c); } -void drawText(NVGcontext* vg, Vec2 vec, float size, const char* str, const char* end, int align, const NVGcolor&& c) { - drawTextIntenal(vg, vec, size, str, end, align, c); -} - -void drawText(NVGcontext* vg, Vec2 vec, float size, const NVGcolor& c, const char* str, int align, const char* end) { - drawTextIntenal(vg, vec, size, str, end, align, c); -} - -void drawText(NVGcontext* vg, Vec2 vec, float size, const NVGcolor&& c, const char* str, int align, const char* end) { - drawTextIntenal(vg, vec, size, str, end, align, c); -} - -void drawTextArgs(NVGcontext* vg, float x, float y, float size, int align, Colour c, const char* str, ...) { - std::va_list v; - va_start(v, str); - char buffer[0x100]; - std::vsnprintf(buffer, sizeof(buffer), str, v); - va_end(v); - drawTextIntenal(vg, {x, y}, size, buffer, nullptr, align, getColour(c)); -} - -void drawScrollbar(NVGcontext* vg, Theme* theme, float x, float y, float h, u32 index_off, u32 count, u32 max_per_page) { +void drawScrollbar(NVGcontext* vg, const Theme* theme, float x, float y, float h, u32 index_off, u32 count, u32 max_per_page) { const s64 SCROLL = index_off; const s64 max_entry_display = max_per_page; const s64 entry_total = count; @@ -478,35 +282,34 @@ void drawScrollbar(NVGcontext* vg, Theme* theme, float x, float y, float h, u32 if (entry_total > max_entry_display) { const float sb_h = 1.f / (float)entry_total * h; const float sb_y = SCROLL; - gfx::drawRect(vg, x, y, scc2, h, theme->elements[ThemeEntryID_GRID].colour, false); - gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(max_entry_display) - scw * 2, theme->elements[ThemeEntryID_TEXT_SELECTED].colour, false); + gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), false); + gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(max_entry_display) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), false); } } -void drawScrollbar(NVGcontext* vg, Theme* theme, u32 index_off, u32 count, u32 max_per_page) { - // drawScrollbar(vg, SCREEN_WIDTH - 50, 100, 500, index_off, count, max_per_page); +void drawScrollbar(NVGcontext* vg, const Theme* theme, u32 index_off, u32 count, u32 max_per_page) { drawScrollbar(vg, theme, SCREEN_WIDTH - 50, 100, SCREEN_HEIGHT-200, index_off, count, max_per_page); } -void drawScrollbar2(NVGcontext* vg, Theme* theme, float x, float y, float h, s64 index_off, s64 count, s64 row, s64 page) { +void drawScrollbar2(NVGcontext* vg, const Theme* theme, float x, float y, float h, s64 index_off, s64 count, s64 row, s64 page) { // round up if (count % row) { count = count + (row - count % row); } - const float scc2 = 8.0; + const float scc2 = 6.0; const float scw = 2.0; // only draw scrollbar if needed if (count > page) { const float sb_h = 1.f / (float)count * h; const float sb_y = index_off; - gfx::drawRect(vg, x, y, scc2, h, theme->elements[ThemeEntryID_GRID].colour, false); - gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(page) - scw * 2, theme->elements[ThemeEntryID_TEXT_SELECTED].colour, false); + gfx::drawRect(vg, x, y, scc2, h, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND), false); + gfx::drawRect(vg, x + scw, y + scw + sb_h * sb_y, scc2 - scw * 2, sb_h * float(page) - scw * 2, theme->GetColour(ThemeEntryID_SCROLLBAR), false); } } -void drawScrollbar2(NVGcontext* vg, Theme* theme, s64 index_off, s64 count, s64 row, s64 page) { +void drawScrollbar2(NVGcontext* vg, const Theme* theme, s64 index_off, s64 count, s64 row, s64 page) { drawScrollbar2(vg, theme, SCREEN_WIDTH - 50, 100, SCREEN_HEIGHT-200, index_off, count, row, page); } diff --git a/sphaira/source/ui/option_box.cpp b/sphaira/source/ui/option_box.cpp index af4df08..9b3cb44 100644 --- a/sphaira/source/ui/option_box.cpp +++ b/sphaira/source/ui/option_box.cpp @@ -12,10 +12,10 @@ OptionBoxEntry::OptionBoxEntry(const std::string& text, Vec4 pos) auto OptionBoxEntry::Draw(NVGcontext* vg, Theme* theme) -> void { if (m_selected) { - gfx::drawRectOutline(vg, 4.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour, m_pos, theme->elements[ThemeEntryID_SELECTED].colour); - gfx::drawText(vg, m_text_pos, 26.f, theme->elements[ThemeEntryID_TEXT_SELECTED].colour, m_text.c_str(), NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + gfx::drawRectOutline(vg, theme, 4.f, m_pos); + gfx::drawText(vg, m_text_pos, 26.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), m_text.c_str(), NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); } else { - gfx::drawText(vg, m_text_pos, 26.f, theme->elements[ThemeEntryID_TEXT].colour, m_text.c_str(), NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + gfx::drawText(vg, m_text_pos, 26.f, theme->GetColour(ThemeEntryID_TEXT), m_text.c_str(), NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); } } @@ -94,14 +94,14 @@ auto OptionBox::Update(Controller* controller, TouchInfo* touch) -> void { auto OptionBox::Draw(NVGcontext* vg, Theme* theme) -> void { const float padding = 15; gfx::dimBackground(vg); - gfx::drawRect(vg, m_pos, theme->elements[ThemeEntryID_SELECTED].colour); + gfx::drawRect(vg, m_pos, theme->GetColour(ThemeEntryID_POPUP)); nvgSave(vg); nvgTextLineHeight(vg, 1.5); - gfx::drawTextBox(vg, m_pos.x + padding, m_pos.y + 110.f, 26.f, m_pos.w - padding*2, theme->elements[ThemeEntryID_TEXT].colour, m_message.c_str(), NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + gfx::drawTextBox(vg, m_pos.x + padding, m_pos.y + 110.f, 26.f, m_pos.w - padding*2, theme->GetColour(ThemeEntryID_TEXT), m_message.c_str(), NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); nvgRestore(vg); - gfx::drawRect(vg, m_spacer_line, theme->elements[ThemeEntryID_TEXT].colour); + gfx::drawRect(vg, m_spacer_line, theme->GetColour(ThemeEntryID_LINE)); for (auto&p: m_entries) { p.Draw(vg, theme); diff --git a/sphaira/source/ui/popup_list.cpp b/sphaira/source/ui/popup_list.cpp index 82ca5e6..c9f30d8 100644 --- a/sphaira/source/ui/popup_list.cpp +++ b/sphaira/source/ui/popup_list.cpp @@ -22,8 +22,8 @@ PopupList::PopupList(std::string title, Items items, std::string& index_ref) const auto it = std::find(m_items.cbegin(), m_items.cend(), index_ref); if (it != m_items.cend()) { m_index = std::distance(m_items.cbegin(), it); - if (m_index >= 7) { - // m_list->SetYoff((m_index - 6) * m_list->GetMaxY()); + if (m_index >= 6) { + m_list->SetYoff((m_index - 5) * m_list->GetMaxY()); } } @@ -50,8 +50,8 @@ PopupList::PopupList(std::string title, Items items, Callback cb, std::string in const auto it = std::find(m_items.cbegin(), m_items.cend(), index); if (it != m_items.cend()) { SetIndex(std::distance(m_items.cbegin(), it)); - if (m_index >= 7) { - // m_list->SetYoff((m_index - 6) * m_list->GetMaxY()); + if (m_index >= 6) { + m_list->SetYoff((m_index - 5) * m_list->GetMaxY()); } } } @@ -84,7 +84,7 @@ PopupList::PopupList(std::string title, Items items, Callback cb, s64 index) ); m_pos.w = 1280.f; - const float a = std::min(405.f, (60.f * static_cast(m_items.size()))); + const float a = std::min(380.f, (60.f * static_cast(m_items.size()))); m_pos.h = 80.f + 140.f + a; m_pos.y = 720.f - m_pos.h; m_line_top = m_pos.y + 70.f; @@ -93,11 +93,11 @@ PopupList::PopupList(std::string title, Items items, Callback cb, s64 index) Vec4 v{m_block}; v.y = m_line_top + 1.f + 42.f; const Vec4 pos{0, m_line_top, 1280.f, m_line_bottom - m_line_top}; - m_list = std::make_unique(1, 7, pos, v); + m_list = std::make_unique(1, 6, pos, v); m_list->SetScrollBarPos(1250, m_line_top + 20, m_line_bottom - m_line_top - 40); - if (m_index >= 7) { - m_list->SetYoff((m_index - 6) * m_list->GetMaxY()); + if (m_index >= 6) { + m_list->SetYoff((m_index - 5) * m_list->GetMaxY()); } } @@ -111,21 +111,21 @@ auto PopupList::Update(Controller* controller, TouchInfo* touch) -> void { auto PopupList::Draw(NVGcontext* vg, Theme* theme) -> void { gfx::dimBackground(vg); - gfx::drawRect(vg, m_pos, theme->elements[ThemeEntryID_SELECTED].colour); - gfx::drawText(vg, m_pos + m_title_pos, 24.f, theme->elements[ThemeEntryID_TEXT].colour, m_title.c_str()); - gfx::drawRect(vg, 30.f, m_line_top, m_line_width, 1.f, theme->elements[ThemeEntryID_TEXT].colour); - gfx::drawRect(vg, 30.f, m_line_bottom, m_line_width, 1.f, theme->elements[ThemeEntryID_TEXT].colour); + gfx::drawRect(vg, m_pos, theme->GetColour(ThemeEntryID_POPUP)); + gfx::drawText(vg, m_pos + m_title_pos, 24.f, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str()); + gfx::drawRect(vg, 30.f, m_line_top, m_line_width, 1.f, theme->GetColour(ThemeEntryID_LINE)); + gfx::drawRect(vg, 30.f, m_line_bottom, m_line_width, 1.f, theme->GetColour(ThemeEntryID_LINE)); m_list->Draw(vg, theme, m_items.size(), [this](auto* vg, auto* theme, auto v, auto i) { const auto& [x, y, w, h] = v; if (m_index == i) { - gfx::drawRect(vg, x - 4.f, y - 4.f, w + 8.f, h + 8.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour); - gfx::drawRect(vg, x, y, w, h, theme->elements[ThemeEntryID_SELECTED].colour); - gfx::drawText(vg, x + m_text_xoffset, y + (h / 2.f), 20.f, m_items[i].c_str(), NULL, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->elements[ThemeEntryID_TEXT_SELECTED].colour); + gfx::drawRectOutline(vg, theme, 4.f, v); + gfx::drawText(vg, x + m_text_xoffset, y + (h / 2.f), 20.f, m_items[i].c_str(), NULL, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_SELECTED)); } else { - gfx::drawRect(vg, x, y, w, 1.f, theme->elements[ThemeEntryID_TEXT].colour); - gfx::drawRect(vg, x, y + h, w, 1.f, theme->elements[ThemeEntryID_TEXT].colour); - gfx::drawText(vg, x + m_text_xoffset, y + (h / 2.f), 20.f, m_items[i].c_str(), NULL, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->elements[ThemeEntryID_TEXT].colour); + if (i != m_items.size() - 1) { + gfx::drawRect(vg, x, y + h, w, 1.f, theme->GetColour(ThemeEntryID_LINE_SEPERATOR)); + } + gfx::drawText(vg, x + m_text_xoffset, y + (h / 2.f), 20.f, m_items[i].c_str(), NULL, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT)); } }); diff --git a/sphaira/source/ui/progress_box.cpp b/sphaira/source/ui/progress_box.cpp index 6a8eaf1..610023a 100644 --- a/sphaira/source/ui/progress_box.cpp +++ b/sphaira/source/ui/progress_box.cpp @@ -83,7 +83,7 @@ auto ProgressBox::Draw(NVGcontext* vg, Theme* theme) -> void { mutexUnlock(&m_mutex); gfx::dimBackground(vg); - gfx::drawRect(vg, m_pos, theme->elements[ThemeEntryID_SELECTED].colour); + gfx::drawRect(vg, m_pos, theme->GetColour(ThemeEntryID_POPUP)); // The pop up shape. // const Vec4 box = { 255, 145, 770, 430 }; @@ -93,19 +93,15 @@ auto ProgressBox::Draw(NVGcontext* vg, Theme* theme) -> void { // shapes. if (offset && size) { - gfx::drawRect(vg, prog_bar, gfx::Colour::SILVER); + gfx::drawRect(vg, prog_bar, theme->GetColour(ThemeEntryID_PROGRESSBAR_BACKGROUND)); const u32 percentage = ((double)offset / (double)size) * 100.0; - gfx::drawRect(vg, prog_bar.x, prog_bar.y, ((float)offset / (float)size) * prog_bar.w, prog_bar.h, gfx::Colour::CYAN); - // gfx::drawTextArgs(vg, prog_bar.x + 85, prog_bar.y + 40, 20, 0, gfx::Colour::WHITE, "%u%%", percentage); - gfx::drawTextArgs(vg, prog_bar.x + prog_bar.w + 10, prog_bar.y, 20, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, gfx::Colour::WHITE, "%u%%", percentage); + gfx::drawRect(vg, prog_bar.x, prog_bar.y, ((float)offset / (float)size) * prog_bar.w, prog_bar.h, theme->GetColour(ThemeEntryID_PROGRESSBAR)); + gfx::drawTextArgs(vg, prog_bar.x + prog_bar.w + 10, prog_bar.y, 20, NVG_ALIGN_LEFT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), "%u%%", percentage); } - gfx::drawTextArgs(vg, center_x, m_pos.y + 60, 25, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, gfx::Colour::WHITE, title.c_str()); - // gfx::drawTextArgs(vg, center_x, 260, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, gfx::Colour::SILVER, "Please do not remove the gamecard or"); - // gfx::drawTextArgs(vg, center_x, 295, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, gfx::Colour::SILVER, "power off the system whilst installing."); - // gfx::drawTextArgs(vg, center_x, 360, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, gfx::Colour::WHITE, "%.2f MiB/s", 24.0); + gfx::drawTextArgs(vg, center_x, m_pos.y + 60, 25, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT), title.c_str()); if (!transfer.empty()) { - gfx::drawTextArgs(vg, center_x, prog_bar.y - 15 - 20 * 1.5, 20, NVG_ALIGN_CENTER, gfx::Colour::WHITE, "%s", transfer.c_str()); + gfx::drawTextArgs(vg, center_x, prog_bar.y - 15 - 20 * 1.5, 20, NVG_ALIGN_CENTER, theme->GetColour(ThemeEntryID_TEXT), "%s", transfer.c_str()); } } diff --git a/sphaira/source/ui/scrollable_text.cpp b/sphaira/source/ui/scrollable_text.cpp index 67c55cc..a4a1cff 100644 --- a/sphaira/source/ui/scrollable_text.cpp +++ b/sphaira/source/ui/scrollable_text.cpp @@ -94,17 +94,15 @@ void ScrollableText::Draw(NVGcontext* vg, Theme* theme) { const auto sb_h = 1.f / max_index * scrollbar_size; const auto in_clip = m_clip_y / m_step - 1; const auto sb_y = m_index; - // gfx::drawRect(vg, banner_vec.x+banner_vec.w-20, m_y_off_base, 10, scrollbar_size, theme->elements[ThemeEntryID_GRID].colour); - // gfx::drawRect(vg, banner_vec.x+banner_vec.w-20+2, m_y_off_base + sb_h * sb_y, 10-4, sb_h + (sb_h * in_clip) - 4, theme->elements[ThemeEntryID_TEXT_SELECTED].colour); - gfx::drawRect(vg, banner_vec.w, m_y_off_base, 10, scrollbar_size, theme->elements[ThemeEntryID_GRID].colour); - gfx::drawRect(vg, banner_vec.w+2, m_y_off_base + sb_h * sb_y, 10-4, sb_h + (sb_h * in_clip) - 4, theme->elements[ThemeEntryID_TEXT_SELECTED].colour); + gfx::drawRect(vg, banner_vec.w, m_y_off_base, 10, scrollbar_size, theme->GetColour(ThemeEntryID_SCROLLBAR_BACKGROUND)); + gfx::drawRect(vg, banner_vec.w+2, m_y_off_base + sb_h * sb_y, 10-4, sb_h + (sb_h * in_clip) - 4, theme->GetColour(ThemeEntryID_SCROLLBAR)); } nvgSave(vg); - nvgScissor(vg, 0, m_y_off_base - m_font_size, 1280, m_clip_y + m_font_size); // clip + nvgIntersectScissor(vg, 0, m_y_off_base - m_font_size, 1280, m_clip_y + m_font_size); // clip nvgTextLineHeight(App::GetVg(), 1.7); - gfx::drawTextBox(vg, banner_vec.x + 40, m_y_off, m_font_size, m_bounds[2] - m_bounds[0], theme->elements[ThemeEntryID_TEXT].colour, m_text.c_str()); + gfx::drawTextBox(vg, banner_vec.x + 40, m_y_off, m_font_size, m_bounds[2] - m_bounds[0], theme->GetColour(ThemeEntryID_TEXT), m_text.c_str()); nvgRestore(vg); } diff --git a/sphaira/source/ui/sidebar.cpp b/sphaira/source/ui/sidebar.cpp index e3fda9d..09bc19c 100644 --- a/sphaira/source/ui/sidebar.cpp +++ b/sphaira/source/ui/sidebar.cpp @@ -24,14 +24,7 @@ SidebarEntryBase::SidebarEntryBase(std::string&& title) auto SidebarEntryBase::Draw(NVGcontext* vg, Theme* theme) -> void { // draw spacers or highlight box if in focus (selected) if (HasFocus()) { - gfx::drawRect(vg, m_pos, nvgRGB(50,50,50)); - gfx::drawRect(vg, m_pos, nvgRGB(0,0,0)); - gfx::drawRectOutline(vg, 4.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour, m_pos, theme->elements[ThemeEntryID_SELECTED].colour); - // gfx::drawRect(vg, m_pos.x - 4.f, m_pos.y - 4.f, m_pos.w + 8.f, m_pos.h + 8.f, theme->elements[ThemeEntryID_SELECTED_OVERLAY].colour); - // gfx::drawRect(vg, m_pos.x, m_pos.y, m_pos.w, m_pos.h, theme->elements[ThemeEntryID_SELECTED].colour); - } else { - gfx::drawRect(vg, m_pos.x, m_pos.y, m_pos.w, 1.f, nvgRGB(81, 81, 81)); // spacer - gfx::drawRect(vg, m_pos.x, m_pos.y + m_pos.h, m_pos.w, 1.f, nvgRGB(81, 81, 81)); // spacer + gfx::drawRectOutline(vg, theme, 4.f, m_pos); } } @@ -60,16 +53,16 @@ auto SidebarEntryBool::Draw(NVGcontext* vg, Theme* theme) -> void { SidebarEntryBase::Draw(vg, theme); // if (HasFocus()) { - // gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->elements[ThemeEntryID_TEXT_SELECTED].colour, m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); + // gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); // } else { // } - gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->elements[ThemeEntryID_TEXT].colour, m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); + gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); if (m_option == true) { - gfx::drawText(vg, Vec2{m_pos.x + m_pos.w - 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->elements[ThemeEntryID_TEXT_SELECTED].colour, m_true_str.c_str(), NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); + gfx::drawText(vg, Vec2{m_pos.x + m_pos.w - 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), m_true_str.c_str(), NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); } else { // text info - gfx::drawText(vg, Vec2{m_pos.x + m_pos.w - 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->elements[ThemeEntryID_TEXT].colour, m_false_str.c_str(), NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); + gfx::drawText(vg, Vec2{m_pos.x + m_pos.w - 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT), m_false_str.c_str(), NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); } } @@ -90,9 +83,9 @@ auto SidebarEntryCallback::Draw(NVGcontext* vg, Theme* theme) -> void { SidebarEntryBase::Draw(vg, theme); // if (HasFocus()) { - // gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->elements[ThemeEntryID_TEXT_SELECTED].colour, m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); + // gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); // } else { - gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->elements[ThemeEntryID_TEXT].colour, m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); + gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); // } } @@ -154,11 +147,11 @@ auto SidebarEntryArray::Draw(NVGcontext* vg, Theme* theme) -> void { SidebarEntryBase::Draw(vg, theme); const auto& text_entry = m_items[m_index]; - // const auto& colour = HasFocus() ? theme->elements[ThemeEntryID_TEXT_SELECTED].colour : theme->elements[ThemeEntryID_TEXT].colour; - const auto& colour = theme->elements[ThemeEntryID_TEXT].colour; + // const auto& colour = HasFocus() ? theme->GetColour(ThemeEntryID_TEXT_SELECTED) : theme->GetColour(ThemeEntryID_TEXT); + const auto& colour = theme->GetColour(ThemeEntryID_TEXT); gfx::drawText(vg, Vec2{m_pos.x + 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, colour, m_title.c_str(), NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE); - gfx::drawText(vg, Vec2{m_pos.x + m_pos.w - 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->elements[ThemeEntryID_TEXT_SELECTED].colour, text_entry.c_str(), NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); + gfx::drawText(vg, Vec2{m_pos.x + m_pos.w - 15.f, m_pos.y + (m_pos.h / 2.f)}, 20.f, theme->GetColour(ThemeEntryID_TEXT_SELECTED), text_entry.c_str(), NVG_ALIGN_RIGHT | NVG_ALIGN_MIDDLE); } Sidebar::Sidebar(std::string title, Side side, Items&& items) @@ -222,18 +215,23 @@ auto Sidebar::Update(Controller* controller, TouchInfo* touch) -> void { } auto Sidebar::Draw(NVGcontext* vg, Theme* theme) -> void { - gfx::drawRect(vg, m_pos, nvgRGBA(0, 0, 0, 220)); - gfx::drawText(vg, m_title_pos, m_title_size, theme->elements[ThemeEntryID_TEXT].colour, m_title.c_str()); + gfx::drawRect(vg, m_pos, theme->GetColour(ThemeEntryID_SIDEBAR)); + gfx::drawText(vg, m_title_pos, m_title_size, theme->GetColour(ThemeEntryID_TEXT), m_title.c_str()); if (!m_sub.empty()) { - gfx::drawTextArgs(vg, m_pos.x + m_pos.w - 30.f, m_title_pos.y + 10.f, 18, NVG_ALIGN_TOP | NVG_ALIGN_RIGHT, theme->elements[ThemeEntryID_TEXT].colour, m_sub.c_str()); + gfx::drawTextArgs(vg, m_pos.x + m_pos.w - 30.f, m_title_pos.y + 10.f, 18, NVG_ALIGN_TOP | NVG_ALIGN_RIGHT, theme->GetColour(ThemeEntryID_TEXT), m_sub.c_str()); } - gfx::drawRect(vg, m_top_bar, theme->elements[ThemeEntryID_TEXT].colour); - gfx::drawRect(vg, m_bottom_bar, theme->elements[ThemeEntryID_TEXT].colour); + gfx::drawRect(vg, m_top_bar, theme->GetColour(ThemeEntryID_LINE)); + gfx::drawRect(vg, m_bottom_bar, theme->GetColour(ThemeEntryID_LINE)); Widget::Draw(vg, theme); m_list->Draw(vg, theme, m_items.size(), [this](auto* vg, auto* theme, auto v, auto i) { const auto& [x, y, w, h] = v; + + if (i != m_items.size() - 1) { + gfx::drawRect(vg, x, y + h, w, 1.f, theme->GetColour(ThemeEntryID_LINE_SEPERATOR)); + } + m_items[i]->SetY(y); m_items[i]->Draw(vg, theme); }); diff --git a/sphaira/source/ui/widget.cpp b/sphaira/source/ui/widget.cpp index 19cb22b..9f52010 100644 --- a/sphaira/source/ui/widget.cpp +++ b/sphaira/source/ui/widget.cpp @@ -10,7 +10,7 @@ auto uiButton::Draw(NVGcontext* vg, Theme* theme) -> void { // gfx::drawRect(vg, m_pos, gfx::Colour::RED); nvgTextAlign(vg, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP); - nvgFillColor(vg, theme->elements[ThemeEntryID_TEXT].colour); + nvgFillColor(vg, theme->GetColour(ThemeEntryID_TEXT)); nvgFontSize(vg, 20); nvgText(vg, m_hint_pos.x, m_hint_pos.y, m_action.m_hint.c_str(), nullptr); nvgFontSize(vg, 26); From 0751fa9a2ed01a18771cbac424c70a86d57a227c Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:55:46 +0000 Subject: [PATCH 2/5] optimise theme inherit, load default_music.bfstm if available. --- sphaira/include/app.hpp | 5 +- sphaira/source/app.cpp | 203 ++++++++++++++++++++++------------------ 2 files changed, 112 insertions(+), 96 deletions(-) diff --git a/sphaira/include/app.hpp b/sphaira/include/app.hpp index 2ab1304..b006cef 100644 --- a/sphaira/include/app.hpp +++ b/sphaira/include/app.hpp @@ -107,7 +107,7 @@ public: auto LoadElementColour(std::string_view value) -> ElementEntry; auto LoadElement(std::string_view data, ElementType type) -> ElementEntry; - void LoadTheme(ThemeMeta meta, int inherit_level = 0); + void LoadTheme(const ThemeMeta& meta); void CloseTheme(); void ScanThemes(const std::string& path); void ScanThemeEntries(); @@ -165,9 +165,6 @@ public: PLSR_BFSAR m_qlaunch_bfsar{}; PLSR_PlayerSoundId m_sound_ids[SoundEffect_MAX]{}; -private: - void CloseMusic(); - private: // from nanovg decko3d example by adubbz static constexpr unsigned NumFramebuffers = 2; static constexpr unsigned StaticCmdSize = 0x1000; diff --git a/sphaira/source/app.cpp b/sphaira/source/app.cpp index a5857fa..954e698 100644 --- a/sphaira/source/app.cpp +++ b/sphaira/source/app.cpp @@ -33,6 +33,44 @@ extern "C" { namespace sphaira { namespace { +struct ThemeData { + fs::FsPath music_path{"/config/sphaira/themes/default_music.bfstm"}; + std::string elements[ThemeEntryID_MAX]{}; +}; + +struct ThemeIdPair { + const char* label; + ThemeEntryID id; + ElementType type{ElementType::None}; +}; + +constexpr ThemeIdPair THEME_ENTRIES[] = { + { "background", ThemeEntryID_BACKGROUND }, + { "grid", ThemeEntryID_GRID }, + { "text", ThemeEntryID_TEXT, ElementType::Colour }, + { "text_info", ThemeEntryID_TEXT_INFO, ElementType::Colour }, + { "text_selected", ThemeEntryID_TEXT_SELECTED, ElementType::Colour }, + { "selected_background", ThemeEntryID_SELECTED_BACKGROUND, ElementType::Colour }, + { "popup", ThemeEntryID_POPUP, ElementType::Colour }, + { "line", ThemeEntryID_LINE, ElementType::Colour }, + { "line_seperator", ThemeEntryID_LINE_SEPERATOR, ElementType::Colour }, + { "sidebar", ThemeEntryID_SIDEBAR, ElementType::Colour }, + { "scrollbar", ThemeEntryID_SCROLLBAR, ElementType::Colour }, + { "scrollbar_background", ThemeEntryID_SCROLLBAR_BACKGROUND, ElementType::Colour }, + { "progressbar", ThemeEntryID_PROGRESSBAR, ElementType::Colour }, + { "progressbar_background", ThemeEntryID_PROGRESSBAR_BACKGROUND, ElementType::Colour }, + { "highlight_1", ThemeEntryID_HIGHLIGHT_1, ElementType::Colour }, + { "highlight_2", ThemeEntryID_HIGHLIGHT_2, ElementType::Colour }, + { "icon_colour", ThemeEntryID_ICON_COLOUR, ElementType::Colour }, + { "icon_audio", ThemeEntryID_ICON_AUDIO, ElementType::Texture }, + { "icon_video", ThemeEntryID_ICON_VIDEO, ElementType::Texture }, + { "icon_image", ThemeEntryID_ICON_IMAGE, ElementType::Texture }, + { "icon_file", ThemeEntryID_ICON_FILE, ElementType::Texture }, + { "icon_folder", ThemeEntryID_ICON_FOLDER, ElementType::Texture }, + { "icon_zip", ThemeEntryID_ICON_ZIP, ElementType::Texture }, + { "icon_nro", ThemeEntryID_ICON_NRO, ElementType::Texture }, +}; + constinit App* g_app{}; void deko3d_error_cb(void* userData, const char* context, DkResult result, const char* message) { @@ -236,6 +274,62 @@ auto LoadThemeMeta(const fs::FsPath& path, ThemeMeta& meta) -> bool { return true; } +void LoadThemeInternal(ThemeMeta meta, ThemeData& theme_data, int inherit_level = 0) { + constexpr auto inherit_level_max = 5; + + // all themes will inherit from black theme by default. + if (meta.inherit.empty() && !inherit_level) { + meta.inherit = "romfs:/themes/base_black_theme.ini"; + } + + // check if the theme inherits from another, if so, load it. + // block inheriting from itself. + if (inherit_level < inherit_level_max && !meta.inherit.empty() && strcasecmp(meta.inherit, "none") && meta.inherit != meta.ini_path) { + log_write("inherit is not empty: %s\n", meta.inherit.s); + if (R_SUCCEEDED(romfsInit())) { + ThemeMeta inherit_meta; + const auto has_meta = LoadThemeMeta(meta.inherit, inherit_meta); + romfsExit(); + + // base themes do not have a meta + if (!has_meta) { + inherit_meta.ini_path = meta.inherit; + } + + LoadThemeInternal(inherit_meta, theme_data, inherit_level + 1); + } + } + + static constexpr auto cb = [](const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData) -> int { + auto theme_data = static_cast(UserData); + + if (!std::strcmp(Section, "theme")) { + if (!std::strcmp(Key, "music")) { + theme_data->music_path = Value; + } else { + for (auto& e : THEME_ENTRIES) { + if (!std::strcmp(Key, e.label)) { + theme_data->elements[e.id] = Value; + break; + } + } + } + } + + return 1; + }; + + if (R_SUCCEEDED(romfsInit())) { + ON_SCOPE_EXIT(romfsExit()); + + if (!ini_browse(cb, &theme_data, meta.ini_path)) { + log_write("failed to open ini: %s\n", meta.ini_path.s); + } else { + log_write("opened ini: %s\n", meta.ini_path); + } + } +} + void haze_callback(const HazeCallbackData *data) { App::NotifyFlashLed(); evman::push(*data, false); @@ -975,16 +1069,12 @@ auto App::LoadElement(std::string_view value, ElementType type) -> ElementEntry return {}; } -void App::CloseMusic() { +void App::CloseTheme() { if (m_sound_ids[SoundEffect_Music]) { plsrPlayerFree(m_sound_ids[SoundEffect_Music]); m_sound_ids[SoundEffect_Music] = nullptr; plsrBFSTMClose(&m_theme.music); } -} - -void App::CloseTheme() { - CloseMusic(); for (auto& e : m_theme.elements) { if (e.type == ElementType::Texture) { @@ -995,100 +1085,29 @@ void App::CloseTheme() { m_theme = {}; } -void App::LoadTheme(ThemeMeta meta, int inherit_level) { +void App::LoadTheme(const ThemeMeta& meta) { // reset theme CloseTheme(); - static constexpr struct ThemeIdPair{ - const char* label; - ThemeEntryID id; - ElementType type{ElementType::None}; - } theme_entries[] = { - { "background", ThemeEntryID_BACKGROUND }, - { "grid", ThemeEntryID_GRID }, - { "text", ThemeEntryID_TEXT, ElementType::Colour }, - { "text_info", ThemeEntryID_TEXT_INFO, ElementType::Colour }, - { "text_selected", ThemeEntryID_TEXT_SELECTED, ElementType::Colour }, - { "selected_background", ThemeEntryID_SELECTED_BACKGROUND, ElementType::Colour }, - { "popup", ThemeEntryID_POPUP, ElementType::Colour }, - { "line", ThemeEntryID_LINE, ElementType::Colour }, - { "line_seperator", ThemeEntryID_LINE_SEPERATOR, ElementType::Colour }, - { "sidebar", ThemeEntryID_SIDEBAR, ElementType::Colour }, - { "scrollbar", ThemeEntryID_SCROLLBAR, ElementType::Colour }, - { "scrollbar_background", ThemeEntryID_SCROLLBAR_BACKGROUND, ElementType::Colour }, - { "progressbar", ThemeEntryID_PROGRESSBAR, ElementType::Colour }, - { "progressbar_background", ThemeEntryID_PROGRESSBAR_BACKGROUND, ElementType::Colour }, - { "highlight_1", ThemeEntryID_HIGHLIGHT_1, ElementType::Colour }, - { "highlight_2", ThemeEntryID_HIGHLIGHT_2, ElementType::Colour }, - { "icon_colour", ThemeEntryID_ICON_COLOUR, ElementType::Colour }, - { "icon_audio", ThemeEntryID_ICON_AUDIO, ElementType::Texture }, - { "icon_video", ThemeEntryID_ICON_VIDEO, ElementType::Texture }, - { "icon_image", ThemeEntryID_ICON_IMAGE, ElementType::Texture }, - { "icon_file", ThemeEntryID_ICON_FILE, ElementType::Texture }, - { "icon_folder", ThemeEntryID_ICON_FOLDER, ElementType::Texture }, - { "icon_zip", ThemeEntryID_ICON_ZIP, ElementType::Texture }, - { "icon_nro", ThemeEntryID_ICON_NRO, ElementType::Texture }, - }; - - const auto inherit_level_max = 5; - - // all themes will inherit from black theme by default. - if (meta.inherit.empty() && !inherit_level) { - meta.inherit = "romfs:/themes/base_black_theme.ini"; - } - - // check if the theme inherits from another, if so, load it. - // block inheriting from itself. - if (inherit_level < inherit_level_max && !meta.inherit.empty() && strcasecmp(meta.inherit, "none") && meta.inherit != meta.ini_path) { - log_write("inherit is not empty: %s\n", meta.inherit.s); - if (R_SUCCEEDED(romfsInit())) { - ThemeMeta inherit_meta; - const auto has_meta = LoadThemeMeta(meta.inherit, inherit_meta); - romfsExit(); - - // base themes do not have a meta - if (!has_meta) { - inherit_meta.ini_path = meta.inherit; - } - - LoadTheme(inherit_meta, inherit_level + 1); - } - } - + ThemeData theme_data{}; + LoadThemeInternal(meta, theme_data); m_theme.meta = meta; - const auto cb = [](const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData) -> int { - auto app = static_cast(UserData); - auto& theme = app->m_theme; - - if (!std::strcmp(Section, "theme")) { - if (!std::strcmp(Key, "music")) { - app->CloseMusic(); - if (R_SUCCEEDED(plsrBFSTMOpen(Value, &theme.music))) { - if (R_SUCCEEDED(plsrPlayerLoadStream(&theme.music, &app->m_sound_ids[SoundEffect_Music]))) { - app->PlaySoundEffect(SoundEffect_Music); - } - } - } else { - for (auto& e : theme_entries) { - if (!std::strcmp(Key, e.label)) { - // log_write("\tfound: %s value: %s\n", Key, Value); - theme.elements[e.id] = app->LoadElement(Value, e.type); - break; - } - } - } - } - - return 1; - }; - if (R_SUCCEEDED(romfsInit())) { ON_SCOPE_EXIT(romfsExit()); - if (!ini_browse(cb, this, meta.ini_path)) { - log_write("failed to open ini: %s\n", meta.ini_path.s); - } else { - log_write("opened ini: %s\n", meta.ini_path); + + // load all assets / colours. + for (auto& e : THEME_ENTRIES) { + m_theme.elements[e.id] = LoadElement(theme_data.elements[e.id], e.type); + } + + // load music + if (!theme_data.music_path.empty()) { + if (R_SUCCEEDED(plsrBFSTMOpen(theme_data.music_path, &m_theme.music))) { + if (R_SUCCEEDED(plsrPlayerLoadStream(&m_theme.music, &m_sound_ids[SoundEffect_Music]))) { + PlaySoundEffect(SoundEffect_Music); + } + } } } } From 91a08d36b481f29c9bc77d3ce284a906a11a0766 Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Thu, 9 Jan 2025 19:34:16 +0000 Subject: [PATCH 3/5] tweek popup_list height to match qlaunch, change white/abyss scrollbar colour, fix menu using text instead of line colours --- assets/romfs/themes/abyss_theme.ini | 9 +++++++++ assets/romfs/themes/base_white_theme.ini | 2 +- sphaira/source/ui/menus/menu_base.cpp | 4 ++-- sphaira/source/ui/popup_list.cpp | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/assets/romfs/themes/abyss_theme.ini b/assets/romfs/themes/abyss_theme.ini index acd1cff..cb37fd0 100644 --- a/assets/romfs/themes/abyss_theme.ini +++ b/assets/romfs/themes/abyss_theme.ini @@ -8,7 +8,16 @@ inherit=romfs:/themes/base_black_theme.ini background = 0x0f111a grid = 0x0f115c30 popup = 0x0f115c + +line = 0xffbc41 +line_seperator = 0xffbc41 + text = 0xffbc41 text_info = 0xffbc41 text_selected = 0x529cff selected_background = 0x0f115c + +scrollbar = 0x3250f0 +scrollbar_background = ; hide the background + +progressbar = 0x3250f0 diff --git a/assets/romfs/themes/base_white_theme.ini b/assets/romfs/themes/base_white_theme.ini index 376598e..ce0011d 100644 --- a/assets/romfs/themes/base_white_theme.ini +++ b/assets/romfs/themes/base_white_theme.ini @@ -14,7 +14,7 @@ selected_background = 0xfdfdfd sidebar = 0xe2e2e2f5 -scrollbar = 0x3250f0 +scrollbar = 0xB0B0B0 scrollbar_background = ; hide the background ; scrollbar_background = 0xababab diff --git a/sphaira/source/ui/menus/menu_base.cpp b/sphaira/source/ui/menus/menu_base.cpp index 0be00f8..24cf868 100644 --- a/sphaira/source/ui/menus/menu_base.cpp +++ b/sphaira/source/ui/menus/menu_base.cpp @@ -58,8 +58,8 @@ void MenuBase::Draw(NVGcontext* vg, Theme* theme) { #undef draw - gfx::drawRect(vg, 30.f, 86.f, 1220.f, 1.f, theme->GetColour(ThemeEntryID_TEXT)); - gfx::drawRect(vg, 30.f, 646.0f, 1220.f, 1.f, theme->GetColour(ThemeEntryID_TEXT)); + gfx::drawRect(vg, 30.f, 86.f, 1220.f, 1.f, theme->GetColour(ThemeEntryID_LINE)); + gfx::drawRect(vg, 30.f, 646.0f, 1220.f, 1.f, theme->GetColour(ThemeEntryID_LINE)); nvgFontSize(vg, 28); gfx::textBounds(vg, 0, 0, bounds, m_title.c_str()); diff --git a/sphaira/source/ui/popup_list.cpp b/sphaira/source/ui/popup_list.cpp index c9f30d8..0a33b76 100644 --- a/sphaira/source/ui/popup_list.cpp +++ b/sphaira/source/ui/popup_list.cpp @@ -84,7 +84,7 @@ PopupList::PopupList(std::string title, Items items, Callback cb, s64 index) ); m_pos.w = 1280.f; - const float a = std::min(380.f, (60.f * static_cast(m_items.size()))); + const float a = std::min(370.f, (60.f * static_cast(m_items.size()))); m_pos.h = 80.f + 140.f + a; m_pos.y = 720.f - m_pos.h; m_line_top = m_pos.y + 70.f; From 7d5876d88149043862caae14b55a9c175757787c Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Sun, 12 Jan 2025 19:16:55 +0000 Subject: [PATCH 4/5] add bubbles not used yet --- assets/romfs/theme/bubble1.png | Bin 0 -> 5147 bytes assets/romfs/theme/bubble2.png | Bin 0 -> 5541 bytes assets/romfs/theme/bubble3.png | Bin 0 -> 6156 bytes sphaira/CMakeLists.txt | 1 + sphaira/include/ui/bubbles.hpp | 10 +++ sphaira/source/app.cpp | 7 ++ sphaira/source/ui/bubbles.cpp | 115 +++++++++++++++++++++++++++++++++ 7 files changed, 133 insertions(+) create mode 100644 assets/romfs/theme/bubble1.png create mode 100644 assets/romfs/theme/bubble2.png create mode 100644 assets/romfs/theme/bubble3.png create mode 100644 sphaira/include/ui/bubbles.hpp create mode 100644 sphaira/source/ui/bubbles.cpp diff --git a/assets/romfs/theme/bubble1.png b/assets/romfs/theme/bubble1.png new file mode 100644 index 0000000000000000000000000000000000000000..ade1b1458ab823d8e6ceaa7832664c2f847e7c88 GIT binary patch literal 5147 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 VzHVJs|7q|5WqCEZ5?RyG{{ouigX;hQ literal 0 HcmV?d00001 diff --git a/assets/romfs/theme/bubble2.png b/assets/romfs/theme/bubble2.png new file mode 100644 index 0000000000000000000000000000000000000000..52e16fa62d6ce7e9eeea7207b80afd2d8e562491 GIT binary patch literal 5541 zcmZ9QcQD-1yT-q(uGLn{E@AbW5WR=p)ky@=L$Es07ZD|^cTuv4x=MtQAP9mW5hX&D z2y3+<3BeL267~Acy>n;oop;Xr%$zfy_nmjnALq=IY+|g(2;qVN0KjOVuWfdr$p0)b z%|(9h8L)66e9ro2Hv!;*2ms*X0O06i3%3RU!O{Tm%Mk!n^8o&jx3FgZj)P6U=>Hg!#5Ar26tLBd?&1OIodn^k4w~kW+L)We^9w_gr#Gg$5 z+-*JmyBN!Gi#IIyoxtu3M(~oS`|cXc>K`A+M(ZSQUM-*(vc!MC5kUM?$^EWcNOnFe zZIXL?{D%be_}P?bP92bFc66Rs?tJ{e`fNPo#PJUasv^o0TbsWN-c!vA{DwC>`c zt|?X@1sAnXY8ri7=lff&GPFs4QlwB?T%|g&%7JVk#hVssOJsw&lv(@OlEsjGWmJ`1 z!fbDOib%g+OVmYXO-!3fWaSXX5*}>)U@Wvx?52ZWTjyBh#67coxVxHc?6;71)q~(M zFC)+?JPvun$7MhRppkSv+=EmhA0qI@g`2M>ePfMe_P8yMDmS$tS`67;8^2n*+uY7i z$@ZUq?!h3J7U_WO-67FZ{h+P%8TqHlH=KJ!+0#Ir(fY=^U=>&z0;UL6_`!zZI`LRobQs;0$a zx(rO%4~;b$_5lo2C{=bOfD~0t#2OPhKE7`AEr2rJF_?^-5z{jNC2rhte)R3tTZT9o zC35*RJd=2jr@~p?oSWvasr(a>ED@SGBp6i<2KR(*T^GP zigDz(g%Dx{QYb(mqGihar^?L*Ys!Wm%@Qg4vC|=<%scO(cfma;l=}BwITB+`Ex2V# zjkljkEC^Zn6r)*8N^I>ii`T9+N@g59O?6;MNPW57dBvJcb1&rjk#C|pgQFx4;1a;d zq3`Lzl_Z4}31VwfS{C+3KFNGZ0^(GS8hdq%*zLs*`#<6fd#L-qK#*C~QFmDfcfnF{ z)pI?3QT75=d`7K4owj+;4M!mw!H|Q!u=D}7_Z2?9D?a^1x1N7)sRs{YeVfq4myYu^ zW;9|+`2xBtbWCn~`8+(|mUh4^>+Jk3Ceg~2G<&)_)a-^SS#yu{kDjSwk|TUwoE5%U&p(l}NYzX#5l-T|{Om^_4*Q%4*y>P`=~SX!oMg z=9)|$OpGKP(VB3m*1!Z+s)m?(jTu+vBkbS*KDgW#vUe$?-hNmwS)9CUf-B$w!qyf3;(Gep(i zyOUyWO;aKyLzNv~HrPmwNnSH~Z8Q@?&HH-CiS{dl_53w9J{pTnMWcJUFzXV{-hV{S zm)(JvTknQ(DEZnA+*1W9BxlvAio~(Iibb<^94~=NMG+B_I2HcX^WQ=EDtT-vm&^<8 zJ88XOBHb81MU)iTQvv3Vxz|^vJo=jR*#^RWm=Ts5w3$o4Izs&`1hnYWGuLZGQ->o1 zTYK|-^GhvB-_z!{#(cic)a6>&f1M#m#Z2GrO5e~+WSzB))u;UXICIl-m&KtqCx>m> zyXxIE#r-WrLlW0W4*ztMba__$m)3r2b&B2>Lv7~$ ztR_+4Yb`&#BYlXJJl0r)qV>;TF&Ff%`OAG#*C&VXM?T_r|5AEF)#_)LL%0bY&q}`a zw0zs*qx-|Kfo>_jC}G^c2&wbdhvl>^=_VpSWD#ke*UfEw!?9WymxnD>fZ0D9Ast-7kN++bi1fGzxAPb`MIeg#jygm{$$d{ z@ID=7CHQ9NzHD7`yc#!CHku=Bt6!lwqo6WHMqCh1Tcqya$qitLQ35rW2cR;tfz2D< z_g|4$@3o^_i4DG^jgcpr!>Mv1?X3JPHNkXQamsa>?V?88CE*hgr}*aKr!hiH$FV9Y zz?^7S_%jZQ2XttDsGV;a3U)2_@rc>i<2q1z3SWwq?_K&8k=KS9R}+2Of@^Vo7L!Yc zz@CbW47XUkr`T7fsR;~egZKfGI+dcaX<|w5AUPV@YTNeYHX56-D)5UUbb`^+K*@c? zxYfvkhM&mpW|Xm&d?n@{&am4+)n+SD`=Sv^{At=|*O%ci5(CET7i2q2_>tVL{P&o1LTuZswvhIZTj)Wg;iAD)y*2vD~cIis})? z8K2#!FzMVIUop=O735TJ;tXr2 zrZ!%346GMegYL8S-SGp7Zg1svFu(O!|HmO1#T57OsC5z4MnBii9Dz+Awh^_KaIcWD z|2j5DZFwNh(ZY_BG?cp^ z@FrY*NNIk?R6}_7_VU@Cz9Bl9(!F8Js3#)8k7JGPE~dFz)>MV*oMmyW?iWKZY8#Mw z&!KM32QR7Ikv7EU$AwbHrLMy^8(xCt8>@O>%VJC9HA735)>B)uNexv6iVo8u>6R<$fx@`; zY7+~dosWbm;r!}+v^Tp#((Sd`B#GsnExX0HaH^&B4Eh_@k58*0l}QEK3R52CUdWwT zE2jF*??gbm;T=Th6$*_X%kOtVVp(iW8pWbtLZ8O3WKwT;?nSck`OZ@S%C*&-!C6qd zl^KPWmj%z0{t|Pdt>P=LTwgki9oSR}$}xu*epD9Fs#H6iM8`u|#I&r#fT-X9Tn7)o z8s7>?D~{un7z2_sPjib{xta(q@J(Hf4q3j3I?10F`BT;6tDak6Dm`P-tUnNs5fqL| z{7RGl3}OpU9+v*1_nps{eIkZVk^+~5^d-@gW+YQQ)GOa^FZ|)&IKJ49(NW`PmcqS) zfcPqjtv=#wvzsQS`IvonN-c9!+d%`$gyY3hSmz#-^e64W40a)Ec7Eh-dY^%eOvq&0 z51$p~_Pu2k6wrt`$oph^!>leT-3XoDrDxZ&{v>UU3&8Uvcr={5yAKwo(7FG+KEbusWJHm zxRxJSM_|^iuQIDaLf7jF^0zAc_8iBjpR%Hwn$zJ&o$?H<`Jbt`=kN|U7PDhlth81d zS)AxSzCd*fS>AbQGp3_jX8uk54t1E{vZ93czE5QCsq#{{ zGBkOEBA=uum3(?fIa_tL^+lIAJ>)>FEgWJV0! z)VWqhVpgWP81P(WEwmH3`0pqGQ|g5EY?M+IP8Vm!WU@|(*>WzAhI1Mr(*zSjc08PA zkR(E5mrU*>DXEj~^P`6Wf9id|1$QR2I)wk~{=8^xjH7ME9s8lb!sLii5Cf%i=rI`TCupS)d;A2|gY~N}owX zk?xro7`w~uVl+oSgRa70f3Hd)9H><6Ep@OQ<8aCXk%SNrX5C8N12n%uy41+vQ%=Sz zpNv+;g!5hR0^V?HZ-#r4aZV4rO z3#Rruvc}hzh~rk?I&+uPU$&&pdq$a#)MJHzlcP~_xYRBdOA{?2lu_~QHIKsSX2Sur zB7>>VD@19Jk8I8Z4OWJ?9K1ibNjg7~oTgn`RZ=hhdcfk}k}&QEk0(`iPSWMq`_vsrkT;QPT11T@@w{JpR~L*{EbRVju^mUlu; zPdNP4`{4bwva9cA4>9dQ);!>CbIjS!H%%_%g-EjX9!6MpPen88u$y=*+vSRhKKt|3 zt>L9|kMabt>Nve{8f*RM@;P6N0zMSy7x79y#E;*0dPY?-Gfm9e3$#02Kk<^4En!FpOpxh z5$m`2$J;hJiHWGik_`<{zimJC<30N`eI^^+cg;c+3?_FmV>DU|AHomCF9p$k5SJ`7 zFrQ+4GxtQ@&TWoc)KdWOuRv~PW-&?HY`rtHnD>P313#6J#CL+Jyu_UFp?ptTN%(Zs zo%g=ZjoZUg6(Gy!T#r582j?XoBqK?c=UB=deYkEwb!&bas_7E7y$+U*-&|39!FjvSr9Eid!~Q zcgp1!7S~0=q1sCVRAytR9A)p#pIW-h=x2yCWaVC#Rbt&3uN{cOQjGrGO%JtN9K;sbL)8L4r>H3H@3gVqUoZVNBAn5%Ntnog;+oErgG6 z=9-wvIBHB>EZxzZZ+{PC46!miEAEs*FOSl>>=6?Kcf4{P&Q6{kH7WkO!Zt;^Jt$_b z;&s`RW1>(fASowpE~Bg}t)MC=dqrAWRa)AycbD`306u;$o^E0PACOm-QT%T}U!LON0ucM( z4p>hg*C4EukN^K+R8*zqRb~H&xuJY|Nq0hCN^11mCVt+&xNt3Hj z4?s5=)6#l@3}`0x=P7tP8{2h?rR7H^n)I_M9$H_0uJiqI@s?+)EpSV~bLWi#rsa() zsFkF?qZK~F)8}o=(aJ87OFuPoaMRm z#f9`w{Cs>#Xj}wj!0i)d)kyZ^Kd)3&mJ9Kl!-juPS}?1Fp*0de?(^g3q)zu^Ii5n4 ziSQ~(;J489(^3r1lYYN zx{V+D^2zT8Rb3r6%^Y}-oevIe;qj0b-<8$FI@C>5^ka~CL8j^WSawV<<8wG891Y2Y zL1`h7YU)RD@)A8p&!Ren9cu^aE~&I4mN5BPXIMGfwyL^FUf3<{&h`7K>ZtHDM&G}C zgu3D0S)pPCE(e(9y8VM6#IplwyV>L8h%&x}%;d1W$9$L+fCxdrHK_psWIi!taM)UK zu-3dm+L4goUA=`L%r^8eCRzn9ka>Z}vi1xsIZ%r!7X3>kD59GD7r(^4O`HC8=7T&2?TKa0kjFT{hRBr$~PhWx`X^7LmZ>Vbd66!pLOH!z?EyGq1tJ@g|mA%~@~ju)Iaj z;$&b_>*WsXyq}?@iPpUy=i( zgaJ)C;(-Q)F@svPWyla+zB}1mGcQ}^$^6*xnXG{C&^&L|y_|$f@LTAowZC`btXqQ4 zs154M0jM@`cTmaVd#V_@>@dQVPj3C4PK+egy)Wu;Dt8P=c`J463xfNJ&jccSvz}tJ zmXeNkQRB6PwJQ$zh!l-<#ng9Y6Xep|8^nek@D7V2>)LvYYQ|BbM!ZfF96afqp>Cv` zlfYjbZd$X$GQV8V`}B>_lRKb9p!;kv@z=77y>Rb?=jtOyGBXJA+Fu}ahM7QusB9iZ zFnMuZ^f*3LQE?)ehTT`Y&^tnT=~w;SUj2fP#IdzO2ix{+Uj@}FoiWBuM}en>ZGM9q zJ;OZO6#f{33amOw`>TDep7FfAwLUGCWxyfuD*bk!KpuMDXzgVy}>*EXq=d#fbC+JxX%au zex)cy#gUn^46p^D_ppfe>>GkUk9dcczMwK~rqc(W4!>$rDNz(&g6+eCW>$^v?^*2b zrtR&pWEABkCIYHB zY?8Rp77+NNY_`9Y>c}%aZByd6mT;&9h}!SAg>1yHM2|?*EQ$DRbfQ^E)y%l3!}N%s zcAN%4kZmVypD!G|7Psq@xD;Hq8yxH3(L3#He95*g{V1jm#h@dx@TV+~3YI_@_6qkk zNzw3KS& z&?JF@;ny~vlw0YIY|$-hpzvkVZVk+;4Q^faRgu2$#|vi(;z29#Lq`o&tCiDP?-s@u z7V?5XvVscc%U2`P!#uP)pYz4wh#E*8;uUY*GsWmtxI94WKX=^L!$p}?M21_mSvR=N z2cwKL|K?r_BxS#xdf|F|QBv#Uj=e>`{|oshw#16bC3A`BHEWEcqW175V>woECIL~M z!t-xR{R74j>(q|agr$dNE0wv_?6rVQM0Z2EP+p}-iC!f<&ZQu4^SS^@mVs@MS8<0u z1O50?OrRV8poEf)E~ftd{Y6V+lkyF+%>-D3{YT2`U1p7YtY<=g`)7#|N*@m3=1W~G zn}|)0(@Xi(__fJExdr8cZgZw)=0uxme}>1*>tAVWAyCN(7XnJ5;VOtw=fsat*{@^v z4taXtu2gbiZMgd&>(q zMhB9ri5zd1ND2g)x`ac%>eS5)_~Tl4ruKthT)f&=j!I0|m_}f`T00?BAg;n}XpHXB zq|_xweJr*KVv!_kUCIscVO`%rje3hH$(iQwkHHYw{%&UE9*!<tvZ;8`|8y~)0OijOIlEP*h=xg^7w&4*@N-hMm6s)25vLXW9m zQZdt<@)LX9)<~ceW)NWiq1(fEG2)+3`8Cd+)pSq|$y%(a`#@tx!|#5k$R?9jnqRvC zn^%lu<&P#h$Dry7>sQV9QE0x&Zhy;_ioDZNt&v8e<#&n)e4UXacowaE%H>Qk%={Mw zvWu0RQal+&6`(Cfqd?L4fh1T(^p0_kv5H!N!GcI0qn#r`V&3UE@oX;itGuId)_}jM zn8`bXVk?3sFwOy?lR~*<5&Qn0#SlyUND(>`Kb$2HPKH0m(Vm4vfA#PLncu1VI=XXs zbghK_u3yMr_(Q@64=qB^sE=~dMw*GLSPXD7xj;q;vbEzxl)05VX$|{I-SIMHgw21G zmS7GIOMv`2@tS@`Z&VoM*BXIY@vy)LQ!Ta)WM)ayY7F-}6*m^e$tB+x_$^>zJ4l&m zxrVyKd&=S3{;>g4iRUwD!z^p0}EQ8Y0qg8-(tEYdirb5Qh%dWLjVTr zmdIoQl4C8k)O1Wb;y&510o5~<>FSIbHvT=}eOqkh#rLt#IjR)Npw`G^)JaZYhk{h@ zU2P$S<}KYd1&QN&#^;MX1H)`tRdve^#M^D%!f$RxL|~_O^9Zk|HYi&I$&|x2uYRcF z#$86ciEEm35qe;nd2#CoY4LAEJCQOGa)mbL0TD}i<`2_C>bB1&YE-QtPX@vCt|}AM zI37SZMcDns_*a1HEBYhSF5+@gN}7XEu1B3DS8GbDglGB$X#mdn405(T%rI*w=1~1C zTQeV$Ao|+7LIikOl*vy-^X+!`<+pw3q+d6G5!&XaPN{<(PM|)grLhbJWZ4n&N$- z%TK4Xv}Swx#twg8G#L^Y#}4dnF$j+4tY=tK55Y^a1&6@u;_zWg?oOH37C3wK*EfCF zZ$t(MFP;bZD&foXF*_+8}QJP zx-ZVBraegPkOp`1YQJ;01N`JlBF(>OX~7bGSB*3}gExMh2ar*!hH1chvv6V-PSGKU z5ao6wR`v-6uqyKK>nhg)73%amBZI!Q!qmcmK`DY*G&WbFsu@~Jo2I)^G1<4ruwoP3 znE_DC-|hG4eD;M-*D}X)g!U!iX{)!^*OD4x_ zRyKtF_{;)z%QSE)xR-IHaeC5F$DmsDk@(4^%{fuD-S39W)AN(Rmz^ZIC`Fe936dPDVhN4EZql9>e!j1`&-!!46p-7 z0t!{)TGcPiaIH-FkUl9=BJK=_HnmCnwlb)JH;D_+N=E`8vu)Uc%z?sW3K<9Z1@f1lhBblAPFqCPaF@{`cCZ1fJnwD z*8V6)p$F5q+I^n@>jLts=d80x*>8T&b6JnRJXw`hdk9Boy6-KL2Dv|UsI2|+}(|KnZ5Zk@|`BS_~iO} zO#|``@lzBZ%@~1@(3o_Y%+qtD0oOAzR8N@D$o~CYe*c?a?X~51j7dK+SEk@tbMgc@ zA*6Gk3^u)_8?tkA>Gi1_b5q;Qc|JaHP{1O1oj#g+e%S60n0V;<(IMlUvw_xK*NVYu z-ma{%#qB73rnGBDvF7B|q$6ZzzAMu6+jsj>mC}CU*`NfO6|lWI=}Tch zk&|WfY#ewuo*Byom!hj?cp3Zk8(WwRwh|rKZOI=%?Hv<9^H5(?)30(h)pT;(q*LI@ z;nZ!Hq$|JntBqTCmtGf(M@%uBnL`30ti!Zw5Gd-o^hk;xxeyQ6PJY5@?T5$ZHA?f6 z5;6nXnMguJ3ANj>x`OWe_=+z6t**kOYwilqQGOfi;9&2rMiKLGkLphAt@f*yR?>sR z_znY98!ZMKZQ~cry4qTRg9UTF*H4;w-}hMI z1HXsy*%*ifms{@ST%owq5i&^+Oh74dFG1UWtD%#?naG%1PzJ(euPLZyK~dUEKAiX^ zv{vS1TksKl@Fs#b?e0L;8E@TdfzVLMV%ys~ai6vEzkH$rapumvlaK~YD}I@+7;Rny z>O}5rh$+%on%XPVe_5M&it&+VDqOn=Wx?4?XwlTmOq@pAe~-=(a7#Pf_`iTx|4vUtQziZBe9rCaJFP9i=yOKavT+OzZDVO!XGW zplRJ2dbwZdOu}t_=3SU|IT1x%)A8dLn$u-G$7BP~!Looz)@am@!&k_$x+{Hk?N zgxCQlT|qK1C~j?G(tW&sGZmjx;{DT<6sFLiz@x5H2}`A#r+;5p+q)&*He9BVheMDY zT{EKK`2r6`C7Xs)%wlIf5lg;!b9zIYkcV|a@5Nazu3z^*J$3o_jJX_y*xtU{5y4ru zvC`Zn^g9C2x+R}n%m;FtWHGv{aeW~64hVp3^}Bfma6XrA2#Xr)4-z9Aon<5_VR2>)2l%dSpnc@3C4|H)6+G} zv%XGpDQ7J`oyCKHLabY%fLPdJ86s0>Iot4Cmn!{cWKJDc3da3 zLJEm_67D@4#4^Kka+t{BBsl-J+hl@->IsWBXcsQmx|j$1zihPU;0)-z#Q*)PB{r|kv*L726X*Ziz0|lOIGdl@#AN^NQoxJp525-3| zc_X)Z`e=p4Z(vhGM&TfYQT#6Gq=%SYCFa_GTeY@Jb*K2fYglq3@b5#Pc=PdwYOo4p zeGBJ7SWVL^uiD2VS8KVQgfTvNnF7O4i*P*yO+_){3s?(al z=r>QeuQug+dVP7Xj#SZ^p-)8FcMhYH2L}hIug+anw9i}>U9D|B2%?fV z?p*&muu}%zaIo^%JtKY+Kdv%5>!{|BTMC1L*s$~#ZjDjLe zT2V^&zYHq#@0WiJ(|;HfUzeZ|hX5p?=IrZ;vg); @@ -1350,6 +1352,9 @@ App::App(const char* argv0) { } } + // soon (tm) + // ui::bubble::Init(); + App::Push(std::make_shared()); log_write("finished app constructor\n"); } @@ -1373,6 +1378,8 @@ App::~App() { i18n::exit(); curl::Exit(); + ui::bubble::Exit(); + // this has to be called before any cleanup to ensure the lifetime of // nvg is still active as some widgets may need to free images. m_widgets.clear(); diff --git a/sphaira/source/ui/bubbles.cpp b/sphaira/source/ui/bubbles.cpp new file mode 100644 index 0000000..f7e580e --- /dev/null +++ b/sphaira/source/ui/bubbles.cpp @@ -0,0 +1,115 @@ +#include "ui/types.hpp" +#include "ui/object.hpp" +#include "ui/nvg_util.hpp" +#include "app.hpp" + +namespace sphaira::ui::bubble { +namespace { + +constexpr auto MAX_BUBBLES = 20; + +struct Bubble { + int start_x; + int texture; + int x,y,w,h; + int y_inc; + float sway_inc; + float sway; + bool sway_right_flag; +}; + +Bubble bubbles[MAX_BUBBLES]{}; +int g_textures[3]; +bool g_is_init = false; + +void setup_bubble(Bubble *bubble) { + // setup normal vars. + bubble->texture = (randomGet64() % std::size(g_textures)); + bubble->start_x = randomGet64() % (int)SCREEN_WIDTH; + bubble->x = bubble->start_x; + bubble->y = (int)SCREEN_HEIGHT - ( randomGet64() % 60 ); + const int size = (randomGet64() % 50) + 40; + bubble->w = size; + bubble->h = size; + bubble->y_inc = (randomGet64() % 5) + 1; + bubble->sway_inc = ((randomGet64() % 6) + 3) / 10; + bubble->sway = 0; +} + +void setup_bubbles(void) { + for (auto& bubble : bubbles) { + setup_bubble(&bubble); + } +} + +void update_bubbles(void) { + for (auto& bubble : bubbles) { + if (bubble.y + bubble.h < 0) { + setup_bubble(&bubble); + } else { + bubble.y -= bubble.y_inc; + + if (bubble.sway_right_flag) { + bubble.x = bubble.start_x + (bubble.sway -= bubble.sway_inc); + if (bubble.sway <= 0) { + bubble.sway_right_flag = false; + } + } else { + bubble.x = bubble.start_x + (bubble.sway += bubble.sway_inc); + if (bubble.sway > 30) { + bubble.sway_right_flag = true; + } + } + } + } +} + +} // namespace + +void Init() { + if (g_is_init) { + return; + } + + if (R_SUCCEEDED(romfsInit())) { + ON_SCOPE_EXIT(romfsExit()); + + auto vg = App::GetVg(); + g_textures[0] = nvgCreateImage(vg, "romfs:/theme/bubble1.png", 0); + g_textures[1] = nvgCreateImage(vg, "romfs:/theme/bubble2.png", 0); + g_textures[2] = nvgCreateImage(vg, "romfs:/theme/bubble3.png", 0); + + setup_bubbles(); + g_is_init = true; + } +} + +void Draw(NVGcontext* vg, Theme* theme) { + if (!g_is_init) { + return; + } + + update_bubbles(); + + for (auto& bubble : bubbles) { + gfx::drawImage(vg, bubble.x, bubble.y, bubble.w, bubble.h, g_textures[bubble.texture]); + } +} + +void Exit() { + if (!g_is_init) { + return; + } + + auto vg = App::GetVg(); + for (auto& texture : g_textures) { + if (texture) { + nvgDeleteImage(vg, texture); + texture = 0; + } + } + + g_is_init = false; +} + +} // namespace sphaira::ui::bubble From e3f846c9ec332d2d0357db5e07413084711fbd48 Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Sun, 12 Jan 2025 22:21:54 +0000 Subject: [PATCH 5/5] Change a few colors of the theme. (#87) Co-authored-by: Yorunokyujitsu --- assets/romfs/themes/abyss_theme.ini | 4 ++-- assets/romfs/themes/base_black_theme.ini | 6 +++--- assets/romfs/themes/base_white_theme.ini | 10 +++++----- sphaira/include/ui/types.hpp | 2 +- sphaira/source/app.cpp | 3 ++- sphaira/source/ui/error_box.cpp | 2 +- sphaira/source/ui/menus/filebrowser.cpp | 6 +++--- sphaira/source/ui/menus/ghdl.cpp | 4 ++-- sphaira/source/ui/option_box.cpp | 2 +- sphaira/source/ui/popup_list.cpp | 2 +- sphaira/source/ui/sidebar.cpp | 2 +- 11 files changed, 22 insertions(+), 21 deletions(-) diff --git a/assets/romfs/themes/abyss_theme.ini b/assets/romfs/themes/abyss_theme.ini index cb37fd0..e66a1dd 100644 --- a/assets/romfs/themes/abyss_theme.ini +++ b/assets/romfs/themes/abyss_theme.ini @@ -13,11 +13,11 @@ line = 0xffbc41 line_seperator = 0xffbc41 text = 0xffbc41 -text_info = 0xffbc41 +text_info = 0xd79f36 text_selected = 0x529cff selected_background = 0x0f115c -scrollbar = 0x3250f0 +scrollbar = 0x529cff scrollbar_background = ; hide the background progressbar = 0x3250f0 diff --git a/assets/romfs/themes/base_black_theme.ini b/assets/romfs/themes/base_black_theme.ini index 3f61226..2af43d6 100644 --- a/assets/romfs/themes/base_black_theme.ini +++ b/assets/romfs/themes/base_black_theme.ini @@ -1,16 +1,16 @@ [theme] background = 0x2d2d2d grid = 0x46464630 -popup = 0x464646 +popup = 0x2d2d2d error = 0xfa5a3a line = 0xfbfbfb -line_seperator = 0xd1d1d1 +line_separator = 0x707070 text = 0xfbfbfb text_info = 0xd1d1d1 text_selected = 0x00ffc8 -selected_background = 0x464646 +selected_background = 0x212227 sidebar = 0x000000dc diff --git a/assets/romfs/themes/base_white_theme.ini b/assets/romfs/themes/base_white_theme.ini index ce0011d..a3cdc6d 100644 --- a/assets/romfs/themes/base_white_theme.ini +++ b/assets/romfs/themes/base_white_theme.ini @@ -1,11 +1,11 @@ [theme] -background = 0xececec -grid = 0xf1f1f1 -popup = 0xf1f1f1 +background = 0xebebeb +grid = 0xf0f0f0 +popup = 0xebebeb error = 0xfa5a3a line = 0x373737 -line_seperator = 0x373737 +line_separator = 0x6d787a text = 0x373737 text_info = 0x808080 @@ -24,7 +24,7 @@ progressbar_background = 0x808080 highlight_1 = 0x1989c6 highlight_2 = 0x89f0f2 -icon_colour = 0x6f7779 +icon_colour = 0x6d787a icon_audio = romfs:/theme/icon_audio.png icon_video = romfs:/theme/icon_video.png icon_image = romfs:/theme/icon_image.png diff --git a/sphaira/include/ui/types.hpp b/sphaira/include/ui/types.hpp index a8b68d2..4d5135e 100644 --- a/sphaira/include/ui/types.hpp +++ b/sphaira/include/ui/types.hpp @@ -182,7 +182,7 @@ enum ThemeEntryID { // colour of line separators in a list. ThemeEntryID_LINE, - ThemeEntryID_LINE_SEPERATOR, + ThemeEntryID_LINE_SEPARATOR, // colour of the sidebar backrgound. ThemeEntryID_SIDEBAR, diff --git a/sphaira/source/app.cpp b/sphaira/source/app.cpp index 954e698..4d2167d 100644 --- a/sphaira/source/app.cpp +++ b/sphaira/source/app.cpp @@ -51,9 +51,10 @@ constexpr ThemeIdPair THEME_ENTRIES[] = { { "text_info", ThemeEntryID_TEXT_INFO, ElementType::Colour }, { "text_selected", ThemeEntryID_TEXT_SELECTED, ElementType::Colour }, { "selected_background", ThemeEntryID_SELECTED_BACKGROUND, ElementType::Colour }, + { "error", ThemeEntryID_ERROR, ElementType::Colour }, { "popup", ThemeEntryID_POPUP, ElementType::Colour }, { "line", ThemeEntryID_LINE, ElementType::Colour }, - { "line_seperator", ThemeEntryID_LINE_SEPERATOR, ElementType::Colour }, + { "line_separator", ThemeEntryID_LINE_SEPARATOR, ElementType::Colour }, { "sidebar", ThemeEntryID_SIDEBAR, ElementType::Colour }, { "scrollbar", ThemeEntryID_SCROLLBAR, ElementType::Colour }, { "scrollbar_background", ThemeEntryID_SCROLLBAR_BACKGROUND, ElementType::Colour }, diff --git a/sphaira/source/ui/error_box.cpp b/sphaira/source/ui/error_box.cpp index c35b61b..108b72d 100644 --- a/sphaira/source/ui/error_box.cpp +++ b/sphaira/source/ui/error_box.cpp @@ -1147,7 +1147,7 @@ auto ErrorBox::Draw(NVGcontext* vg, Theme* theme) -> void { gfx::drawTextArgs(vg, center_x, 380, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "If this message appears repeatedly, please open an issue."_i18n.c_str()); gfx::drawTextArgs(vg, center_x, 415, 20, NVG_ALIGN_CENTER | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_INFO), "https://github.com/ITotalJustice/sphaira/issues"); gfx::drawRectOutline(vg, theme, 4.f, box); - gfx::drawTextArgs(vg, center_x, box.y + box.h/2, 23, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT), "OK"_i18n.c_str()); + gfx::drawTextArgs(vg, center_x, box.y + box.h/2, 23, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_SELECTED), "OK"_i18n.c_str()); } } // namespace sphaira::ui diff --git a/sphaira/source/ui/menus/filebrowser.cpp b/sphaira/source/ui/menus/filebrowser.cpp index 3eb8f60..7bde01c 100644 --- a/sphaira/source/ui/menus/filebrowser.cpp +++ b/sphaira/source/ui/menus/filebrowser.cpp @@ -581,7 +581,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { const auto& text_col = theme->GetColour(ThemeEntryID_TEXT); if (m_entries_current.empty()) { - gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, text_col, "Empty..."_i18n.c_str()); + gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "Empty..."_i18n.c_str()); return; } @@ -605,7 +605,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { } if (e.IsSelected()) { - gfx::drawText(vg, Vec2{x, y + (h / 2.f) - (24.f / 2)}, 24.f, "\uE14B", nullptr, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_SELECTED)); + gfx::drawText(vg, Vec2{x - 10.f, y + (h / 2.f) - (24.f / 2)}, 24.f, "\uE14B", nullptr, NVG_ALIGN_RIGHT | NVG_ALIGN_TOP, theme->GetColour(ThemeEntryID_TEXT_SELECTED)); } auto text_id = ThemeEntryID_TEXT; @@ -614,7 +614,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { gfx::drawRectOutline(vg, theme, 4.f, v); } else { if (i != m_entries_current.size() - 1) { - gfx::drawRect(vg, Vec4{x, y + h, w, 1.f}, theme->GetColour(ThemeEntryID_LINE_SEPERATOR)); + gfx::drawRect(vg, Vec4{x, y + h, w, 1.f}, theme->GetColour(ThemeEntryID_LINE_SEPARATOR)); } } diff --git a/sphaira/source/ui/menus/ghdl.cpp b/sphaira/source/ui/menus/ghdl.cpp index 2414b4a..c161235 100644 --- a/sphaira/source/ui/menus/ghdl.cpp +++ b/sphaira/source/ui/menus/ghdl.cpp @@ -389,7 +389,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { const auto& text_col = theme->GetColour(ThemeEntryID_TEXT); if (m_entries.empty()) { - gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, text_col, "Empty..."_i18n.c_str()); + gfx::drawTextArgs(vg, SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 36.f, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_INFO), "Empty..."_i18n.c_str()); return; } @@ -405,7 +405,7 @@ void Menu::Draw(NVGcontext* vg, Theme* theme) { gfx::drawRectOutline(vg, theme, 4.f, v); } else { if (i != m_entries.size() - 1) { - gfx::drawRect(vg, x, y + h, w, 1.f, theme->GetColour(ThemeEntryID_LINE_SEPERATOR)); + gfx::drawRect(vg, x, y + h, w, 1.f, theme->GetColour(ThemeEntryID_LINE_SEPARATOR)); } } diff --git a/sphaira/source/ui/option_box.cpp b/sphaira/source/ui/option_box.cpp index 9b3cb44..adff8b4 100644 --- a/sphaira/source/ui/option_box.cpp +++ b/sphaira/source/ui/option_box.cpp @@ -101,7 +101,7 @@ auto OptionBox::Draw(NVGcontext* vg, Theme* theme) -> void { gfx::drawTextBox(vg, m_pos.x + padding, m_pos.y + 110.f, 26.f, m_pos.w - padding*2, theme->GetColour(ThemeEntryID_TEXT), m_message.c_str(), NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); nvgRestore(vg); - gfx::drawRect(vg, m_spacer_line, theme->GetColour(ThemeEntryID_LINE)); + gfx::drawRect(vg, m_spacer_line, theme->GetColour(ThemeEntryID_LINE_SEPARATOR)); for (auto&p: m_entries) { p.Draw(vg, theme); diff --git a/sphaira/source/ui/popup_list.cpp b/sphaira/source/ui/popup_list.cpp index 0a33b76..48bf462 100644 --- a/sphaira/source/ui/popup_list.cpp +++ b/sphaira/source/ui/popup_list.cpp @@ -123,7 +123,7 @@ auto PopupList::Draw(NVGcontext* vg, Theme* theme) -> void { gfx::drawText(vg, x + m_text_xoffset, y + (h / 2.f), 20.f, m_items[i].c_str(), NULL, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_SELECTED)); } else { if (i != m_items.size() - 1) { - gfx::drawRect(vg, x, y + h, w, 1.f, theme->GetColour(ThemeEntryID_LINE_SEPERATOR)); + gfx::drawRect(vg, x, y + h, w, 1.f, theme->GetColour(ThemeEntryID_LINE_SEPARATOR)); } gfx::drawText(vg, x + m_text_xoffset, y + (h / 2.f), 20.f, m_items[i].c_str(), NULL, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT)); } diff --git a/sphaira/source/ui/sidebar.cpp b/sphaira/source/ui/sidebar.cpp index 09bc19c..74f8dc0 100644 --- a/sphaira/source/ui/sidebar.cpp +++ b/sphaira/source/ui/sidebar.cpp @@ -229,7 +229,7 @@ auto Sidebar::Draw(NVGcontext* vg, Theme* theme) -> void { const auto& [x, y, w, h] = v; if (i != m_items.size() - 1) { - gfx::drawRect(vg, x, y + h, w, 1.f, theme->GetColour(ThemeEntryID_LINE_SEPERATOR)); + gfx::drawRect(vg, x, y + h, w, 1.f, theme->GetColour(ThemeEntryID_LINE_SEPARATOR)); } m_items[i]->SetY(y);