From fca5935d344a8a3049b1cfcb44ef9e52724838d2 Mon Sep 17 00:00:00 2001 From: "Daniel K. O. (dkosmari)" Date: Sun, 5 Jul 2026 04:04:23 -0300 Subject: [PATCH 1/7] Support theme shuffling. --- external/CMakeLists.txt | 3 +- external/glaze | 2 +- src/App.cpp | 4 + src/installer.cpp | 275 +++++++++++++++++++---------- src/installer.h | 31 +++- src/screens/HomeScreen.cpp | 95 +++++----- src/screens/InstallThemePopup.cpp | 2 +- src/screens/ManageThemesScreen.cpp | 94 +++++----- src/screens/ManageThemesScreen.h | 2 - src/screens/ThemeDetailsPopup.cpp | 29 +-- src/screens/ThemeDetailsPopup.h | 3 +- src/utils.cpp | 65 +++++++ src/utils.h | 17 ++ 13 files changed, 404 insertions(+), 218 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 1826e7c..77d7a6b 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -19,14 +19,13 @@ add_library(imgui STATIC ) target_include_directories(imgui PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/imgui ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends ${CMAKE_CURRENT_SOURCE_DIR}/imgui/misc/carousel ${CMAKE_CURRENT_SOURCE_DIR}/imgui/misc/cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgui/misc/freetype ) -target_compile_definitions(imgui PUBLIC IMGUI_USER_CONFIG="custom_imconfig.h") +target_compile_definitions(imgui PUBLIC IMGUI_USER_CONFIG="${CMAKE_CURRENT_SOURCE_DIR}/custom_imconfig.h") target_link_libraries(imgui PUBLIC PkgConfig::sdl2 PkgConfig::freetype2) diff --git a/external/glaze b/external/glaze index 9618ef8..0a21fd9 160000 --- a/external/glaze +++ b/external/glaze @@ -1 +1 @@ -Subproject commit 9618ef8ef503c72b10e7b2769839784f09d24d2c +Subproject commit 0a21fd9dbd36963790b6f26b9539050e13d78649 diff --git a/src/App.cpp b/src/App.cpp index d3a58b8..3d7efaa 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -15,6 +15,7 @@ #include "DownloadManager.h" #include "Camera.h" #include "utils.h" +#include "installer.h" #include #include @@ -238,6 +239,8 @@ namespace App { Camera::initialize(renderer); Camera::open(); + Installer::initialize(); + DownloadManager::initialize(user_agent); ImageLoader::initialize(renderer); NavBar::initialize(renderer); @@ -277,6 +280,7 @@ namespace App { NavBar::finalize(); ContentPanel::finalize(); + Installer::finalize(); ImageLoader::finalize(); DownloadManager::finalize(); diff --git a/src/installer.cpp b/src/installer.cpp index 3b256e8..bd67b75 100644 --- a/src/installer.cpp +++ b/src/installer.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ #include "installer.h" #include "utils.h" +#include "tracer.hpp" using std::cout; using std::cerr; @@ -41,7 +43,7 @@ using namespace std::literals; namespace Installer { - std::unordered_map regionLangMap = { + std::unordered_map regionLangMap = { {"UsEn", "UsEnglish/Message/AllMessage.szs"}, {"UsFr", "UsFrench/Message/AllMessage.szs"}, {"UsPt", "UsPortuguese/Message/AllMessage.szs"}, @@ -57,23 +59,125 @@ namespace Installer { {"JpJa", "JpJapanese/Message/AllMessage.szs"} }; - static std::string ReadWholeFile(std::ifstream& file) - { - std::ostringstream ss; - ss << file.rdbuf(); - return ss.str(); - } + struct StyleMiiUCfg { + std::string enabledThemes = {}; + bool mashupThemes = false; + bool showNotification = false; + bool suffleThemes = false; // NOTE the typo! + bool themeManagerEnabled = false; + }; + + struct StyleMiiUJson { + StyleMiiUCfg storageitems; + }; + + std::optional currentStyleMiiUCfg; + + std::unordered_set active_themes; + + namespace { + + std::filesystem::path + realGetStyleMiiUConfigPath() + { + char buffer[256]; + auto res = Mocha_GetEnvironmentPath(buffer, sizeof buffer); + if (res) { + std::runtime_error e{"Could not get Aroma environment path: "s + + Mocha_GetStatusStr(res)}; + cerr << "ERROR: " << e.what() << endl; + throw e; + } + return std::filesystem::path{buffer} / "plugins/config/style-mii-u.json"; + } + + std::filesystem::path + GetStyleMiiUConfigPath() + { + static const std::filesystem::path result = realGetStyleMiiUConfigPath(); + return result; + } + + static void LoadStyleMiiUCfg() { + currentStyleMiiUCfg.reset(); + active_themes.clear(); + auto stylemiiu_cfg_path = GetStyleMiiUConfigPath(); + if (!exists(stylemiiu_cfg_path)) { + // If config doesn't exist yet, it's not an error. + currentStyleMiiUCfg.emplace(); + return; + } + StyleMiiUJson json; + glz::ex::read_file_json(json, stylemiiu_cfg_path.string(), std::string{}); + currentStyleMiiUCfg = std::move(json.storageitems); + if (currentStyleMiiUCfg->suffleThemes) { + auto themes = split(currentStyleMiiUCfg->enabledThemes, "|", true); + for (const auto& theme : themes) + if (!theme.empty()) + active_themes.insert(theme); + } else { + active_themes.insert(currentStyleMiiUCfg->enabledThemes); + } + } + + static void SaveStyleMiiUCfg() { + if (!currentStyleMiiUCfg) + throw std::runtime_error{"No valid StyleMiiU config state to store."}; + StyleMiiUJson json; + json.storageitems = *currentStyleMiiUCfg; + glz::ex::write_file_json(json, GetStyleMiiUConfigPath().string(), std::string{}); + } + + StyleMiiUCfg& + GetStyleMiiUCfg() + { + try { + if (!currentStyleMiiUCfg) + LoadStyleMiiUCfg(); + return *currentStyleMiiUCfg; + } + catch (std::exception& e) { + cerr << "ERROR in GetSTyleMiiUCfg(): " << e.what() << endl; + throw; + } + } + + std::filesystem::path GetMenuContentPath() { + uint64_t menuTitleID = _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_WII_U_MENU); + + uint32_t menuIDParentDir = menuTitleID >> 32; + uint32_t menuIDChildDir = menuTitleID; + + char splitMenuID[18]; + snprintf(splitMenuID, sizeof splitMenuID, "%08x/%08x", menuIDParentDir, menuIDChildDir); + + return "storage_mlc:/sys/title" / std::filesystem::path{splitMenuID} / "content"; + } - std::filesystem::path GetMenuContentPath() { - uint64_t menuTitleID = _SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_WII_U_MENU); + } // namespace - uint32_t menuIDParentDir = menuTitleID >> 32; - uint32_t menuIDChildDir = menuTitleID; - char splitMenuID[18]; - snprintf(splitMenuID, sizeof splitMenuID, "%08x/%08x", menuIDParentDir, menuIDChildDir); + void initialize() + { + TRACE_FUNC; + + try { + LoadStyleMiiUCfg(); + } + catch (std::exception &e) { + cerr << "ERROR: failed to load StyleMiiU config: " << e.what() << endl; + } + } - return "storage_mlc:/sys/title" / std::filesystem::path{splitMenuID} / "content"; + void finalize() + { + TRACE_FUNC; + try { + SaveStyleMiiUCfg(); + } + catch (std::exception &e) { + cerr << "ERROR: failed to save StyleMiiU config: " << e.what() << endl; + } } void CreateCacheFile(std::ifstream &sourceFile, const std::filesystem::path &outputPath) { @@ -586,101 +690,29 @@ namespace Installer { DeletePath(meta.themePath); } - std::string GetStyleMiiUConfigPath() { - char environmentPathBuffer[0x100]; - - MochaUtilsStatus res; - if ((res = Mocha_GetEnvironmentPath(environmentPathBuffer, sizeof(environmentPathBuffer))) != MOCHA_RESULT_SUCCESS) { - cerr << "Failed to get environment path. Are you running on Aroma? Result: " - << Mocha_GetStatusStr(res) << endl; - return ""; // TOOD: should we use the default aroma path as fallback? - } - - return std::string(environmentPathBuffer) + "/plugins/config/style-mii-u.json"; - } - - bool SetCurrentTheme(const InstalledThemeMetadata &meta) { - try { - cout << "Trying to set current theme: " << meta.themePath << endl; - auto styleMiiUConfigPath = GetStyleMiiUConfigPath(); - - std::ifstream configFile(styleMiiUConfigPath); - if (!configFile.is_open()) { - cerr << "Failed to open config file: " << styleMiiUConfigPath << endl; - return false; - } - - std::string jsonStr = ReadWholeFile(configFile); - configFile.close(); - - glz::generic configJson; - if (auto err = glz::read_json(configJson, jsonStr)) { - cerr << "Failed to parse config file: " - << glz::format_error(err, jsonStr) << endl; - return false; - } - - configJson["storageitems"]["enabledThemes"] = meta.themePath.filename().string(); - - auto outputJson = glz::write(configJson); - if (!outputJson) { - cerr << "Failed to serialize config json" << endl; - return false; - } - - std::ofstream outFile{styleMiiUConfigPath, std::ios::trunc | std::ios::out}; - if (!outFile.is_open()) { - cerr << "Failed to open for write: " << styleMiiUConfigPath << endl; - return false; - } - - outFile << *outputJson; - outFile.close(); - - std::println("Succesfully set {} as current StyleMiiU theme!", - meta.themePath.string()); - - return true; - } - catch (std::exception& e) { - cerr << "ERROR in SetCurrentTheme(): " << e.what() << endl; - return false; - } - } - - std::string GetCurrentThemeName() { - std::string styleMiiUConfigPath = GetStyleMiiUConfigPath(); - - std::ifstream configFile(styleMiiUConfigPath); - if (!configFile.is_open()) { - cerr << "Failed to open config file: " << styleMiiUConfigPath << endl; - return ""; - } - - std::string jsonStr = ReadWholeFile(configFile); - configFile.close(); - - glz::generic configJson; - if (auto err = glz::read_json(configJson, jsonStr)) { - cerr << "Failed to parse config file: " - << glz::format_error(err, jsonStr) << endl; - return ""; - } + std::string + GetCurrentThemeName() + { + auto& cfg = GetStyleMiiUCfg(); + if (cfg.suffleThemes) + return {}; - return configJson.at("storageitems").at("enabledThemes").get(); + return cfg.enabledThemes; } std::optional - GetCurrentTheme() { - // TODO: handle shuffle mode + GetCurrentTheme() + { auto themeName = GetCurrentThemeName(); + if (themeName.empty()) + return {}; auto themePath = THEMES_ROOT / themeName; if (!exists(themePath)) return {}; InstalledThemeMetadata result; if (!GetInstalledThemeMetadata(themePath, result)) return {}; - return {std::move(result)}; + return { std::move(result) }; } std::filesystem::path @@ -689,4 +721,51 @@ namespace Installer { return THEMES_ROOT / make_theme_folder_name(meta.themeName, meta.themeID); } + + bool IsShuffling() { + return GetStyleMiiUCfg().suffleThemes; + } + + void ToggleShuffling() { + auto &cfg = GetStyleMiiUCfg(); + cfg.suffleThemes = !cfg.suffleThemes; + if (!cfg.suffleThemes) { + active_themes.clear(); + cfg.enabledThemes.clear(); + } + } + + bool IsActive(const InstalledThemeMetadata& meta) { + return active_themes.contains(meta.themePath.filename()); + } + + void SetActive(const InstalledThemeMetadata& meta) { + auto& cfg = GetStyleMiiUCfg(); + if (cfg.suffleThemes) { + active_themes.insert(meta.themePath.filename()); + cfg.enabledThemes.clear(); + for (const auto& theme : active_themes) + cfg.enabledThemes += theme + "|"; + } else { + active_themes.clear(); + auto theme_str = meta.themePath.filename().string(); + active_themes.insert(theme_str); + cfg.enabledThemes = theme_str; + } + } + + void UnsetActive(const InstalledThemeMetadata& meta) { + auto& cfg = GetStyleMiiUCfg(); + auto theme_str = meta.themePath.filename().string(); + if (cfg.suffleThemes) { + active_themes.erase(theme_str); + cfg.enabledThemes.clear(); + for (const auto& theme : active_themes) + cfg.enabledThemes += theme + "|"; + } else { + if (active_themes.erase(theme_str)) + cfg.enabledThemes.clear(); + } + } + } // namespace Installer diff --git a/src/installer.h b/src/installer.h index 7b28499..317f315 100644 --- a/src/installer.h +++ b/src/installer.h @@ -32,14 +32,6 @@ namespace Installer { std::vector files; }; - bool GetUThemeMetadata(const std::filesystem::path &themePath, - UThemeMetadata &meta); - - bool GetInstalledThemeMetadata(const std::filesystem::path &installedThemePath, - InstalledThemeMetadata &imeta); - - std::vector GetInstalledThemes(std::stop_token& stopper); - using progress_function_sig = void (const std::string &msg); using progress_function_t = std::function; @@ -49,6 +41,17 @@ namespace Installer { using error_function_sig = void (const std::exception &e); using error_function_t = std::function; + void initialize(); + void finalize(); + + bool GetUThemeMetadata(const std::filesystem::path &themePath, + UThemeMetadata &meta); + + bool GetInstalledThemeMetadata(const std::filesystem::path &installedThemePath, + InstalledThemeMetadata &imeta); + + std::vector GetInstalledThemes(std::stop_token& stopper); + void InstallTheme(std::stop_token &stopper, const std::filesystem::path &themePath, UThemeMetadata themeMetadata, @@ -56,9 +59,19 @@ namespace Installer { success_function_t successCallback, error_function_t errorCallback); void DeleteTheme(const InstalledThemeMetadata& meta); - bool SetCurrentTheme(const InstalledThemeMetadata &meta); + std::string GetCurrentThemeName(); std::optional GetCurrentTheme(); std::filesystem::path GetThemePath(const UThemeMetadata& meta); + + bool IsShuffling(); + void ToggleShuffling(); + + bool IsActive(const InstalledThemeMetadata& meta); + void SetActive(const InstalledThemeMetadata& meta); + void UnsetActive(const InstalledThemeMetadata& meta); + + void ReloadStyleMiiUCfg(); + } // namespace Installer diff --git a/src/screens/HomeScreen.cpp b/src/screens/HomeScreen.cpp index bcf0b31..2000d1b 100644 --- a/src/screens/HomeScreen.cpp +++ b/src/screens/HomeScreen.cpp @@ -42,7 +42,7 @@ namespace HomeScreen { SDL_Texture *themiify_logo = nullptr; - std::optional current_theme_data; + std::optional current_theme; bool current_theme_refresh = true; @@ -63,7 +63,7 @@ namespace HomeScreen { } void refresh_current_theme() { - current_theme_data = Installer::GetCurrentTheme(); + current_theme = Installer::GetCurrentTheme(); current_theme_refresh = false; } @@ -114,6 +114,51 @@ namespace HomeScreen { } } + void show_current_theme() { + using namespace ImGui::RAII; + { + Font font{nullptr, 35}; + ImGui::Text("Your current theme:"); + } + + ImGui::Spacing(); + + if (!current_theme) { + if (Installer::IsShuffling()) { + ImGui::Text("StyleMiiU is shuffling themes."); + } else { + ImGui::Text("No current theme found."); + } + ImGui::Spacing(); + } + else { + if (Child theme_frame{"theme_frame", + {800, 300}, + ImGuiChildFlags_NavFlattened | + ImGuiChildFlags_FrameStyle, + ImGuiWindowFlags_NoSavedSettings}) { + if (!current_theme->previewPaths.empty()) { + auto img = ImageLoader::get(current_theme->previewPaths.front()); + const ImVec2 img_size = {640, 360}; + ImGui::Image((ImTextureID)img, img_size); + ImGui::SameLine(); + } + + { + Group right_group; + + { + Font font_guard{nullptr, 30}; + ImGui::TextWrapped(current_theme->uthemeMetadata.themeName); + if (current_theme->uthemeMetadata.themeAuthor) + ImGui::TextWrapped("by: " + + *current_theme->uthemeMetadata.themeAuthor); + } + } + } + } + } + void process_ui() { using namespace ImGui::RAII; @@ -166,51 +211,7 @@ namespace HomeScreen { if (!scrollable_content) return; - { - Font font{nullptr, 35}; - ImGui::Text("Your current theme:"); - } - - ImGui::Spacing(); - - if (!current_theme_data) { - ImGui::Text("No current theme found."); - ImGui::Spacing(); - } - else { - ImGui::Indent(140); - - { - Child theme_frame{ - "CurrentTheme", - {800, 300}, - ImGuiChildFlags_NavFlattened | - ImGuiChildFlags_FrameStyle, - ImGuiWindowFlags_NoSavedSettings - }; - - if (!current_theme_data->previewPaths.empty()) { - auto img = ImageLoader::get(current_theme_data->previewPaths.front()); - ImGui::Image((ImTextureID)img, {426, 240}); - ImGui::SameLine(); - } - - { - Group right_group; - - { - Font font_guard{nullptr, 30}; - ImGui::TextWrapped(current_theme_data->uthemeMetadata.themeName); - if (current_theme_data->uthemeMetadata.themeAuthor) - ImGui::TextWrapped("by: " + - *current_theme_data->uthemeMetadata.themeAuthor); - } - } - } - - ImGui::Unindent(140); - } - + show_current_theme(); if (ImGui::Button("Download Themes")) NavBar::set_current_tab(NavBar::Tab::themezer); diff --git a/src/screens/InstallThemePopup.cpp b/src/screens/InstallThemePopup.cpp index 5768547..82dde63 100644 --- a/src/screens/InstallThemePopup.cpp +++ b/src/screens/InstallThemePopup.cpp @@ -224,7 +224,7 @@ namespace InstallThemePopup { auto theme_path = Installer::GetThemePath(theme_data); Installer::InstalledThemeMetadata imeta; if (Installer::GetInstalledThemeMetadata(theme_path, imeta)) - Installer::SetCurrentTheme(imeta); + Installer::SetActive(imeta); } }); diff --git a/src/screens/ManageThemesScreen.cpp b/src/screens/ManageThemesScreen.cpp index 3f3f223..b3f5442 100644 --- a/src/screens/ManageThemesScreen.cpp +++ b/src/screens/ManageThemesScreen.cpp @@ -51,7 +51,7 @@ namespace ManageThemesScreen { Tab current_tab = Tab::manage_installed; std::vector local_uthemes; - bool local_uthemes_need_refresh = true; + bool local_uthemes_needs_refresh = true; std::jthread installed_themes_scanner; thread_safe> safe_installed_themes; @@ -71,9 +71,6 @@ namespace ManageThemesScreen { std::string search; - std::string current_theme_name; - bool current_theme_need_refresh = true; - int similarity_score(std::string haystack, std::string needle) { haystack = as_lower_case(haystack); needle = as_lower_case(needle); @@ -147,7 +144,6 @@ namespace ManageThemesScreen { void refresh_all() { refresh_installed_themes(); - refresh_current_theme(); refresh_local_uthemes(); } @@ -155,13 +151,9 @@ namespace ManageThemesScreen { installed_themes_scan_state = InstalledThemesScanState::requested; } - void refresh_current_theme() { - current_theme_need_refresh = true; - } - void refresh_local_uthemes() { - local_uthemes_need_refresh = true; + local_uthemes_needs_refresh = true; } static void text_limited(float width, const std::string& text) { @@ -173,7 +165,6 @@ namespace ManageThemesScreen { } void show_installed_theme(const Installer::InstalledThemeMetadata& theme_data, - bool is_active, const ImVec2& inner_size, const ImVec2& padding) { // NOTE: to create a complex button, we create a button with no text, then overlap @@ -218,14 +209,21 @@ namespace ManageThemesScreen { ImGui::Image((ImTextureID)img, img_size); } - // NOTE: Measure size for the active star, but don't place it yet, to not mess + bool is_shuffling = Installer::IsShuffling(); + bool is_active = Installer::IsActive(theme_data); + + // NOTE: Measure size for the active marker, but don't place it yet, to not mess // with the cursor position. - const std::string star_label = is_active ? ICON_FA_STAR : ICON_FA_STAR_O; - const float star_font_size = 48; - ImVec2 star_size; + + const std::string active_label = is_shuffling + ? (is_active ? ICON_FA_CHECK_SQUARE_O : ICON_FA_SQUARE_O) + : (is_active ? ICON_FA_STAR : ICON_FA_STAR_O); + + const float active_font_size = 48; + ImVec2 active_size; { - Font star_font{nullptr, star_font_size}; - star_size = ImGui::CalcTextSize(star_label); + Font active_font{nullptr, active_font_size}; + active_size = ImGui::CalcTextSize(active_label); } { @@ -234,7 +232,7 @@ namespace ManageThemesScreen { // covered by the star. float name_width = inner_size.x; if (!theme_data.previewPaths.empty()) - name_width -= star_size.x + style.ItemSpacing.x; + name_width -= active_size.x + style.ItemSpacing.x; text_limited(name_width, theme_data.uthemeMetadata.themeName); } @@ -244,27 +242,29 @@ namespace ManageThemesScreen { // If there's an image, make sure to limit the width, so it doesn't get // covered by the star. if (!theme_data.previewPaths.empty()) - author_width -= star_size.x + style.ItemSpacing.x; + author_width -= active_size.x + style.ItemSpacing.x; text_limited(author_width, "by " + *theme_data.uthemeMetadata.themeAuthor); } - // Put active star on bottom right. + // Put active marker on bottom right. { - Font star_font{nullptr, star_font_size}; - StyleColor star_color{ImGuiCol_Text, {1.0f, 0.9f, 0.0f, 1.0f}}; - ImGui::SetCursorPos(inner_size - star_size); - ImGui::Text(star_label); + Font active_font{nullptr, active_font_size}; + StyleColor active_color{ImGuiCol_Text, {1.0f, 0.9f, 0.0f, 1.0f}}; + ImGui::SetCursorPos(inner_size - active_size); + ImGui::Text(active_label); if (clicked && ImGui::IsItemHovered()) { clicked = false; // cancel the click - // TODO: when shuffle is implemented, this would be a toggle. - Installer::SetCurrentTheme(theme_data); + if (is_active) { + Installer::UnsetActive(theme_data); + } else { + Installer::SetActive(theme_data); + } HomeScreen::force_refresh(); - refresh_current_theme(); } } if (clicked) - ThemeDetailsPopup::open_local(theme_data, is_active); + ThemeDetailsPopup::open_local(theme_data); } void show_utheme(const std::filesystem::path& utheme_path) { @@ -322,16 +322,11 @@ namespace ManageThemesScreen { void show_tab_manage_installed() { using namespace ImGui::RAII; - ImGui::AlignTextToFramePadding(); // align vertically with the InputText widget - ImGui::Text("Search installed theme:"); - - ImGui::SameLine(); - SDL_WiiUSetSWKBDHintText("Write some search terms..."); SDL_WiiUSetSWKBDOKLabel("Search"); SDL_WiiUSetSWKBDHighlightInitialText(SDL_TRUE); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + ImGui::SetNextItemWidth(300); ImGui::InputTextWithHint("##local_search"s, "Search..."s, search); // if (ImGui::IsItemDeactivatedAfterEdit()) { @@ -342,11 +337,6 @@ namespace ManageThemesScreen { scan_installed_themes(); } - if (current_theme_need_refresh) { - current_theme_name = Installer::GetCurrentThemeName(); - current_theme_need_refresh = false; - } - std::vector visible_indexes; auto installed_themes = safe_installed_themes.lock(); @@ -372,6 +362,24 @@ namespace ManageThemesScreen { ); } + ImGui::SameLine(); + + bool is_shuffling = Installer::IsShuffling(); + if (ImGui::Checkbox("Shuffle", is_shuffling)) { + Installer::ToggleShuffling(); + } + + if (is_shuffling) { + ImGui::SameLine(); + if (ImGui::Button("Enable All")) { + + } + ImGui::SameLine(); + if (ImGui::Button("Disable All")) { + + } + } + // To keep the search widget visible, put the search results inside // another child. if (Child search_results{"ThemeGrid"}) { @@ -386,13 +394,10 @@ namespace ManageThemesScreen { for (auto [counter, index] : visible_indexes | std::views::enumerate) { auto& theme_data = (*installed_themes)[index]; - bool is_current_theme = current_theme_name == theme_data.themePath.filename(); - ImVec2 grid_pos = { float(counter % 3), float(counter / 3) }; ImVec2 pos = grid_pos * (outer_size + spacing); ImGui::SetCursorPos(grid_start_pos + pos); show_installed_theme(theme_data, - is_current_theme, inner_size, padding); } @@ -407,9 +412,9 @@ namespace ManageThemesScreen { ImGui::Separator(); - if (local_uthemes_need_refresh) { + if (local_uthemes_needs_refresh) { scan_local_uthemes(); - local_uthemes_need_refresh = false; + local_uthemes_needs_refresh = false; } for (const auto& utheme_path : local_uthemes) @@ -443,7 +448,6 @@ namespace ManageThemesScreen { {tab_width, tab_height})) { current_tab = Tab::manage_installed; refresh_installed_themes(); - refresh_current_theme(); } ImGui::SameLine(); diff --git a/src/screens/ManageThemesScreen.h b/src/screens/ManageThemesScreen.h index ed54835..34a0a75 100644 --- a/src/screens/ManageThemesScreen.h +++ b/src/screens/ManageThemesScreen.h @@ -20,8 +20,6 @@ namespace ManageThemesScreen { void refresh_installed_themes(); - void refresh_current_theme(); - void refresh_local_uthemes(); void process_ui(); diff --git a/src/screens/ThemeDetailsPopup.cpp b/src/screens/ThemeDetailsPopup.cpp index 44d411a..3847e38 100644 --- a/src/screens/ThemeDetailsPopup.cpp +++ b/src/screens/ThemeDetailsPopup.cpp @@ -22,9 +22,9 @@ #include "ManageThemesScreen.h" #include "ThemePreviewPopup.h" #include "../App.h" -#include "../installer.h" #include "../DownloadManager.h" #include "../IconsFontAwesome4.h" +#include "../installer.h" #include "../ImageLoader.h" #include "../NavBar.h" #include "../ThemezerAPI.h" @@ -54,7 +54,6 @@ namespace ThemeDetailsPopup { WiiuThemeSmall smallTheme; Installer::InstalledThemeMetadata installedThemeData; const std::string popup_id = "ThemeDetailsPopup"s; - bool isCurrent; void open_themezer(const WiiuThemeSmall &small_theme) { popup_queued = true; @@ -73,12 +72,10 @@ namespace ThemeDetailsPopup { state = State::waiting_themezer; } - void open_local(const Installer::InstalledThemeMetadata& installed_theme_data, - bool is_current) { + void open_local(const Installer::InstalledThemeMetadata& installed_theme_data) { popup_queued = true; installedThemeData = installed_theme_data; state = State::ready_local; - isCurrent = is_current; } void show_label_text(const std::string& label, @@ -167,16 +164,26 @@ namespace ThemeDetailsPopup { } } - { - Disabled disabled_if{isCurrent}; - if (ImGui::Button(ICON_FA_STAR " Apply Theme", {-1, 0})) { - Installer::SetCurrentTheme(installedThemeData); + bool is_shuffling = Installer::IsShuffling(); + bool is_active = Installer::IsActive(installedThemeData); + + if (is_shuffling) { + if (ImGui::Checkbox("Enable", is_active)) { + if (is_active) + Installer::UnsetActive(installedThemeData); + else + Installer::SetActive(installedThemeData); + HomeScreen::force_refresh(); + } + } else { + Disabled disabled_if{is_active}; + if (ImGui::Button(ICON_FA_STAR " Apply", {-1, 0})) { + Installer::SetActive(installedThemeData); ImGui::CloseCurrentPopup(); HomeScreen::force_refresh(); - ManageThemesScreen::refresh_current_theme(); } - ImGui::SetItemDefaultFocus(); } + ImGui::SetItemDefaultFocus(); { Disabled if_no_previews{installedThemeData.previewPaths.empty()}; diff --git a/src/screens/ThemeDetailsPopup.h b/src/screens/ThemeDetailsPopup.h index f292020..6d2371c 100644 --- a/src/screens/ThemeDetailsPopup.h +++ b/src/screens/ThemeDetailsPopup.h @@ -18,8 +18,7 @@ namespace ThemeDetailsPopup { void open_themezer(const ThemezerAPI::WiiuThemeSmall &small_theme); - void open_local(const Installer::InstalledThemeMetadata& installed_theme_data, - bool is_current); + void open_local(const Installer::InstalledThemeMetadata& installed_theme_data); void process_ui(); } diff --git a/src/utils.cpp b/src/utils.cpp index e57dd36..eef8502 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -164,3 +165,67 @@ make_theme_folder_name(const std::string& name, } return sanitize_element(result); } + + +// Used by the split() functions. +namespace { + + std::tuple::size_type> + find_first_of(const std::string& haystack, + const std::vector& needles, + std::string::size_type start = 0) + { + std::string::size_type result_pos = std::string::npos; + std::vector::size_type result_index = 0; + for (std::vector::size_type i = 0; i < needles.size(); ++i) { + auto pos = haystack.find(needles[i], start); + if (pos < result_pos) { + result_pos = pos; + result_index = i; + } + } + return { result_pos, result_index }; + } + +} // namespace + +std::vector +split(const std::string& input, + const std::vector& separators, + bool compress, + std::size_t max_tokens) +{ + std::vector result; + + using size_type = std::string::size_type; + auto [sep_start, sep_index] = find_first_of(input, separators); + size_type tok_start = 0; + + // Loop until no more separators are found. + while (sep_start != std::string::npos) { + if (!compress || sep_start > tok_start) { + // If this token reaches the maximum allowed, stop the looop + if (max_tokens && result.size() + 1 == max_tokens) + break; + result.push_back(input.substr(tok_start, sep_start - tok_start)); + } + tok_start = sep_start + separators[sep_index].size(); + if (tok_start >= input.size()) + break; + std::tie(sep_start, sep_index) = find_first_of(input, separators, tok_start); + } + // The remainder of the string is the last token, unless (compress && empty) + if (!compress || tok_start < input.size()) + result.push_back(input.substr(tok_start)); + return result; +} + +std::vector +split(const std::string& input, + const std::string& separator, + bool compress, + std::size_t max_tokens) +{ + return split(input, std::vector{separator}, compress, max_tokens); +} diff --git a/src/utils.h b/src/utils.h index b695dc6..c9d81e9 100644 --- a/src/utils.h +++ b/src/utils.h @@ -13,6 +13,7 @@ #include #include #include +#include #ifndef THEMIIFY_VERSION #define THEMIIFY_VERSION "?.?" @@ -60,3 +61,19 @@ make_theme_id_filename(const std::string& themeID); std::filesystem::path make_theme_folder_name(const std::string& name, const std::optional& themeID); + + + +[[nodiscard]] +std::vector +split(const std::string& input, + const std::vector& separators = {","}, + bool compress = true, + std::size_t max_tokens = 0); + +[[nodiscard]] +std::vector +split(const std::string& input, + const std::string& separator = ",", + bool compress = true, + std::size_t max_tokens = 0); From 942fefbddfdf8cfd2d0f8737a6996244e90b2ac3 Mon Sep 17 00:00:00 2001 From: "Daniel K. O. (dkosmari)" Date: Mon, 6 Jul 2026 09:22:20 -0300 Subject: [PATCH 2/7] Fixed performance issues with ImageLoader. --- CMakeLists.txt | 3 +- src/App.cpp | 12 +- src/ImageLoader.cpp | 474 +++++++++++++++++++---------- src/ImageLoader.h | 6 +- src/installer.cpp | 2 +- src/screens/HomeScreen.cpp | 6 +- src/screens/ManageThemesScreen.cpp | 2 +- src/timer.cpp | 27 ++ src/timer.hpp | 91 ++++++ 9 files changed, 447 insertions(+), 176 deletions(-) create mode 100644 src/timer.cpp create mode 100644 src/timer.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3748e5d..33e3b53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable(themiify src/humanize.cpp src/installer.cpp src/ThemezerAPI.cpp + src/timer.cpp src/ImageLoader.cpp src/DownloadManager.cpp src/Camera.cpp @@ -68,7 +69,7 @@ target_link_libraries(themiify PRIVATE quirc hips PkgConfig::zlib - PkgConfig::freetype2 + PkgConfig::freetype2 PkgConfig::harfbuzz PkgConfig::libcurl PkgConfig::libpng diff --git a/src/App.cpp b/src/App.cpp index 3d7efaa..c68df6b 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -16,7 +16,9 @@ #include "Camera.h" #include "utils.h" #include "installer.h" +#include "timer.hpp" +#include #include #include #include @@ -54,6 +56,7 @@ using std::cout; using std::cerr; using std::endl; +using namespace std::literals; namespace App { SDL_Window *window; @@ -352,6 +355,8 @@ namespace App { } } + ImageLoader::process(); + ImGui_ImplSDLRenderer2_NewFrame(); ImGui_ImplSDL2_NewFrame(); @@ -383,7 +388,12 @@ namespace App { StyleVar restore_rounding{ImGuiStyleVar_WindowRounding, orig_rounding}; NavBar::process_ui(); ImGui::SameLine(0, 0); // NOTE: ignore ItemSpacing - ContentPanel::process_ui(NavBar::get_current_tab()); + { + TimerReporter slow_content{std::cout, + "ContentPanel::process_ui()", + 10ms}; + ContentPanel::process_ui(NavBar::get_current_tab()); + } } } diff --git a/src/ImageLoader.cpp b/src/ImageLoader.cpp index 5445ecb..493fec7 100644 --- a/src/ImageLoader.cpp +++ b/src/ImageLoader.cpp @@ -16,14 +16,16 @@ #include #include #include -#include +#include #include #include #include #include #include #include +#include #include +#include #include #include @@ -36,22 +38,43 @@ #include "App.h" #include "async_queue.hpp" -#include "thread_safe.hpp" +#include "timer.hpp" #include "tracer.hpp" -using std::cout; -using std::cerr; using std::endl; using namespace std::literals; +#define COUT (resources->sync_cout) +#define CERR (resources->sync_cerr) + +#define TCOUT (resources->sync_tcout) +#define TCERR (resources->sync_tcerr) + +// #define MEASURE_IMG_LOAD +// #define MEASURE_CREATE_TEXTURE +#define MEASURE_GET + namespace ImageLoader { + + struct Resources { + std::osyncstream sync_cout{std::cout}; + std::osyncstream sync_cerr{std::cerr}; + + std::osyncstream sync_tcout{std::cout}; + std::osyncstream sync_tcerr{std::cerr}; + + }; + + std::optional resources; + std::string user_agent = App::user_agent; std::filesystem::path content_prefix = "fs:/vol/content"; const std::size_t max_cache_size = 64; - std::uint64_t use_counter = 0; + using Timestamp = std::uint64_t; + Timestamp timestamp = 0; SDL_Renderer *renderer = nullptr; SDL_Texture *load_error_image = nullptr; @@ -70,51 +93,68 @@ namespace ImageLoader { std::string to_string(LoadState st); struct CacheEntry { - std::atomic state{LoadState::unloaded}; - std::uint64_t last_use = 0; + std::atomic state{LoadState::requested}; + Timestamp last_use = 0; SDL_Surface *img = nullptr; SDL_Texture *tex = nullptr; + std::string location; + CURL *easy = nullptr; curl_slist *headers = nullptr; std::optional> raw_buf; - std::string location; - }; - using cache_t = std::unordered_map; - thread_safe safe_cache; + CacheEntry(Timestamp now, + const std::string& location); + + ~CacheEntry() noexcept; + + void prepare_download(); + void cleanup_download(); + + static CacheEntry* get_entry(CURL* handle); + }; // struct CacheEntry - async_queue requests_queue; + using CacheEntryPtr = std::shared_ptr; + using Cache = std::unordered_map; + Cache cache; + + async_queue requests_queue; std::jthread worker_thread; - static void destroy_entry(CacheEntry& entry) + CacheEntry::CacheEntry(Timestamp now, + const std::string& location) : + last_use{now}, + location{location} + {} + + CacheEntry::~CacheEntry() + noexcept { - if (multi && entry.easy) - curl_multi_remove_handle(multi, entry.easy); + if (multi && easy) + curl_multi_remove_handle(multi, easy); - if (entry.headers) { - curl_slist_free_all(entry.headers); - entry.headers = nullptr; + if (headers) { + curl_slist_free_all(headers); + headers = nullptr; } - if (entry.easy) { - curl_easy_cleanup(entry.easy); - entry.easy = nullptr; + if (easy) { + curl_easy_cleanup(easy); + easy = nullptr; } - if (entry.tex) { - SDL_DestroyTexture(entry.tex); - entry.tex = nullptr; + if (tex) { + SDL_DestroyTexture(tex); + tex = nullptr; } - if (entry.img) { - SDL_FreeSurface(entry.img); - entry.img = nullptr; + if (img) { + SDL_FreeSurface(img); + img = nullptr; } - - entry.raw_buf.reset(); } static size_t write_cb(char* ptr, size_t size, size_t nmemb, void* userdata) @@ -130,10 +170,75 @@ namespace ImageLoader { return total; } + void + CacheEntry::prepare_download() + { + easy = curl_easy_init(); + if (!easy) + throw std::runtime_error{"curl_easy_init() failed"}; + + curl_easy_setopt(easy, CURLOPT_PRIVATE, this); + + headers = curl_slist_append(headers, "Accept: image/*"); + curl_easy_setopt(easy, CURLOPT_VERBOSE, 0L); + curl_easy_setopt(easy, CURLOPT_URL, location.data()); + curl_easy_setopt(easy, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(easy, CURLOPT_SSL_VERIFYPEER, 1L); + curl_easy_setopt(easy, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(easy, CURLOPT_AUTOREFERER, 1L); + curl_easy_setopt(easy, CURLOPT_ACCEPT_ENCODING, ""); + curl_easy_setopt(easy, CURLOPT_TRANSFER_ENCODING, 1L); + curl_easy_setopt(easy, CURLOPT_BUFFERSIZE, 65536L); + curl_easy_setopt(easy, CURLOPT_TCP_NODELAY, 0L); + curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1L); + curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, write_cb); + curl_easy_setopt(easy, CURLOPT_WRITEDATA, this); + + if (!user_agent.empty()) + curl_easy_setopt(easy, CURLOPT_USERAGENT, user_agent.data()); + + curl_multi_add_handle(multi, easy); + } + + void + CacheEntry::cleanup_download() + { + curl_multi_remove_handle(multi, easy); + + if (headers) { + curl_slist_free_all(headers); + headers = nullptr; + } + + if (easy) { + curl_easy_cleanup(easy); + easy = nullptr; + } + raw_buf.reset(); + } + + CacheEntry* + CacheEntry::get_entry(CURL *handle) + { + if (!handle) + return nullptr; + CacheEntry* result = nullptr; + auto e = curl_easy_getinfo(handle, CURLINFO_PRIVATE, &result); + if (e != CURLE_OK) + return nullptr; + return result; + } + void worker_func(std::stop_token token); void initialize(SDL_Renderer* rend) { + resources.emplace(); + COUT.rdbuf()->set_emit_on_sync(true); + CERR.rdbuf()->set_emit_on_sync(true); + TCOUT.rdbuf()->set_emit_on_sync(true); + TCERR.rdbuf()->set_emit_on_sync(true); + curl_global_init(CURL_GLOBAL_DEFAULT); renderer = rend; @@ -154,7 +259,7 @@ namespace ImageLoader { requests_queue.reset(); - cout << "ImageLoader: launching worker thread." << endl; + COUT << "ImageLoader: launching worker thread." << endl; worker_thread = std::jthread{worker_func}; assert((std::atomic{}.is_lock_free())); @@ -162,24 +267,17 @@ namespace ImageLoader { void finalize() { - cout << "Stopping requests_queue" << endl; + COUT << "Stopping requests_queue" << endl; requests_queue.stop(); - cout << "Destroying thread" << endl; + COUT << "Destroying thread" << endl; worker_thread = {}; - cout << "Thread destroyed" << endl; + COUT << "Thread destroyed" << endl; - { - cout << "Clearing safe_cache" << endl; - auto cache = safe_cache.lock(); + COUT << "Clearing cache" << endl; + cache.clear(); - for (auto& [location, entry] : *cache) - destroy_entry(entry); - - cache->clear(); - } - - cout << "Destroying predefined icons" << endl; + COUT << "Destroying predefined icons" << endl; if (loading_image) { SDL_DestroyTexture(loading_image); @@ -192,33 +290,46 @@ namespace ImageLoader { } curl_global_cleanup(); + + resources.reset(); } SDL_Texture* get(const std::string& location) { - ++use_counter; +#ifdef MEASURE_GET + TimerReporter get_timer{COUT, "ImageLoader::get()", 5ms}; +#endif - auto cache = safe_cache.lock(); - auto it = cache->find(location); + CacheEntryPtr entry; + auto it = cache.find(location); + if (it != cache.end()) + entry = it->second; try { - if (it != cache->end()) { - auto& entry = it->second; - entry.last_use = use_counter; + if (entry) { + entry->last_use = timestamp; - switch (entry.state.load()) { + switch (entry->state.load()) { case LoadState::loaded: - if (!entry.tex && entry.img) { - entry.tex = SDL_CreateTextureFromSurface(renderer, entry.img); - if (entry.tex) - SDL_SetTextureBlendMode(entry.tex, SDL_BLENDMODE_BLEND); - - SDL_FreeSurface(entry.img); - entry.img = nullptr; + if (!entry->tex && entry->img) { +#ifdef MEASURE_CREATE_TEXTURE + Timer timer{"SDL_CreateTextureFromSurface()"}; + timer.start(); +#endif + entry->tex = SDL_CreateTextureFromSurface(renderer, entry->img); +#ifdef MEASURE_CREATE_TEXTURE + timer.stop(); + timer.print(COUT) << endl; +#endif + if (entry->tex) + SDL_SetTextureBlendMode(entry->tex, SDL_BLENDMODE_BLEND); + + SDL_FreeSurface(entry->img); + entry->img = nullptr; } - if (entry.tex) - return entry.tex; + if (entry->tex) + return entry->tex; return load_error_image; @@ -230,114 +341,123 @@ namespace ImageLoader { return loading_image; case LoadState::unloaded: - entry.state = LoadState::requested; - requests_queue.push(location); + entry->state = LoadState::requested; + requests_queue.push(entry); return loading_image; default: throw std::logic_error{ - "invalid entry state: " + to_string(entry.state.load()) + "invalid entry state: " + to_string(entry->state.load()) }; } + } else { + // entry not found, so prepare a request + entry = std::make_shared(timestamp, location); + cache.emplace(location, entry); + requests_queue.push(std::move(entry)); + return loading_image; } - - auto& entry = (*cache)[location]; - entry.state = LoadState::requested; - entry.last_use = use_counter; - - requests_queue.push(location); - - return loading_image; } catch (std::exception& e) { - cerr << "ERROR: ImageLoader::get(): " << e.what() << endl; + CERR << "ERROR: ImageLoader::get(): " << e.what() << endl; return load_error_image; } } - CacheEntry* find(thread_safe::guard& cache, CURL* easy) + /* + * NOTE: GX2 only supports a few texture formats, so this allows converting the image + * to a supported format early. + */ + static SDL_Surface* optimized(SDL_Surface* input) { - for (auto& [location, entry] : *cache) { - if (entry.easy == easy) - return &entry; + if (!input) + return nullptr; + switch (input->format->format) { + // Supported formats, see SDL_render_wiiu.h from the SDL2 port. + case SDL_PIXELFORMAT_ARGB4444: + case SDL_PIXELFORMAT_RGBA4444: + case SDL_PIXELFORMAT_ABGR4444: + case SDL_PIXELFORMAT_BGRA4444: + case SDL_PIXELFORMAT_ARGB1555: + case SDL_PIXELFORMAT_ABGR1555: + case SDL_PIXELFORMAT_RGBA5551: + case SDL_PIXELFORMAT_BGRA5551: + case SDL_PIXELFORMAT_RGB565: + case SDL_PIXELFORMAT_BGR565: + case SDL_PIXELFORMAT_RGBX8888: + case SDL_PIXELFORMAT_RGBA8888: + case SDL_PIXELFORMAT_ARGB8888: + case SDL_PIXELFORMAT_BGRX8888: + case SDL_PIXELFORMAT_BGRA8888: + case SDL_PIXELFORMAT_ABGR8888: + case SDL_PIXELFORMAT_ARGB2101010: + return input; + default: + auto output = SDL_ConvertSurfaceFormat(input, SDL_PIXELFORMAT_RGBA32, 0); + SDL_FreeSurface(input); + return output; } - - return nullptr; } - void process_one_request(const std::string& location) + void process_one_request(CacheEntryPtr& entry) { - auto cache = safe_cache.lock(); - auto it = cache->find(location); - - if (it == cache->end()) + if (!entry) return; - - auto& entry = it->second; - LoadState expected = LoadState::requested; - if (!entry.state.compare_exchange_strong(expected, LoadState::loading)) { - cerr << "ERROR: ImageLoader::process_one_request() wrong cache entry state: " - << to_string(expected) - << endl; + if (!entry->state.compare_exchange_strong(expected, LoadState::loading)) { + TCERR << "ERROR: ImageLoader::process_one_request() wrong cache entry state: " + << to_string(expected) + << endl; return; } - entry.location = location; - try { - if (location.starts_with("http://") || location.starts_with("https://")) { - entry.easy = curl_easy_init(); - if (!entry.easy) - throw std::runtime_error{"curl_easy_init() failed"}; - - entry.headers = curl_slist_append(entry.headers, "Accept: image/*"); - - curl_easy_setopt(entry.easy, CURLOPT_VERBOSE, 1L); - curl_easy_setopt(entry.easy, CURLOPT_URL, location.c_str()); - curl_easy_setopt(entry.easy, CURLOPT_HTTPHEADER, entry.headers); - curl_easy_setopt(entry.easy, CURLOPT_SSL_VERIFYPEER, 1L); - curl_easy_setopt(entry.easy, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(entry.easy, CURLOPT_AUTOREFERER, 1L); - curl_easy_setopt(entry.easy, CURLOPT_ACCEPT_ENCODING, ""); - curl_easy_setopt(entry.easy, CURLOPT_TRANSFER_ENCODING, 1L); - curl_easy_setopt(entry.easy, CURLOPT_BUFFERSIZE, 65536L); - curl_easy_setopt(entry.easy, CURLOPT_TCP_NODELAY, 0L); - curl_easy_setopt(entry.easy, CURLOPT_FAILONERROR, 1L); - curl_easy_setopt(entry.easy, CURLOPT_WRITEFUNCTION, write_cb); - curl_easy_setopt(entry.easy, CURLOPT_WRITEDATA, &entry); - - if (!user_agent.empty()) - curl_easy_setopt(entry.easy, CURLOPT_USERAGENT, user_agent.c_str()); - - curl_multi_add_handle(multi, entry.easy); + if (entry->location.starts_with("http://") || + entry->location.starts_with("https://")) { + entry->prepare_download(); } - else if (location.starts_with("ui/")) { - const auto path = content_prefix / location; - - entry.img = IMG_Load(path.c_str()); - if (!entry.img) + else if (entry->location.starts_with("ui/")) { + const auto path = content_prefix / entry->location; + +#ifdef MEASURE_IMG_LOAD + Timer timer{"IMG_Load() for ui/ image"}; + timer.start(); +#endif + entry->img = optimized(IMG_Load(path.c_str())); +#ifdef MEASURE_IMG_LOAD + timer.stop(); + timer.print(TCOUT) << endl; +#endif + if (!entry->img) throw std::runtime_error{IMG_GetError()}; - entry.state = LoadState::loaded; + entry->state = LoadState::loaded; } - else if (location.starts_with("fs:/")) { - entry.img = IMG_Load(location.c_str()); - if (!entry.img) + else if (entry->location.starts_with("fs:/")) { +#ifdef MEASURE_IMG_LOAD + Timer timer{"IMG_Load() for fs:/"}; + timer.start(); +#endif + entry->img = optimized(IMG_Load(entry->location.c_str())); +#ifdef MEASURE_IMG_LOAD + timer.stop(); + timer.print(TCOUT) << endl; +#endif + if (!entry->img) throw std::runtime_error{IMG_GetError()}; - entry.state = LoadState::loaded; + entry->state = LoadState::loaded; } else { throw std::runtime_error{"invalid location"}; } } catch (std::exception& e) { - std::println(cerr, + std::println(TCERR, "ERROR: ImageLoader::process_one_request(): location=\"{}\", exception={}", - location, + entry->location, e.what()); - entry.state = LoadState::error; + entry->state = LoadState::error; } } @@ -380,24 +500,32 @@ namespace ImageLoader { } } - std::uint64_t& by_last_use(cache_t::iterator it) noexcept + Timestamp& by_last_use(const Cache::iterator& it) noexcept { - return it->second.last_use; + return it->second->last_use; } + struct CompareLastUse { + bool + operator ()(const Cache::iterator& a, const Cache::iterator& b) + const noexcept + { + return by_last_use(a) < by_last_use(b); + } + }; + void trim_cache() { - auto cache = safe_cache.lock(); - - if (cache->size() <= max_cache_size) + if (cache.size() <= max_cache_size) return; - std::size_t excess = cache->size() - max_cache_size; + std::size_t excess = cache.size() - max_cache_size; - std::vector to_remove(excess); +#if 1 + std::vector to_remove(excess); auto to_remove_end = to_remove.begin(); - for (auto it = cache->begin(); it != cache->end(); ++it) { + for (auto it = cache.begin(); it != cache.end(); ++it) { if (to_remove_end != to_remove.end()) { *to_remove_end++ = it; std::ranges::push_heap(to_remove.begin(), @@ -412,11 +540,28 @@ namespace ImageLoader { } } } - - for (auto it : to_remove) { - destroy_entry(it->second); - cache->erase(it); + for (auto it : to_remove) + cache.erase(it); +#else + std::priority_queue, + CompareLastUse> to_remove; + for (auto it = cache.begin(); it != cache.end(); ++it) { + to_remove.push(it); + if (to_remove.size() > excess) + to_remove.pop(); } + while (!to_remove.empty()) { + cache.erase(to_remove.top()); + to_remove.pop(); + } +#endif + } + + void process() + { + trim_cache(); + ++timestamp; } void handle_finished_downloads() @@ -429,11 +574,9 @@ namespace ImageLoader { CURL* easy = msg->easy_handle; - auto cache = safe_cache.lock(); - auto* entry = find(cache, easy); - + auto entry = CacheEntry::get_entry(easy); if (!entry) { - cerr << "ERROR: ImageLoader::handle_finished_downloads(): failed to find entry" << endl; + TCERR << "ERROR: ImageLoader::handle_finished_downloads(): no entry" << endl; curl_multi_remove_handle(multi, easy); curl_easy_cleanup(easy); continue; @@ -465,30 +608,26 @@ namespace ImageLoader { if (!rw) throw std::runtime_error{SDL_GetError()}; - entry->img = IMG_Load_RW(rw, 1); +#ifdef MEASURE_IMG_LOAD + Timer timer{"IMG_Load_RW()"}; + timer.start(); +#endif + entry->img = optimized(IMG_Load_RW(rw, 1)); +#ifdef MEASURE_IMG_LOAD + timer.stop(); + timer.print(TCOUT) << endl; +#endif if (!entry->img) throw std::runtime_error{IMG_GetError()}; entry->state = LoadState::loaded; } catch (std::exception& e) { - cerr << "ERROR: ImageLoader::handle_finished_downloads(): " << e.what() << endl; + TCERR << "ERROR: ImageLoader::handle_finished_downloads(): " << e.what() << endl; entry->state = LoadState::error; } - curl_multi_remove_handle(multi, entry->easy); - - if (entry->headers) { - curl_slist_free_all(entry->headers); - entry->headers = nullptr; - } - - if (entry->easy) { - curl_easy_cleanup(entry->easy); - entry->easy = nullptr; - } - - entry->raw_buf.reset(); + entry->cleanup_download(); } } @@ -503,29 +642,28 @@ namespace ImageLoader { curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, 10L); while (!token.stop_requested()) { - auto location = requests_queue.try_pop_for(50ms); + auto entry = requests_queue.try_pop_for(50ms); - if (location) { - process_one_request(*location); + if (entry) { + process_one_request(*entry); } - else if (location.error() == async_queue_error::stop) { + else if (entry.error() == async_queue_error::stop) { break; } - else if (location.error() == async_queue_error::locked) { - cout << "WARNING: requests_queue was locked" << endl; + else if (entry.error() == async_queue_error::locked) { + TCOUT << "WARNING: requests_queue was locked" << endl; } int running = 0; curl_multi_perform(multi, &running); handle_finished_downloads(); - trim_cache(); std::this_thread::sleep_for(50ms); } } catch (std::exception& e) { - cerr << "ERROR: ImageLoader::worker_func(): " << e.what() << endl; + TCERR << "ERROR: ImageLoader::worker_func(): " << e.what() << endl; } if (multi) { diff --git a/src/ImageLoader.h b/src/ImageLoader.h index 6806b0d..9a1543f 100644 --- a/src/ImageLoader.h +++ b/src/ImageLoader.h @@ -1,6 +1,6 @@ /* * Themiify - A theme manager for the Nintendo Wii U - * Copyright (C) 2026 Fangal-Airbag + * Copyright (C) 2026 Fangal-Airbag * Copyright (C) 2026 AlphaCraft9658 * Copyright (C) 2026 Daniel K. O. * @@ -18,5 +18,7 @@ namespace ImageLoader { void finalize(); + void process(); + SDL_Texture *get(const std::string& location); -} \ No newline at end of file +} diff --git a/src/installer.cpp b/src/installer.cpp index bd67b75..7ec107e 100644 --- a/src/installer.cpp +++ b/src/installer.cpp @@ -137,7 +137,7 @@ namespace Installer { return *currentStyleMiiUCfg; } catch (std::exception& e) { - cerr << "ERROR in GetSTyleMiiUCfg(): " << e.what() << endl; + cerr << "ERROR in GetStyleMiiUCfg(): " << e.what() << endl; throw; } } diff --git a/src/screens/HomeScreen.cpp b/src/screens/HomeScreen.cpp index 2000d1b..198dfd0 100644 --- a/src/screens/HomeScreen.cpp +++ b/src/screens/HomeScreen.cpp @@ -126,6 +126,7 @@ namespace HomeScreen { if (!current_theme) { if (Installer::IsShuffling()) { ImGui::Text("StyleMiiU is shuffling themes."); + ImGui::Text("TODO: show a placeholder image for shuffling"); } else { ImGui::Text("No current theme found."); } @@ -133,9 +134,10 @@ namespace HomeScreen { } else { if (Child theme_frame{"theme_frame", - {800, 300}, + {0, 0}, ImGuiChildFlags_NavFlattened | - ImGuiChildFlags_FrameStyle, + ImGuiChildFlags_Borders | + ImGuiChildFlags_AutoResizeY, ImGuiWindowFlags_NoSavedSettings}) { if (!current_theme->previewPaths.empty()) { auto img = ImageLoader::get(current_theme->previewPaths.front()); diff --git a/src/screens/ManageThemesScreen.cpp b/src/screens/ManageThemesScreen.cpp index b3f5442..5ce977f 100644 --- a/src/screens/ManageThemesScreen.cpp +++ b/src/screens/ManageThemesScreen.cpp @@ -216,7 +216,7 @@ namespace ManageThemesScreen { // with the cursor position. const std::string active_label = is_shuffling - ? (is_active ? ICON_FA_CHECK_SQUARE_O : ICON_FA_SQUARE_O) + ? (is_active ? ICON_FA_CHECK_CIRCLE_O : ICON_FA_CIRCLE_O) : (is_active ? ICON_FA_STAR : ICON_FA_STAR_O); const float active_font_size = 48; diff --git a/src/timer.cpp b/src/timer.cpp new file mode 100644 index 0000000..71cf60f --- /dev/null +++ b/src/timer.cpp @@ -0,0 +1,27 @@ +#include + +#include "timer.hpp" + + +Timer::Timer(const std::string& name) : + name{name} +{} + + +std::ostream& +Timer::print(std::ostream& out) +{ + out << "Timer"; + if (!name.empty()) + out << " \"" << name << "\""; + out << ": " << duration_cast(elapsed()); + return out; +} + + +TimerReporter::~TimerReporter() +{ + auto diff = timer.stop(); + if (diff > threshold) + timer.print(out) << std::endl; +} diff --git a/src/timer.hpp b/src/timer.hpp new file mode 100644 index 0000000..1fa87ef --- /dev/null +++ b/src/timer.hpp @@ -0,0 +1,91 @@ +#ifndef TIMER_HPP +#define TIMER_HPP + +#include +#include +#include + +struct Timer { + + using clock_type = std::chrono::steady_clock; + using time_point = clock_type::time_point; + using duration = clock_type::duration; + + + std::string name = {}; + time_point start_time = {}; + time_point finish_time = {}; + + + constexpr + Timer() + noexcept = default; + + Timer(const std::string& name); + + inline + void + start() + noexcept + { + start_time = clock_type::now(); + } + + inline + duration + stop() + noexcept + { + finish_time = clock_type::now(); + return elapsed(); + } + + [[nodiscard]] + inline + duration + elapsed() + const noexcept + { + return finish_time - start_time; + } + + std::ostream& + print(std::ostream& out); + +}; // struct Timer + + +struct TimerReporter { + + std::ostream& out; + Timer timer; + Timer::duration threshold; + + + TimerReporter(std::ostream& out, + Timer::duration threshold = Timer::duration{0}) + noexcept : + out(out), + threshold{threshold} + { + timer.start(); + } + + + TimerReporter(std::ostream& out, + const std::string& name, + Timer::duration threshold = Timer::duration{0}) + noexcept: + out(out), + timer{name}, + threshold{threshold} + { + timer.start(); + } + + + ~TimerReporter(); + +}; // struct TimerReporter + +#endif From 0d2c465aa5710a42f30595dfdde2fb6d836faa8b Mon Sep 17 00:00:00 2001 From: "Daniel K. O. (dkosmari)" Date: Wed, 8 Jul 2026 12:25:31 -0300 Subject: [PATCH 3/7] Make enable/disable all buttons functional. --- src/screens/ManageThemesScreen.cpp | 46 ++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/screens/ManageThemesScreen.cpp b/src/screens/ManageThemesScreen.cpp index 5ce977f..08b35e4 100644 --- a/src/screens/ManageThemesScreen.cpp +++ b/src/screens/ManageThemesScreen.cpp @@ -322,17 +322,41 @@ namespace ManageThemesScreen { void show_tab_manage_installed() { using namespace ImGui::RAII; + const auto &style = ImGui::GetStyle(); + SDL_WiiUSetSWKBDHintText("Write some search terms..."); SDL_WiiUSetSWKBDOKLabel("Search"); SDL_WiiUSetSWKBDHighlightInitialText(SDL_TRUE); - ImGui::SetNextItemWidth(300); + // Let search widget expand, leaving space for the buttons. + const std::string shuffle_label = "Shuffle"; + const float shuffle_width = + ImGui::CalcTextSize(shuffle_label).x + + style.ItemInnerSpacing.x + + ImGui::GetTextLineHeight() + // defines the size of the box + 2 * style.FramePadding.x; + + const std::string enable_all_label = ICON_FA_CHECK_SQUARE_O " All"; + const float enable_all_width = + ImGui::CalcTextSize(enable_all_label).x + + 2 * style.FramePadding.x; + + const std::string disable_all_label = ICON_FA_SQUARE_O " All"; + const float disable_all_width = + ImGui::CalcTextSize(disable_all_label).x + + 2 * style.FramePadding.x; + + const float buttons_width = + shuffle_width + + style.ItemSpacing.x + + enable_all_width + + style.ItemSpacing.x + + disable_all_width; + + auto available = ImGui::GetContentRegionAvail(); + ImGui::SetNextItemWidth(available.x - style.ItemSpacing.x - buttons_width); ImGui::InputTextWithHint("##local_search"s, "Search..."s, search); - // if (ImGui::IsItemDeactivatedAfterEdit()) { - // cout << "Searching: " << search << endl; - // } - if (installed_themes_scan_state == InstalledThemesScanState::requested) { scan_installed_themes(); } @@ -371,12 +395,16 @@ namespace ManageThemesScreen { if (is_shuffling) { ImGui::SameLine(); - if (ImGui::Button("Enable All")) { - + if (ImGui::Button(enable_all_label)) { + auto installed_themes = safe_installed_themes.lock(); + for (auto& theme : *installed_themes) + Installer::SetActive(theme); } ImGui::SameLine(); - if (ImGui::Button("Disable All")) { - + if (ImGui::Button(disable_all_label)) { + auto installed_themes = safe_installed_themes.lock(); + for (auto& theme : *installed_themes) + Installer::UnsetActive(theme); } } From 61ffa550752b16fadd0be6259cd8b03ea76a8d80 Mon Sep 17 00:00:00 2001 From: "Daniel K. O. (dkosmari)" Date: Wed, 8 Jul 2026 12:29:26 -0300 Subject: [PATCH 4/7] Added some spacing between nav bar and content panel. --- src/App.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.cpp b/src/App.cpp index c68df6b..d016ce1 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -387,7 +387,7 @@ namespace App { StyleVar restore_border{ImGuiStyleVar_WindowBorderSize, orig_border}; StyleVar restore_rounding{ImGuiStyleVar_WindowRounding, orig_rounding}; NavBar::process_ui(); - ImGui::SameLine(0, 0); // NOTE: ignore ItemSpacing + ImGui::SameLine(0, 9); // NOTE: override ItemSpacing { TimerReporter slow_content{std::cout, "ContentPanel::process_ui()", From 8b1429d71d9390f7c7dc554c599cf9cee46aa791 Mon Sep 17 00:00:00 2001 From: "Daniel K. O. (dkosmari)" Date: Thu, 9 Jul 2026 04:27:47 -0300 Subject: [PATCH 5/7] - Limit surface-to-texture conversion to once per frame. - Small changes to placeholder images (added placeholders for missing preview, random, no theme.) --- content/ui/theme-placeholder-icon.png | Bin 5587 -> 0 bytes content/ui/theme-placeholder-loading.png | Bin 0 -> 7545 bytes content/ui/theme-placeholder-no-preview.png | Bin 0 -> 10789 bytes content/ui/theme-placeholder-no-theme.png | Bin 0 -> 8077 bytes content/ui/theme-placeholder-random.png | Bin 0 -> 55047 bytes src/ImageLoader.cpp | 109 ++++++++++---------- src/async_queue.hpp | 8 ++ src/installer.cpp | 49 +++++---- src/installer.h | 8 +- src/screens/HomeScreen.cpp | 56 ++++++---- src/screens/InstallThemePopup.cpp | 2 +- src/screens/ManageThemesScreen.cpp | 61 ++++++----- src/screens/ThemeDetailsPopup.cpp | 14 +-- 13 files changed, 168 insertions(+), 139 deletions(-) delete mode 100644 content/ui/theme-placeholder-icon.png create mode 100644 content/ui/theme-placeholder-loading.png create mode 100644 content/ui/theme-placeholder-no-preview.png create mode 100644 content/ui/theme-placeholder-no-theme.png create mode 100644 content/ui/theme-placeholder-random.png diff --git a/content/ui/theme-placeholder-icon.png b/content/ui/theme-placeholder-icon.png deleted file mode 100644 index fae39798f72d398c395c8457476e2138fc8cf00f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5587 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 NnUR%Yg}z(#KL9{=i|qga diff --git a/content/ui/theme-placeholder-loading.png b/content/ui/theme-placeholder-loading.png new file mode 100644 index 0000000000000000000000000000000000000000..507f0b40b014b471fbbc20c67937c7a1158330ad GIT binary patch literal 7545 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 OWF!@zdH literal 0 HcmV?d00001 diff --git a/content/ui/theme-placeholder-no-theme.png b/content/ui/theme-placeholder-no-theme.png new file mode 100644 index 0000000000000000000000000000000000000000..032a940db3e841853b543cde592ef3021893801c GIT binary patch literal 8077 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 Uj|~sDKT63$|DKZ2$lO literal 0 HcmV?d00001 diff --git a/content/ui/theme-placeholder-random.png b/content/ui/theme-placeholder-random.png new file mode 100644 index 0000000000000000000000000000000000000000..35593b824026f982d073c226aae38da288cf15a2 GIT binary patch literal 55047 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
12YNxRT(cE`WpNHWkz>O3+ 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 { std::atomic state{LoadState::requested}; Timestamp last_use = 0; @@ -114,7 +115,7 @@ namespace ImageLoader { void prepare_download(); void cleanup_download(); - static CacheEntry* get_entry(CURL* handle); + static std::shared_ptr get_entry(CURL* handle); }; // struct CacheEntry using CacheEntryPtr = std::shared_ptr; @@ -124,6 +125,8 @@ namespace ImageLoader { async_queue requests_queue; std::jthread worker_thread; + async_queue convert_queue; + CacheEntry::CacheEntry(Timestamp now, const std::string& location) : last_use{now}, @@ -217,16 +220,16 @@ namespace ImageLoader { raw_buf.reset(); } - CacheEntry* + CacheEntryPtr CacheEntry::get_entry(CURL *handle) { if (!handle) - return nullptr; - CacheEntry* result = nullptr; - auto e = curl_easy_getinfo(handle, CURLINFO_PRIVATE, &result); + return {}; + CacheEntry* self = nullptr; + auto e = curl_easy_getinfo(handle, CURLINFO_PRIVATE, &self); if (e != CURLE_OK) - return nullptr; - return result; + return {}; + return self->shared_from_this(); } void worker_func(std::stop_token token); @@ -245,7 +248,7 @@ namespace ImageLoader { loading_image = IMG_LoadTexture( renderer, - "fs:/vol/content/ui/theme-placeholder-icon.png"); + "fs:/vol/content/ui/theme-placeholder-loading.png"); load_error_image = IMG_LoadTexture( renderer, @@ -267,6 +270,9 @@ namespace ImageLoader { void finalize() { + COUT << "Stopping convert_queue" << endl; + convert_queue.stop(); + COUT << "Stopping requests_queue" << endl; requests_queue.stop(); @@ -274,6 +280,9 @@ namespace ImageLoader { worker_thread = {}; COUT << "Thread destroyed" << endl; + convert_queue.clear(); + requests_queue.clear(); + COUT << "Clearing cache" << endl; cache.clear(); @@ -310,34 +319,15 @@ namespace ImageLoader { entry->last_use = timestamp; switch (entry->state.load()) { - case LoadState::loaded: - if (!entry->tex && entry->img) { -#ifdef MEASURE_CREATE_TEXTURE - Timer timer{"SDL_CreateTextureFromSurface()"}; - timer.start(); -#endif - entry->tex = SDL_CreateTextureFromSurface(renderer, entry->img); -#ifdef MEASURE_CREATE_TEXTURE - timer.stop(); - timer.print(COUT) << endl; -#endif - if (entry->tex) - SDL_SetTextureBlendMode(entry->tex, SDL_BLENDMODE_BLEND); - - SDL_FreeSurface(entry->img); - entry->img = nullptr; - } - - if (entry->tex) - return entry->tex; - - return load_error_image; + case LoadState::converted: + return entry->tex; case LoadState::error: return load_error_image; case LoadState::requested: case LoadState::loading: + case LoadState::loaded: return loading_image; case LoadState::unloaded: @@ -416,14 +406,19 @@ namespace ImageLoader { entry->location.starts_with("https://")) { entry->prepare_download(); } - else if (entry->location.starts_with("ui/")) { - const auto path = content_prefix / entry->location; + else { + // Assume everything else is a local path. + std::filesystem::path img_path; + if (entry->location.starts_with("ui/")) + img_path = content_prefix / entry->location; + else + img_path = entry->location; #ifdef MEASURE_IMG_LOAD - Timer timer{"IMG_Load() for ui/ image"}; + Timer timer{"IMG_Load()"}; timer.start(); #endif - entry->img = optimized(IMG_Load(path.c_str())); + entry->img = optimized(IMG_Load(img_path.c_str())); #ifdef MEASURE_IMG_LOAD timer.stop(); timer.print(TCOUT) << endl; @@ -432,23 +427,7 @@ namespace ImageLoader { throw std::runtime_error{IMG_GetError()}; entry->state = LoadState::loaded; - } - else if (entry->location.starts_with("fs:/")) { -#ifdef MEASURE_IMG_LOAD - Timer timer{"IMG_Load() for fs:/"}; - timer.start(); -#endif - entry->img = optimized(IMG_Load(entry->location.c_str())); -#ifdef MEASURE_IMG_LOAD - timer.stop(); - timer.print(TCOUT) << endl; -#endif - if (!entry->img) - throw std::runtime_error{IMG_GetError()}; - entry->state = LoadState::loaded; - } - else { - throw std::runtime_error{"invalid location"}; + convert_queue.push(entry); } } catch (std::exception& e) { @@ -562,6 +541,27 @@ namespace ImageLoader { { trim_cache(); ++timestamp; + + // Convert exactly one surface into a texture. + if (auto entry = convert_queue.try_pop()) { + if ((*entry)->state == LoadState::loaded) { +#ifdef MEASURE_CREATE_TEXTURE + Timer timer{"SDL_CreateTextureFromSurface()"}; + timer.start(); +#endif + (*entry)->tex = SDL_CreateTextureFromSurface(renderer, (*entry)->img); +#ifdef MEASURE_CREATE_TEXTURE + timer.stop(); + timer.print(COUT) << endl; +#endif + if ((*entry)->tex) + SDL_SetTextureBlendMode((*entry)->tex, SDL_BLENDMODE_BLEND); + + SDL_FreeSurface((*entry)->img); + (*entry)->img = nullptr; + (*entry)->state = LoadState::converted; + } + } } void handle_finished_downloads() @@ -621,6 +621,7 @@ namespace ImageLoader { throw std::runtime_error{IMG_GetError()}; entry->state = LoadState::loaded; + convert_queue.push(entry); } catch (std::exception& e) { TCERR << "ERROR: ImageLoader::handle_finished_downloads(): " << e.what() << endl; @@ -659,7 +660,7 @@ namespace ImageLoader { handle_finished_downloads(); - std::this_thread::sleep_for(50ms); + // std::this_thread::sleep_for(50ms); } } catch (std::exception& e) { diff --git a/src/async_queue.hpp b/src/async_queue.hpp index e2ad388..2c42991 100644 --- a/src/async_queue.hpp +++ b/src/async_queue.hpp @@ -151,6 +151,14 @@ class async_queue { return result; } + + void + clear() + { + std::lock_guard guard{mutex}; + queue = {}; + } + }; // class async_queue #endif diff --git a/src/installer.cpp b/src/installer.cpp index 7ec107e..5891858 100644 --- a/src/installer.cpp +++ b/src/installer.cpp @@ -35,6 +35,7 @@ #include "installer.h" #include "utils.h" #include "tracer.hpp" +#include "thread_safe.hpp" using std::cout; using std::cerr; @@ -73,7 +74,11 @@ namespace Installer { std::optional currentStyleMiiUCfg; - std::unordered_set active_themes; + std::unordered_set enabled_themes; + + using InstalledThemesList = std::vector; + + thread_safe safe_themes_list; namespace { @@ -100,7 +105,7 @@ namespace Installer { static void LoadStyleMiiUCfg() { currentStyleMiiUCfg.reset(); - active_themes.clear(); + enabled_themes.clear(); auto stylemiiu_cfg_path = GetStyleMiiUConfigPath(); if (!exists(stylemiiu_cfg_path)) { // If config doesn't exist yet, it's not an error. @@ -114,9 +119,9 @@ namespace Installer { auto themes = split(currentStyleMiiUCfg->enabledThemes, "|", true); for (const auto& theme : themes) if (!theme.empty()) - active_themes.insert(theme); + enabled_themes.insert(theme); } else { - active_themes.insert(currentStyleMiiUCfg->enabledThemes); + enabled_themes.insert(currentStyleMiiUCfg->enabledThemes); } } @@ -125,7 +130,11 @@ namespace Installer { throw std::runtime_error{"No valid StyleMiiU config state to store."}; StyleMiiUJson json; json.storageitems = *currentStyleMiiUCfg; - glz::ex::write_file_json(json, GetStyleMiiUConfigPath().string(), std::string{}); + glz::ex::write_file_json( + json, + GetStyleMiiUConfigPath().string(), + std::string{} + ); } StyleMiiUCfg& @@ -694,10 +703,10 @@ namespace Installer { GetCurrentThemeName() { auto& cfg = GetStyleMiiUCfg(); - if (cfg.suffleThemes) + if (enabled_themes.size() == 1) + return *enabled_themes.begin(); + else return {}; - - return cfg.enabledThemes; } std::optional @@ -730,40 +739,40 @@ namespace Installer { auto &cfg = GetStyleMiiUCfg(); cfg.suffleThemes = !cfg.suffleThemes; if (!cfg.suffleThemes) { - active_themes.clear(); + enabled_themes.clear(); cfg.enabledThemes.clear(); } } - bool IsActive(const InstalledThemeMetadata& meta) { - return active_themes.contains(meta.themePath.filename()); + bool IsEnabled(const InstalledThemeMetadata& meta) { + return enabled_themes.contains(meta.themePath.filename()); } - void SetActive(const InstalledThemeMetadata& meta) { + void Enable(const InstalledThemeMetadata& meta) { auto& cfg = GetStyleMiiUCfg(); if (cfg.suffleThemes) { - active_themes.insert(meta.themePath.filename()); + enabled_themes.insert(meta.themePath.filename()); cfg.enabledThemes.clear(); - for (const auto& theme : active_themes) + for (const auto& theme : enabled_themes) cfg.enabledThemes += theme + "|"; } else { - active_themes.clear(); + enabled_themes.clear(); auto theme_str = meta.themePath.filename().string(); - active_themes.insert(theme_str); + enabled_themes.insert(theme_str); cfg.enabledThemes = theme_str; } } - void UnsetActive(const InstalledThemeMetadata& meta) { + void Disable(const InstalledThemeMetadata& meta) { auto& cfg = GetStyleMiiUCfg(); auto theme_str = meta.themePath.filename().string(); if (cfg.suffleThemes) { - active_themes.erase(theme_str); + enabled_themes.erase(theme_str); cfg.enabledThemes.clear(); - for (const auto& theme : active_themes) + for (const auto& theme : enabled_themes) cfg.enabledThemes += theme + "|"; } else { - if (active_themes.erase(theme_str)) + if (enabled_themes.erase(theme_str)) cfg.enabledThemes.clear(); } } diff --git a/src/installer.h b/src/installer.h index 317f315..fb542dc 100644 --- a/src/installer.h +++ b/src/installer.h @@ -44,6 +44,8 @@ namespace Installer { void initialize(); void finalize(); + void process(); + bool GetUThemeMetadata(const std::filesystem::path &themePath, UThemeMetadata &meta); @@ -68,9 +70,9 @@ namespace Installer { bool IsShuffling(); void ToggleShuffling(); - bool IsActive(const InstalledThemeMetadata& meta); - void SetActive(const InstalledThemeMetadata& meta); - void UnsetActive(const InstalledThemeMetadata& meta); + bool IsEnabled(const InstalledThemeMetadata& meta); + void Enable(const InstalledThemeMetadata& meta); + void Disable(const InstalledThemeMetadata& meta); void ReloadStyleMiiUCfg(); diff --git a/src/screens/HomeScreen.cpp b/src/screens/HomeScreen.cpp index 198dfd0..844e4f4 100644 --- a/src/screens/HomeScreen.cpp +++ b/src/screens/HomeScreen.cpp @@ -121,41 +121,53 @@ namespace HomeScreen { ImGui::Text("Your current theme:"); } - ImGui::Spacing(); - - if (!current_theme) { - if (Installer::IsShuffling()) { - ImGui::Text("StyleMiiU is shuffling themes."); - ImGui::Text("TODO: show a placeholder image for shuffling"); - } else { - ImGui::Text("No current theme found."); + // const ImVec2 img_size = {640, 360}; + // const ImVec2 img_size = {560, 315}; + const ImVec2 img_size = {512, 288}; + + if (Child theme_frame{"theme_frame", + {0, 0}, + ImGuiChildFlags_NavFlattened | + ImGuiChildFlags_FrameStyle | + ImGuiChildFlags_AutoResizeY, + ImGuiWindowFlags_NoSavedSettings}) { + + StyleVar no_border{ImGuiStyleVar_ImageBorderSize, 0}; + + if (!current_theme) { + if (Installer::IsShuffling()) { + auto img = ImageLoader::get("ui/theme-placeholder-random.png"); + ImGui::Image((ImTextureID)img, img_size); + ImGui::SameLine(); + ImGui::TextWrapped("StyleMiiU is shuffling themes."); + } else { + auto img = ImageLoader::get("ui/theme-placeholder-no-theme.png"); + ImGui::Image((ImTextureID)img, img_size); + ImGui::SameLine(); + ImGui::TextWrapped("No theme set."); + } } - ImGui::Spacing(); - } - else { - if (Child theme_frame{"theme_frame", - {0, 0}, - ImGuiChildFlags_NavFlattened | - ImGuiChildFlags_Borders | - ImGuiChildFlags_AutoResizeY, - ImGuiWindowFlags_NoSavedSettings}) { + else { if (!current_theme->previewPaths.empty()) { auto img = ImageLoader::get(current_theme->previewPaths.front()); - const ImVec2 img_size = {640, 360}; ImGui::Image((ImTextureID)img, img_size); - ImGui::SameLine(); + } else { + auto img = ImageLoader::get("ui/theme-placeholder-no-preview.png"); + ImGui::Image((ImTextureID)img, img_size); } + ImGui::SameLine(); + { Group right_group; { Font font_guard{nullptr, 30}; ImGui::TextWrapped(current_theme->uthemeMetadata.themeName); - if (current_theme->uthemeMetadata.themeAuthor) - ImGui::TextWrapped("by: " + - *current_theme->uthemeMetadata.themeAuthor); } + if (current_theme->uthemeMetadata.themeAuthor) + ImGui::TextWrapped("by: " + + *current_theme->uthemeMetadata.themeAuthor); } } } diff --git a/src/screens/InstallThemePopup.cpp b/src/screens/InstallThemePopup.cpp index 82dde63..493b46b 100644 --- a/src/screens/InstallThemePopup.cpp +++ b/src/screens/InstallThemePopup.cpp @@ -224,7 +224,7 @@ namespace InstallThemePopup { auto theme_path = Installer::GetThemePath(theme_data); Installer::InstalledThemeMetadata imeta; if (Installer::GetInstalledThemeMetadata(theme_path, imeta)) - Installer::SetActive(imeta); + Installer::Enable(imeta); } }); diff --git a/src/screens/ManageThemesScreen.cpp b/src/screens/ManageThemesScreen.cpp index 08b35e4..d4207ed 100644 --- a/src/screens/ManageThemesScreen.cpp +++ b/src/screens/ManageThemesScreen.cpp @@ -202,63 +202,60 @@ namespace ManageThemesScreen { ImGui::SetCursorPos(start_pos); Group grp; - if (!theme_data.previewPaths.empty()) { + { + const ImVec2 img_size = {inner_size.x, inner_size.x * 9.0f / 16.0f}; StyleVar no_border{ImGuiStyleVar_ImageBorderSize, 0}; - auto img = ImageLoader::get(theme_data.previewPaths.front()); - ImVec2 img_size = {inner_size.x, inner_size.x * 9.0f / 16.0f}; + auto img = !theme_data.previewPaths.empty() + ? ImageLoader::get(theme_data.previewPaths.front()) + : ImageLoader::get("ui/theme-placeholder-no-preview.png"); ImGui::Image((ImTextureID)img, img_size); } bool is_shuffling = Installer::IsShuffling(); - bool is_active = Installer::IsActive(theme_data); + bool is_enabled = Installer::IsEnabled(theme_data); // NOTE: Measure size for the active marker, but don't place it yet, to not mess // with the cursor position. - const std::string active_label = is_shuffling - ? (is_active ? ICON_FA_CHECK_CIRCLE_O : ICON_FA_CIRCLE_O) - : (is_active ? ICON_FA_STAR : ICON_FA_STAR_O); + const std::string enabled_label = is_shuffling + ? (is_enabled ? ICON_FA_CHECK_CIRCLE_O : ICON_FA_CIRCLE_O) + : (is_enabled ? ICON_FA_STAR : ICON_FA_STAR_O); - const float active_font_size = 48; - ImVec2 active_size; + const float enabled_font_size = 48; + ImVec2 enabled_size; { - Font active_font{nullptr, active_font_size}; - active_size = ImGui::CalcTextSize(active_label); + Font enabled_font{nullptr, enabled_font_size}; + enabled_size = ImGui::CalcTextSize(enabled_label); } { Font font{nullptr, 24}; - // If there's an image, make sure to limit the width, so it doesn't get - // covered by the star. - float name_width = inner_size.x; - if (!theme_data.previewPaths.empty()) - name_width -= active_size.x + style.ItemSpacing.x; + // Make sure to limit the name width, so it doesn't get covered by the enabled + // icon. + float name_width = inner_size.x - enabled_size.x - style.ItemSpacing.x; text_limited(name_width, theme_data.uthemeMetadata.themeName); } if (theme_data.uthemeMetadata.themeAuthor) { Font font{nullptr, 18}; - float author_width = inner_size.x; - // If there's an image, make sure to limit the width, so it doesn't get - // covered by the star. - if (!theme_data.previewPaths.empty()) - author_width -= active_size.x + style.ItemSpacing.x; + // Make sure to limit the author width, so it doesn't get + // covered by the enabled icon. + float author_width = inner_size.x - enabled_size.x - style.ItemSpacing.x; text_limited(author_width, "by " + *theme_data.uthemeMetadata.themeAuthor); } // Put active marker on bottom right. { - Font active_font{nullptr, active_font_size}; - StyleColor active_color{ImGuiCol_Text, {1.0f, 0.9f, 0.0f, 1.0f}}; - ImGui::SetCursorPos(inner_size - active_size); - ImGui::Text(active_label); + Font enabled_font{nullptr, enabled_font_size}; + StyleColor enabled_color{ImGuiCol_Text, {1.0f, 0.9f, 0.0f, 1.0f}}; + ImGui::SetCursorPos(inner_size - enabled_size); + ImGui::Text(enabled_label); if (clicked && ImGui::IsItemHovered()) { clicked = false; // cancel the click - if (is_active) { - Installer::UnsetActive(theme_data); - } else { - Installer::SetActive(theme_data); - } + if (is_enabled) + Installer::Disable(theme_data); + else + Installer::Enable(theme_data); HomeScreen::force_refresh(); } } @@ -398,13 +395,13 @@ namespace ManageThemesScreen { if (ImGui::Button(enable_all_label)) { auto installed_themes = safe_installed_themes.lock(); for (auto& theme : *installed_themes) - Installer::SetActive(theme); + Installer::Enable(theme); } ImGui::SameLine(); if (ImGui::Button(disable_all_label)) { auto installed_themes = safe_installed_themes.lock(); for (auto& theme : *installed_themes) - Installer::UnsetActive(theme); + Installer::Disable(theme); } } diff --git a/src/screens/ThemeDetailsPopup.cpp b/src/screens/ThemeDetailsPopup.cpp index 3847e38..bb2852e 100644 --- a/src/screens/ThemeDetailsPopup.cpp +++ b/src/screens/ThemeDetailsPopup.cpp @@ -165,20 +165,20 @@ namespace ThemeDetailsPopup { } bool is_shuffling = Installer::IsShuffling(); - bool is_active = Installer::IsActive(installedThemeData); + bool is_enabled = Installer::IsEnabled(installedThemeData); if (is_shuffling) { - if (ImGui::Checkbox("Enable", is_active)) { - if (is_active) - Installer::UnsetActive(installedThemeData); + if (ImGui::Checkbox("Enabled", is_enabled)) { + if (is_enabled) + Installer::Enable(installedThemeData); else - Installer::SetActive(installedThemeData); + Installer::Disable(installedThemeData); HomeScreen::force_refresh(); } } else { - Disabled disabled_if{is_active}; + Disabled disabled_if{is_enabled}; if (ImGui::Button(ICON_FA_STAR " Apply", {-1, 0})) { - Installer::SetActive(installedThemeData); + Installer::Enable(installedThemeData); ImGui::CloseCurrentPopup(); HomeScreen::force_refresh(); } From f563757f444b7caba92e376b1aa2514436e587e8 Mon Sep 17 00:00:00 2001 From: "Daniel K. O. (dkosmari)" Date: Thu, 9 Jul 2026 15:45:44 -0300 Subject: [PATCH 6/7] Differentiate build version from official releases. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 33e3b53..5bcc77c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,7 @@ target_link_libraries(themiify PRIVATE PkgConfig::SDL2_mixer ) -target_compile_definitions(themiify PRIVATE THEMIIFY_VERSION="1.1") +target_compile_definitions(themiify PRIVATE THEMIIFY_VERSION="1.1-dev") # run program using wiiload From f5d804bc528359a4b72ae3f6a3fc815ea9d5e2e9 Mon Sep 17 00:00:00 2001 From: "Daniel K. O. (dkosmari)" Date: Thu, 9 Jul 2026 16:58:50 -0300 Subject: [PATCH 7/7] Updated random theme placeholder. --- content/ui/theme-placeholder-random.png | Bin 55047 -> 18695 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/content/ui/theme-placeholder-random.png b/content/ui/theme-placeholder-random.png index 35593b824026f982d073c226aae38da288cf15a2..b3aafe8feb74a8bdd3dbffed2a025bee63ab9084 100644 GIT binary patch literal 18695 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 literal 55047 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
12YNxRT(cE`WpNHWkz>O3+ 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