From a772d660f388e842b891e201456267b91e7ba79e Mon Sep 17 00:00:00 2001 From: ITotalJustice <47043333+ITotalJustice@users.noreply.github.com> Date: Sun, 21 Sep 2025 04:08:36 +0100 Subject: [PATCH] use spinner instead of default icon for homebrew + games menus. more menus will use it soon. need to have a way to show the spinner when loading, then revert to the default icon if failed to load, or an icon doesn't exist. otherwise, the user may think that the icon is still loading and wait for it. --- sphaira/include/ui/nvg_util.hpp | 2 ++ sphaira/source/ui/menus/grid_menu_base.cpp | 16 ++++++++++- sphaira/source/ui/nvg_util.cpp | 30 ++++++++++++++++++++ sphaira/source/ui/progress_box.cpp | 32 +--------------------- 4 files changed, 48 insertions(+), 32 deletions(-) diff --git a/sphaira/include/ui/nvg_util.hpp b/sphaira/include/ui/nvg_util.hpp index d53d7a9..b162ec3 100644 --- a/sphaira/include/ui/nvg_util.hpp +++ b/sphaira/include/ui/nvg_util.hpp @@ -42,6 +42,8 @@ void drawScrollbar2(NVGcontext*, const Theme*, s64 index_off, s64 count, s64 row void drawAppLable(NVGcontext* vg, const Theme*, ScrollingText& st, float x, float y, float w, const char* name); +void drawSpinner(NVGcontext* vg, const Theme*, float cx, float cy, float r, float t); + void updateHighlightAnimation(); void getHighlightAnimation(float* gradientX, float* gradientY, float* color); diff --git a/sphaira/source/ui/menus/grid_menu_base.cpp b/sphaira/source/ui/menus/grid_menu_base.cpp index 4719d7e..c890375 100644 --- a/sphaira/source/ui/menus/grid_menu_base.cpp +++ b/sphaira/source/ui/menus/grid_menu_base.cpp @@ -2,6 +2,8 @@ #include "ui/menus/grid_menu_base.hpp" #include "ui/nvg_util.hpp" +#include + namespace sphaira::ui::menu::grid { void Menu::DrawEntry(NVGcontext* vg, Theme* theme, int layout, const Vec4& v, bool selected, int image, const char* name, const char* author, const char* version) { @@ -45,7 +47,19 @@ Vec4 Menu::DrawEntry(NVGcontext* vg, Theme* theme, bool draw_image, int layout, } if (draw_image) { - gfx::drawImage(vg, image_v, image ?: App::GetDefaultImage(), 5); + if (image > 0) { + gfx::drawImage(vg, image_v, image, 5); + } else { + // https://www.mathopenref.com/arcradius.html + auto spinner = image_v; + spinner.w /= 2; + spinner.h /= 2; + spinner.x += (image_v.w / 2); + spinner.y += (image_v.h / 2); + + const auto rad = (spinner.h / 2) + (std::powf(spinner.w, 2) / (spinner.h * 8)); + gfx::drawSpinner(vg, theme, spinner.x, spinner.y, rad, armTicksToNs(armGetSystemTick()) / 1e+9); + } } return image_v; diff --git a/sphaira/source/ui/nvg_util.cpp b/sphaira/source/ui/nvg_util.cpp index 0a49013..9381ed9 100644 --- a/sphaira/source/ui/nvg_util.cpp +++ b/sphaira/source/ui/nvg_util.cpp @@ -387,6 +387,36 @@ void drawAppLable(NVGcontext* vg, const Theme* theme, ScrollingText& st, float x st.Draw(vg, true, text_x, text_y, box_w - text_pad * 2, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT_SELECTED), name); } +// https://github.com/memononen/nanovg/blob/f93799c078fa11ed61c078c65a53914c8782c00b/example/demo.c#L500 +void drawSpinner(NVGcontext* vg, const Theme* theme, float cx, float cy, float r, float t) +{ + float a0 = 0.0f + t*6; + float a1 = NVG_PI + t*6; + float r0 = r; + float r1 = r * 0.75f; + float ax,ay, bx,by; + NVGpaint paint; + + nvgSave(vg); + + auto colourb = theme->GetColour(ThemeEntryID_PROGRESSBAR); + colourb.a = 0.5; + + nvgBeginPath(vg); + nvgArc(vg, cx,cy, r0, a0, a1, NVG_CW); + nvgArc(vg, cx,cy, r1, a1, a0, NVG_CCW); + nvgClosePath(vg); + ax = cx + cosf(a0) * (r0+r1)*0.5f; + ay = cy + sinf(a0) * (r0+r1)*0.5f; + bx = cx + cosf(a1) * (r0+r1)*0.5f; + by = cy + sinf(a1) * (r0+r1)*0.5f; + paint = nvgLinearGradient(vg, ax,ay, bx,by, nvgRGBA(0,0,0,0), colourb); + nvgFillPaint(vg, paint); + nvgFill(vg); + + nvgRestore(vg); +} + #define HIGHLIGHT_SPEED 350.0 static double highlightGradientX = 0; diff --git a/sphaira/source/ui/progress_box.cpp b/sphaira/source/ui/progress_box.cpp index 52b7226..342684c 100644 --- a/sphaira/source/ui/progress_box.cpp +++ b/sphaira/source/ui/progress_box.cpp @@ -21,36 +21,6 @@ void threadFunc(void* arg) { d->pbox->RequestExit(); } -// https://github.com/memononen/nanovg/blob/f93799c078fa11ed61c078c65a53914c8782c00b/example/demo.c#L500 -void drawSpinner(NVGcontext* vg, Theme* theme, float cx, float cy, float r, float t) -{ - float a0 = 0.0f + t*6; - float a1 = NVG_PI + t*6; - float r0 = r; - float r1 = r * 0.75f; - float ax,ay, bx,by; - NVGpaint paint; - - nvgSave(vg); - - auto colourb = theme->GetColour(ThemeEntryID_PROGRESSBAR); - colourb.a = 0.5; - - nvgBeginPath(vg); - nvgArc(vg, cx,cy, r0, a0, a1, NVG_CW); - nvgArc(vg, cx,cy, r1, a1, a0, NVG_CCW); - nvgClosePath(vg); - ax = cx + cosf(a0) * (r0+r1)*0.5f; - ay = cy + sinf(a0) * (r0+r1)*0.5f; - bx = cx + cosf(a1) * (r0+r1)*0.5f; - by = cy + sinf(a1) * (r0+r1)*0.5f; - paint = nvgLinearGradient(vg, ax,ay, bx,by, nvgRGBA(0,0,0,0), colourb); - nvgFillPaint(vg, paint); - nvgFill(vg); - - nvgRestore(vg); -} - } // namespace ProgressBox::ProgressBox(int image, const std::string& action, const std::string& title, const ProgressBoxCallback& callback, const ProgressBoxDoneCallback& done) @@ -180,7 +150,7 @@ auto ProgressBox::Draw(NVGcontext* vg, Theme* theme) -> void { gfx::drawTextArgs(vg, prog_bar.x + prog_bar.w + pad, prog_bar.y + prog_bar.h / 2, font_size, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE, theme->GetColour(ThemeEntryID_TEXT), "%u%%", percentage); const auto rad = 15; - drawSpinner(vg, theme, prog_bar.x - pad - rad, prog_bar.y + prog_bar.h / 2, rad, armTicksToNs(armGetSystemTick()) / 1e+9); + gfx::drawSpinner(vg, theme, prog_bar.x - pad - rad, prog_bar.y + prog_bar.h / 2, rad, armTicksToNs(armGetSystemTick()) / 1e+9); const double speed_mb = (double)speed / (1024.0 * 1024.0); const double speed_kb = (double)speed / (1024.0);