diff --git a/src/citron/configuration/configure_per_game.cpp b/src/citron/configuration/configure_per_game.cpp index f6717fbbf..514c5af21 100644 --- a/src/citron/configuration/configure_per_game.cpp +++ b/src/citron/configuration/configure_per_game.cpp @@ -45,6 +45,7 @@ #include "citron/configuration/configure_per_game.h" #include "citron/configuration/configure_per_game_addons.h" #include "citron/configuration/configure_system.h" +#include "citron/theme.h" #include "citron/uisettings.h" #include "citron/util/util.h" #include "citron/vk_device_info.h" @@ -74,14 +75,33 @@ tab_group{std::make_shared>()} { ui->setupUi(this); - // THIS IS THE NEW FIX: Force a minimum height on the window. + // This block processes the theme and passes it to the graphics tab + { + // 1. Read the raw stylesheet from the UI property. + QString raw_stylesheet = property("templateStyleSheet").toString(); + + // 2. Process a copy of the stylesheet for this dialog itself. + QString processed_stylesheet = raw_stylesheet; + QColor accent_color(Theme::GetAccentColor()); + QString accent_color_hover = accent_color.lighter(115).name(QColor::HexRgb); + QString accent_color_pressed = accent_color.darker(120).name(QColor::HexRgb); + + processed_stylesheet.replace(QStringLiteral("%%ACCENT_COLOR%%"), accent_color.name(QColor::HexRgb)); + processed_stylesheet.replace(QStringLiteral("%%ACCENT_COLOR_HOVER%%"), accent_color_hover); + processed_stylesheet.replace(QStringLiteral("%%ACCENT_COLOR_PRESSED%%"), accent_color_pressed); + setStyleSheet(processed_stylesheet); + + // 3. Pass the RAW, UNPROCESSED stylesheet to the graphics tab. + // This allows the graphics tab to do its own color replacements correctly. + graphics_tab->SetTemplateStyleSheet(raw_stylesheet); + } + setMinimumHeight(400); layout()->setSizeConstraint(QLayout::SetDefaultConstraint); ui->tabWidget->addTab(addons_tab.get(), tr("Add-Ons")); - // Create a scroll area for the system tab QScrollArea* system_scroll_area = new QScrollArea(this); system_scroll_area->setWidgetResizable(true); system_scroll_area->setWidget(system_tab.get()); @@ -89,13 +109,11 @@ tab_group{std::make_shared>()} { ui->tabWidget->addTab(cpu_tab.get(), tr("CPU")); - // Create a scroll area for the graphics tab QScrollArea* graphics_scroll_area = new QScrollArea(this); graphics_scroll_area->setWidgetResizable(true); graphics_scroll_area->setWidget(graphics_tab.get()); ui->tabWidget->addTab(graphics_scroll_area, tr("Graphics")); - // Create a scroll area for the advanced graphics tab QScrollArea* graphics_advanced_scroll_area = new QScrollArea(this); graphics_advanced_scroll_area->setWidgetResizable(true); graphics_advanced_scroll_area->setWidget(graphics_advanced_tab.get()); @@ -104,7 +122,6 @@ tab_group{std::make_shared>()} { ui->tabWidget->addTab(audio_tab.get(), tr("Audio")); ui->tabWidget->addTab(input_tab.get(), tr("Input Profiles")); - // Only show Linux tab on Unix linux_tab->setVisible(false); #ifdef __unix__ linux_tab->setVisible(true); @@ -232,33 +249,27 @@ void ConfigurePerGame::LoadConfiguration() { const auto valueText = ReadableByteSize(file->GetSize()); ui->display_size->setText(valueText); - // Display Build ID(s) if available std::string base_build_id_hex; std::string update_build_id_hex; - // Try to get build ID based on file type const auto file_type = loader->GetFileType(); if (file_type == Loader::FileType::NSO) { - // For NSO files, read the build ID directly from the header if (file->GetSize() >= 0x100) { std::array header_data{}; if (file->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { - // Build ID is at offset 0x40 in NSO header std::array build_id{}; std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); base_build_id_hex = Common::HexToString(build_id, false); } } } else if (file_type == Loader::FileType::DeconstructedRomDirectory) { - // For deconstructed ROM directories, read from the main NSO file const auto main_dir = file->GetContainingDirectory(); if (main_dir) { const auto main_nso = main_dir->GetFile("main"); if (main_nso && main_nso->GetSize() >= 0x100) { std::array header_data{}; if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { - // Build ID is at offset 0x40 in NSO header std::array build_id{}; std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); base_build_id_hex = Common::HexToString(build_id, false); @@ -266,16 +277,12 @@ void ConfigurePerGame::LoadConfiguration() { } } } else { - // For other file types (XCI, NSP, NCA), try to extract build ID directly try { if (file_type == Loader::FileType::XCI) { - // For XCI files, try to construct with the proper parameters try { - // First try to get the program ID from the XCI to use proper parameters FileSys::XCI xci_temp(file); if (xci_temp.GetStatus() == Loader::ResultStatus::Success) { - // Try to get the program NCA from the secure partition - FileSys::XCI xci(file, title_id, 0); // Use detected title_id + FileSys::XCI xci(file, title_id, 0); if (xci.GetStatus() == Loader::ResultStatus::Success) { auto program_nca = xci.GetNCAByType(FileSys::NCAContentType::Program); if (program_nca && program_nca->GetStatus() == Loader::ResultStatus::Success) { @@ -295,8 +302,6 @@ void ConfigurePerGame::LoadConfiguration() { } } } catch (...) { - // XCI might be encrypted or have other issues - // Fall back to checking if it's installed in the content provider const auto& content_provider = system.GetContentProvider(); auto base_nca = content_provider.GetEntry(title_id, FileSys::ContentRecordType::Program); if (base_nca && base_nca->GetStatus() == Loader::ResultStatus::Success) { @@ -315,7 +320,6 @@ void ConfigurePerGame::LoadConfiguration() { } } } else if (file_type == Loader::FileType::NSP) { - // For NSP files, try to construct and parse directly FileSys::NSP nsp(file); if (nsp.GetStatus() == Loader::ResultStatus::Success) { auto exefs = nsp.GetExeFS(); @@ -332,7 +336,6 @@ void ConfigurePerGame::LoadConfiguration() { } } } else if (file_type == Loader::FileType::NCA) { - // For NCA files, try to construct and parse directly FileSys::NCA nca(file); if (nca.GetStatus() == Loader::ResultStatus::Success) { auto exefs = nca.GetExeFS(); @@ -350,23 +353,15 @@ void ConfigurePerGame::LoadConfiguration() { } } } catch (...) { - // If anything fails, continue without the build ID } } - // Try to get update build ID from patch manager and content provider try { - // Method 1: Try through patch manager (more reliable for updates) const FileSys::PatchManager pm_update{title_id, system.GetFileSystemController(), system.GetContentProvider()}; - // Check if patch manager has update information const auto update_version = pm_update.GetGameVersion(); if (update_version.has_value() && update_version.value() > 0) { - // There's an update, try to get its build ID through the patch manager - // The patch manager should have access to the update NCA - - // Try to get the update NCA through the patch manager's content provider const auto& content_provider = system.GetContentProvider(); const auto update_title_id = FileSys::GetUpdateTitleID(title_id); auto update_nca = content_provider.GetEntry(update_title_id, FileSys::ContentRecordType::Program); @@ -387,7 +382,6 @@ void ConfigurePerGame::LoadConfiguration() { } } - // Method 2: If patch manager approach didn't work, try direct content provider access if (update_build_id_hex.empty()) { const auto& content_provider = system.GetContentProvider(); const auto update_title_id = FileSys::GetUpdateTitleID(title_id); @@ -409,47 +403,35 @@ void ConfigurePerGame::LoadConfiguration() { } } - // Method 3: Try to use the patch manager's GetPatches to detect updates if (update_build_id_hex.empty()) { const auto patches = pm_update.GetPatches(); for (const auto& patch : patches) { if (patch.type == FileSys::PatchType::Update && patch.enabled) { - // There's an enabled update patch, but we couldn't get its build ID - // This indicates an update is available but not currently loaded break; } } } } catch (...) { - // If update build ID extraction fails, continue with just base } - // Try to get the actual running build ID from system (this will be the update if one is applied) const auto& system_build_id = system.GetApplicationProcessBuildID(); const auto system_build_id_hex = Common::HexToString(system_build_id, false); - // If we have a system build ID and it's different from the base, it's likely the update if (!system_build_id_hex.empty() && system_build_id_hex != std::string(64, '0')) { if (!base_build_id_hex.empty() && system_build_id_hex != base_build_id_hex) { - // System build ID is different from base, so it's the update update_build_id_hex = system_build_id_hex; } else if (base_build_id_hex.empty()) { - // No base build ID found, use system as base base_build_id_hex = system_build_id_hex; } } - // Additional check: if we still don't have an update build ID but we know there's an update - // (from the Add-Ons tab showing v1.0.1 etc), try alternative detection methods bool update_detected = false; if (update_build_id_hex.empty() && !base_build_id_hex.empty()) { - // Check if the patch manager indicates an update is available const auto update_version = pm.GetGameVersion(); if (update_version.has_value() && update_version.value() > 0) { update_detected = true; } - // Also check patches const auto patches = pm.GetPatches(); for (const auto& patch : patches) { if (patch.type == FileSys::PatchType::Update && patch.enabled) { @@ -459,18 +441,15 @@ void ConfigurePerGame::LoadConfiguration() { } } - // Display the Build IDs in separate fields bool has_base = !base_build_id_hex.empty() && base_build_id_hex != std::string(64, '0'); bool has_update = !update_build_id_hex.empty() && update_build_id_hex != std::string(64, '0'); - // Set Base Build ID if (has_base) { ui->display_build_id->setText(QString::fromStdString(base_build_id_hex)); } else { ui->display_build_id->setText(tr("Not Available")); } - // Set Update Build ID if (has_update) { ui->display_update_build_id->setText(QString::fromStdString(update_build_id_hex)); } else if (update_detected) {