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] initial work on theme v2 see #78 --- assets/romfs/themes/abyss_theme.ini | 15 +- assets/romfs/themes/base_black_theme.ini | 46 ++-- 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 | 46 +++- sphaira/source/app.cpp | 190 ++++++++++----- 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 - -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 +background = 0x2d2d2d +grid = 0x46464630 +popup = 0x464646 +error = 0xfa5a3a + +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 @@ class App { // 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 @@ class App { 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 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 drawRect(NVGcontext*, const Vec4& v, const NVGpaint& p, bool rounded = false); -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 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 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, + // 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, Vec4 vec, const NVGpaint& p, bool rounded) { - drawRectIntenal(vg, vec, p, rounded); -} - -void drawRect(NVGcontext* vg, Vec4 vec, const NVGpaint&& p, bool rounded) { - drawRectIntenal(vg, vec, p, rounded); +void drawRect(NVGcontext* vg, const Vec4& v, const NVGpaint& p, bool rounded) { + drawRectIntenal(vg, v, 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, 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 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, 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 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 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);