// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team // SPDX-License-Identifier: GPL-3.0+ #include "GS/Renderers/Common/GSDevice.h" #include "GS/Renderers/Common/GSTexture.h" #include "Achievements.h" #include "GameList.h" #include "Host.h" #include "Host/AudioStream.h" #include "INISettingsInterface.h" #include "ImGui/FullscreenUI_Internal.h" #include "ImGui/ImGuiFullscreen.h" #include "ImGui/ImGuiManager.h" #include "Input/InputManager.h" #include "MTGS.h" #include "Patch.h" #include "USB/USB.h" #include "VMManager.h" #include "ps2/BiosTools.h" #include "DEV9/ATA/HddCreate.h" #include "DEV9/pcap_io.h" #include "DEV9/sockets.h" #ifdef _WIN32 #include "DEV9/Win32/tap.h" #endif #include "common/Console.h" #include "common/FileSystem.h" #include "common/Path.h" #include "common/SettingsInterface.h" #include "common/StringUtil.h" #include "common/SmallString.h" #include "common/Threading.h" #include "SIO/Memcard/MemoryCardFile.h" #include "SIO/Pad/Pad.h" #include "SIO/Sio.h" #include "IconsFontAwesome.h" #include "IconsPromptFont.h" #include "imgui.h" #include "imgui_internal.h" #include "fmt/format.h" #include namespace FullscreenUI { class HddCreateInProgress : public HddCreate { private: std::string m_dialogId; int m_reqMiB = 0; static std::vector> s_activeOperations; static std::mutex s_operationsMutex; static std::atomic_int s_nextOperationId; public: HddCreateInProgress(const std::string& dialogId) : m_dialogId(dialogId) { } static bool StartCreation(const std::string& filePath, int sizeInGB, bool use48BitLBA) { if (filePath.empty() || sizeInGB <= 0) return false; std::string dialogId = fmt::format("hdd_create_{}", s_nextOperationId.fetch_add(1, std::memory_order_relaxed)); std::shared_ptr instance = std::make_shared(dialogId); // Convert GB to bytes const u64 sizeBytes = static_cast(sizeInGB) * static_cast(_1gb); // Make sure the file doesn't already exist (or delete it if it does) if (FileSystem::FileExists(filePath.c_str())) { if (!FileSystem::DeleteFilePath(filePath.c_str())) { ShowToast( fmt::format("{} HDD Creation Failed", ICON_FA_TRIANGLE_EXCLAMATION), fmt::format("Failed to delete existing HDD image file '{}'. Please check file permissions and try again.", Path::GetFileName(filePath)), 5.0f); return false; } } // Setup the creation parameters instance->filePath = filePath; instance->neededSize = sizeBytes; // Register the operation { std::lock_guard lock(s_operationsMutex); s_activeOperations.push_back(instance); } // Start the HDD creation std::thread([instance = std::move(instance)]() { instance->Start(); if (!instance->errored) MTGS::RunOnGSThread([size_gb = static_cast(instance->neededSize / static_cast(_1gb))]() { ShowToast( ICON_FA_CIRCLE_CHECK, fmt::format("HDD image ({} GB) created successfully.", size_gb), 3.0f); }); else MTGS::RunOnGSThread([]() { ShowToast( ICON_FA_TRIANGLE_EXCLAMATION, "Failed to create HDD image.", 3.0f); }); std::lock_guard lock(s_operationsMutex); for (auto it = s_activeOperations.begin(); it != s_activeOperations.end(); ++it) { if (it->get() == instance.get()) { s_activeOperations.erase(it); break; } } }).detach(); return true; } static void CancelAllOperations() { std::lock_guard lock(s_operationsMutex); for (auto& operation : s_activeOperations) operation->SetCanceled(); s_activeOperations.clear(); } protected: virtual void Init() override { m_reqMiB = static_cast((neededSize + ((1024 * 1024) - 1)) / (1024 * 1024)); const std::string message = fmt::format("{} Creating HDD Image\n{} / {} MiB", ICON_FA_HARD_DRIVE, 0, m_reqMiB); ImGuiFullscreen::OpenProgressDialog(m_dialogId.c_str(), message, 0, m_reqMiB, 0); } virtual void SetFileProgress(u64 currentSize) override { const int writtenMiB = static_cast((currentSize + ((1024 * 1024) - 1)) / (1024 * 1024)); const std::string message = fmt::format("{} Creating HDD Image\n{} / {} MiB", ICON_FA_HARD_DRIVE, writtenMiB, m_reqMiB); ImGuiFullscreen::UpdateProgressDialog(m_dialogId.c_str(), message, 0, m_reqMiB, writtenMiB); } virtual void Cleanup() override { ImGuiFullscreen::CloseProgressDialog(m_dialogId.c_str()); } }; std::vector> HddCreateInProgress::s_activeOperations; std::mutex HddCreateInProgress::s_operationsMutex; std::atomic_int HddCreateInProgress::s_nextOperationId{0}; bool CreateHardDriveWithProgress(const std::string& filePath, int sizeInGB, bool use48BitLBA) { // Validate size limits based on the LBA mode set const int min_size = use48BitLBA ? 100 : 40; const int max_size = use48BitLBA ? 2000 : 120; if (sizeInGB < min_size || sizeInGB > max_size) { ShowToast(std::string(), fmt::format("Invalid HDD size. Size must be between {} and {} GB.", min_size, max_size).c_str()); return false; } return HddCreateInProgress::StartCreation(filePath, sizeInGB, use48BitLBA); } void CancelAllHddOperations() { HddCreateInProgress::CancelAllOperations(); } } // namespace FullscreenUI bool FullscreenUI::IsEditingGameSettings(SettingsInterface* bsi) { return (bsi == s_game_settings_interface.get()); } SettingsInterface* FullscreenUI::GetEditingSettingsInterface() { return s_game_settings_interface ? s_game_settings_interface.get() : Host::Internal::GetBaseSettingsLayer(); } SettingsInterface* FullscreenUI::GetEditingSettingsInterface(bool game_settings) { return (game_settings && s_game_settings_interface) ? s_game_settings_interface.get() : Host::Internal::GetBaseSettingsLayer(); } bool FullscreenUI::ShouldShowAdvancedSettings(SettingsInterface* bsi) { return IsEditingGameSettings(bsi) ? Host::GetBaseBoolSettingValue("UI", "ShowAdvancedSettings", false) : bsi->GetBoolValue("UI", "ShowAdvancedSettings", false); } void FullscreenUI::SetSettingsChanged(SettingsInterface* bsi) { if (bsi && bsi == s_game_settings_interface.get()) s_game_settings_changed.store(true, std::memory_order_release); else s_settings_changed.store(true, std::memory_order_release); } bool FullscreenUI::GetEffectiveBoolSetting(SettingsInterface* bsi, const char* section, const char* key, bool default_value) { if (IsEditingGameSettings(bsi)) { std::optional value = bsi->GetOptionalBoolValue(section, key, std::nullopt); if (value.has_value()) return value.value(); } return Host::Internal::GetBaseSettingsLayer()->GetBoolValue(section, key, default_value); } s32 FullscreenUI::GetEffectiveIntSetting(SettingsInterface* bsi, const char* section, const char* key, s32 default_value) { if (IsEditingGameSettings(bsi)) { std::optional value = bsi->GetOptionalIntValue(section, key, std::nullopt); if (value.has_value()) return value.value(); } return Host::Internal::GetBaseSettingsLayer()->GetIntValue(section, key, default_value); } void FullscreenUI::DrawInputBindingButton( SettingsInterface* bsi, InputBindingInfo::Type type, const char* section, const char* name, const char* display_name, const char* icon_name, bool show_type) { TinyString title; title.format("{}/{}", section, name); SmallString value = bsi->GetSmallStringValue(section, name); const bool oneline = (value.count('&') <= 1); ImRect bb; bool visible, hovered, clicked; clicked = MenuButtonFrame(title, true, oneline ? ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY : ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT, &visible, &hovered, &bb.Min, &bb.Max); if (!visible) return; if (oneline) InputManager::PrettifyInputBinding(value, true); else InputManager::PrettifyInputBinding(value, false); if (show_type) { if (icon_name) { title.format("{} {}", icon_name, display_name); } else { switch (type) { case InputBindingInfo::Type::Button: title.format(ICON_FA_CIRCLE_DOT " {}", display_name); break; case InputBindingInfo::Type::Axis: case InputBindingInfo::Type::HalfAxis: title.format(ICON_FA_BULLSEYE " {}", display_name); break; case InputBindingInfo::Type::Motor: title.format(ICON_PF_CONTROLLER_VIBRATION " {}", display_name); break; case InputBindingInfo::Type::Macro: title.format(ICON_PF_THUNDERBOLT " {}", display_name); break; default: title = display_name; break; } } } const float midpoint = bb.Min.y + g_large_font.second + LayoutScale(4.0f); if (oneline) { ImGui::PushFont(g_large_font.first, g_large_font.second); const ImVec2 value_size(ImGui::CalcTextSize(value.empty() ? FSUI_CSTR("-") : value.c_str(), nullptr)); const float text_end = bb.Max.x - value_size.x; const ImRect title_bb(bb.Min, ImVec2(text_end, midpoint)); ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, show_type ? title.c_str() : display_name, nullptr, nullptr, ImVec2(0.0f, 0.0f), &title_bb); ImGui::RenderTextClipped(bb.Min, bb.Max, value.empty() ? FSUI_CSTR("-") : value.c_str(), nullptr, &value_size, ImVec2(1.0f, 0.5f), &bb); ImGui::PopFont(); } else { const ImRect title_bb(bb.Min, ImVec2(bb.Max.x, midpoint)); const ImRect summary_bb(ImVec2(bb.Min.x, midpoint), bb.Max); ImGui::PushFont(g_large_font.first, g_large_font.second); ImGui::RenderTextClipped(title_bb.Min, title_bb.Max, show_type ? title.c_str() : display_name, nullptr, nullptr, ImVec2(0.0f, 0.0f), &title_bb); ImGui::PopFont(); ImGui::PushFont(g_medium_font.first, g_medium_font.second); ImGui::RenderTextClipped(summary_bb.Min, summary_bb.Max, value.empty() ? FSUI_CSTR("No Binding") : value.c_str(), nullptr, nullptr, ImVec2(0.0f, 0.0f), &summary_bb); ImGui::PopFont(); } if (clicked) { BeginInputBinding(bsi, type, section, name, display_name); } else if (hovered && (ImGui::IsItemClicked(ImGuiMouseButton_Right) || ImGui::Shortcut(ImGuiKey_NavGamepadMenu))) { bsi->DeleteValue(section, name); SetSettingsChanged(bsi); } else { if (hovered) { if (ImGuiFullscreen::IsGamepadInputSource()) { const bool swapNorthWest = ImGuiManager::IsGamepadNorthWestSwapped(); ImGuiFullscreen::QueueFooterHint(std::array{ std::make_pair(swapNorthWest ? ICON_PF_BUTTON_TRIANGLE : ICON_PF_BUTTON_SQUARE, FSUI_VSTR("Clear Binding")), }); } else { ImGuiFullscreen::QueueFooterHint(std::array{ std::make_pair(ICON_PF_RIGHT_CLICK, FSUI_VSTR("Clear Binding")), }); } } } } void FullscreenUI::ClearInputBindingVariables() { s_input_binding_type = InputBindingInfo::Type::Unknown; s_input_binding_section = {}; s_input_binding_key = {}; s_input_binding_display_name = {}; s_input_binding_new_bindings = {}; s_input_binding_value_ranges = {}; } void FullscreenUI::BeginInputBinding(SettingsInterface* bsi, InputBindingInfo::Type type, const std::string_view section, const std::string_view key, const std::string_view display_name) { if (s_input_binding_type != InputBindingInfo::Type::Unknown) { InputManager::RemoveHook(); ClearInputBindingVariables(); } s_input_binding_type = type; s_input_binding_section = section; s_input_binding_key = key; s_input_binding_display_name = display_name; s_input_binding_new_bindings = {}; s_input_binding_value_ranges = {}; s_input_binding_timer.Reset(); const bool game_settings = IsEditingGameSettings(bsi); InputManager::SetHook([game_settings](InputBindingKey key, float value) -> InputInterceptHook::CallbackResult { if (s_input_binding_type == InputBindingInfo::Type::Unknown) return InputInterceptHook::CallbackResult::StopProcessingEvent; // holding the settings lock here will protect the input binding list auto lock = Host::GetSettingsLock(); float initial_value = value; float min_value = value; auto it = std::find_if(s_input_binding_value_ranges.begin(), s_input_binding_value_ranges.end(), [key](const auto& it) { return it.first.bits == key.bits; }); if (it != s_input_binding_value_ranges.end()) { initial_value = it->second.first; min_value = it->second.second = std::min(it->second.second, value); } else { s_input_binding_value_ranges.emplace_back(key, std::make_pair(initial_value, min_value)); } const float abs_value = std::abs(value); const bool reverse_threshold = (key.source_subtype == InputSubclass::ControllerAxis && initial_value > 0.5f); for (InputBindingKey& other_key : s_input_binding_new_bindings) { // if this key is in our new binding list, it's a "release", and we're done if (other_key.MaskDirection() == key.MaskDirection()) { // for pedals, we wait for it to go back to near its starting point to commit the binding if ((reverse_threshold ? ((initial_value - value) <= 0.25f) : (abs_value < 0.5f))) { // did we go the full range? if (reverse_threshold && initial_value > 0.5f && min_value <= -0.5f) other_key.modifier = InputModifier::FullAxis; SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); const std::string new_binding(InputManager::ConvertInputBindingKeysToString( s_input_binding_type, s_input_binding_new_bindings.data(), s_input_binding_new_bindings.size())); bsi->SetStringValue(s_input_binding_section.c_str(), s_input_binding_key.c_str(), new_binding.c_str()); SetSettingsChanged(bsi); ClearInputBindingVariables(); return InputInterceptHook::CallbackResult::RemoveHookAndStopProcessingEvent; } // otherwise, keep waiting return InputInterceptHook::CallbackResult::StopProcessingEvent; } } // new binding, add it to the list, but wait for a decent distance first, and then wait for release if ((reverse_threshold ? (abs_value < 0.5f) : (abs_value >= 0.5f))) { InputBindingKey key_to_add = key; key_to_add.modifier = (value < 0.0f && !reverse_threshold) ? InputModifier::Negate : InputModifier::None; key_to_add.invert = reverse_threshold; s_input_binding_new_bindings.push_back(key_to_add); } return InputInterceptHook::CallbackResult::StopProcessingEvent; }); } void FullscreenUI::DrawInputBindingWindow() { pxAssert(s_input_binding_type != InputBindingInfo::Type::Unknown); const double time_remaining = INPUT_BINDING_TIMEOUT_SECONDS - s_input_binding_timer.GetTimeSeconds(); if (time_remaining <= 0.0) { InputManager::RemoveHook(); ClearInputBindingVariables(); return; } const char* title = FSUI_ICONSTR(ICON_FA_GAMEPAD, "Set Input Binding"); ImGui::SetNextWindowSize(LayoutScale(500.0f, 0.0f)); ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::OpenPopup(title); ImGui::PushFont(g_large_font.first, g_large_font.second); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(20.0f, 20.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING, ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING)); if (ImGui::BeginPopupModal(title, nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoInputs)) { ImGui::TextWrapped(FSUI_CSTR("Setting %s binding %s."), s_input_binding_section.c_str(), s_input_binding_display_name.c_str()); ImGui::TextUnformatted(FSUI_CSTR("Push a controller button or axis now.")); ImGui::NewLine(); ImGui::Text(FSUI_CSTR("Timing out in %.0f seconds..."), time_remaining); ImGui::EndPopup(); } ImGui::PopStyleVar(4); ImGui::PopFont(); } bool FullscreenUI::DrawToggleSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, bool default_value, bool enabled, bool allow_tristate, float height, std::pair font, std::pair summary_font) { if (!allow_tristate || !IsEditingGameSettings(bsi)) { bool value = bsi->GetBoolValue(section, key, default_value); if (!ToggleButton(title, summary, &value, enabled, height, font, summary_font)) return false; bsi->SetBoolValue(section, key, value); } else { std::optional value(false); if (!bsi->GetBoolValue(section, key, &value.value())) value.reset(); if (!ThreeWayToggleButton(title, summary, &value, enabled, height, font, summary_font)) return false; if (value.has_value()) bsi->SetBoolValue(section, key, value.value()); else bsi->DeleteValue(section, key); } SetSettingsChanged(bsi); return true; } void FullscreenUI::DrawIntListSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, int default_value, const char* const* options, size_t option_count, bool translate_options, int option_offset, bool enabled, float height, std::pair font, std::pair summary_font) { if (options && option_count == 0) { while (options[option_count] != nullptr) option_count++; } const bool game_settings = IsEditingGameSettings(bsi); const std::optional value = bsi->GetOptionalIntValue(section, key, game_settings ? std::nullopt : std::optional(default_value)); const int index = value.has_value() ? (value.value() - option_offset) : std::numeric_limits::min(); const char* value_text = (value.has_value()) ? ((index < 0 || static_cast(index) >= option_count) ? FSUI_CSTR("Unknown") : (translate_options ? Host::TranslateToCString(TR_CONTEXT, options[index]) : options[index])) : FSUI_CSTR("Use Global Setting"); if (MenuButtonWithValue(title, summary, value_text, enabled, height, font, summary_font)) { ImGuiFullscreen::ChoiceDialogOptions cd_options; cd_options.reserve(option_count + 1); if (game_settings) cd_options.emplace_back(FSUI_STR("Use Global Setting"), !value.has_value()); for (size_t i = 0; i < option_count; i++) { cd_options.emplace_back(translate_options ? Host::TranslateToString(TR_CONTEXT, options[i]) : std::string(options[i]), (i == static_cast(index))); } OpenChoiceDialog(title, false, std::move(cd_options), [game_settings, section, key, option_offset](s32 index, const std::string& title, bool checked) { if (index >= 0) { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); if (game_settings) { if (index == 0) bsi->DeleteValue(section, key); else bsi->SetIntValue(section, key, index - 1 + option_offset); } else { bsi->SetIntValue(section, key, index + option_offset); } SetSettingsChanged(bsi); } CloseChoiceDialog(); }); } } void FullscreenUI::DrawIntRangeSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, int default_value, int min_value, int max_value, const char* format, bool enabled, float height, std::pair font, std::pair summary_font) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value = bsi->GetOptionalIntValue(section, key, game_settings ? std::nullopt : std::optional(default_value)); const SmallString value_text = value.has_value() ? SmallString::from_sprintf(format, value.value()) : SmallString(FSUI_VSTR("Use Global Setting")); if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font)) ImGui::OpenPopup(title); ImGui::SetNextWindowSize(LayoutScale(500.0f, 192.0f)); ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::PushFont(g_large_font.first, g_large_font.second); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(20.0f, 20.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING, ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING)); bool is_open = true; if (ImGui::BeginPopupModal(title, &is_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar)) { BeginMenuButtons(); const float end = ImGui::GetCurrentWindow()->WorkRect.GetWidth(); ImGui::SetNextItemWidth(end); s32 dlg_value = static_cast(value.value_or(default_value)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(8.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, LayoutScale(1.0f)); ImGui::PushStyleVar(ImGuiStyleVar_GrabRounding, LayoutScale(8.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.25f, 0.25f, 0.25f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.4f, 0.4f, 0.4f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.45f, 0.65f, 0.95f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, ImVec4(0.55f, 0.75f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); if (ImGui::SliderInt("##value", &dlg_value, min_value, max_value, format, ImGuiSliderFlags_NoInput)) { if (IsEditingGameSettings(bsi) && dlg_value == default_value) bsi->DeleteValue(section, key); else bsi->SetIntValue(section, key, dlg_value); SetSettingsChanged(bsi); } ImGui::PopStyleColor(7); ImGui::PopStyleVar(3); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(10.0f)); if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, g_large_font, ImVec2(0.5f, 0.0f))) { ImGui::CloseCurrentPopup(); } EndMenuButtons(); ImGui::EndPopup(); } ImGui::PopStyleVar(4); ImGui::PopFont(); } void FullscreenUI::DrawIntSpinBoxSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, int default_value, int min_value, int max_value, int step_value, const char* format, bool enabled, float height, std::pair font, std::pair summary_font) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value = bsi->GetOptionalIntValue(section, key, game_settings ? std::nullopt : std::optional(default_value)); const SmallString value_text = value.has_value() ? SmallString::from_sprintf(format, value.value()) : SmallString(FSUI_VSTR("Use Global Setting")); static bool manual_input = false; if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font)) { ImGui::OpenPopup(title); manual_input = false; } ImGui::SetNextWindowSize(LayoutScale(500.0f, 192.0f)); ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::PushFont(g_large_font.first, g_large_font.second); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(20.0f, 20.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING, ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING)); bool is_open = true; if (ImGui::BeginPopupModal(title, &is_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar)) { BeginMenuButtons(); s32 dlg_value = static_cast(value.value_or(default_value)); bool dlg_value_changed = false; char str_value[32]; std::snprintf(str_value, std::size(str_value), format, dlg_value); if (manual_input) { const float end = ImGui::GetCurrentWindow()->WorkRect.GetWidth(); ImGui::SetNextItemWidth(end); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(8.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(12.0f, 10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, LayoutScale(1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.25f, 0.25f, 0.25f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.4f, 0.4f, 0.4f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); if (ImGui::InputText("##value", str_value, std::size(str_value), ImGuiInputTextFlags_CharsDecimal)) { const s32 new_value = StringUtil::FromChars(str_value).value_or(dlg_value); dlg_value_changed = (dlg_value != new_value); dlg_value = new_value; } ImGui::PopStyleColor(5); ImGui::PopStyleVar(3); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(10.0f)); } else { const ImVec2& padding(ImGui::GetStyle().FramePadding); ImVec2 button_pos(ImGui::GetCursorPos()); // Align value text in middle. ImGui::SetCursorPosY( button_pos.y + ((LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) + padding.y * 2.0f) - g_large_font.second) * 0.5f); ImGui::TextUnformatted(str_value); s32 step = 0; if (FloatingButton( ICON_FA_CHEVRON_UP, padding.x, button_pos.y, -1.0f, -1.0f, 1.0f, 0.0f, true, g_large_font, &button_pos, true)) { step = step_value; } if (FloatingButton(ICON_FA_CHEVRON_DOWN, button_pos.x - padding.x, button_pos.y, -1.0f, -1.0f, -1.0f, 0.0f, true, g_large_font, &button_pos, true)) { step = -step_value; } if (FloatingButton( ICON_FA_KEYBOARD, button_pos.x - padding.x, button_pos.y, -1.0f, -1.0f, -1.0f, 0.0f, true, g_large_font, &button_pos)) { manual_input = true; } if (FloatingButton( ICON_FA_TRASH, button_pos.x - padding.x, button_pos.y, -1.0f, -1.0f, -1.0f, 0.0f, true, g_large_font, &button_pos)) { dlg_value = default_value; dlg_value_changed = true; } if (step != 0) { dlg_value += step; dlg_value_changed = true; } ImGui::SetCursorPosY(button_pos.y + (padding.y * 2.0f) + LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f)); } if (dlg_value_changed) { dlg_value = std::clamp(dlg_value, min_value, max_value); if (IsEditingGameSettings(bsi) && dlg_value == default_value) bsi->DeleteValue(section, key); else bsi->SetIntValue(section, key, dlg_value); SetSettingsChanged(bsi); } if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, g_large_font, ImVec2(0.5f, 0.0f))) { ImGui::CloseCurrentPopup(); } EndMenuButtons(); ImGui::EndPopup(); } ImGui::PopStyleVar(4); ImGui::PopFont(); } void FullscreenUI::DrawFloatRangeSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, float default_value, float min_value, float max_value, const char* format, float multiplier, bool enabled, float height, std::pair font, std::pair summary_font) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value = bsi->GetOptionalFloatValue(section, key, game_settings ? std::nullopt : std::optional(default_value)); const SmallString value_text = value.has_value() ? SmallString::from_sprintf(format, value.value() * multiplier) : SmallString(FSUI_VSTR("Use Global Setting")); if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font)) ImGui::OpenPopup(title); ImGui::SetNextWindowSize(LayoutScale(500.0f, 190.0f)); ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::PushFont(g_large_font.first, g_large_font.second); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(20.0f, 20.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING, ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING)); bool is_open = true; if (ImGui::BeginPopupModal(title, &is_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar)) { BeginMenuButtons(); const float end = ImGui::GetCurrentWindow()->WorkRect.GetWidth(); ImGui::SetNextItemWidth(end); float dlg_value = value.value_or(default_value) * multiplier; ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(8.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, LayoutScale(1.0f)); ImGui::PushStyleVar(ImGuiStyleVar_GrabRounding, LayoutScale(8.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.25f, 0.25f, 0.25f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.4f, 0.4f, 0.4f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.45f, 0.65f, 0.95f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, ImVec4(0.55f, 0.75f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); if (ImGui::SliderFloat("##value", &dlg_value, min_value * multiplier, max_value * multiplier, format, ImGuiSliderFlags_NoInput)) { dlg_value /= multiplier; if (IsEditingGameSettings(bsi) && dlg_value == default_value) bsi->DeleteValue(section, key); else bsi->SetFloatValue(section, key, dlg_value); SetSettingsChanged(bsi); } ImGui::PopStyleColor(7); ImGui::PopStyleVar(3); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(10.0f)); if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, g_large_font, ImVec2(0.5f, 0.0f))) { ImGui::CloseCurrentPopup(); } EndMenuButtons(); ImGui::EndPopup(); } ImGui::PopStyleVar(4); ImGui::PopFont(); } void FullscreenUI::DrawFloatSpinBoxSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, float default_value, float min_value, float max_value, float step_value, float multiplier, const char* format, bool enabled, float height, std::pair font, std::pair summary_font) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value = bsi->GetOptionalFloatValue(section, key, game_settings ? std::nullopt : std::optional(default_value)); const SmallString value_text = value.has_value() ? SmallString::from_sprintf(format, value.value() * multiplier) : SmallString(FSUI_VSTR("Use Global Setting")); static bool manual_input = false; if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font)) { ImGui::OpenPopup(title); manual_input = false; } ImGui::SetNextWindowSize(LayoutScale(500.0f, 192.0f)); ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::PushFont(g_large_font.first, g_large_font.second); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(20.0f, 20.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING, ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING)); bool is_open = true; if (ImGui::BeginPopupModal(title, &is_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) { BeginMenuButtons(); float dlg_value = value.value_or(default_value) * multiplier; bool dlg_value_changed = false; char str_value[32]; std::snprintf(str_value, std::size(str_value), format, dlg_value); if (manual_input) { const float end = ImGui::GetCurrentWindow()->WorkRect.GetWidth(); ImGui::SetNextItemWidth(end); // round trip to drop any suffixes (e.g. percent) if (auto tmp_value = StringUtil::FromChars(str_value); tmp_value.has_value()) { std::snprintf(str_value, std::size(str_value), ((tmp_value.value() - std::floor(tmp_value.value())) < 0.01f) ? "%.0f" : "%f", tmp_value.value()); } ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(8.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(12.0f, 10.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.25f, 0.25f, 0.25f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); if (ImGui::InputText("##value", str_value, std::size(str_value), ImGuiInputTextFlags_CharsDecimal)) { const float new_value = StringUtil::FromChars(str_value).value_or(dlg_value); dlg_value_changed = (dlg_value != new_value); dlg_value = new_value; } ImGui::PopStyleColor(4); ImGui::PopStyleVar(2); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(10.0f)); } else { const ImVec2& padding(ImGui::GetStyle().FramePadding); ImVec2 button_pos(ImGui::GetCursorPos()); // Align value text in middle. ImGui::SetCursorPosY( button_pos.y + ((LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) + padding.y * 2.0f) - g_large_font.second) * 0.5f); ImGui::TextUnformatted(str_value); float step = 0; if (FloatingButton( ICON_FA_CHEVRON_UP, padding.x, button_pos.y, -1.0f, -1.0f, 1.0f, 0.0f, true, g_large_font, &button_pos, true)) { step = step_value; } if (FloatingButton(ICON_FA_CHEVRON_DOWN, button_pos.x - padding.x, button_pos.y, -1.0f, -1.0f, -1.0f, 0.0f, true, g_large_font, &button_pos, true)) { step = -step_value; } if (FloatingButton( ICON_FA_KEYBOARD, button_pos.x - padding.x, button_pos.y, -1.0f, -1.0f, -1.0f, 0.0f, true, g_large_font, &button_pos)) { manual_input = true; } if (FloatingButton( ICON_FA_TRASH, button_pos.x - padding.x, button_pos.y, -1.0f, -1.0f, -1.0f, 0.0f, true, g_large_font, &button_pos)) { dlg_value = default_value * multiplier; dlg_value_changed = true; } if (step != 0) { dlg_value += step * multiplier; dlg_value_changed = true; } ImGui::SetCursorPosY(button_pos.y + (padding.y * 2.0f) + LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f)); } if (dlg_value_changed) { dlg_value = std::clamp(dlg_value / multiplier, min_value, max_value); if (IsEditingGameSettings(bsi) && dlg_value == default_value) bsi->DeleteValue(section, key); else bsi->SetFloatValue(section, key, dlg_value); SetSettingsChanged(bsi); } if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, g_large_font, ImVec2(0.5f, 0.0f))) { ImGui::CloseCurrentPopup(); } EndMenuButtons(); ImGui::EndPopup(); } ImGui::PopStyleVar(4); ImGui::PopFont(); } void FullscreenUI::DrawIntRectSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* left_key, int default_left, const char* top_key, int default_top, const char* right_key, int default_right, const char* bottom_key, int default_bottom, int min_value, int max_value, int step_value, const char* format, bool enabled, float height, std::pair font, std::pair summary_font) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional left_value = bsi->GetOptionalIntValue(section, left_key, game_settings ? std::nullopt : std::optional(default_left)); const std::optional top_value = bsi->GetOptionalIntValue(section, top_key, game_settings ? std::nullopt : std::optional(default_top)); const std::optional right_value = bsi->GetOptionalIntValue(section, right_key, game_settings ? std::nullopt : std::optional(default_right)); const std::optional bottom_value = bsi->GetOptionalIntValue(section, bottom_key, game_settings ? std::nullopt : std::optional(default_bottom)); const SmallString value_text = SmallString::from_format(FSUI_FSTR("{0}/{1}/{2}/{3}"), left_value.has_value() ? TinyString::from_sprintf(format, left_value.value()) : TinyString(FSUI_VSTR("Default")), top_value.has_value() ? TinyString::from_sprintf(format, top_value.value()) : TinyString(FSUI_VSTR("Default")), right_value.has_value() ? TinyString::from_sprintf(format, right_value.value()) : TinyString(FSUI_VSTR("Default")), bottom_value.has_value() ? TinyString::from_sprintf(format, bottom_value.value()) : TinyString(FSUI_VSTR("Default"))); static bool manual_input = false; if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font)) { ImGui::OpenPopup(title); manual_input = false; } ImGui::SetNextWindowSize(LayoutScale(550.0f, 370.0f)); ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::PushFont(g_large_font.first, g_large_font.second); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(20.0f, 20.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING, ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING)); bool is_open = true; if (ImGui::BeginPopupModal(title, &is_open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar)) { static constexpr const char* labels[4] = { FSUI_NSTR("Left: "), FSUI_NSTR("Top: "), FSUI_NSTR("Right: "), FSUI_NSTR("Bottom: "), }; const char* keys[4] = { left_key, top_key, right_key, bottom_key, }; int defaults[4] = { default_left, default_top, default_right, default_bottom, }; s32 values[4] = { static_cast(left_value.value_or(default_left)), static_cast(top_value.value_or(default_top)), static_cast(right_value.value_or(default_right)), static_cast(bottom_value.value_or(default_bottom)), }; BeginMenuButtons(); const ImVec2& padding(ImGui::GetStyle().FramePadding); for (u32 i = 0; i < std::size(labels); i++) { s32 dlg_value = values[i]; bool dlg_value_changed = false; char str_value[32]; std::snprintf(str_value, std::size(str_value), format, dlg_value); ImGui::PushID(i); const float midpoint = LayoutScale(125.0f); const float end = (ImGui::GetCurrentWindow()->WorkRect.GetWidth() - midpoint) + ImGui::GetStyle().WindowPadding.x; ImVec2 button_pos(ImGui::GetCursorPos()); // Align value text in middle. ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ((LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) + padding.y * 2.0f) - g_large_font.second) * 0.5f); ImGui::TextUnformatted(Host::TranslateToCString(TR_CONTEXT, labels[i])); ImGui::SameLine(midpoint); ImGui::SetNextItemWidth(end); button_pos.x = ImGui::GetCursorPosX(); if (manual_input) { ImGui::SetNextItemWidth(end); ImGui::SetCursorPosY(button_pos.y); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(8.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(12.0f, 10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, LayoutScale(1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.25f, 0.25f, 0.25f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.4f, 0.4f, 0.4f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); if (ImGui::InputText("##value", str_value, std::size(str_value), ImGuiInputTextFlags_CharsDecimal)) { const s32 new_value = StringUtil::FromChars(str_value).value_or(dlg_value); dlg_value_changed = (dlg_value != new_value); dlg_value = new_value; } ImGui::PopStyleColor(5); ImGui::PopStyleVar(3); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(10.0f)); } else { ImGui::TextUnformatted(str_value); s32 step = 0; if (FloatingButton( ICON_FA_CHEVRON_UP, padding.x, button_pos.y, -1.0f, -1.0f, 1.0f, 0.0f, true, g_large_font, &button_pos, true)) { step = step_value; } if (FloatingButton(ICON_FA_CHEVRON_DOWN, button_pos.x - padding.x, button_pos.y, -1.0f, -1.0f, -1.0f, 0.0f, true, g_large_font, &button_pos, true)) { step = -step_value; } if (FloatingButton(ICON_FA_KEYBOARD, button_pos.x - padding.x, button_pos.y, -1.0f, -1.0f, -1.0f, 0.0f, true, g_large_font, &button_pos)) { manual_input = true; } if (FloatingButton( ICON_FA_TRASH, button_pos.x - padding.x, button_pos.y, -1.0f, -1.0f, -1.0f, 0.0f, true, g_large_font, &button_pos)) { dlg_value = defaults[i]; dlg_value_changed = true; } if (step != 0) { dlg_value += step; dlg_value_changed = true; } ImGui::SetCursorPosY(button_pos.y + (padding.y * 2.0f) + LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + 10.0f)); } if (dlg_value_changed) { dlg_value = std::clamp(dlg_value, min_value, max_value); if (IsEditingGameSettings(bsi) && dlg_value == defaults[i]) bsi->DeleteValue(section, keys[i]); else bsi->SetIntValue(section, keys[i], dlg_value); SetSettingsChanged(bsi); } ImGui::PopID(); } if (MenuButtonWithoutSummary(FSUI_CSTR("OK"), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY, g_large_font, ImVec2(0.5f, 0.0f))) { ImGui::CloseCurrentPopup(); } EndMenuButtons(); ImGui::EndPopup(); } ImGui::PopStyleVar(4); ImGui::PopFont(); } void FullscreenUI::DrawStringListSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, const char* default_value, const char* const* options, const char* const* option_values, size_t option_count, bool translate_options, bool enabled, float height, std::pair font, std::pair summary_font, const char* translation_ctx) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value( bsi->GetOptionalSmallStringValue(section, key, game_settings ? std::nullopt : std::optional(default_value))); if (option_count == 0) { // select from null entry while (options && options[option_count] != nullptr) option_count++; } size_t index = option_count; if (value.has_value()) { for (size_t i = 0; i < option_count; i++) { if (value == option_values[i]) { index = i; break; } } } if (MenuButtonWithValue(title, summary, value.has_value() ? ((index < option_count) ? (translate_options ? Host::TranslateToCString(translation_ctx, options[index]) : options[index]) : FSUI_CSTR("Unknown")) : FSUI_CSTR("Use Global Setting"), enabled, height, font, summary_font)) { ImGuiFullscreen::ChoiceDialogOptions cd_options; cd_options.reserve(option_count + 1); if (game_settings) cd_options.emplace_back(FSUI_STR("Use Global Setting"), !value.has_value()); for (size_t i = 0; i < option_count; i++) { cd_options.emplace_back(translate_options ? Host::TranslateToString(translation_ctx, options[i]) : std::string(options[i]), (value.has_value() && i == static_cast(index))); } OpenChoiceDialog(title, false, std::move(cd_options), [game_settings, section, key, option_values](s32 index, const std::string& title, bool checked) { if (index >= 0) { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); if (game_settings) { if (index == 0) bsi->DeleteValue(section, key); else bsi->SetStringValue(section, key, option_values[index - 1]); } else { bsi->SetStringValue(section, key, option_values[index]); } SetSettingsChanged(bsi); } CloseChoiceDialog(); }); } } void FullscreenUI::DrawStringListSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, const char* default_value, SettingInfo::GetOptionsCallback option_callback, bool enabled, float height, std::pair font, std::pair summary_font) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value( bsi->GetOptionalSmallStringValue(section, key, game_settings ? std::nullopt : std::optional(default_value))); if (MenuButtonWithValue( title, summary, value.has_value() ? value->c_str() : FSUI_CSTR("Use Global Setting"), enabled, height, font, summary_font)) { std::vector> raw_options(option_callback()); ImGuiFullscreen::ChoiceDialogOptions cd_options; cd_options.reserve(raw_options.size() + 1); if (game_settings) cd_options.emplace_back(FSUI_STR("Use Global Setting"), !value.has_value()); for (size_t i = 0; i < raw_options.size(); i++) cd_options.emplace_back(raw_options[i].second, (value.has_value() && value.value() == raw_options[i].first)); OpenChoiceDialog(title, false, std::move(cd_options), [game_settings, section, key, raw_options = std::move(raw_options)](s32 index, const std::string& title, bool checked) { if (index >= 0) { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); if (game_settings) { if (index == 0) bsi->DeleteValue(section, key); else bsi->SetStringValue(section, key, raw_options[index - 1].first.c_str()); } else { bsi->SetStringValue(section, key, raw_options[index].first.c_str()); } SetSettingsChanged(bsi); } CloseChoiceDialog(); }); } } void FullscreenUI::DrawFloatListSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, float default_value, const char* const* options, const float* option_values, size_t option_count, bool translate_options, bool enabled, float height, std::pair font, std::pair summary_font) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value( bsi->GetOptionalFloatValue(section, key, game_settings ? std::nullopt : std::optional(default_value))); if (option_count == 0) { // select from null entry while (options && options[option_count] != nullptr) option_count++; } size_t index = option_count; if (value.has_value()) { for (size_t i = 0; i < option_count; i++) { if (value == option_values[i]) { index = i; break; } } } if (MenuButtonWithValue(title, summary, value.has_value() ? ((index < option_count) ? (translate_options ? Host::TranslateToCString(TR_CONTEXT, options[index]) : options[index]) : FSUI_CSTR("Unknown")) : FSUI_CSTR("Use Global Setting"), enabled, height, font, summary_font)) { ImGuiFullscreen::ChoiceDialogOptions cd_options; cd_options.reserve(option_count + 1); if (game_settings) cd_options.emplace_back(FSUI_STR("Use Global Setting"), !value.has_value()); for (size_t i = 0; i < option_count; i++) { cd_options.emplace_back(translate_options ? Host::TranslateToString(TR_CONTEXT, options[i]) : std::string(options[i]), (value.has_value() && i == static_cast(index))); } OpenChoiceDialog(title, false, std::move(cd_options), [game_settings, section, key, option_values](s32 index, const std::string& title, bool checked) { if (index >= 0) { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); if (game_settings) { if (index == 0) bsi->DeleteValue(section, key); else bsi->SetFloatValue(section, key, option_values[index - 1]); } else { bsi->SetFloatValue(section, key, option_values[index]); } SetSettingsChanged(bsi); } CloseChoiceDialog(); }); } } template void FullscreenUI::DrawEnumSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, DataType default_value, std::optional (*from_string_function)(const char* str), const char* (*to_string_function)(DataType value), const char* (*to_display_string_function)(DataType value), SizeType option_count, bool enabled, float height, std::pair font, std::pair summary_font) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value(bsi->GetOptionalSmallStringValue( section, key, game_settings ? std::nullopt : std::optional(to_string_function(default_value)))); const std::optional typed_value(value.has_value() ? from_string_function(value->c_str()) : std::nullopt); if (MenuButtonWithValue(title, summary, typed_value.has_value() ? to_display_string_function(typed_value.value()) : FSUI_CSTR("Use Global Setting"), enabled, height, font, summary_font)) { ImGuiFullscreen::ChoiceDialogOptions cd_options; cd_options.reserve(static_cast(option_count) + 1); if (game_settings) cd_options.emplace_back(FSUI_CSTR("Use Global Setting"), !value.has_value()); for (u32 i = 0; i < static_cast(option_count); i++) cd_options.emplace_back(to_display_string_function(static_cast(i)), (typed_value.has_value() && i == static_cast(typed_value.value()))); OpenChoiceDialog( title, false, std::move(cd_options), [section, key, to_string_function, game_settings](s32 index, const std::string& title, bool checked) { if (index >= 0) { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); if (game_settings) { if (index == 0) bsi->DeleteValue(section, key); else bsi->SetStringValue(section, key, to_string_function(static_cast(index - 1))); } else { bsi->SetStringValue(section, key, to_string_function(static_cast(index))); } SetSettingsChanged(bsi); } CloseChoiceDialog(); }); } } void FullscreenUI::DrawFolderSetting(SettingsInterface* bsi, const char* title, const char* section, const char* key, const std::string& runtime_var, float height /* = ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT */, std::pair font /* = g_large_font */, std::pair summary_font /* = g_medium_font */) { if (MenuButton(title, runtime_var.c_str())) { OpenFileSelector(title, true, [game_settings = IsEditingGameSettings(bsi), section = std::string(section), key = std::string(key)](const std::string& dir) { if (dir.empty()) return; auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); std::string relative_path(Path::MakeRelative(dir, EmuFolders::DataRoot)); bsi->SetStringValue(section.c_str(), key.c_str(), relative_path.c_str()); SetSettingsChanged(bsi); Host::RunOnCPUThread(&VMManager::Internal::UpdateEmuFolders); s_cover_image_map.clear(); CloseFileSelector(); }); } } void FullscreenUI::DrawPathSetting(SettingsInterface* bsi, const char* title, const char* section, const char* key, const char* default_value, bool enabled /* = true */, float height /* = ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT */, std::pair font /* = g_large_font */, std::pair summary_font /* = g_medium_font */) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value( bsi->GetOptionalSmallStringValue(section, key, game_settings ? std::nullopt : std::optional(default_value))); if (MenuButton(title, value.has_value() ? value->c_str() : FSUI_CSTR("Use Global Setting"))) { auto callback = [game_settings = IsEditingGameSettings(bsi), section = std::string(section), key = std::string(key)]( const std::string& dir) { if (dir.empty()) return; auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); std::string relative_path(Path::MakeRelative(dir, EmuFolders::DataRoot)); bsi->SetStringValue(section.c_str(), key.c_str(), relative_path.c_str()); SetSettingsChanged(bsi); Host::RunOnCPUThread(&VMManager::Internal::UpdateEmuFolders); s_cover_image_map.clear(); CloseFileSelector(); }; std::string initial_path; if (value.has_value()) initial_path = Path::GetDirectory(value.value()); OpenFileSelector(title, false, std::move(callback), {"*"}, std::move(initial_path)); } } void FullscreenUI::DrawIPAddressSetting(SettingsInterface* bsi, const char* title, const char* summary, const char* section, const char* key, const char* default_value, bool enabled, float height, std::pair font, std::pair summary_font, IPAddressType ip_type) { const bool game_settings = IsEditingGameSettings(bsi); const std::optional value( bsi->GetOptionalSmallStringValue(section, key, game_settings ? std::nullopt : std::optional(default_value))); const SmallString value_text = value.has_value() ? value.value() : SmallString(FSUI_VSTR("Use Global Setting")); static std::array ip_octets = {0, 0, 0, 0}; if (MenuButtonWithValue(title, summary, value_text.c_str(), enabled, height, font, summary_font)) { const std::string current_ip = value.has_value() ? std::string(value->c_str()) : std::string(default_value); std::istringstream iss(current_ip); std::string segment; int i = 0; while (std::getline(iss, segment, '.') && i < 4) { ip_octets[i] = std::clamp(std::atoi(segment.c_str()), 0, 255); i++; } for (; i < 4; i++) ip_octets[i] = 0; char ip_str[16]; std::snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d", ip_octets[0], ip_octets[1], ip_octets[2], ip_octets[3]); const char* message; switch (ip_type) { case IPAddressType::DNS1: case IPAddressType::DNS2: message = FSUI_CSTR("Enter the DNS server address"); break; case IPAddressType::Gateway: message = FSUI_CSTR("Enter the Gateway address"); break; case IPAddressType::SubnetMask: message = FSUI_CSTR("Enter the Subnet Mask"); break; case IPAddressType::PS2IP: message = FSUI_CSTR("Enter the PS2 IP address"); break; case IPAddressType::Other: default: message = FSUI_CSTR("Enter the IP address"); break; } ImGuiFullscreen::CloseInputDialog(); std::string ip_str_value(ip_str); ImGuiFullscreen::OpenInputStringDialog( title, message, "", std::string(FSUI_ICONSTR(ICON_FA_CHECK, "OK")), [bsi, section, key, default_value](std::string text) { // Validate and clean up the IP address std::array new_octets = {0, 0, 0, 0}; std::istringstream iss(text); std::string segment; int i = 0; while (std::getline(iss, segment, '.') && i < 4) { new_octets[i] = std::clamp(std::atoi(segment.c_str()), 0, 255); i++; } char ip_str[16]; std::snprintf(ip_str, sizeof(ip_str), "%d.%d.%d.%d", new_octets[0], new_octets[1], new_octets[2], new_octets[3]); if (IsEditingGameSettings(bsi) && strcmp(ip_str, default_value) == 0) bsi->DeleteValue(section, key); else bsi->SetStringValue(section, key, ip_str); SetSettingsChanged(bsi); }, ip_str_value, ImGuiFullscreen::InputFilterType::IPAddress); } } void FullscreenUI::StartAutomaticBinding(u32 port) { // messy because the enumeration has to happen on the input thread Host::RunOnCPUThread([port]() { std::vector> devices(InputManager::EnumerateDevices()); MTGS::RunOnGSThread([port, devices = std::move(devices)]() { if (devices.empty()) { ShowToast({}, FSUI_STR("Automatic binding failed, no devices are available.")); return; } std::vector names; ImGuiFullscreen::ChoiceDialogOptions options; options.reserve(devices.size()); names.reserve(devices.size()); for (auto& [name, display_name] : devices) { if (!StringUtil::compareNoCase(name, display_name)) options.emplace_back(fmt::format("{}: {}", name, display_name), false); else options.emplace_back(std::move(display_name), false); names.push_back(std::move(name)); } OpenChoiceDialog(FSUI_CSTR("Select Device"), false, std::move(options), [port, names = std::move(names)](s32 index, const std::string& title, bool checked) { if (index < 0) return; // since this is working with the device, it has to happen on the input thread too Host::RunOnCPUThread([port, name = std::move(names[index])]() { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(); const bool result = Pad::MapController(*bsi, port, InputManager::GetGenericBindingMapping(name)); SetSettingsChanged(bsi); // and the toast needs to happen on the UI thread. MTGS::RunOnGSThread([result, name = std::move(name)]() { ShowToast({}, result ? fmt::format(FSUI_FSTR("Automatic mapping completed for {}."), name) : fmt::format(FSUI_FSTR("Automatic mapping failed for {}."), name)); }); }); CloseChoiceDialog(); }); }); }); } void FullscreenUI::DrawSettingInfoSetting(SettingsInterface* bsi, const char* section, const char* key, const SettingInfo& si, const char* translation_ctx) { SmallString title; title.format(ICON_FA_GEAR " {}", Host::TranslateToStringView(translation_ctx, si.display_name)); switch (si.type) { case SettingInfo::Type::Boolean: DrawToggleSetting(bsi, title.c_str(), si.description, section, key, si.BooleanDefaultValue(), true, false); break; case SettingInfo::Type::Integer: DrawIntRangeSetting(bsi, title.c_str(), si.description, section, key, si.IntegerDefaultValue(), si.IntegerMinValue(), si.IntegerMaxValue(), si.format, true); break; case SettingInfo::Type::IntegerList: DrawIntListSetting( bsi, title.c_str(), si.description, section, key, si.IntegerDefaultValue(), si.options, 0, true, si.IntegerMinValue()); break; case SettingInfo::Type::Float: DrawFloatSpinBoxSetting(bsi, title.c_str(), si.description, section, key, si.FloatDefaultValue(), si.FloatMinValue(), si.FloatMaxValue(), si.FloatStepValue(), si.multiplier, si.format, true); break; case SettingInfo::Type::StringList: { if (si.get_options) { DrawStringListSetting(bsi, title.c_str(), si.description, section, key, si.StringDefaultValue(), si.get_options, true); } else { DrawStringListSetting( bsi, title.c_str(), si.description, section, key, si.StringDefaultValue(), si.options, si.options, 0, false, true, LAYOUT_MENU_BUTTON_HEIGHT, g_large_font, g_medium_font, translation_ctx); } } break; case SettingInfo::Type::Path: DrawPathSetting(bsi, title.c_str(), section, key, si.StringDefaultValue(), true); break; default: break; } } void FullscreenUI::SwitchToSettings() { s_game_settings_entry.reset(); s_game_settings_interface.reset(); s_game_patch_list = {}; s_enabled_game_patch_cache = {}; s_game_cheats_list = {}; s_enabled_game_cheat_cache = {}; PopulateGraphicsAdapterList(); s_current_main_window = MainWindowType::Settings; s_settings_page = SettingsPage::Interface; } void FullscreenUI::SwitchToGameSettings(const std::string_view serial, u32 crc) { s_game_settings_entry.reset(); s_game_settings_interface = std::make_unique(VMManager::GetGameSettingsPath(serial, crc)); s_game_settings_interface->Load(); PopulatePatchesAndCheatsList(serial, crc); s_current_main_window = MainWindowType::Settings; s_settings_page = SettingsPage::Summary; QueueResetFocus(FocusResetType::WindowChanged); } void FullscreenUI::SwitchToGameSettings() { if (s_current_disc_serial.empty() || s_current_disc_crc == 0) return; auto lock = GameList::GetLock(); const GameList::Entry* entry = GameList::GetEntryForPath(s_current_disc_path.c_str()); if (!entry) entry = GameList::GetEntryBySerialAndCRC(s_current_disc_serial.c_str(), s_current_disc_crc); if (entry) SwitchToGameSettings(entry); } void FullscreenUI::SwitchToGameSettings(const std::string& path) { auto lock = GameList::GetLock(); const GameList::Entry* entry = GameList::GetEntryForPath(path.c_str()); if (entry) SwitchToGameSettings(entry); } void FullscreenUI::SwitchToGameSettings(const GameList::Entry* entry) { SwitchToGameSettings((entry->type != GameList::EntryType::ELF) ? std::string_view(entry->serial) : std::string_view(), entry->crc); s_game_settings_entry = std::make_unique(*entry); } void FullscreenUI::PopulateGraphicsAdapterList() { s_graphics_adapter_list_cache = GSGetAdapterInfo(GSConfig.Renderer); } void FullscreenUI::PopulateGameListDirectoryCache(SettingsInterface* si) { s_game_list_directories_cache.clear(); for (std::string& dir : si->GetStringList("GameList", "Paths")) s_game_list_directories_cache.emplace_back(std::move(dir), false); for (std::string& dir : si->GetStringList("GameList", "RecursivePaths")) s_game_list_directories_cache.emplace_back(std::move(dir), true); } void FullscreenUI::PopulatePatchesAndCheatsList(const std::string_view serial, u32 crc) { constexpr auto sort_patches = [](std::vector& list) { std::sort(list.begin(), list.end(), [](const Patch::PatchInfo& lhs, const Patch::PatchInfo& rhs) { return lhs.name < rhs.name; }); }; s_game_patch_list = Patch::GetPatchInfo(serial, crc, false, true, nullptr); sort_patches(s_game_patch_list); s_game_cheats_list = Patch::GetPatchInfo(serial, crc, true, true, &s_game_cheat_unlabelled_count); sort_patches(s_game_cheats_list); pxAssert(s_game_settings_interface); s_enabled_game_patch_cache = s_game_settings_interface->GetStringList(Patch::PATCHES_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY); s_enabled_game_cheat_cache = s_game_settings_interface->GetStringList(Patch::CHEATS_CONFIG_SECTION, Patch::PATCH_ENABLE_CONFIG_KEY); } void FullscreenUI::DoCopyGameSettings() { if (!s_game_settings_interface) return; Pcsx2Config::CopyConfiguration(s_game_settings_interface.get(), *GetEditingSettingsInterface(false)); Pcsx2Config::ClearInvalidPerGameConfiguration(s_game_settings_interface.get()); SetSettingsChanged(s_game_settings_interface.get()); ShowToast(std::string(), fmt::format(FSUI_FSTR("Game settings initialized with global settings for '{}'."), Path::GetFileTitle(s_game_settings_interface->GetFileName()))); } void FullscreenUI::DoClearGameSettings() { if (!s_game_settings_interface) return; Pcsx2Config::ClearConfiguration(s_game_settings_interface.get()); SetSettingsChanged(s_game_settings_interface.get()); ShowToast(std::string(), fmt::format(FSUI_FSTR("Game settings have been cleared for '{}'."), Path::GetFileTitle(s_game_settings_interface->GetFileName()))); } void FullscreenUI::DrawSettingsWindow() { ImGuiIO& io = ImGui::GetIO(); const ImVec2 heading_size = ImVec2(io.DisplaySize.x, LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY) + (LayoutScale(LAYOUT_MENU_BUTTON_Y_PADDING) * 2.0f) + LayoutScale(2.0f)); const bool using_custom_bg = !VMManager::HasValidVM() && s_custom_background_enabled && s_custom_background_texture; const float header_bg_alpha = VMManager::HasValidVM() ? 0.90f : 1.0f; const float content_bg_alpha = using_custom_bg ? 0.0f : (VMManager::HasValidVM() ? 0.90f : 1.0f); SettingsInterface* bsi = GetEditingSettingsInterface(); const bool game_settings = IsEditingGameSettings(bsi); const bool show_advanced_settings = ShouldShowAdvancedSettings(bsi); if (BeginFullscreenWindow( ImVec2(0.0f, 0.0f), heading_size, "settings_category", ImVec4(UIPrimaryColor.x, UIPrimaryColor.y, UIPrimaryColor.z, header_bg_alpha))) { static constexpr float ITEM_WIDTH = 25.0f; static constexpr const char* global_icons[] = { ICON_FA_TV, ICON_PF_MICROCHIP, ICON_PF_GEARS_OPTIONS_SETTINGS, ICON_PF_PICTURE, ICON_PF_SOUND, ICON_PF_MEMORY_CARD, ICON_FA_NETWORK_WIRED, ICON_FA_FOLDER_OPEN, ICON_FA_TROPHY, ICON_PF_GAMEPAD_ALT, ICON_PF_KEYBOARD_ALT, ICON_FA_TRIANGLE_EXCLAMATION, }; static constexpr const char* per_game_icons[] = { ICON_FA_INFO, ICON_PF_GEARS_OPTIONS_SETTINGS, ICON_FA_BANDAGE, ICON_PF_INFINITY, ICON_PF_PICTURE, ICON_PF_SOUND, ICON_PF_MEMORY_CARD, ICON_FA_TRIANGLE_EXCLAMATION, }; static constexpr SettingsPage global_pages[] = { SettingsPage::Interface, SettingsPage::BIOS, SettingsPage::Emulation, SettingsPage::Graphics, SettingsPage::Audio, SettingsPage::MemoryCard, SettingsPage::NetworkHDD, SettingsPage::Folders, SettingsPage::Achievements, SettingsPage::Controller, SettingsPage::Hotkey, SettingsPage::Advanced, }; static constexpr SettingsPage per_game_pages[] = { SettingsPage::Summary, SettingsPage::Emulation, SettingsPage::Patches, SettingsPage::Cheats, SettingsPage::Graphics, SettingsPage::Audio, SettingsPage::MemoryCard, SettingsPage::GameFixes, }; static constexpr const char* titles[] = { FSUI_NSTR("Summary"), FSUI_NSTR("Interface Settings"), FSUI_NSTR("BIOS Settings"), FSUI_NSTR("Emulation Settings"), FSUI_NSTR("Graphics Settings"), FSUI_NSTR("Audio Settings"), FSUI_NSTR("Memory Card Settings"), FSUI_NSTR("Network & HDD Settings"), FSUI_NSTR("Folder Settings"), FSUI_NSTR("Achievements Settings"), FSUI_NSTR("Controller Settings"), FSUI_NSTR("Hotkey Settings"), FSUI_NSTR("Advanced Settings"), FSUI_NSTR("Patches"), FSUI_NSTR("Cheats"), FSUI_NSTR("Game Fixes"), }; const u32 count = game_settings ? (show_advanced_settings ? std::size(per_game_pages) : (std::size(per_game_pages) - 1)) : std::size(global_pages); const char* const* icons = game_settings ? per_game_icons : global_icons; const SettingsPage* pages = game_settings ? per_game_pages : global_pages; u32 index = 0; for (u32 i = 0; i < count; i++) { if (pages[i] == s_settings_page) { index = i; break; } } BeginNavBar(); if (!ImGui::IsPopupOpen(0u, ImGuiPopupFlags_AnyPopup)) { if (ImGui::IsKeyPressed(ImGuiKey_GamepadDpadLeft, true) || ImGui::IsKeyPressed(ImGuiKey_NavGamepadTweakSlow, true) || ImGui::IsKeyPressed(ImGuiKey_LeftArrow, true)) { index = (index == 0) ? (count - 1) : (index - 1); s_settings_page = pages[index]; QueueResetFocus(FocusResetType::WindowChanged); } else if (ImGui::IsKeyPressed(ImGuiKey_GamepadDpadRight, true) || ImGui::IsKeyPressed(ImGuiKey_NavGamepadTweakFast, true) || ImGui::IsKeyPressed(ImGuiKey_RightArrow, true)) { index = (index + 1) % count; s_settings_page = pages[index]; QueueResetFocus(FocusResetType::WindowChanged); } } if (NavButton(ICON_PF_BACKWARD, true, true)) { if (VMManager::HasValidVM()) ReturnToPreviousWindow(); else SwitchToLanding(); } if (s_game_settings_entry) { NavTitle(SmallString::from_format( "{} ({})", Host::TranslateToCString(TR_CONTEXT, titles[static_cast(pages[index])]), s_game_settings_entry->GetTitle(true))); } else { NavTitle(Host::TranslateToCString(TR_CONTEXT, titles[static_cast(pages[index])])); } RightAlignNavButtons(count, ITEM_WIDTH, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); for (u32 i = 0; i < count; i++) { if (NavButton(icons[i], i == index, true, ITEM_WIDTH, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY)) { s_settings_page = pages[i]; QueueResetFocus(FocusResetType::WindowChanged); } } EndNavBar(); } EndFullscreenWindow(); // we have to do this here, because otherwise it uses target, and jumps a frame later. if (IsFocusResetQueued()) if (FocusResetType focus_reset = GetQueuedFocusResetType(); focus_reset != FocusResetType::None && focus_reset != FocusResetType::PopupOpened && focus_reset != FocusResetType::PopupClosed) { ImGui::SetNextWindowScroll(ImVec2(0.0f, 0.0f)); } if (BeginFullscreenWindow( ImVec2(0.0f, heading_size.y), ImVec2(io.DisplaySize.x, io.DisplaySize.y - heading_size.y - LayoutScale(LAYOUT_FOOTER_HEIGHT)), TinyString::from_format("settings_page_{}", static_cast(s_settings_page)).c_str(), ImVec4(UIBackgroundColor.x, UIBackgroundColor.y, UIBackgroundColor.z, content_bg_alpha), 0.0f, ImVec2(ImGuiFullscreen::LAYOUT_MENU_WINDOW_X_PADDING, 0.0f))) { ResetFocusHere(); if (ImGui::IsWindowFocused() && WantsToCloseMenu()) ReturnToPreviousWindow(); auto lock = Host::GetSettingsLock(); switch (s_settings_page) { case SettingsPage::Summary: DrawSummarySettingsPage(); break; case SettingsPage::Interface: DrawInterfaceSettingsPage(); break; case SettingsPage::BIOS: DrawBIOSSettingsPage(); break; case SettingsPage::Emulation: DrawEmulationSettingsPage(); break; case SettingsPage::Graphics: DrawGraphicsSettingsPage(bsi, show_advanced_settings); break; case SettingsPage::Audio: DrawAudioSettingsPage(); break; case SettingsPage::MemoryCard: DrawMemoryCardSettingsPage(); break; case SettingsPage::NetworkHDD: DrawNetworkHDDSettingsPage(); break; case SettingsPage::Folders: DrawFoldersSettingsPage(); break; case SettingsPage::Achievements: DrawAchievementsSettingsPage(lock); break; case SettingsPage::Controller: DrawControllerSettingsPage(); break; case SettingsPage::Hotkey: DrawHotkeySettingsPage(); break; case SettingsPage::Patches: DrawPatchesOrCheatsSettingsPage(false); break; case SettingsPage::Cheats: DrawPatchesOrCheatsSettingsPage(true); break; case SettingsPage::Advanced: DrawAdvancedSettingsPage(); break; case SettingsPage::GameFixes: DrawGameFixesSettingsPage(); break; default: break; } } EndFullscreenWindow(); if (IsGamepadInputSource()) { const bool circleOK = ImGui::GetIO().ConfigNavSwapGamepadButtons; SetFullscreenFooterText(std::array{ std::make_pair(ICON_PF_DPAD_LEFT_RIGHT, FSUI_VSTR("Change Page")), std::make_pair(ICON_PF_DPAD_UP_DOWN, FSUI_VSTR("Navigate")), std::make_pair(circleOK ? ICON_PF_BUTTON_CIRCLE : ICON_PF_BUTTON_CROSS, FSUI_VSTR("Select")), std::make_pair(circleOK ? ICON_PF_BUTTON_CROSS : ICON_PF_BUTTON_CIRCLE, FSUI_VSTR("Back")), }); } else { SetFullscreenFooterText(std::array{ std::make_pair(ICON_PF_ARROW_LEFT ICON_PF_ARROW_RIGHT, FSUI_VSTR("Change Page")), std::make_pair(ICON_PF_ARROW_UP ICON_PF_ARROW_DOWN, FSUI_VSTR("Navigate")), std::make_pair(ICON_PF_ENTER, FSUI_VSTR("Select")), std::make_pair(ICON_PF_ESC, FSUI_VSTR("Back")), }); } } void FullscreenUI::DrawSummarySettingsPage() { SettingsInterface* bsi = GetEditingSettingsInterface(); BeginMenuButtons(); MenuHeading(FSUI_CSTR("Details")); if (s_game_settings_entry) { if (MenuButton(FSUI_ICONSTR(ICON_FA_TAG, "Title"), s_game_settings_entry->GetTitle(true).c_str(), true)) CopyTextToClipboard(FSUI_STR("Game title copied to clipboard."), s_game_settings_entry->GetTitle(true)); if (MenuButton(FSUI_ICONSTR(ICON_FA_PAGER, "Serial"), s_game_settings_entry->serial.c_str(), true)) CopyTextToClipboard(FSUI_STR("Game serial copied to clipboard."), s_game_settings_entry->serial); if (MenuButton(FSUI_ICONSTR(ICON_FA_CODE, "CRC"), fmt::format("{:08X}", s_game_settings_entry->crc).c_str(), true)) CopyTextToClipboard(FSUI_STR("Game CRC copied to clipboard."), fmt::format("{:08X}", s_game_settings_entry->crc)); if (MenuButton(FSUI_ICONSTR(ICON_FA_BOX, "Type"), GameList::EntryTypeToString(s_game_settings_entry->type, true), true)) CopyTextToClipboard(FSUI_STR("Game type copied to clipboard."), GameList::EntryTypeToString(s_game_settings_entry->type, true)); if (MenuButton(FSUI_ICONSTR(ICON_FA_GLOBE, "Region"), GameList::RegionToString(s_game_settings_entry->region, true), true)) CopyTextToClipboard(FSUI_STR("Game region copied to clipboard."), GameList::RegionToString(s_game_settings_entry->region, true)); if (MenuButton(FSUI_ICONSTR(ICON_FA_STAR, "Compatibility Rating"), GameList::EntryCompatibilityRatingToString(s_game_settings_entry->compatibility_rating, true), true)) { CopyTextToClipboard(FSUI_STR("Game compatibility copied to clipboard."), GameList::EntryCompatibilityRatingToString(s_game_settings_entry->compatibility_rating, true)); } if (MenuButton(FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Path"), s_game_settings_entry->path.c_str(), true)) CopyTextToClipboard(FSUI_STR("Game path copied to clipboard."), s_game_settings_entry->path); if (s_game_settings_entry->type == GameList::EntryType::ELF) { const SmallString iso_path = bsi->GetSmallStringValue("EmuCore", "DiscPath"); if (MenuButton(FSUI_ICONSTR(ICON_FA_COMPACT_DISC, "Disc Path"), iso_path.empty() ? "No Disc" : iso_path.c_str())) { auto callback = [](const std::string& path) { if (!path.empty()) { { auto lock = Host::GetSettingsLock(); if (s_game_settings_interface) { s_game_settings_interface->SetStringValue("EmuCore", "DiscPath", path.c_str()); s_game_settings_interface->Save(); } } if (s_game_settings_entry) { // re-scan the entry to update its serial. if (GameList::RescanPath(s_game_settings_entry->path)) { auto lock = GameList::GetLock(); const GameList::Entry* entry = GameList::GetEntryForPath(s_game_settings_entry->path.c_str()); if (entry) *s_game_settings_entry = *entry; } } } QueueResetFocus(FocusResetType::PopupClosed); CloseFileSelector(); }; OpenFileSelector(FSUI_ICONSTR(ICON_FA_COMPACT_DISC, "Select Disc Path"), false, std::move(callback), GetDiscImageFilters()); } } const std::optional value = bsi->GetOptionalSmallStringValue("EmuCore", "InputProfileName", "Shared"); if (MenuButtonWithValue(FSUI_ICONSTR_S(ICON_PF_GAMEPAD_ALT, "Input Profile", "input_profile"), FSUI_CSTR("The selected input profile will be used for this game."), value.has_value() ? value->c_str() : FSUI_CSTR("Shared"), true)) { ImGuiFullscreen::ChoiceDialogOptions options; std::vector names; options.emplace_back(fmt::format(FSUI_FSTR("Shared")), (value.has_value() && !value->empty() && value == "Shared") ? true : false); names.emplace_back("Shared"); for (const std::string& name : Pad::GetInputProfileNames()) { options.emplace_back(name, (value.has_value() && !value->empty() && value == name) ? true : false); names.push_back(std::move(name)); } OpenChoiceDialog(FSUI_CSTR("Input Profile"), false, options, [game_settings = IsEditingGameSettings(bsi), names = std::move(names)](s32 index, const std::string& title, bool checked) { if (index < 0) return; auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetStringValue("EmuCore", "InputProfileName", names[index].c_str()); SetSettingsChanged(bsi); CloseChoiceDialog(); }); } } else { MenuButton(FSUI_ICONSTR(ICON_FA_BAN, "Cannot show details for games which were not scanned in the game list."), ""); } MenuHeading(FSUI_CSTR("Options")); if (MenuButton(FSUI_ICONSTR(ICON_FA_COPY, "Copy Settings"), FSUI_CSTR("Copies the current global settings to this game."))) DoCopyGameSettings(); if (MenuButton(FSUI_ICONSTR(ICON_FA_TRASH, "Clear Settings"), FSUI_CSTR("Clears all settings set for this game."))) DoClearGameSettings(); EndMenuButtons(); } void FullscreenUI::DrawInterfaceSettingsPage() { static constexpr const char* s_theme_name[] = { FSUI_NSTR("Dark"), FSUI_NSTR("Light"), FSUI_NSTR("Grey Matter"), FSUI_NSTR("Untouched Lagoon"), FSUI_NSTR("Baby Pastel"), FSUI_NSTR("Pizza Time!"), FSUI_NSTR("PCSX2 Blue"), FSUI_NSTR("Scarlet Devil"), FSUI_NSTR("Violet Angel"), FSUI_NSTR("Cobalt Sky"), FSUI_NSTR("AMOLED"), }; static constexpr const char* s_theme_value[] = { "Dark", "Light", "GreyMatter", "UntouchedLagoon", "BabyPastel", "PizzaBrown", "PCSX2Blue", "ScarletDevil", "VioletAngel", "CobaltSky", "AMOLED", }; SettingsInterface* bsi = GetEditingSettingsInterface(); BeginMenuButtons(); MenuHeading(FSUI_CSTR("Appearance")); DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINTBRUSH, "Theme"), FSUI_CSTR("Selects the color style to be used for Big Picture Mode."), "UI", "FullscreenUITheme", "Dark", s_theme_name, s_theme_value, std::size(s_theme_name), true); DrawToggleSetting( bsi, FSUI_ICONSTR(ICON_FA_LIST, "Default To Game List"), FSUI_CSTR("When Big Picture mode is started, the game list will be displayed instead of the main menu."), "UI", "FullscreenUIDefaultToGameList", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CIRCLE_INFO, "Use Save State Selector"), FSUI_CSTR("Show a save state selector UI when switching slots instead of showing a notification bubble."), "EmuCore", "UseSavestateSelector", true); MenuHeading(FSUI_CSTR("Background")); std::string background_path = bsi->GetStringValue("UI", "FSUIBackgroundPath", ""); std::string background_display = FSUI_STR("None"); if (!background_path.empty()) { background_display = Path::GetFileName(background_path); } if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_IMAGE, "Background Image"), FSUI_CSTR("Select a custom background image to use in Big Picture Mode menus.\n\nSupported formats: PNG, JPG, JPEG, BMP."), background_display.c_str())) { OpenFileSelector(FSUI_ICONSTR(ICON_FA_IMAGE, "Select Background Image"), false, [](const std::string& path) { if (!path.empty()) { { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(false); std::string relative_path = Path::MakeRelative(path, EmuFolders::DataRoot); bsi->SetStringValue("UI", "FSUIBackgroundPath", relative_path.c_str()); bsi->SetBoolValue("UI", "FSUIBackgroundEnabled", true); SetSettingsChanged(bsi); } LoadCustomBackground(); } CloseFileSelector(); }, GetImageFileFilters()); } if (MenuButton(FSUI_ICONSTR(ICON_FA_XMARK, "Clear Background Image"), FSUI_CSTR("Removes the custom background image."))) { bsi->DeleteValue("UI", "FSUIBackgroundPath"); SetSettingsChanged(bsi); s_custom_background_texture.reset(); s_custom_background_path.clear(); s_custom_background_enabled = false; } DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_DROPLET, "Background Opacity"), FSUI_CSTR("Sets the transparency of the custom background image."), "UI", "FSUIBackgroundOpacity", 100, 0, 100, "%d%%"); static constexpr const char* s_background_mode_names[] = { FSUI_NSTR("Fit"), FSUI_NSTR("Fill"), FSUI_NSTR("Stretch"), FSUI_NSTR("Center"), FSUI_NSTR("Tile"), }; static constexpr const char* s_background_mode_values[] = { "fit", "fill", "stretch", "center", "tile", }; DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_EXPAND, "Background Mode"), FSUI_CSTR("Select how to display the background image."), "UI", "FSUIBackgroundMode", "fit", s_background_mode_names, s_background_mode_values, std::size(s_background_mode_names), true); MenuHeading(FSUI_CSTR("Behaviour")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_SNOOZE, "Inhibit Screensaver"), FSUI_CSTR("Prevents the screen saver from activating and the host from sleeping while emulation is running."), "EmuCore", "InhibitScreensaver", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_PAUSE, "Pause On Start"), FSUI_CSTR("Pauses the emulator when a game is started."), "UI", "StartPaused", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_EYE, "Pause On Focus Loss"), FSUI_CSTR("Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back."), "UI", "PauseOnFocusLoss", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GAMEPAD, "Pause On Controller Disconnection"), FSUI_CSTR("Pauses the emulator when a controller with bindings is disconnected."), "UI", "PauseOnControllerDisconnection", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_RECTANGLE_LIST, "Pause On Menu"), FSUI_CSTR("Pauses the emulator when you open the quick menu, and unpauses when you close it."), "UI", "PauseOnMenu", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FLOPPY_DISK, "Prompt On State Load/Save Failure"), FSUI_CSTR("Display a modal dialog when a save state load/save operation fails."), "UI", "PromptOnStateLoadSaveFailure", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_POWER_OFF, "Confirm Shutdown"), FSUI_CSTR("Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed."), "UI", "ConfirmShutdown", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FLOPPY_DISK, "Save State On Shutdown"), FSUI_CSTR("Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left " "off next time."), "EmuCore", "SaveStateOnShutdown", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BOX_ARCHIVE, "Create Save State Backups"), FSUI_CSTR("Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix"), "EmuCore", "BackupSavestate", true); // DrawStringListSetting dosn't have a callback for applying settings const SmallString swap_mode = bsi->GetSmallStringValue("UI", "SwapOKFullscreenUI", "auto"); static constexpr const char* swap_names[] = { FSUI_NSTR("Automatic"), FSUI_NSTR("Enabled"), FSUI_NSTR("Disabled"), }; static constexpr const char* swap_values[] = { "auto", "true", "false", }; size_t swap_index = std::size(swap_values); for (size_t i = 0; i < std::size(swap_values); i++) { if (swap_mode == swap_values[i]) { swap_index = i; break; } } SmallStackString<256> swap_summery; swap_summery.format(FSUI_FSTR("Uses {} as confirm when using a controller."), ICON_PF_BUTTON_CIRCLE); if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Swap OK/Cancel in Big Picture Mode"), swap_summery.c_str(), (swap_index < std::size(swap_values)) ? Host::TranslateToCString(TR_CONTEXT, swap_names[swap_index]) : FSUI_CSTR("Unknown"))) { ImGuiFullscreen::ChoiceDialogOptions cd_options; cd_options.reserve(std::size(swap_values)); for (size_t i = 0; i < std::size(swap_values); i++) cd_options.emplace_back(Host::TranslateToString(TR_CONTEXT, swap_names[i]), i == static_cast(swap_index)); OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Swap OK/Cancel in Big Picture Mode"), false, std::move(cd_options), [](s32 index, const std::string& title, bool checked) { if (index >= 0) { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(false); bsi->SetStringValue("UI", "SwapOKFullscreenUI", swap_values[index]); SetSettingsChanged(bsi); ApplyLayoutSettings(bsi); } CloseChoiceDialog(); }); } const SmallString nintendo_mode = bsi->GetSmallStringValue("UI", "SDL2NintendoLayout", "false"); size_t nintendo_index = std::size(swap_values); for (size_t i = 0; i < std::size(swap_values); i++) { if (nintendo_mode == swap_values[i]) { nintendo_index = i; break; } } swap_summery.format(FSUI_FSTR("Swaps both {}/{} (When Swap OK/Cancel is set to automatic) and {}/{} buttons"), ICON_PF_BUTTON_CROSS, ICON_PF_BUTTON_CIRCLE, ICON_PF_BUTTON_SQUARE, ICON_PF_BUTTON_TRIANGLE); if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Use Legacy Nintendo Layout in Big Picture Mode"), swap_summery.c_str(), (nintendo_index < std::size(swap_values)) ? Host::TranslateToCString(TR_CONTEXT, swap_names[nintendo_index]) : FSUI_CSTR("Unknown"))) { ImGuiFullscreen::ChoiceDialogOptions cd_options; cd_options.reserve(std::size(swap_values)); for (size_t i = 0; i < std::size(swap_values); i++) cd_options.emplace_back(Host::TranslateToString(TR_CONTEXT, swap_names[i]), i == static_cast(nintendo_index)); OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_GAMEPAD, "Use Legacy Nintendo Layout in Big Picture Mode"), false, std::move(cd_options), [](s32 index, const std::string& title, bool checked) { if (index >= 0) { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(false); bsi->SetStringValue("UI", "SDL2NintendoLayout", swap_values[index]); SetSettingsChanged(bsi); ApplyLayoutSettings(bsi); } CloseChoiceDialog(); }); } MenuHeading(FSUI_CSTR("Integration")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CIRCLE_USER, "Enable Discord Presence"), FSUI_CSTR("Shows the game you are currently playing as part of your profile on Discord."), "EmuCore", "EnableDiscordPresence", false); MenuHeading(FSUI_CSTR("Game Display")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TV, "Start Fullscreen"), FSUI_CSTR("Automatically switches to fullscreen mode when a game is started."), "UI", "StartFullscreen", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPUTER_MOUSE, "Double-Click Toggles Fullscreen"), FSUI_CSTR("Switches between full screen and windowed when the window is double-clicked."), "UI", "DoubleClickTogglesFullscreen", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_POINTER, "Hide Cursor In Fullscreen"), FSUI_CSTR("Hides the mouse pointer/cursor when the emulator is in fullscreen mode."), "UI", "HideMouseCursor", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TABLET_SCREEN_BUTTON, "Start Big Picture UI"), FSUI_CSTR("Automatically starts Big Picture Mode instead of the regular Qt interface when PCSX2 launches."), "UI", "StartBigPictureMode", false); MenuHeading(FSUI_CSTR("On-Screen Display")); DrawIntSpinBoxSetting(bsi, FSUI_ICONSTR(ICON_FA_MAGNIFYING_GLASS, "OSD Scale"), FSUI_CSTR("Determines how large the on-screen messages and monitors are."), "EmuCore/GS", "OsdScale", 100, 25, 500, 1, FSUI_CSTR("%d%%")); // OSD Positioning Options static constexpr const char* s_osd_position_options[] = { FSUI_NSTR("None"), FSUI_NSTR("Top Left"), FSUI_NSTR("Top Center"), FSUI_NSTR("Top Right"), FSUI_NSTR("Center Left"), FSUI_NSTR("Center"), FSUI_NSTR("Center Right"), FSUI_NSTR("Bottom Left"), FSUI_NSTR("Bottom Center"), FSUI_NSTR("Bottom Right"), }; static constexpr const char* s_osd_position_values[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_COMMENT, "OSD Messages Position"), FSUI_CSTR("Determines where on-screen display messages are positioned."), "EmuCore/GS", "OsdMessagesPos", "1", s_osd_position_options, s_osd_position_values, std::size(s_osd_position_options), true); DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_CHART_BAR, "OSD Performance Position"), FSUI_CSTR("Determines where performance statistics are positioned."), "EmuCore/GS", "OsdPerformancePos", "3", s_osd_position_options, s_osd_position_values, std::size(s_osd_position_options), true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CODE_MERGE, "Show PCSX2 Version"), FSUI_CSTR("Shows the current PCSX2 version."), "EmuCore/GS", "OsdShowVersion", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GAUGE_SIMPLE_HIGH, "Show Speed"), FSUI_CSTR("Shows the current emulation speed of the system as a percentage."), "EmuCore/GS", "OsdShowSpeed", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FILM, "Show FPS"), FSUI_CSTR("Shows the number of internal video frames displayed per second by the system."), "EmuCore/GS", "OsdShowFPS", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CLAPPERBOARD, "Show VPS"), FSUI_CSTR("Shows the number of Vsyncs performed per second by the system."), "EmuCore/GS", "OsdShowVPS", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_MONITOR_CODE, "Show Resolution"), FSUI_CSTR("Shows the internal resolution of the game."), "EmuCore/GS", "OsdShowResolution", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPUTER, "Show Hardware Info"), FSUI_CSTR("Shows the current system CPU and GPU information."), "EmuCore/GS", "OsdShowHardwareInfo", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CHART_PIE, "Show GS Statistics"), FSUI_CSTR("Shows statistics about the emulated GS such as primitives and draw calls."), "EmuCore/GS", "OsdShowGSStats", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_MICROCHIP_ALT, "Show CPU Usage"), FSUI_CSTR("Shows the host's CPU utilization based on threads."), "EmuCore/GS", "OsdShowCPU", false); // TODO: Change this to a GPU icon when FA gets one or PromptFont fixes their codepoints. DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_IMAGE, "Show GPU Usage"), FSUI_CSTR("Shows the host's GPU utilization."), "EmuCore/GS", "OsdShowGPU", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_PLAY, "Show Status Indicators"), FSUI_CSTR("Shows indicators when fast forwarding, pausing, and other abnormal states are active."), "EmuCore/GS", "OsdShowIndicators", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_HEARTBEAT_ALT, "Show Frame Times"), FSUI_CSTR("Shows a visual history of frame times."), "EmuCore/GS", "OsdShowFrameTimes", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SLIDERS, "Show Settings"), FSUI_CSTR("Shows the current configuration in the bottom-right corner of the display."), "EmuCore/GS", "OsdShowSettings", false); bool show_settings = (bsi->GetBoolValue("EmuCore/GS", "OsdShowSettings", false) == false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_HAMMER, "Show Patches"), FSUI_CSTR("Shows the amount of currently active patches/cheats on the bottom-right corner of the display."), "EmuCore/GS", "OsdshowPatches", false, !show_settings); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_GAMEPAD_ALT, "Show Inputs"), FSUI_CSTR("Shows the current controller state of the system in the bottom-left corner of the display."), "EmuCore/GS", "OsdShowInputs", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_VIDEO, "Show Video Capture Status"), FSUI_CSTR("Shows the status of the currently active video capture."), "EmuCore/GS", "OsdShowVideoCapture", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_KEYBOARD, "Show Input Recording Status"), FSUI_CSTR("Shows the status of the currently active input recording."), "EmuCore/GS", "OsdShowInputRec", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_IMAGES, "Show Texture Replacement Status"), FSUI_CSTR("Shows the number of dumped and loaded texture replacements on the OSD."), "EmuCore/GS", "OsdShowTextureReplacements", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TRIANGLE_EXCLAMATION, "Warn About Unsafe Settings"), FSUI_CSTR("Displays warnings when settings are enabled which may break games."), "EmuCore", "WarnAboutUnsafeSettings", true); MenuHeading(FSUI_CSTR("Operations")); if (MenuButton(FSUI_ICONSTR(u8"🔥", "Reset Settings"), FSUI_CSTR("Resets configuration to defaults (excluding controller settings)."), !IsEditingGameSettings(bsi))) { DoResetSettings(); } EndMenuButtons(); } void FullscreenUI::DrawBIOSSettingsPage() { SettingsInterface* bsi = GetEditingSettingsInterface(); BeginMenuButtons(); MenuHeading(FSUI_CSTR("BIOS Configuration")); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Change Search Directory"), "Folders", "Bios", EmuFolders::Bios); const SmallString bios_selection = GetEditingSettingsInterface()->GetSmallStringValue("Filenames", "BIOS", ""); if (MenuButtonWithValue(FSUI_ICONSTR(ICON_PF_MICROCHIP, "BIOS Selection"), FSUI_CSTR("Changes the BIOS image used to start future sessions."), bios_selection.empty() ? FSUI_CSTR("Automatic") : bios_selection.c_str())) { ImGuiFullscreen::ChoiceDialogOptions choices; choices.emplace_back(FSUI_STR("Automatic"), bios_selection.empty()); std::vector values; values.push_back(""); FileSystem::FindResultsArray results; FileSystem::FindFiles(EmuFolders::Bios.c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES, &results); for (const FILESYSTEM_FIND_DATA& fd : results) { u32 version, region; std::string description, zone; if (!IsBIOS(fd.FileName.c_str(), version, description, region, zone)) continue; const std::string_view filename(Path::GetFileName(fd.FileName)); choices.emplace_back(fmt::format("{} ({})", description, filename), bios_selection == filename); values.emplace_back(filename); } OpenChoiceDialog(FSUI_CSTR("BIOS Selection"), false, std::move(choices), [game_settings = IsEditingGameSettings(bsi), values = std::move(values)](s32 index, const std::string& title, bool checked) { if (index < 0) return; auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetStringValue("Filenames", "BIOS", values[index].c_str()); SetSettingsChanged(bsi); ApplyLayoutSettings(bsi); CloseChoiceDialog(); }); } MenuHeading(FSUI_CSTR("Fast Boot Options")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FORWARD_FAST, "Fast Boot"), FSUI_CSTR("Skips the intro screen, and bypasses region checks."), "EmuCore", "EnableFastBoot", true); EndMenuButtons(); } void FullscreenUI::DrawEmulationSettingsPage() { static constexpr int DEFAULT_FRAME_LATENCY = 2; static constexpr const char* speed_entries[] = { FSUI_NSTR("2% [1 FPS (NTSC) / 1 FPS (PAL)]"), FSUI_NSTR("10% [6 FPS (NTSC) / 5 FPS (PAL)]"), FSUI_NSTR("25% [15 FPS (NTSC) / 12 FPS (PAL)]"), FSUI_NSTR("50% [30 FPS (NTSC) / 25 FPS (PAL)]"), FSUI_NSTR("75% [45 FPS (NTSC) / 37 FPS (PAL)]"), FSUI_NSTR("90% [54 FPS (NTSC) / 45 FPS (PAL)]"), FSUI_NSTR("100% [60 FPS (NTSC) / 50 FPS (PAL)]"), FSUI_NSTR("110% [66 FPS (NTSC) / 55 FPS (PAL)]"), FSUI_NSTR("120% [72 FPS (NTSC) / 60 FPS (PAL)]"), FSUI_NSTR("150% [90 FPS (NTSC) / 75 FPS (PAL)]"), FSUI_NSTR("175% [105 FPS (NTSC) / 87 FPS (PAL)]"), FSUI_NSTR("200% [120 FPS (NTSC) / 100 FPS (PAL)]"), FSUI_NSTR("300% [180 FPS (NTSC) / 150 FPS (PAL)]"), FSUI_NSTR("400% [240 FPS (NTSC) / 200 FPS (PAL)]"), FSUI_NSTR("500% [300 FPS (NTSC) / 250 FPS (PAL)]"), FSUI_NSTR("1000% [600 FPS (NTSC) / 500 FPS (PAL)]"), }; static constexpr const float speed_values[] = { 0.02f, 0.10f, 0.25f, 0.50f, 0.75f, 0.90f, 1.00f, 1.10f, 1.20f, 1.50f, 1.75f, 2.00f, 3.00f, 4.00f, 5.00f, 10.00f, }; static constexpr const char* ee_cycle_rate_settings[] = { FSUI_NSTR("50% Speed"), FSUI_NSTR("60% Speed"), FSUI_NSTR("75% Speed"), FSUI_NSTR("100% Speed (Default)"), FSUI_NSTR("130% Speed"), FSUI_NSTR("180% Speed"), FSUI_NSTR("300% Speed"), }; static constexpr const char* ee_cycle_skip_settings[] = { FSUI_NSTR("Normal (Default)"), FSUI_NSTR("Mild Underclock"), FSUI_NSTR("Moderate Underclock"), FSUI_NSTR("Maximum Underclock"), }; static constexpr const char* queue_entries[] = { FSUI_NSTR("0 Frames (Hard Sync)"), FSUI_NSTR("1 Frame"), FSUI_NSTR("2 Frames"), FSUI_NSTR("3 Frames"), }; SettingsInterface* bsi = GetEditingSettingsInterface(); BeginMenuButtons(); MenuHeading(FSUI_CSTR("Speed Control")); DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_PLAY, "Normal Speed"), FSUI_CSTR("Sets the speed when running without fast forwarding."), "Framerate", "NominalScalar", 1.00f, speed_entries, speed_values, std::size(speed_entries), true); DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_FORWARD_FAST, "Fast Forward Speed"), FSUI_CSTR("Sets the speed when using the fast forward hotkey."), "Framerate", "TurboScalar", 2.00f, speed_entries, speed_values, std::size(speed_entries), true); DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_PF_SLOW_MOTION, "Slow Motion Speed"), FSUI_CSTR("Sets the speed when using the slow motion hotkey."), "Framerate", "SlomoScalar", 0.50f, speed_entries, speed_values, std::size(speed_entries), true); MenuHeading(FSUI_CSTR("System Settings")); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_GAUGE_HIGH, "EE Cycle Rate"), FSUI_CSTR("Underclocks or overclocks the emulated Emotion Engine CPU."), "EmuCore/Speedhacks", "EECycleRate", 0, ee_cycle_rate_settings, std::size(ee_cycle_rate_settings), true, -3); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_TREND_DOWN, "EE Cycle Skipping"), FSUI_CSTR("Makes the emulated Emotion Engine skip cycles. Helps a small subset of games like SOTC. Most of the time it's harmful to performance."), "EmuCore/Speedhacks", "EECycleSkip", 0, ee_cycle_skip_settings, std::size(ee_cycle_skip_settings), true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_USERS, "Enable MTVU (Multi-Threaded VU1)"), FSUI_CSTR("Generally a speedup on CPUs with 4 or more cores. Safe for most games, but a few are incompatible and may hang."), "EmuCore/Speedhacks", "vuThread", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LOCATION_PIN_LOCK, "Thread Pinning"), FSUI_CSTR("Pins emulation threads to CPU cores to potentially improve performance/frame time variance."), "EmuCore", "EnableThreadPinning", false); DrawToggleSetting( bsi, FSUI_ICONSTR(ICON_FA_FACE_ROLLING_EYES, "Enable Cheats"), FSUI_CSTR("Enables loading cheats from pnach files."), "EmuCore", "EnableCheats", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_HARD_DRIVE, "Enable Host Filesystem"), FSUI_CSTR("Enables access to files from the host: namespace in the virtual machine."), "EmuCore", "HostFs", false); if (IsEditingGameSettings(bsi)) { DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPACT_DISC, "Enable Fast CDVD"), FSUI_CSTR("Fast disc access, less loading times. Not recommended."), "EmuCore/Speedhacks", "fastCDVD", false); } DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPACT_DISC, "Enable CDVD Precaching"), FSUI_CSTR("Loads the disc image into RAM before starting the virtual machine."), "EmuCore", "CdvdPrecache", false); MenuHeading(FSUI_CSTR("Frame Pacing/Latency Control")); bool optimal_frame_pacing = (bsi->GetIntValue("EmuCore/GS", "VsyncQueueSize", DEFAULT_FRAME_LATENCY) == 0); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_CLOCK_ROTATE_LEFT, "Maximum Frame Latency"), FSUI_CSTR("Sets the number of frames which can be queued."), "EmuCore/GS", "VsyncQueueSize", DEFAULT_FRAME_LATENCY, queue_entries, std::size(queue_entries), true, 0, !optimal_frame_pacing); if (ToggleButton(FSUI_ICONSTR(ICON_PF_HEARTBEAT_ALT, "Optimal Frame Pacing"), FSUI_CSTR("Synchronize EE and GS threads after each frame. Lowest input latency, but increases system requirements."), &optimal_frame_pacing)) { bsi->SetIntValue("EmuCore/GS", "VsyncQueueSize", optimal_frame_pacing ? 0 : DEFAULT_FRAME_LATENCY); SetSettingsChanged(bsi); } DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROWS_SPIN, "Vertical Sync (VSync)"), FSUI_CSTR("Synchronizes frame presentation with host refresh."), "EmuCore/GS", "VsyncEnable", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_MONITOR_CODE, "Sync to Host Refresh Rate"), FSUI_CSTR("Speeds up emulation so that the guest refresh rate matches the host."), "EmuCore/GS", "SyncToHostRefreshRate", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_PF_HEARTBEAT_CIRCLE, "Use Host VSync Timing"), FSUI_CSTR("Disables PCSX2's internal frame timing, and uses host vsync instead."), "EmuCore/GS", "UseVSyncForTiming", false, GetEffectiveBoolSetting(bsi, "EmuCore/GS", "VsyncEnable", false) && GetEffectiveBoolSetting(bsi, "EmuCore/GS", "SyncToHostRefreshRate", false)); EndMenuButtons(); } void FullscreenUI::DrawClampingModeSetting(SettingsInterface* bsi, const char* title, const char* summary, int vunum) { // This is so messy... maybe we should just make the mode an int in the settings too... const bool base = IsEditingGameSettings(bsi) ? 1 : 0; std::optional default_false = IsEditingGameSettings(bsi) ? std::nullopt : std::optional(false); std::optional default_true = IsEditingGameSettings(bsi) ? std::nullopt : std::optional(true); std::optional third = bsi->GetOptionalBoolValue( "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0SignOverflow" : "vu1SignOverflow") : "fpuFullMode"), default_false); std::optional second = bsi->GetOptionalBoolValue("EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0ExtraOverflow" : "vu1ExtraOverflow") : "fpuExtraOverflow"), default_false); std::optional first = bsi->GetOptionalBoolValue( "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0Overflow" : "vu1Overflow") : "fpuOverflow"), default_true); int index; if (third.has_value() && third.value()) index = base + 3; else if (second.has_value() && second.value()) index = base + 2; else if (first.has_value() && first.value()) index = base + 1; else if (first.has_value()) index = base + 0; // none else index = 0; // no per game override static constexpr const char* ee_clamping_mode_settings[] = { FSUI_NSTR("Use Global Setting"), FSUI_NSTR("None"), FSUI_NSTR("Normal (Default)"), FSUI_NSTR("Extra + Preserve Sign"), FSUI_NSTR("Full"), }; static constexpr const char* vu_clamping_mode_settings[] = { FSUI_NSTR("Use Global Setting"), FSUI_NSTR("None"), FSUI_NSTR("Normal (Default)"), FSUI_NSTR("Extra"), FSUI_NSTR("Extra + Preserve Sign"), }; const char* const* options = (vunum >= 0) ? vu_clamping_mode_settings : ee_clamping_mode_settings; const int setting_offset = IsEditingGameSettings(bsi) ? 0 : 1; if (MenuButtonWithValue(title, summary, Host::TranslateToCString(TR_CONTEXT, options[index + setting_offset]))) { ImGuiFullscreen::ChoiceDialogOptions cd_options; cd_options.reserve(std::size(ee_clamping_mode_settings)); for (int i = setting_offset; i < static_cast(std::size(ee_clamping_mode_settings)); i++) cd_options.emplace_back(Host::TranslateToString(TR_CONTEXT, options[i]), (i == (index + setting_offset))); OpenChoiceDialog(title, false, std::move(cd_options), [game_settings = IsEditingGameSettings(bsi), vunum](s32 index, const std::string& title, bool checked) { if (index >= 0) { auto lock = Host::GetSettingsLock(); std::optional first, second, third; if (!game_settings || index > 0) { const bool base = game_settings ? 1 : 0; third = (index >= (base + 3)); second = (index >= (base + 2)); first = (index >= (base + 1)); } SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetOptionalBoolValue("EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0SignOverflow" : "vu1SignOverflow") : "fpuFullMode"), third); bsi->SetOptionalBoolValue("EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0ExtraOverflow" : "vu1ExtraOverflow") : "fpuExtraOverflow"), second); bsi->SetOptionalBoolValue( "EmuCore/CPU/Recompiler", (vunum >= 0 ? ((vunum == 0) ? "vu0Overflow" : "vu1Overflow") : "fpuOverflow"), first); SetSettingsChanged(bsi); } CloseChoiceDialog(); }); } } void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_advanced_settings) { static constexpr const char* s_renderer_names[] = { FSUI_NSTR("Automatic (Default)"), #ifdef _WIN32 FSUI_NSTR("Direct3D 11 (Legacy)"), FSUI_NSTR("Direct3D 12"), #endif #ifdef ENABLE_OPENGL FSUI_NSTR("OpenGL"), #endif #ifdef ENABLE_VULKAN FSUI_NSTR("Vulkan"), #endif #ifdef __APPLE__ FSUI_NSTR("Metal"), #endif FSUI_NSTR("Software Renderer"), FSUI_NSTR("Null"), }; static constexpr const char* s_renderer_values[] = { "-1", //GSRendererType::Auto, #ifdef _WIN32 "3", //GSRendererType::DX11, "15", //GSRendererType::DX12, #endif #ifdef ENABLE_OPENGL "12", //GSRendererType::OGL, #endif #ifdef ENABLE_VULKAN "14", //GSRendererType::VK, #endif #ifdef __APPLE__ "17", //GSRendererType::Metal, #endif "13", //GSRendererType::SW, "11", //GSRendererType::Null }; static constexpr const char* s_bilinear_present_options[] = { FSUI_NSTR("Off"), FSUI_NSTR("Bilinear (Smooth)"), FSUI_NSTR("Bilinear (Sharp)"), }; static constexpr const char* s_deinterlacing_options[] = { FSUI_NSTR("Automatic (Default)"), FSUI_NSTR("No Deinterlacing"), FSUI_NSTR("Weave (Top Field First, Sawtooth)"), FSUI_NSTR("Weave (Bottom Field First, Sawtooth)"), FSUI_NSTR("Bob (Top Field First)"), FSUI_NSTR("Bob (Bottom Field First)"), FSUI_NSTR("Blend (Top Field First, Half FPS)"), FSUI_NSTR("Blend (Bottom Field First, Half FPS)"), FSUI_NSTR("Adaptive (Top Field First)"), FSUI_NSTR("Adaptive (Bottom Field First)"), }; static const char* s_resolution_options[] = { FSUI_NSTR("Native (PS2)"), FSUI_NSTR("2x Native (~720px/HD)"), FSUI_NSTR("3x Native (~1080px/FHD)"), FSUI_NSTR("4x Native (~1440px/QHD)"), FSUI_NSTR("5x Native (~1800px/QHD+)"), FSUI_NSTR("6x Native (~2160px/4K UHD)"), FSUI_NSTR("7x Native (~2520px)"), FSUI_NSTR("8x Native (~2880px/5K UHD)"), FSUI_NSTR("9x Native (~3240px)"), FSUI_NSTR("10x Native (~3600px/6K UHD)"), FSUI_NSTR("11x Native (~3960px)"), FSUI_NSTR("12x Native (~4320px/8K UHD)"), }; static const char* s_resolution_values[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", }; static constexpr const char* s_bilinear_options[] = { FSUI_NSTR("Nearest"), FSUI_NSTR("Bilinear (Forced)"), FSUI_NSTR("Bilinear (PS2)"), FSUI_NSTR("Bilinear (Forced excluding sprite)"), }; static constexpr const char* s_trilinear_options[] = { FSUI_NSTR("Automatic (Default)"), FSUI_NSTR("Off (None)"), FSUI_NSTR("Trilinear (PS2)"), FSUI_NSTR("Trilinear (Forced)"), }; static constexpr const char* s_dithering_options[] = { FSUI_NSTR("Off"), FSUI_NSTR("Scaled"), FSUI_NSTR("Unscaled (Default)"), FSUI_NSTR("Force 32bit"), }; static constexpr const char* s_blending_options[] = { FSUI_NSTR("Minimum"), FSUI_NSTR("Basic (Recommended)"), FSUI_NSTR("Medium"), FSUI_NSTR("High"), FSUI_NSTR("Full (Slow)"), FSUI_NSTR("Maximum (Very Slow)"), }; static constexpr const char* s_anisotropic_filtering_entries[] = { FSUI_NSTR("Off (Default)"), FSUI_NSTR("2x"), FSUI_NSTR("4x"), FSUI_NSTR("8x"), FSUI_NSTR("16x"), }; static constexpr const char* s_anisotropic_filtering_values[] = { "0", "2", "4", "8", "16", }; static constexpr const char* s_preloading_options[] = { FSUI_NSTR("None"), FSUI_NSTR("Partial"), FSUI_NSTR("Full (Hash Cache)"), }; static constexpr const char* s_generic_options[] = { FSUI_NSTR("Automatic (Default)"), FSUI_NSTR("Force Disabled"), FSUI_NSTR("Force Enabled"), }; static constexpr const char* s_hw_download[] = { FSUI_NSTR("Accurate (Recommended)"), FSUI_NSTR("Disable Readbacks (Synchronize GS Thread)"), FSUI_NSTR("Unsynchronized (Non-Deterministic)"), FSUI_NSTR("Disabled (Ignore Transfers)"), }; static constexpr const char* s_screenshot_sizes[] = { FSUI_NSTR("Display Resolution (Aspect Corrected)"), FSUI_NSTR("Internal Resolution (Aspect Corrected)"), FSUI_NSTR("Internal Resolution (No Aspect Correction)"), }; static constexpr const char* s_screenshot_formats[] = { FSUI_NSTR("PNG"), FSUI_NSTR("JPEG"), FSUI_NSTR("WebP"), }; const GSRendererType renderer = static_cast(GetEffectiveIntSetting(bsi, "EmuCore/GS", "Renderer", static_cast(GSRendererType::Auto))); const bool is_hardware = (renderer == GSRendererType::Auto || renderer == GSRendererType::DX11 || renderer == GSRendererType::DX12 || renderer == GSRendererType::OGL || renderer == GSRendererType::VK || renderer == GSRendererType::Metal); //const bool is_software = (renderer == GSRendererType::SW); #ifndef PCSX2_DEVBUILD const bool hw_fixes_visible = is_hardware && IsEditingGameSettings(bsi); #else const bool hw_fixes_visible = is_hardware; #endif BeginMenuButtons(); MenuHeading(FSUI_CSTR("Graphics API")); DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINTBRUSH, "Graphics API"), FSUI_CSTR("Selects the API used to render the emulated GS."), "EmuCore/GS", "Renderer", "-1", s_renderer_names, s_renderer_values, std::size(s_renderer_names), true); MenuHeading(FSUI_CSTR("Display")); DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPRESS, "Aspect Ratio"), FSUI_CSTR("Selects the aspect ratio to display the game content at."), "EmuCore/GS", "AspectRatio", "Auto 4:3/3:2", Pcsx2Config::GSOptions::AspectRatioNames, Pcsx2Config::GSOptions::AspectRatioNames, 0, false); DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_VIDEO, "FMV Aspect Ratio Override"), FSUI_CSTR("Selects the aspect ratio for display when a FMV is detected as playing."), "EmuCore/GS", "FMVAspectRatioSwitch", "Auto 4:3/3:2", Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames, Pcsx2Config::GSOptions::FMVAspectRatioSwitchNames, 0, false); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_TV, "Deinterlacing"), FSUI_CSTR("Selects the algorithm used to convert the PS2's interlaced output to progressive for display."), "EmuCore/GS", "deinterlace_mode", static_cast(GSInterlaceMode::Automatic), s_deinterlacing_options, std::size(s_deinterlacing_options), true); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROWS_UP_DOWN_LEFT_RIGHT, "Screenshot Size"), FSUI_CSTR("Determines the resolution at which screenshots will be saved."), "EmuCore/GS", "ScreenshotSize", static_cast(GSScreenshotSize::WindowResolution), s_screenshot_sizes, std::size(s_screenshot_sizes), true); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_PHOTO_FILM, "Screenshot Format"), FSUI_CSTR("Selects the format which will be used to save screenshots."), "EmuCore/GS", "ScreenshotFormat", static_cast(GSScreenshotFormat::PNG), s_screenshot_formats, std::size(s_screenshot_formats), true); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_GAUGE, "Screenshot Quality"), FSUI_CSTR("Selects the quality at which screenshots will be compressed."), "EmuCore/GS", "ScreenshotQuality", 90, 1, 100, FSUI_CSTR("%d%%")); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_RIGHT_ARROW_LEFT, "Vertical Stretch"), FSUI_CSTR("Increases or decreases the virtual picture size vertically."), "EmuCore/GS", "StretchY", 100, 10, 300, FSUI_CSTR("%d%%")); DrawIntRectSetting(bsi, FSUI_ICONSTR(ICON_FA_CROP, "Crop"), FSUI_CSTR("Crops the image, while respecting aspect ratio."), "EmuCore/GS", "CropLeft", 0, "CropTop", 0, "CropRight", 0, "CropBottom", 0, 0, 720, 1, FSUI_CSTR("%dpx")); if (!IsEditingGameSettings(bsi)) { DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TV, "Enable Widescreen Patches"), FSUI_CSTR("Enables loading widescreen patches from pnach files."), "EmuCore", "EnableWideScreenPatches", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TV, "Enable No-Interlacing Patches"), FSUI_CSTR("Enables loading no-interlacing patches from pnach files."), "EmuCore", "EnableNoInterlacingPatches", false); } DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_TABLE_CELLS, "Bilinear Upscaling"), FSUI_CSTR("Smooths out the image when upscaling the console to the screen."), "EmuCore/GS", "linear_present_mode", static_cast(GSPostBilinearMode::BilinearSharp), s_bilinear_present_options, std::size(s_bilinear_present_options), true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SQUARE_ARROW_UP_RIGHT, "Integer Upscaling"), FSUI_CSTR("Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an " "integer number. May result in a sharper image in some 2D games."), "EmuCore/GS", "IntegerScaling", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SQUARE_UP_RIGHT, "Screen Offsets"), FSUI_CSTR("Enables PCRTC Offsets which position the screen as the game requests."), "EmuCore/GS", "pcrtc_offsets", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MAXIMIZE, "Show Overscan"), FSUI_CSTR("Enables the option to show the overscan area on games which draw more than the safe area of the screen."), "EmuCore/GS", "pcrtc_overscan", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GLASSES, "Anti-Blur"), FSUI_CSTR("Enables internal Anti-Blur hacks. Less accurate to PS2 rendering but will make a lot of games look less blurry."), "EmuCore/GS", "pcrtc_antiblur", true); MenuHeading(FSUI_CSTR("Rendering")); if (is_hardware) { DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_UP_RIGHT_FROM_SQUARE, "Internal Resolution"), FSUI_CSTR("Multiplies the render resolution by the specified factor (upscaling)."), "EmuCore/GS", "upscale_multiplier", "1.000000", s_resolution_options, s_resolution_values, std::size(s_resolution_options), true); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_TABLE_CELLS_LARGE, "Bilinear Filtering"), FSUI_CSTR("Selects where bilinear filtering is utilized when rendering textures."), "EmuCore/GS", "filter", static_cast(BiFiltering::PS2), s_bilinear_options, std::size(s_bilinear_options), true); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_TABLE_CELLS_LARGE, "Trilinear Filtering"), FSUI_CSTR("Selects where trilinear filtering is utilized when rendering textures."), "EmuCore/GS", "TriFilter", static_cast(TriFiltering::Automatic), s_trilinear_options, std::size(s_trilinear_options), true, -1); DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_EYE_LOW_VISION, "Anisotropic Filtering"), FSUI_CSTR("Selects where anisotropic filtering is utilized when rendering textures."), "EmuCore/GS", "MaxAnisotropy", "0", s_anisotropic_filtering_entries, s_anisotropic_filtering_values, std::size(s_anisotropic_filtering_entries), true); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_DROPLET_SLASH, "Dithering"), FSUI_CSTR("Selects the type of dithering applies when the game requests it."), "EmuCore/GS", "dithering_ps2", 2, s_dithering_options, std::size(s_dithering_options), true); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_SPLOTCH, "Blending Accuracy"), FSUI_CSTR("Determines the level of accuracy when emulating blend modes not supported by the host graphics API."), "EmuCore/GS", "accurate_blending_unit", static_cast(AccBlendLevel::Basic), s_blending_options, std::size(s_blending_options), true); DrawToggleSetting( bsi, FSUI_ICONSTR(ICON_FA_BULLSEYE, "Mipmapping"), FSUI_CSTR("Enables emulation of the GS's texture mipmapping."), "EmuCore/GS", "hw_mipmap", true); } else { DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_USERS, "Software Rendering Threads"), FSUI_CSTR("Number of threads to use in addition to the main GS thread for rasterization."), "EmuCore/GS", "extrathreads", 2, 0, 10); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TOILET, "Auto Flush (Software)"), FSUI_CSTR("Force a primitive flush when a framebuffer is also an input texture."), "EmuCore/GS", "autoflush_sw", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_EYE_DROPPER, "Edge AA (AA1)"), FSUI_CSTR("Enables emulation of the GS's edge anti-aliasing (AA1)."), "EmuCore/GS", "aa1", true); DrawToggleSetting( bsi, FSUI_ICONSTR(ICON_FA_BULLSEYE, "Mipmapping"), FSUI_CSTR("Enables emulation of the GS's texture mipmapping."), "EmuCore/GS", "mipmap", true); } if (hw_fixes_visible) { MenuHeading(FSUI_CSTR("Hardware Fixes")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TOOLBOX, "Manual Hardware Fixes"), FSUI_CSTR("Disables automatic hardware fixes, allowing you to set fixes manually."), "EmuCore/GS", "UserHacks", false); const bool manual_hw_fixes = GetEffectiveBoolSetting(bsi, "EmuCore/GS", "UserHacks", false); if (manual_hw_fixes) { static constexpr const char* s_cpu_sprite_render_bw_options[] = { FSUI_NSTR("0 (Disabled)"), FSUI_NSTR("1 (64 Max Width)"), FSUI_NSTR("2 (128 Max Width)"), FSUI_NSTR("3 (192 Max Width)"), FSUI_NSTR("4 (256 Max Width)"), FSUI_NSTR("5 (320 Max Width)"), FSUI_NSTR("6 (384 Max Width)"), FSUI_NSTR("7 (448 Max Width)"), FSUI_NSTR("8 (512 Max Width)"), FSUI_NSTR("9 (576 Max Width)"), FSUI_NSTR("10 (640 Max Width)"), }; static constexpr const char* s_cpu_sprite_render_level_options[] = { FSUI_NSTR("Sprites Only"), FSUI_NSTR("Sprites/Triangles"), FSUI_NSTR("Blended Sprites/Triangles"), }; static constexpr const char* s_cpu_clut_render_options[] = { FSUI_NSTR("0 (Disabled)"), FSUI_NSTR("1 (Normal)"), FSUI_NSTR("2 (Aggressive)"), }; static constexpr const char* s_texture_inside_rt_options[] = { FSUI_NSTR("Disabled"), FSUI_NSTR("Inside Target"), FSUI_NSTR("Merge Targets"), }; static constexpr const char* s_half_pixel_offset_options[] = { FSUI_NSTR("Off (Default)"), FSUI_NSTR("Normal (Vertex)"), FSUI_NSTR("Special (Texture)"), FSUI_NSTR("Special (Texture - Aggressive)"), FSUI_NSTR("Align to Native"), FSUI_NSTR("Align to Native - with Texture Offset"), }; static constexpr const char* s_native_scaling_options[] = { FSUI_NSTR("Off (Default)"), FSUI_NSTR("Normal"), FSUI_NSTR("Aggressive"), FSUI_NSTR("Normal (Maintain Upscale)"), FSUI_NSTR("Aggressive (Maintain Upscale)"), }; static constexpr const char* s_round_sprite_options[] = { FSUI_NSTR("Off (Default)"), FSUI_NSTR("Half"), FSUI_NSTR("Full"), }; static constexpr const char* s_bilinear_dirty_options[] = { FSUI_NSTR("Automatic (Default)"), FSUI_NSTR("Force Bilinear"), FSUI_NSTR("Force Nearest"), }; static constexpr const char* s_auto_flush_options[] = { FSUI_NSTR("Disabled (Default)"), FSUI_NSTR("Enabled (Sprites Only)"), FSUI_NSTR("Enabled (All Primitives)"), }; static constexpr const char* s_gpu_clut_options[] = { FSUI_NSTR("Disabled (Default)"), FSUI_NSTR("Enabled (Exact Match)"), FSUI_NSTR("Enabled (Check Inside Target)"), }; DrawIntListSetting(bsi, FSUI_CSTR("CPU Sprite Render Size"), FSUI_CSTR("Uses software renderer to draw texture decompression-like sprites."), "EmuCore/GS", "UserHacks_CPUSpriteRenderBW", 0, s_cpu_sprite_render_bw_options, std::size(s_cpu_sprite_render_bw_options), true); DrawIntListSetting(bsi, FSUI_CSTR("CPU Sprite Render Level"), FSUI_CSTR("Determines filter level for CPU sprite render."), "EmuCore/GS", "UserHacks_CPUSpriteRenderLevel", 0, s_cpu_sprite_render_level_options, std::size(s_cpu_sprite_render_level_options), true); DrawIntListSetting(bsi, FSUI_CSTR("Software CLUT Render"), FSUI_CSTR("Uses software renderer to draw texture CLUT points/sprites."), "EmuCore/GS", "UserHacks_CPUCLUTRender", 0, s_cpu_clut_render_options, std::size(s_cpu_clut_render_options), true); DrawIntListSetting(bsi, FSUI_CSTR("GPU Target CLUT"), FSUI_CSTR("Try to detect when a game is drawing its own color palette and then renders it on the GPU with special handling."), "EmuCore/GS", "UserHacks_GPUTargetCLUTMode", 0, s_gpu_clut_options, std::size(s_gpu_clut_options), true, 0, manual_hw_fixes); DrawIntSpinBoxSetting(bsi, FSUI_CSTR("Skip Draw Start"), FSUI_CSTR("Object range to skip drawing."), "EmuCore/GS", "UserHacks_SkipDraw_Start", 0, 0, 5000, 1); DrawIntSpinBoxSetting(bsi, FSUI_CSTR("Skip Draw End"), FSUI_CSTR("Object range to skip drawing."), "EmuCore/GS", "UserHacks_SkipDraw_End", 0, 0, 5000, 1); DrawIntListSetting(bsi, FSUI_CSTR("Auto Flush (Hardware)"), FSUI_CSTR("Force a primitive flush when a framebuffer is also an input texture."), "EmuCore/GS", "UserHacks_AutoFlushLevel", 0, s_auto_flush_options, std::size(s_auto_flush_options), true, 0, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("CPU Framebuffer Conversion"), FSUI_CSTR("Convert 4-bit and 8-bit framebuffer on the CPU instead of the GPU."), "EmuCore/GS", "UserHacks_CPU_FB_Conversion", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Disable Depth Conversion"), FSUI_CSTR("Disable the support of depth buffers in the texture cache."), "EmuCore/GS", "UserHacks_DisableDepthSupport", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Disable Safe Features"), FSUI_CSTR("This option disables multiple safe features."), "EmuCore/GS", "UserHacks_Disable_Safe_Features", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Disable Render Fixes"), FSUI_CSTR("This option disables game-specific render fixes."), "EmuCore/GS", "UserHacks_DisableRenderFixes", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Preload Frame Data"), FSUI_CSTR("Uploads GS data when rendering a new frame to reproduce some effects accurately."), "EmuCore/GS", "preload_frame_with_gs_data", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Disable Partial Invalidation"), FSUI_CSTR("Removes texture cache entries when there is any intersection, rather than only the intersected areas."), "EmuCore/GS", "UserHacks_DisablePartialInvalidation", false, manual_hw_fixes); DrawIntListSetting(bsi, FSUI_CSTR("Texture Inside RT"), FSUI_CSTR("Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer."), "EmuCore/GS", "UserHacks_TextureInsideRt", 0, s_texture_inside_rt_options, std::size(s_texture_inside_rt_options), true, 0, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Read Targets When Closing"), FSUI_CSTR("Flushes all targets in the texture cache back to local memory when shutting down."), "EmuCore/GS", "UserHacks_ReadTCOnClose", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Estimate Texture Region"), FSUI_CSTR("Attempts to reduce the texture size when games do not set it themselves (e.g. Snowblind games)."), "EmuCore/GS", "UserHacks_EstimateTextureRegion", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("GPU Palette Conversion"), FSUI_CSTR("When enabled GPU converts colormap-textures, otherwise the CPU will. It is a trade-off between GPU and CPU."), "EmuCore/GS", "paltex", false, manual_hw_fixes); MenuHeading(FSUI_CSTR("Upscaling Fixes")); DrawIntListSetting(bsi, FSUI_CSTR("Half Pixel Offset"), FSUI_CSTR("Adjusts vertices relative to upscaling."), "EmuCore/GS", "UserHacks_HalfPixelOffset", 0, s_half_pixel_offset_options, std::size(s_half_pixel_offset_options), true); DrawIntListSetting(bsi, FSUI_CSTR("Native Scaling"), FSUI_CSTR("Attempt to do rescaling at native resolution."), "EmuCore/GS", "UserHacks_native_scaling", 0, s_native_scaling_options, std::size(s_native_scaling_options), true); DrawIntListSetting(bsi, FSUI_CSTR("Round Sprite"), FSUI_CSTR("Adjusts sprite coordinates."), "EmuCore/GS", "UserHacks_round_sprite_offset", 0, s_round_sprite_options, std::size(s_round_sprite_options), true); DrawIntListSetting(bsi, FSUI_CSTR("Bilinear Dirty Upscale"), FSUI_CSTR("Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare."), "EmuCore/GS", "UserHacks_BilinearHack", static_cast(GSBilinearDirtyMode::Automatic), s_bilinear_dirty_options, std::size(s_bilinear_dirty_options), true); DrawIntSpinBoxSetting(bsi, FSUI_CSTR("Texture Offset X"), FSUI_CSTR("Adjusts target texture offsets."), "EmuCore/GS", "UserHacks_TCOffsetX", 0, -4096, 4096, 1); DrawIntSpinBoxSetting(bsi, FSUI_CSTR("Texture Offset Y"), FSUI_CSTR("Adjusts target texture offsets."), "EmuCore/GS", "UserHacks_TCOffsetY", 0, -4096, 4096, 1); DrawToggleSetting(bsi, FSUI_CSTR("Align Sprite"), FSUI_CSTR("Fixes issues with upscaling (vertical lines) in some games."), "EmuCore/GS", "UserHacks_align_sprite_X", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Merge Sprite"), FSUI_CSTR("Replaces multiple post-processing sprites with a larger single sprite."), "EmuCore/GS", "UserHacks_merge_pp_sprite", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Force Even Sprite Position"), FSUI_CSTR("Lowers the GS precision to avoid gaps between pixels when upscaling. Fixes the text on Wild Arms games."), "EmuCore/GS", "UserHacks_ForceEvenSpritePosition", false, manual_hw_fixes); DrawToggleSetting(bsi, FSUI_CSTR("Unscaled Palette Texture Draws"), FSUI_CSTR("Can fix some broken effects which rely on pixel perfect precision."), "EmuCore/GS", "UserHacks_NativePaletteDraw", false, manual_hw_fixes); } } if (is_hardware) { const bool dumping_active = GetEffectiveBoolSetting(bsi, "EmuCore/GS", "DumpReplaceableTextures", false); const bool replacement_active = GetEffectiveBoolSetting(bsi, "EmuCore/GS", "LoadTextureReplacements", false); MenuHeading(FSUI_CSTR("Texture Replacement")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_IMAGES, "Load Textures"), FSUI_CSTR("Loads replacement textures where available and user-provided."), "EmuCore/GS", "LoadTextureReplacements", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SPINNER, "Asynchronous Texture Loading"), FSUI_CSTR("Loads replacement textures on a worker thread, reducing microstutter when replacements are enabled."), "EmuCore/GS", "LoadTextureReplacementsAsync", true, replacement_active); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_DATABASE, "Precache Replacements"), FSUI_CSTR("Preloads all replacement textures to memory. Not necessary with asynchronous loading."), "EmuCore/GS", "PrecacheTextureReplacements", false, replacement_active); if (!IsEditingGameSettings(bsi)) { DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Replacements Directory"), FSUI_CSTR("Folders"), "Textures", EmuFolders::Textures); } MenuHeading(FSUI_CSTR("Texture Dumping")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_DOWNLOAD, "Dump Textures"), FSUI_CSTR("Dumps replaceable textures to disk. Will reduce performance."), "EmuCore/GS", "DumpReplaceableTextures", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_IMAGES, "Dump Mipmaps"), FSUI_CSTR("Includes mipmaps when dumping textures."), "EmuCore/GS", "DumpReplaceableMipmaps", false, dumping_active); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_VIDEO, "Dump FMV Textures"), FSUI_CSTR("Allows texture dumping when FMVs are active. You should not enable this."), "EmuCore/GS", "DumpTexturesWithFMVActive", false, dumping_active); } MenuHeading(FSUI_CSTR("Post-Processing")); { static constexpr const char* s_cas_options[] = { FSUI_NSTR("None (Default)"), FSUI_NSTR("Sharpen Only (Internal Resolution)"), FSUI_NSTR("Sharpen and Resize (Display Resolution)"), }; const bool cas_active = (GetEffectiveIntSetting(bsi, "EmuCore/GS", "CASMode", 0) != static_cast(GSCASMode::Disabled)); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_EYE, "FXAA"), FSUI_CSTR("Enables FXAA post-processing shader."), "EmuCore/GS", "fxaa", false); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_SUN, "Contrast Adaptive Sharpening"), FSUI_CSTR("Enables FidelityFX Contrast Adaptive Sharpening."), "EmuCore/GS", "CASMode", static_cast(GSCASMode::Disabled), s_cas_options, std::size(s_cas_options), true); DrawIntSpinBoxSetting(bsi, FSUI_ICONSTR(ICON_FA_PENCIL, "CAS Sharpness"), FSUI_CSTR("Determines the intensity the sharpening effect in CAS post-processing."), "EmuCore/GS", "CASSharpness", 50, 0, 100, 1, FSUI_CSTR("%d%%"), cas_active); } MenuHeading(FSUI_CSTR("Filters")); { const bool shadeboost_active = GetEffectiveBoolSetting(bsi, "EmuCore/GS", "ShadeBoost", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GEM, "Shade Boost"), FSUI_CSTR("Enables brightness/contrast/gamma/saturation adjustment."), "EmuCore/GS", "ShadeBoost", false); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_SUN, "Shade Boost Brightness"), FSUI_CSTR("Adjusts brightness. 50 is normal."), "EmuCore/GS", "ShadeBoost_Brightness", 50, 1, 100, "%d", shadeboost_active); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_LIGHTBULB, "Shade Boost Contrast"), FSUI_CSTR("Adjusts contrast. 50 is normal."), "EmuCore/GS", "ShadeBoost_Contrast", 50, 1, 100, "%d", shadeboost_active); DrawIntRangeSetting(bsi, FSUI_CSTR("Shade Boost Gamma"), FSUI_CSTR("Adjusts gamma. 50 is normal."), "EmuCore/GS", "ShadeBoost_Gamma", 50, 1, 100, "%d", shadeboost_active); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_DROPLET, "Shade Boost Saturation"), FSUI_CSTR("Adjusts saturation. 50 is normal."), "EmuCore/GS", "ShadeBoost_Saturation", 50, 1, 100, "%d", shadeboost_active); static constexpr const char* s_tv_shaders[] = { FSUI_NSTR("None (Default)"), FSUI_NSTR("Scanline Filter"), FSUI_NSTR("Diagonal Filter"), FSUI_NSTR("Triangular Filter"), FSUI_NSTR("Wave Filter"), FSUI_NSTR("Lottes CRT"), FSUI_NSTR("4xRGSS"), FSUI_NSTR("NxAGSS"), }; DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_TV, "TV Shaders"), FSUI_CSTR("Applies a shader which replicates the visual effects of different styles of television set."), "EmuCore/GS", "TVShader", 0, s_tv_shaders, std::size(s_tv_shaders), true); } static constexpr const char* s_gsdump_compression[] = { FSUI_NSTR("Uncompressed"), FSUI_NSTR("LZMA (xz)"), FSUI_NSTR("Zstandard (zst)"), }; if (show_advanced_settings) { MenuHeading(FSUI_CSTR("Advanced")); DrawToggleSetting(bsi, FSUI_CSTR("Skip Presenting Duplicate Frames"), FSUI_CSTR("Skips displaying frames that don't change in 25/30fps games. Can improve speed, but increase input lag/make frame pacing " "worse."), "EmuCore/GS", "SkipDuplicateFrames", false); DrawToggleSetting(bsi, FSUI_CSTR("Disable Mailbox Presentation"), FSUI_CSTR("Forces the use of FIFO over Mailbox presentation, i.e. double buffering instead of triple buffering. " "Usually results in worse frame pacing."), "EmuCore/GS", "DisableMailboxPresentation", false); /* DrawToggleSetting(bsi, FSUI_CSTR("Extended Upscaling Multipliers"), FSUI_CSTR("Displays additional, very high upscaling multipliers dependent on GPU capability."), "EmuCore/GS", "ExtendedUpscalingMultipliers", false); */ // TODO: Immplement this button properly if (IsEditingGameSettings(bsi)) { DrawIntListSetting(bsi, FSUI_CSTR("Hardware Download Mode"), FSUI_CSTR("Changes synchronization behavior for GS downloads."), "EmuCore/GS", "HWDownloadMode", static_cast(GSHardwareDownloadMode::Enabled), s_hw_download, std::size(s_hw_download), true); } DrawIntListSetting(bsi, FSUI_CSTR("Allow Exclusive Fullscreen"), FSUI_CSTR("Overrides the driver's heuristics for enabling exclusive fullscreen, or direct flip/scanout."), "EmuCore/GS", "ExclusiveFullscreenControl", -1, s_generic_options, std::size(s_generic_options), true, -1, (renderer == GSRendererType::Auto || renderer == GSRendererType::VK)); DrawIntListSetting(bsi, FSUI_CSTR("Override Texture Barriers"), FSUI_CSTR("Forces texture barrier functionality to the specified value."), "EmuCore/GS", "OverrideTextureBarriers", -1, s_generic_options, std::size(s_generic_options), true, -1); DrawIntListSetting(bsi, FSUI_CSTR("GS Dump Compression"), FSUI_CSTR("Sets the compression algorithm for GS dumps."), "EmuCore/GS", "GSDumpCompression", static_cast(GSDumpCompressionMethod::LZMA), s_gsdump_compression, std::size(s_gsdump_compression), true); DrawToggleSetting(bsi, FSUI_CSTR("Disable Framebuffer Fetch"), FSUI_CSTR("Prevents the usage of framebuffer fetch when supported by host GPU."), "EmuCore/GS", "DisableFramebufferFetch", false); DrawToggleSetting(bsi, FSUI_CSTR("Disable Shader Cache"), FSUI_CSTR("Prevents the loading and saving of shaders/pipelines to disk."), "EmuCore/GS", "DisableShaderCache", false); DrawToggleSetting(bsi, FSUI_CSTR("Disable Vertex Shader Expand"), FSUI_CSTR("Falls back to the CPU for expanding sprites/lines."), "EmuCore/GS", "DisableVertexShaderExpand", false); DrawIntListSetting(bsi, FSUI_CSTR("Texture Preloading"), FSUI_CSTR( "Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games."), "EmuCore/GS", "texture_preloading", static_cast(TexturePreloadingLevel::Off), s_preloading_options, std::size(s_preloading_options), true); DrawFloatRangeSetting(bsi, FSUI_CSTR("NTSC Frame Rate"), FSUI_CSTR("Determines what frame rate NTSC games run at."), "EmuCore/GS", "FrameRateNTSC", 59.94f, 10.0f, 300.0f, "%.2f Hz"); DrawFloatRangeSetting(bsi, FSUI_CSTR("PAL Frame Rate"), FSUI_CSTR("Determines what frame rate PAL games run at."), "EmuCore/GS", "FrameRatePAL", 50.0f, 10.0f, 300.0f, "%.2f Hz"); } EndMenuButtons(); } void FullscreenUI::DrawAudioSettingsPage() { SettingsInterface* bsi = GetEditingSettingsInterface(); BeginMenuButtons(); MenuHeading(FSUI_CSTR("Audio Control")); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_VOLUME_HIGH, "Standard Volume"), FSUI_CSTR("Controls the volume of the audio played on the host at normal speed."), "SPU2/Output", "StandardVolume", 100, 0, 100, "%d%%"); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_FORWARD_FAST, "Fast Forward Volume"), FSUI_CSTR("Controls the volume of the audio played on the host when fast forwarding."), "SPU2/Output", "FastForwardVolume", 100, 0, 100, "%d%%"); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_VOLUME_XMARK, "Mute All Sound"), FSUI_CSTR("Prevents the emulator from producing any audible sound."), "SPU2/Output", "OutputMuted", false); MenuHeading(FSUI_CSTR("Backend Settings")); DrawEnumSetting( bsi, FSUI_ICONSTR(ICON_FA_VOLUME_OFF, "Audio Backend"), FSUI_CSTR("Determines how audio frames produced by the emulator are submitted to the host."), "SPU2/Output", "Backend", Pcsx2Config::SPU2Options::DEFAULT_BACKEND, &AudioStream::ParseBackendName, &AudioStream::GetBackendName, &AudioStream::GetBackendDisplayName, AudioBackend::Count); DrawEnumSetting(bsi, FSUI_ICONSTR(ICON_PF_SPEAKER_ALT, "Expansion"), FSUI_CSTR("Determines how audio is expanded from stereo to surround for supported games."), "SPU2/Output", "ExpansionMode", AudioStreamParameters::DEFAULT_EXPANSION_MODE, &AudioStream::ParseExpansionMode, &AudioStream::GetExpansionModeName, &AudioStream::GetExpansionModeDisplayName, AudioExpansionMode::Count); DrawEnumSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROWS_SPIN, "Synchronization"), FSUI_CSTR("Changes when SPU samples are generated relative to system emulation."), "SPU2/Output", "SyncMode", Pcsx2Config::SPU2Options::DEFAULT_SYNC_MODE, &Pcsx2Config::SPU2Options::ParseSyncMode, &Pcsx2Config::SPU2Options::GetSyncModeName, &Pcsx2Config::SPU2Options::GetSyncModeDisplayName, Pcsx2Config::SPU2Options::SPU2SyncMode::Count); DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_BUCKET, "Buffer Size"), FSUI_CSTR("Determines the amount of audio buffered before being pulled by the host API."), "SPU2/Output", "BufferMS", AudioStreamParameters::DEFAULT_BUFFER_MS, 10, 500, FSUI_CSTR("%d ms")); if (!GetEffectiveBoolSetting(bsi, "Audio", "OutputLatencyMinimal", AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MINIMAL)) { DrawIntRangeSetting( bsi, FSUI_ICONSTR(ICON_FA_STOPWATCH_20, "Output Latency"), FSUI_CSTR("Determines how much latency there is between the audio being picked up by the host API, and " "played through speakers."), "SPU2/Output", "OutputLatencyMS", AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MS, 1, 500, FSUI_CSTR("%d ms")); } DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_STOPWATCH, "Minimal Output Latency"), FSUI_CSTR("When enabled, the minimum supported output latency will be used for the host API."), "SPU2/Output", "OutputLatencyMinimal", AudioStreamParameters::DEFAULT_OUTPUT_LATENCY_MINIMAL); EndMenuButtons(); } void FullscreenUI::DrawMemoryCardSettingsPage() { BeginMenuButtons(); SettingsInterface* bsi = GetEditingSettingsInterface(); MenuHeading(FSUI_CSTR("Settings and Operations")); if (MenuButton(FSUI_ICONSTR(ICON_FA_FILE_CIRCLE_PLUS, "Create Memory Card"), FSUI_CSTR("Creates a new memory card file or folder."))) OpenMemoryCardCreateDialog(); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Memory Card Directory"), "Folders", "MemoryCards", EmuFolders::MemoryCards); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MAGNIFYING_GLASS, "Folder Memory Card Filter"), FSUI_CSTR("Simulates a larger memory card by filtering saves only to the current game."), "EmuCore", "McdFolderAutoManage", true); for (u32 port = 0; port < NUM_MEMORY_CARD_PORTS; port++) { SmallString str; str.format(FSUI_FSTR("Slot {}"), port + 1); MenuHeading(str.c_str()); std::string enable_key(fmt::format("Slot{}_Enable", port + 1)); std::string file_key(fmt::format("Slot{}_Filename", port + 1)); DrawToggleSetting(bsi, SmallString::from_format(fmt::runtime(FSUI_ICONSTR_S(ICON_PF_MEMORY_CARD, "Memory Card Enabled", "##card_enabled_{}")), port), FSUI_CSTR("If not set, this card will be considered unplugged."), "MemoryCards", enable_key.c_str(), true); const bool enabled = GetEffectiveBoolSetting(bsi, "MemoryCards", enable_key.c_str(), true); const std::optional value = bsi->GetOptionalSmallStringValue("MemoryCards", file_key.c_str(), IsEditingGameSettings(bsi) ? std::nullopt : std::optional(FileMcd_GetDefaultName(port).c_str())); if (MenuButtonWithValue(SmallString::from_format(fmt::runtime(FSUI_ICONSTR_S(ICON_FA_FILE, "Card Name", "##card_name_{}")), port), FSUI_CSTR("The selected memory card image will be used for this slot."), value.has_value() ? value->c_str() : FSUI_CSTR("Use Global Setting"), enabled)) { ImGuiFullscreen::ChoiceDialogOptions options; std::vector names; if (IsEditingGameSettings(bsi)) options.emplace_back(FSUI_STR("Use Global Setting"), !value.has_value()); if (value.has_value() && !value->empty()) { options.emplace_back(fmt::format(FSUI_FSTR("{} (Current)"), value.value()), true); names.emplace_back(value->view()); } for (AvailableMcdInfo& mci : FileMcd_GetAvailableCards(IsEditingGameSettings(bsi))) { if (mci.type == MemoryCardType::Folder) { options.emplace_back(fmt::format(FSUI_FSTR("{} (Folder)"), mci.name), false); } else { static constexpr const char* file_type_names[] = { FSUI_NSTR("Unknown"), FSUI_NSTR("PS2 (8MB)"), FSUI_NSTR("PS2 (16MB)"), FSUI_NSTR("PS2 (32MB)"), FSUI_NSTR("PS2 (64MB)"), FSUI_NSTR("PS1"), }; options.emplace_back(fmt::format("{} ({})", mci.name, Host::TranslateToStringView(TR_CONTEXT, file_type_names[static_cast(mci.file_type)])), false); } names.push_back(std::move(mci.name)); } OpenChoiceDialog(str.c_str(), false, std::move(options), [game_settings = IsEditingGameSettings(bsi), names = std::move(names), file_key = std::move(file_key)]( s32 index, const std::string& title, bool checked) { if (index < 0) return; auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); if (game_settings && index == 0) { bsi->DeleteValue("MemoryCards", file_key.c_str()); } else { if (game_settings) index--; bsi->SetStringValue("MemoryCards", file_key.c_str(), names[index].c_str()); } SetSettingsChanged(bsi); CloseChoiceDialog(); }); } if (MenuButton(SmallString::from_format(fmt::runtime(FSUI_ICONSTR_S(ICON_FA_EJECT, "Eject Card", "##eject_card_{}")), port), FSUI_CSTR("Removes the current card from the slot."), enabled)) { bsi->SetStringValue("MemoryCards", file_key.c_str(), ""); SetSettingsChanged(bsi); } } EndMenuButtons(); } void FullscreenUI::DrawNetworkHDDSettingsPage() { static constexpr const char* dns_options[] = { FSUI_NSTR("Manual"), FSUI_NSTR("Auto"), FSUI_NSTR("Internal"), }; static constexpr const char* dns_values[] = { "Manual", "Auto", "Internal", }; SettingsInterface* bsi = GetEditingSettingsInterface(); BeginMenuButtons(); MenuHeading(FSUI_CSTR("Network Adapter")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_NETWORK_WIRED, "Enable Network Adapter"), FSUI_CSTR("Enables the network adapter for online functionality and LAN play."), "DEV9/Eth", "EthEnable", false); const bool network_enabled = GetEffectiveBoolSetting(bsi, "DEV9/Eth", "EthEnable", false); const std::string current_api = bsi->GetStringValue("DEV9/Eth", "EthApi", "Unset"); static std::vector> adapter_lists; static std::vector api_types; static std::vector api_display_names; static bool adapters_loaded = false; if (!adapters_loaded && network_enabled) { adapter_lists.clear(); api_types.clear(); api_display_names.clear(); adapter_lists.emplace_back(); api_types.emplace_back(Pcsx2Config::DEV9Options::NetApi::Unset); api_display_names.emplace_back("Unset"); std::vector pcap_adapters = PCAPAdapter::GetAdapters(); if (!pcap_adapters.empty()) { std::vector pcap_bridged_adapters; std::vector pcap_switched_adapters; std::set seen_bridged_guids; std::set seen_switched_guids; for (const auto& adapter : pcap_adapters) { if (adapter.type == Pcsx2Config::DEV9Options::NetApi::PCAP_Bridged) { if (seen_bridged_guids.find(adapter.guid) == seen_bridged_guids.end()) { seen_bridged_guids.insert(adapter.guid); pcap_bridged_adapters.push_back(adapter); } } else if (adapter.type == Pcsx2Config::DEV9Options::NetApi::PCAP_Switched) { if (seen_switched_guids.find(adapter.guid) == seen_switched_guids.end()) { seen_switched_guids.insert(adapter.guid); pcap_switched_adapters.push_back(adapter); } } } // Sort adapters alphabetically by name std::sort(pcap_bridged_adapters.begin(), pcap_bridged_adapters.end(), [](const AdapterEntry& a, const AdapterEntry& b) { return a.name < b.name; }); std::sort(pcap_switched_adapters.begin(), pcap_switched_adapters.end(), [](const AdapterEntry& a, const AdapterEntry& b) { return a.name < b.name; }); if (!pcap_bridged_adapters.empty()) { adapter_lists.emplace_back(pcap_bridged_adapters); api_types.emplace_back(Pcsx2Config::DEV9Options::NetApi::PCAP_Bridged); api_display_names.emplace_back("PCAP Bridged"); } if (!pcap_switched_adapters.empty()) { adapter_lists.emplace_back(pcap_switched_adapters); api_types.emplace_back(Pcsx2Config::DEV9Options::NetApi::PCAP_Switched); api_display_names.emplace_back("PCAP Switched"); } } #ifdef _WIN32 std::vector tap_adapters = TAPAdapter::GetAdapters(); if (!tap_adapters.empty()) { // Sort adapters alphabetically by name std::sort(tap_adapters.begin(), tap_adapters.end(), [](const AdapterEntry& a, const AdapterEntry& b) { return a.name < b.name; }); adapter_lists.emplace_back(tap_adapters); api_types.emplace_back(Pcsx2Config::DEV9Options::NetApi::TAP); api_display_names.emplace_back("TAP"); } #endif std::vector socket_adapters = SocketAdapter::GetAdapters(); if (!socket_adapters.empty()) { // Sort adapters alphabetically by name std::sort(socket_adapters.begin(), socket_adapters.end(), [](const AdapterEntry& a, const AdapterEntry& b) { return a.name < b.name; }); adapter_lists.emplace_back(socket_adapters); api_types.emplace_back(Pcsx2Config::DEV9Options::NetApi::Sockets); api_display_names.emplace_back("Sockets"); } adapters_loaded = true; } size_t current_api_index = 0; for (size_t i = 0; i < api_types.size(); i++) { if (current_api == Pcsx2Config::DEV9Options::NetApiNames[static_cast(api_types[i])]) { current_api_index = i; break; } } if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_PLUG, "Ethernet Device Type"), FSUI_CSTR("Determines the simulated Ethernet adapter type."), current_api_index < api_display_names.size() ? api_display_names[current_api_index].c_str() : "Unset", network_enabled)) { ImGuiFullscreen::ChoiceDialogOptions options; for (size_t i = 0; i < api_display_names.size(); i++) { options.emplace_back(api_display_names[i], i == current_api_index); } std::vector current_api_types = api_types; std::vector> current_adapter_lists = adapter_lists; OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_PLUG, "Ethernet Device Type"), false, std::move(options), [bsi, current_api_types, current_adapter_lists](s32 index, const std::string& title, bool checked) { if (index < 0 || index >= static_cast(current_api_types.size())) return; auto lock = Host::GetSettingsLock(); const std::string selected_api = Pcsx2Config::DEV9Options::NetApiNames[static_cast(current_api_types[index])]; const std::string previous_api = bsi->GetStringValue("DEV9/Eth", "EthApi", "Unset"); const std::string previous_device = bsi->GetStringValue("DEV9/Eth", "EthDevice", ""); bsi->SetStringValue("DEV9/Eth", "EthApi", selected_api.c_str()); std::string new_device = ""; if (index < static_cast(current_adapter_lists.size())) { const auto& new_adapter_list = current_adapter_lists[index]; // Try to find the same GUID in the new adapter list if (!previous_device.empty()) { for (const auto& adapter : new_adapter_list) { if (adapter.guid == previous_device) { new_device = adapter.guid; break; } } } // If no matching device found, use the first available device if (new_device.empty() && !new_adapter_list.empty()) { new_device = new_adapter_list[0].guid; } } bsi->SetStringValue("DEV9/Eth", "EthDevice", new_device.c_str()); SetSettingsChanged(bsi); CloseChoiceDialog(); }); } const std::string current_device = bsi->GetStringValue("DEV9/Eth", "EthDevice", ""); const bool show_device_setting = (current_api_index > 0 && current_api_index < api_types.size()); std::string device_display = ""; if (show_device_setting && !current_device.empty()) { if (current_api_index < adapter_lists.size()) { const auto& adapter_list = adapter_lists[current_api_index]; for (const auto& adapter : adapter_list) { if (adapter.guid == current_device) { device_display = adapter.name; break; } } } if (device_display.empty()) device_display = current_device; } else if (show_device_setting && current_device.empty()) { device_display = "Not Selected"; } if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_ETHERNET, "Ethernet Device"), FSUI_CSTR("Network adapter to use for PS2 network emulation."), device_display.c_str(), network_enabled && show_device_setting)) { ImGuiFullscreen::ChoiceDialogOptions options; if (current_api_index > 0 && current_api_index < adapter_lists.size()) { const auto& adapter_list = adapter_lists[current_api_index]; for (size_t i = 0; i < adapter_list.size(); i++) { const auto& adapter = adapter_list[i]; options.emplace_back(adapter.name, adapter.guid == current_device); } } if (options.empty()) { options.emplace_back("No adapters found", false); } std::vector current_adapter_list; if (current_api_index > 0 && current_api_index < adapter_lists.size()) { current_adapter_list = adapter_lists[current_api_index]; } std::string current_api_choice = bsi->GetStringValue("DEV9/Eth", "EthApi", "Unset"); OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_ETHERNET, "Ethernet Device"), false, std::move(options), [bsi, current_adapter_list, current_api_choice](s32 index, const std::string& title, bool checked) { if (index < 0 || title == "No adapters found") return; if (index < static_cast(current_adapter_list.size())) { const auto& selected_adapter = current_adapter_list[index]; auto lock = Host::GetSettingsLock(); bsi->SetStringValue("DEV9/Eth", "EthApi", current_api_choice.c_str()); bsi->SetStringValue("DEV9/Eth", "EthDevice", selected_adapter.guid.c_str()); SetSettingsChanged(bsi); } CloseChoiceDialog(); }); } AdapterOptions adapter_options = AdapterOptions::None; const std::string final_api = bsi->GetStringValue("DEV9/Eth", "EthApi", "Unset"); if (final_api == "PCAP Bridged" || final_api == "PCAP Switched") adapter_options = PCAPAdapter::GetAdapterOptions(); #ifdef _WIN32 else if (final_api == "TAP") adapter_options = TAPAdapter::GetAdapterOptions(); #endif else if (final_api == "Sockets") adapter_options = SocketAdapter::GetAdapterOptions(); const bool dhcp_can_be_disabled = (adapter_options & AdapterOptions::DHCP_ForcedOn) == AdapterOptions::None; DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SHIELD_HALVED, "Intercept DHCP"), FSUI_CSTR("When enabled, DHCP packets will be intercepted and replaced with internal responses."), "DEV9/Eth", "InterceptDHCP", false, network_enabled && dhcp_can_be_disabled); MenuHeading(FSUI_CSTR("Network Configuration")); const bool intercept_dhcp = GetEffectiveBoolSetting(bsi, "DEV9/Eth", "InterceptDHCP", false); const bool dhcp_forced_on = (adapter_options & AdapterOptions::DHCP_ForcedOn) == AdapterOptions::DHCP_ForcedOn; const bool ip_settings_enabled = network_enabled && (intercept_dhcp || dhcp_forced_on); const bool ip_can_be_edited = (adapter_options & AdapterOptions::DHCP_OverrideIP) == AdapterOptions::None; const bool subnet_can_be_edited = (adapter_options & AdapterOptions::DHCP_OverideSubnet) == AdapterOptions::None; const bool gateway_can_be_edited = (adapter_options & AdapterOptions::DHCP_OverideGateway) == AdapterOptions::None; DrawIPAddressSetting(bsi, FSUI_ICONSTR(ICON_FA_NETWORK_WIRED, "Address"), FSUI_CSTR("IP address for the PS2 virtual network adapter."), "DEV9/Eth", "PS2IP", "0.0.0.0", ip_settings_enabled && ip_can_be_edited, LAYOUT_MENU_BUTTON_HEIGHT, g_large_font, g_medium_font, IPAddressType::PS2IP); const bool mask_auto = GetEffectiveBoolSetting(bsi, "DEV9/Eth", "AutoMask", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_WAND_MAGIC, "Auto Subnet Mask"), FSUI_CSTR("Automatically determine the subnet mask based on the IP address class."), "DEV9/Eth", "AutoMask", true, ip_settings_enabled && subnet_can_be_edited); DrawIPAddressSetting(bsi, FSUI_ICONSTR(ICON_FA_NETWORK_WIRED, "Subnet Mask"), FSUI_CSTR("Subnet mask for the PS2 virtual network adapter."), "DEV9/Eth", "Mask", "0.0.0.0", ip_settings_enabled && subnet_can_be_edited && !mask_auto, LAYOUT_MENU_BUTTON_HEIGHT, g_large_font, g_medium_font, IPAddressType::SubnetMask); const bool gateway_auto = GetEffectiveBoolSetting(bsi, "DEV9/Eth", "AutoGateway", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_WAND_MAGIC, "Auto Gateway"), FSUI_CSTR("Automatically determine the gateway address based on the IP address."), "DEV9/Eth", "AutoGateway", true, ip_settings_enabled && gateway_can_be_edited); DrawIPAddressSetting(bsi, FSUI_ICONSTR(ICON_FA_NETWORK_WIRED, "Gateway Address"), FSUI_CSTR("Gateway address for the PS2 virtual network adapter."), "DEV9/Eth", "Gateway", "0.0.0.0", ip_settings_enabled && gateway_can_be_edited && !gateway_auto, LAYOUT_MENU_BUTTON_HEIGHT, g_large_font, g_medium_font, IPAddressType::Gateway); // DNS Configuration const std::string dns1_mode = bsi->GetStringValue("DEV9/Eth", "ModeDNS1", "Auto"); const std::string dns2_mode = bsi->GetStringValue("DEV9/Eth", "ModeDNS2", "Auto"); const bool dns1_editable = dns1_mode == "Manual" && ip_settings_enabled; const bool dns2_editable = dns2_mode == "Manual" && ip_settings_enabled; DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_SERVER, "DNS1 Mode"), FSUI_CSTR("Determines how primary DNS requests are handled."), "DEV9/Eth", "ModeDNS1", "Auto", dns_options, dns_values, std::size(dns_options), true, ip_settings_enabled); DrawIPAddressSetting(bsi, FSUI_ICONSTR(ICON_FA_SERVER, "DNS1 Address"), FSUI_CSTR("Primary DNS server address for the PS2 virtual network adapter."), "DEV9/Eth", "DNS1", "0.0.0.0", dns1_editable, LAYOUT_MENU_BUTTON_HEIGHT, g_large_font, g_medium_font, IPAddressType::DNS1); DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_SERVER, "DNS2 Mode"), FSUI_CSTR("Determines how secondary DNS requests are handled."), "DEV9/Eth", "ModeDNS2", "Auto", dns_options, dns_values, std::size(dns_options), true, ip_settings_enabled); DrawIPAddressSetting(bsi, FSUI_ICONSTR(ICON_FA_SERVER, "DNS2 Address"), FSUI_CSTR("Secondary DNS server address for the PS2 virtual network adapter."), "DEV9/Eth", "DNS2", "0.0.0.0", dns2_editable, LAYOUT_MENU_BUTTON_HEIGHT, g_large_font, g_medium_font, IPAddressType::DNS2); MenuHeading(FSUI_CSTR("Internal HDD")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FLOPPY_DISK, "Enable HDD"), FSUI_CSTR("Enables the internal Hard Disk Drive for expanded storage."), "DEV9/Hdd", "HddEnable", false); const bool hdd_enabled = GetEffectiveBoolSetting(bsi, "DEV9/Hdd", "HddEnable", false); const SmallString hdd_selection = GetEditingSettingsInterface()->GetSmallStringValue("DEV9/Hdd", "HddFile", ""); const std::string current_display = hdd_selection.empty() ? std::string(FSUI_CSTR("None")) : std::string(Path::GetFileName(hdd_selection.c_str())); if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_HARD_DRIVE, "HDD Image Selection"), FSUI_CSTR("Changes the HDD image used for PS2 internal storage."), current_display.c_str(), hdd_enabled)) { ImGuiFullscreen::ChoiceDialogOptions choices; choices.emplace_back(FSUI_STR("None"), hdd_selection.empty()); std::vector values; values.push_back(""); FileSystem::FindResultsArray results; FileSystem::FindFiles(EmuFolders::DataRoot.c_str(), "*.raw", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES, &results); for (const FILESYSTEM_FIND_DATA& fd : results) { const std::string full_path = fd.FileName; const std::string filename = std::string(Path::GetFileName(full_path)); // Get file size and determine LBA mode const s64 file_size = FileSystem::GetPathFileSize(full_path.c_str()); if (file_size > 0) { const int size_gb = static_cast(file_size / _1gb); const bool uses_lba48 = (file_size > static_cast(120) * _1gb); const std::string lba_mode = uses_lba48 ? "LBA48" : "LBA28"; choices.emplace_back(fmt::format("{} ({} GB, {})", filename, size_gb, lba_mode), hdd_selection == full_path); values.emplace_back(full_path); } } choices.emplace_back(FSUI_STR("Browse..."), false); values.emplace_back("__browse__"); choices.emplace_back(FSUI_STR("Create New..."), false); values.emplace_back("__create__"); OpenChoiceDialog(FSUI_CSTR("HDD Image Selection"), false, std::move(choices), [game_settings = IsEditingGameSettings(bsi), values = std::move(values)](s32 index, const std::string& title, bool checked) { if (index < 0) return; if (values[index] == "__browse__") { CloseChoiceDialog(); OpenFileSelector(FSUI_ICONSTR(ICON_FA_HARD_DRIVE, "Select HDD Image File"), false, [game_settings](const std::string& path) { if (path.empty()) return; auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetStringValue("DEV9/Hdd", "HddFile", path.c_str()); SetSettingsChanged(bsi); ShowToast(std::string(), fmt::format(FSUI_FSTR("Selected HDD image: {}"), Path::GetFileName(path))); }, {"*.raw", "*"}, EmuFolders::DataRoot); } else if (values[index] == "__create__") { CloseChoiceDialog(); std::vector> size_options = { {"40 GB (Recommended)", 40}, {"80 GB", 80}, {"120 GB (Max LBA28)", 120}, {"200 GB", 200}, {"Custom...", -1}}; ImGuiFullscreen::ChoiceDialogOptions size_choices; std::vector size_values; for (const auto& [label, size] : size_options) { size_choices.emplace_back(label, false); size_values.push_back(size); } OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_PLUS, "Select HDD Size"), false, std::move(size_choices), [game_settings, size_values = std::move(size_values)](s32 size_index, const std::string& size_title, bool size_checked) { if (size_index < 0) return; if (size_values[size_index] == -1) { CloseChoiceDialog(); OpenInputStringDialog( FSUI_ICONSTR(ICON_FA_PEN_TO_SQUARE, "Custom HDD Size"), FSUI_STR("Enter custom HDD size in gigabytes (40–2000):"), std::string(), FSUI_ICONSTR(ICON_FA_CHECK, "Create"), [game_settings](std::string input) { if (input.empty()) return; std::optional custom_size_opt = StringUtil::FromChars(input); if (!custom_size_opt.has_value()) { ShowToast(std::string(), FSUI_STR("Invalid size. Please enter a number between 40 and 2000.")); return; } int custom_size_gb = custom_size_opt.value(); if (custom_size_gb < 40 || custom_size_gb > 2000) { ShowToast(std::string(), FSUI_STR("HDD size must be between 40 GB and 2000 GB.")); return; } const bool lba48 = (custom_size_gb > 120); const std::string filename = fmt::format("DEV9hdd_{}GB_{}.raw", custom_size_gb, lba48 ? "LBA48" : "LBA28"); const std::string filepath = Path::Combine(EmuFolders::DataRoot, filename); if (FileSystem::FileExists(filepath.c_str())) { OpenConfirmMessageDialog( FSUI_ICONSTR(ICON_FA_TRIANGLE_EXCLAMATION, "File Already Exists"), fmt::format(FSUI_FSTR("HDD image '{}' already exists. Do you want to overwrite it?"), filename), [filepath, custom_size_gb, lba48, game_settings](bool confirmed) { if (confirmed) { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetStringValue("DEV9/Hdd", "HddFile", filepath.c_str()); SetSettingsChanged(bsi); FullscreenUI::CreateHardDriveWithProgress(filepath, custom_size_gb, lba48); } }); } else { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetStringValue("DEV9/Hdd", "HddFile", filepath.c_str()); SetSettingsChanged(bsi); FullscreenUI::CreateHardDriveWithProgress(filepath, custom_size_gb, lba48); } }, "40", InputFilterType::Numeric); return; } const int size_gb = size_values[size_index]; const bool lba48 = (size_gb > 120); const std::string filename = fmt::format("DEV9hdd_{}GB_{}.raw", size_gb, lba48 ? "LBA48" : "LBA28"); const std::string filepath = Path::Combine(EmuFolders::DataRoot, filename); if (FileSystem::FileExists(filepath.c_str())) { OpenConfirmMessageDialog( FSUI_ICONSTR(ICON_FA_TRIANGLE_EXCLAMATION, "File Already Exists"), fmt::format(FSUI_FSTR("HDD image '{}' already exists. Do you want to overwrite it?"), filename), [filepath, size_gb, lba48, game_settings](bool confirmed) { if (confirmed) { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetStringValue("DEV9/Hdd", "HddFile", filepath.c_str()); SetSettingsChanged(bsi); FullscreenUI::CreateHardDriveWithProgress(filepath, size_gb, lba48); } }); } else { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetStringValue("DEV9/Hdd", "HddFile", filepath.c_str()); SetSettingsChanged(bsi); FullscreenUI::CreateHardDriveWithProgress(filepath, size_gb, lba48); } CloseChoiceDialog(); }); } else { auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetStringValue("DEV9/Hdd", "HddFile", values[index].c_str()); SetSettingsChanged(bsi); CloseChoiceDialog(); } }); } EndMenuButtons(); } void FullscreenUI::OpenMemoryCardCreateDialog() { OpenInputStringDialog(FSUI_ICONSTR(ICON_FA_PLUS, "Create Memory Card"), FSUI_STR("Enter the name for the new memory card."), std::string(), FSUI_ICONSTR(ICON_FA_CHECK, "Create"), [](std::string name) { if (name.empty()) return; name.erase(std::remove(name.begin(), name.end(), '.'), name.end()); if (name.empty()) { ShowToast(std::string(), FSUI_STR("Memory card name cannot be empty.")); return; } // Show memory card selection dialog ImGuiFullscreen::ChoiceDialogOptions options; options.emplace_back(FSUI_STR("PS2 (8MB)"), true); options.emplace_back(FSUI_STR("PS2 (16MB)"), false); options.emplace_back(FSUI_STR("PS2 (32MB)"), false); options.emplace_back(FSUI_STR("PS2 (64MB)"), false); options.emplace_back(FSUI_STR("PS1 (128KB)"), false); options.emplace_back(FSUI_STR("Folder"), false); OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_FLOPPY_DISK, "Memory Card Type"), false, std::move(options), [name](s32 index, const std::string& title, bool checked) { if (index < 0) return; MemoryCardType type; MemoryCardFileType file_type; switch (index) { case 0: // PS2 (8MB) type = MemoryCardType::File; file_type = MemoryCardFileType::PS2_8MB; break; case 1: // PS2 (16MB) type = MemoryCardType::File; file_type = MemoryCardFileType::PS2_16MB; break; case 2: // PS2 (32MB) type = MemoryCardType::File; file_type = MemoryCardFileType::PS2_32MB; break; case 3: // PS2 (64MB) type = MemoryCardType::File; file_type = MemoryCardFileType::PS2_64MB; break; case 4: // PS1 (128KB) type = MemoryCardType::File; file_type = MemoryCardFileType::PS1; break; case 5: // Folder type = MemoryCardType::Folder; file_type = MemoryCardFileType::Unknown; break; default: return; } #ifdef _WIN32 // On Windows, show NTFS compression option for only file options (not folder) if (type == MemoryCardType::File) { ImGuiFullscreen::ChoiceDialogOptions compression_options; compression_options.emplace_back(FSUI_STR("Yes - Enable NTFS compression"), true); compression_options.emplace_back(FSUI_STR("No - Disable NTFS compression"), false); OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_BOX_ARCHIVE, "Use NTFS Compression?"), false, std::move(compression_options), [name, type, file_type](s32 compression_index, const std::string& compression_title, bool compression_checked) { if (compression_index < 0) return; const bool use_compression = (compression_index == 0); // 0 = Yes, 1 = No DoCreateMemoryCard(name, type, file_type, use_compression); CloseChoiceDialog(); }); return; } else { DoCreateMemoryCard(name, type, file_type, false); CloseChoiceDialog(); } #else DoCreateMemoryCard(name, type, file_type, false); CloseChoiceDialog(); #endif }); }); } void FullscreenUI::DoCreateMemoryCard(std::string name, MemoryCardType type, MemoryCardFileType file_type, bool use_ntfs_compression) { // Build the filename with the extension const std::string name_str = fmt::format("{}.{}", name, (file_type == MemoryCardFileType::PS1) ? "mcr" : "ps2"); // check the filename if (!Path::IsValidFileName(name_str, false)) { ShowToast(std::string(), fmt::format(FSUI_FSTR("Failed to create the Memory Card, because the name '{}' contains one or more invalid characters."), name)); return; } // Check if a memory card with this name already exists if (FileMcd_GetCardInfo(name_str).has_value()) { ShowToast(std::string(), fmt::format(FSUI_FSTR("Failed to create the Memory Card, because another card with the name '{}' already exists."), name)); return; } // Create the memory card if (!FileMcd_CreateNewCard(name_str, type, file_type)) { ShowToast(std::string(), FSUI_STR("Failed to create the Memory Card, the log may contain more information.")); return; } #ifdef _WIN32 if (type == MemoryCardType::File && use_ntfs_compression) { const std::string full_path = Path::Combine(EmuFolders::MemoryCards, name_str); FileSystem::SetPathCompression(full_path.c_str(), true); } #endif ShowToast(std::string(), fmt::format(FSUI_FSTR("Memory Card '{}' created."), name)); } void FullscreenUI::ResetControllerSettings() { OpenConfirmMessageDialog(FSUI_ICONSTR(u8"🔥", "Reset Controller Settings"), FSUI_STR("Are you sure you want to restore the default controller configuration?\n\n" "All shared bindings and configuration will be lost, but your input profiles will remain.\n\n" "You cannot undo this action."), [](bool result) { if (result) { SettingsInterface* dsi = GetEditingSettingsInterface(); Pad::SetDefaultControllerConfig(*dsi); Pad::SetDefaultHotkeyConfig(*dsi); USB::SetDefaultConfiguration(dsi); ShowToast(std::string(), FSUI_STR("Controller settings reset to default.")); } }); } void FullscreenUI::DoLoadInputProfile() { std::vector profiles = Pad::GetInputProfileNames(); if (profiles.empty()) { ShowToast(std::string(), FSUI_STR("No input profiles available.")); return; } ImGuiFullscreen::ChoiceDialogOptions coptions; coptions.reserve(profiles.size()); for (std::string& name : profiles) coptions.emplace_back(std::move(name), false); OpenChoiceDialog(FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Load Profile"), false, std::move(coptions), [](s32 index, const std::string& title, bool checked) { if (index < 0) return; INISettingsInterface ssi(VMManager::GetInputProfilePath(title)); if (!ssi.Load()) { ShowToast(std::string(), fmt::format(FSUI_FSTR("Failed to load '{}'."), title)); CloseChoiceDialog(); return; } auto lock = Host::GetSettingsLock(); SettingsInterface* dsi = GetEditingSettingsInterface(); Pad::CopyConfiguration(dsi, ssi, true, true, IsEditingGameSettings(dsi)); USB::CopyConfiguration(dsi, ssi, true, true); SetSettingsChanged(dsi); ShowToast(std::string(), fmt::format(FSUI_FSTR("Input profile '{}' loaded."), title)); CloseChoiceDialog(); }); } void FullscreenUI::DoSaveInputProfile(const std::string& name) { INISettingsInterface dsi(VMManager::GetInputProfilePath(name)); auto lock = Host::GetSettingsLock(); SettingsInterface* ssi = GetEditingSettingsInterface(); Pad::CopyConfiguration(&dsi, *ssi, true, true, IsEditingGameSettings(ssi)); USB::CopyConfiguration(&dsi, *ssi, true, true); if (dsi.Save()) ShowToast(std::string(), fmt::format(FSUI_FSTR("Input profile '{}' saved."), name)); else ShowToast(std::string(), fmt::format(FSUI_FSTR("Failed to save input profile '{}'."), name)); } void FullscreenUI::DoSaveInputProfile() { std::vector profiles = Pad::GetInputProfileNames(); ImGuiFullscreen::ChoiceDialogOptions coptions; coptions.reserve(profiles.size() + 1); coptions.emplace_back(FSUI_STR("Create New..."), false); for (std::string& name : profiles) coptions.emplace_back(std::move(name), false); OpenChoiceDialog( FSUI_ICONSTR(ICON_FA_FLOPPY_DISK, "Save Profile"), false, std::move(coptions), [](s32 index, const std::string& title, bool checked) { if (index < 0) return; if (index > 0) { DoSaveInputProfile(title); CloseChoiceDialog(); return; } CloseChoiceDialog(); OpenInputStringDialog(FSUI_ICONSTR(ICON_FA_FLOPPY_DISK, "Save Profile"), FSUI_STR("Custom input profiles are used to override the Shared input profile for specific games.\n\n" "To apply a custom input profile to a game, go to its Game Properties, then change the 'Input Profile' on the Summary tab.\n\n" "Enter the name for the new input profile:"), std::string(), FSUI_ICONSTR(ICON_FA_CHECK, "Create"), [](std::string title) { if (!title.empty()) DoSaveInputProfile(title); }); }); } void FullscreenUI::DoResetSettings() { OpenConfirmMessageDialog(FSUI_ICONSTR(u8"🔥", "Reset Settings"), FSUI_STR("Are you sure you want to restore the default settings? Any preferences will be lost."), [](bool result) { if (result) { Host::RunOnCPUThread([]() { Host::RequestResetSettings(false, true, false, false, false); }); ShowToast(std::string(), FSUI_STR("Settings reset to defaults.")); } }); } void FullscreenUI::DrawControllerSettingsPage() { BeginMenuButtons(); SettingsInterface* bsi = GetEditingSettingsInterface(); MenuHeading(FSUI_CSTR("Configuration")); if (MenuButton( FSUI_ICONSTR(ICON_FA_FOLDER_OPEN, "Load Profile"), FSUI_CSTR("Replaces these settings with a previously saved input profile."))) { DoLoadInputProfile(); } if (MenuButton(FSUI_ICONSTR(ICON_FA_FLOPPY_DISK, "Save Profile"), FSUI_CSTR("Stores the current settings to an input profile."))) { DoSaveInputProfile(); } if (MenuButton(FSUI_ICONSTR(u8"🔥", "Reset Settings"), FSUI_CSTR("Resets all configuration to defaults (including bindings)."))) { ResetControllerSettings(); } MenuHeading(FSUI_CSTR("Input Sources")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GEAR, "Enable SDL Input Source"), FSUI_CSTR("The SDL input source supports most controllers."), "InputSources", "SDL", true, true, false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_WIFI, "SDL DualShock 4 / DualSense Enhanced Mode"), FSUI_CSTR("Provides vibration and LED control support over Bluetooth."), "InputSources", "SDLControllerEnhancedMode", true, bsi->GetBoolValue("InputSources", "SDL", true), false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LIGHTBULB, "SDL DualSense Player LED"), FSUI_CSTR("Enable/Disable the Player LED on DualSense controllers."), "InputSources", "SDLPS5PlayerLED", true, bsi->GetBoolValue("InputSources", "SDLControllerEnhancedMode", true), true); #ifdef _WIN32 DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GEAR, "SDL Raw Input"), FSUI_CSTR("Allow SDL to use raw access to input devices."), "InputSources", "SDLRawInput", false, bsi->GetBoolValue("InputSources", "SDL", true), false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GEAR, "Enable XInput Input Source"), FSUI_CSTR("The XInput source provides support for XBox 360/XBox One/XBox Series controllers."), "InputSources", "XInput", false, true, false); #endif MenuHeading(FSUI_CSTR("Multitap")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SQUARE_PLUS, "Enable Console Port 1 Multitap"), FSUI_CSTR("Enables an additional three controller slots. Not supported in all games."), "Pad", "MultitapPort1", false, true, false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SQUARE_PLUS, "Enable Console Port 2 Multitap"), FSUI_CSTR("Enables an additional three controller slots. Not supported in all games."), "Pad", "MultitapPort2", false, true, false); const std::array mtap_enabled = { {bsi->GetBoolValue("Pad", "MultitapPort1", false), bsi->GetBoolValue("Pad", "MultitapPort2", false)}}; // we reorder things a little to make it look less silly for mtap static constexpr const std::array mtap_slot_names = {{'A', 'B', 'C', 'D'}}; static constexpr const std::array mtap_port_order = {{0, 2, 3, 4, 1, 5, 6, 7}}; static constexpr const std::array sections = { {"Pad1", "Pad2", "Pad3", "Pad4", "Pad5", "Pad6", "Pad7", "Pad8"}}; // create the ports for (u32 global_slot : mtap_port_order) { const bool is_mtap_port = sioPadIsMultitapSlot(global_slot); const auto [mtap_port, mtap_slot] = sioConvertPadToPortAndSlot(global_slot); if (is_mtap_port && !mtap_enabled[mtap_port]) continue; ImGui::PushID(global_slot); if (mtap_enabled[mtap_port]) { MenuHeading(SmallString::from_format( fmt::runtime(FSUI_ICONSTR(ICON_FA_PLUG, "Controller Port {}{}")), mtap_port + 1, mtap_slot_names[mtap_slot])); } else { MenuHeading(SmallString::from_format(fmt::runtime(FSUI_ICONSTR(ICON_FA_PLUG, "Controller Port {}")), mtap_port + 1)); } const char* section = sections[global_slot]; const Pad::ControllerInfo* ci = Pad::GetConfigControllerType(*bsi, section, global_slot); if (MenuButton(FSUI_ICONSTR(ICON_PF_GAMEPAD_ALT, "Controller Type"), ci ? ci->GetLocalizedName() : FSUI_CSTR("Unknown"))) { const std::vector> raw_options = Pad::GetControllerTypeNames(); ImGuiFullscreen::ChoiceDialogOptions options; options.reserve(raw_options.size()); for (auto& it : raw_options) options.emplace_back(it.second, (ci && ci->name == it.first)); OpenChoiceDialog(fmt::format(FSUI_FSTR("Port {} Controller Type"), global_slot + 1).c_str(), false, std::move(options), [game_settings = IsEditingGameSettings(bsi), section, raw_options = std::move(raw_options)]( s32 index, const std::string& title, bool checked) { if (index < 0) return; auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); bsi->SetStringValue(section, "Type", raw_options[index].first); SetSettingsChanged(bsi); CloseChoiceDialog(); }); } if (!ci || ci->bindings.empty()) { ImGui::PopID(); continue; } if (MenuButton( FSUI_ICONSTR(ICON_FA_WAND_MAGIC_SPARKLES, "Automatic Mapping"), FSUI_CSTR("Attempts to map the selected port to a chosen controller."))) StartAutomaticBinding(global_slot); for (const InputBindingInfo& bi : ci->bindings) if (bi.name) [[likely]] DrawInputBindingButton(bsi, bi.bind_type, section, bi.name, Host::TranslateToCString("Pad", bi.display_name), bi.icon_name, true); if (mtap_enabled[mtap_port]) { MenuHeading(SmallString::from_format( fmt::runtime(FSUI_ICONSTR(ICON_PF_EMPTY_KEYCAP, "Controller Port {}{} Macros")), mtap_port + 1, mtap_slot_names[mtap_slot])); } else { MenuHeading(SmallString::from_format(fmt::runtime(FSUI_ICONSTR(ICON_PF_EMPTY_KEYCAP, "Controller Port {} Macros")), mtap_port + 1)); } static bool macro_button_expanded[Pad::NUM_CONTROLLER_PORTS][Pad::NUM_MACRO_BUTTONS_PER_CONTROLLER] = {}; for (u32 macro_index = 0; macro_index < Pad::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_index++) { bool& expanded = macro_button_expanded[global_slot][macro_index]; expanded ^= MenuHeadingButton(SmallString::from_format(fmt::runtime(FSUI_ICONSTR(ICON_PF_EMPTY_KEYCAP, "Macro Button {}")), macro_index + 1), macro_button_expanded[global_slot][macro_index] ? ICON_FA_CHEVRON_UP : ICON_FA_CHEVRON_DOWN); if (!expanded) continue; ImGui::PushID(&expanded); DrawInputBindingButton( bsi, InputBindingInfo::Type::Macro, section, TinyString::from_format("Macro{}", macro_index + 1), FSUI_CSTR("Trigger"), nullptr); SmallString binds_string = bsi->GetSmallStringValue(section, fmt::format("Macro{}Binds", macro_index + 1).c_str()); TinyString pretty_binds_string; if (!binds_string.empty()) { for (const std::string_view& bind : StringUtil::SplitString(binds_string, '&', true)) { const char* dispname = nullptr; for (const InputBindingInfo& bi : ci->bindings) { if (bind == bi.name) { dispname = bi.icon_name ? bi.icon_name : Host::TranslateToCString("Pad", bi.display_name); break; } } pretty_binds_string.append_format("{}{}", pretty_binds_string.empty() ? "" : " ", dispname); } } if (MenuButtonWithValue(FSUI_ICONSTR(ICON_FA_KEYBOARD, "Buttons"), nullptr, pretty_binds_string.empty() ? FSUI_CSTR("-") : pretty_binds_string.c_str(), true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY)) { std::vector buttons_split(StringUtil::SplitString(binds_string, '&', true)); ImGuiFullscreen::ChoiceDialogOptions options; for (const InputBindingInfo& bi : ci->bindings) { if (bi.bind_type != InputBindingInfo::Type::Button && bi.bind_type != InputBindingInfo::Type::Axis && bi.bind_type != InputBindingInfo::Type::HalfAxis) { continue; } options.emplace_back(Host::TranslateToCString("Pad", bi.display_name), std::any_of( buttons_split.begin(), buttons_split.end(), [bi](const std::string_view& it) { return (it == bi.name); })); } OpenChoiceDialog(fmt::format(FSUI_FSTR("Select Macro {} Binds"), macro_index + 1).c_str(), true, std::move(options), [section, macro_index, ci](s32 index, const std::string& title, bool checked) { // convert display name back to bind name std::string_view to_modify; for (const InputBindingInfo& bi : ci->bindings) { if (bi.display_name == title) { to_modify = bi.name; break; } } if (to_modify.empty()) { // wtf? return; } auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(); const std::string key(fmt::format("Macro{}Binds", macro_index + 1)); std::string binds_string(bsi->GetStringValue(section, key.c_str())); std::vector buttons_split(StringUtil::SplitString(binds_string, '&', true)); auto it = std::find(buttons_split.begin(), buttons_split.end(), to_modify); if (checked) { if (it == buttons_split.end()) buttons_split.push_back(to_modify); } else { if (it != buttons_split.end()) buttons_split.erase(it); } binds_string = StringUtil::JoinString(buttons_split.begin(), buttons_split.end(), " & "); if (binds_string.empty()) bsi->DeleteValue(section, key.c_str()); else bsi->SetStringValue(section, key.c_str(), binds_string.c_str()); SetSettingsChanged(bsi); }); } DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GAMEPAD, "Press To Toggle"), FSUI_CSTR("Toggles the macro when the button is pressed, instead of held."), section, TinyString::from_format("Macro{}Toggle", macro_index + 1), false, true, false); const TinyString freq_key = TinyString::from_format("Macro{}Frequency", macro_index + 1); const TinyString freq_label = TinyString::from_format(ICON_FA_CLOCK " {}##macro_{}_frequency", FSUI_VSTR("Frequency"), macro_index + 1); s32 frequency = bsi->GetIntValue(section, freq_key.c_str(), 0); const SmallString freq_summary = ((frequency == 0) ? TinyString(FSUI_VSTR("Disabled")) : TinyString::from_format(FSUI_FSTR("{} Frames"), frequency)); if (MenuButtonWithValue(freq_label, FSUI_CSTR("Determines the frequency at which the macro will toggle the buttons on and off (aka auto fire)."), freq_summary, true)) ImGui::OpenPopup(freq_label.c_str()); const std::string pressure_key(fmt::format("Macro{}Pressure", macro_index + 1)); DrawFloatSpinBoxSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_DOWN, "Pressure"), FSUI_CSTR("Determines how much pressure is simulated when macro is active."), section, pressure_key.c_str(), 1.0f, 0.01f, 1.0f, 0.01f, 100.0f, "%.0f%%"); const std::string deadzone_key(fmt::format("Macro{}Deadzone", macro_index + 1)); DrawFloatSpinBoxSetting(bsi, FSUI_ICONSTR(ICON_FA_SKULL, "Deadzone"), FSUI_CSTR("Determines the pressure required to activate the macro."), section, deadzone_key.c_str(), 0.0f, 0.00f, 1.0f, 0.01f, 100.0f, "%.0f%%"); ImGui::SetNextWindowSize(LayoutScale(500.0f, 180.0f)); ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::PushFont(g_large_font.first, g_large_font.second); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, LayoutScale(10.0f)); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, LayoutScale(20.0f, 20.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, LayoutScale(ImGuiFullscreen::LAYOUT_MENU_BUTTON_X_PADDING, ImGuiFullscreen::LAYOUT_MENU_BUTTON_Y_PADDING)); if (ImGui::BeginPopupModal( freq_label.c_str(), nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) { ImGui::SetNextItemWidth(LayoutScale(450.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, LayoutScale(8.0f)); ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, LayoutScale(1.0f)); ImGui::PushStyleVar(ImGuiStyleVar_GrabRounding, LayoutScale(8.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(0.25f, 0.25f, 0.25f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.3f, 0.3f, 0.3f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.4f, 0.4f, 0.4f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.45f, 0.65f, 0.95f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_SliderGrabActive, ImVec4(0.55f, 0.75f, 1.0f, 1.0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); if (ImGui::SliderInt("##value", &frequency, 0, 60, FSUI_CSTR("Toggle every %d frames"), ImGuiSliderFlags_NoInput)) { if (frequency == 0) bsi->DeleteValue(section, freq_key.c_str()); else bsi->SetIntValue(section, freq_key.c_str(), frequency); SetSettingsChanged(bsi); } ImGui::PopStyleColor(7); ImGui::PopStyleVar(3); BeginMenuButtons(); if (MenuButton("OK", nullptr, true, LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY)) ImGui::CloseCurrentPopup(); EndMenuButtons(); ImGui::EndPopup(); } ImGui::PopStyleVar(4); ImGui::PopFont(); ImGui::PopID(); } if (!ci->settings.empty()) { if (mtap_enabled[mtap_port]) { MenuHeading(SmallString::from_format(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS, "Controller Port {}{} Settings")), mtap_port + 1, mtap_slot_names[mtap_slot])); } else { MenuHeading( SmallString::from_format(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS, "Controller Port {} Settings")), mtap_port + 1)); } for (const SettingInfo& si : ci->settings) DrawSettingInfoSetting(bsi, section, Host::TranslateToCString("Pad", si.name), si, "Pad"); } ImGui::PopID(); } for (u32 port = 0; port < USB::NUM_PORTS; port++) { ImGui::PushID(port); MenuHeading(TinyString::from_format(fmt::runtime(FSUI_ICONSTR(ICON_FA_PLUG, "USB Port {}")), port + 1)); const std::string type(USB::GetConfigDevice(*bsi, port)); if (MenuButton(FSUI_ICONSTR(ICON_PF_USB, "Device Type"), USB::GetDeviceName(type))) { const std::vector> raw_options = USB::GetDeviceTypes(); ImGuiFullscreen::ChoiceDialogOptions options; options.reserve(raw_options.size()); for (auto& it : raw_options) { options.emplace_back(it.second, type == it.first); } OpenChoiceDialog(fmt::format(FSUI_FSTR("Port {} Device"), port + 1).c_str(), false, std::move(options), [game_settings = IsEditingGameSettings(bsi), raw_options = std::move(raw_options), port]( s32 index, const std::string& title, bool checked) { if (index < 0) return; auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); USB::SetConfigDevice(*bsi, port, raw_options[static_cast(index)].first); SetSettingsChanged(bsi); CloseChoiceDialog(); }); } if (type.empty() || type == "None") { ImGui::PopID(); continue; } const u32 subtype = USB::GetConfigSubType(*bsi, port, type); const std::span subtypes(USB::GetDeviceSubtypes(type)); if (!subtypes.empty()) { const char* subtype_name = USB::GetDeviceSubtypeName(type, subtype); if (MenuButton(FSUI_ICONSTR(ICON_FA_GEAR, "Device Subtype"), subtype_name)) { ImGuiFullscreen::ChoiceDialogOptions options; options.reserve(subtypes.size()); for (u32 i = 0; i < subtypes.size(); i++) options.emplace_back(subtypes[i], i == subtype); OpenChoiceDialog(fmt::format(FSUI_FSTR("Port {} Subtype"), port + 1).c_str(), false, std::move(options), [game_settings = IsEditingGameSettings(bsi), port, type](s32 index, const std::string& title, bool checked) { if (index < 0) return; auto lock = Host::GetSettingsLock(); SettingsInterface* bsi = GetEditingSettingsInterface(game_settings); USB::SetConfigSubType(*bsi, port, type.c_str(), static_cast(index)); SetSettingsChanged(bsi); CloseChoiceDialog(); }); } } const std::span bindings(USB::GetDeviceBindings(type, subtype)); if (!bindings.empty()) { MenuHeading(TinyString::from_format(fmt::runtime(FSUI_ICONSTR(ICON_FA_KEYBOARD, "{} Bindings")), USB::GetDeviceName(type))); if (MenuButton(FSUI_ICONSTR(ICON_FA_TRASH, "Clear Bindings"), FSUI_CSTR("Clears all bindings for this USB controller."))) { USB::ClearPortBindings(*bsi, port); SetSettingsChanged(bsi); } const std::string section(USB::GetConfigSection(port)); for (const InputBindingInfo& bi : bindings) { DrawInputBindingButton(bsi, bi.bind_type, section.c_str(), USB::GetConfigSubKey(type, bi.name).c_str(), Host::TranslateToCString("USB", bi.display_name), bi.icon_name); } } const std::span settings(USB::GetDeviceSettings(type, subtype)); if (!settings.empty()) { MenuHeading(TinyString::from_format(fmt::runtime(FSUI_ICONSTR(ICON_FA_SLIDERS, "{} Settings")), USB::GetDeviceName(type))); const std::string section(USB::GetConfigSection(port)); for (const SettingInfo& si : settings) DrawSettingInfoSetting(bsi, section.c_str(), USB::GetConfigSubKey(type, si.name).c_str(), si, "USB"); } ImGui::PopID(); } EndMenuButtons(); } void FullscreenUI::DrawHotkeySettingsPage() { SettingsInterface* bsi = GetEditingSettingsInterface(); BeginMenuButtons(); const HotkeyInfo* last_category = nullptr; for (const HotkeyInfo* hotkey : s_hotkey_list_cache) { if (!last_category || std::strcmp(hotkey->category, last_category->category) != 0) { MenuHeading(Host::TranslateToCString("Hotkeys", hotkey->category)); last_category = hotkey; } DrawInputBindingButton( bsi, InputBindingInfo::Type::Button, "Hotkeys", hotkey->name, Host::TranslateToCString("Hotkeys", hotkey->display_name), nullptr, false); } EndMenuButtons(); } void FullscreenUI::DrawFoldersSettingsPage() { SettingsInterface* bsi = GetEditingSettingsInterface(); BeginMenuButtons(); MenuHeading(FSUI_CSTR("Data Save Locations")); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_CUBES, "Cache Directory"), "Folders", "Cache", EmuFolders::Cache); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_IMAGES, "Covers Directory"), "Folders", "Covers", EmuFolders::Covers); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_CAMERA, "Snapshots Directory"), "Folders", "Snapshots", EmuFolders::Snapshots); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_FLOPPY_DISK, "Save States Directory"), "Folders", "Savestates", EmuFolders::Savestates); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_WRENCH, "Game Settings Directory"), "Folders", "GameSettings", EmuFolders::GameSettings); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_PF_GAMEPAD_ALT, "Input Profile Directory"), "Folders", "InputProfiles", EmuFolders::InputProfiles); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_PF_INFINITY, "Cheats Directory"), "Folders", "Cheats", EmuFolders::Cheats); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_BANDAGE, "Patches Directory"), "Folders", "Patches", EmuFolders::Patches); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_SHIRT, "Texture Replacements Directory"), "Folders", "Textures", EmuFolders::Textures); DrawFolderSetting(bsi, FSUI_ICONSTR(ICON_FA_VIDEO, "Video Dumping Directory"), "Folders", "Videos", EmuFolders::Videos); EndMenuButtons(); } void FullscreenUI::DrawAdvancedSettingsPage() { static constexpr const char* ee_rounding_mode_settings[] = { FSUI_NSTR("Nearest"), FSUI_NSTR("Negative"), FSUI_NSTR("Positive"), FSUI_NSTR("Chop/Zero (Default)"), }; SettingsInterface* bsi = GetEditingSettingsInterface(); const bool show_advanced_settings = ShouldShowAdvancedSettings(bsi); BeginMenuButtons(); if (!IsEditingGameSettings(bsi)) { DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BIOHAZARD, "Show Advanced Settings"), FSUI_CSTR("Changing these options may cause games to become non-functional. Modify at your own risk, the PCSX2 team will not " "provide support for configurations with these settings changed."), "UI", "ShowAdvancedSettings", false); } MenuHeading(FSUI_CSTR("Logging")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TERMINAL, "System Console"), FSUI_CSTR("Writes log messages to the system console (console window/standard output)."), "Logging", "EnableSystemConsole", false); DrawToggleSetting( bsi, FSUI_ICONSTR(ICON_FA_SCROLL, "File Logging"), FSUI_CSTR("Writes log messages to emulog.txt."), "Logging", "EnableFileLogging", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_SCROLL, "Verbose Logging"), FSUI_CSTR("Writes dev log messages to log sinks."), "Logging", "EnableVerbose", false, !IsDevBuild); if (show_advanced_settings) { DrawToggleSetting( bsi, FSUI_ICONSTR(ICON_FA_CLOCK, "Log Timestamps"), FSUI_CSTR("Writes timestamps alongside log messages."), "Logging", "EnableTimestamps", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MICROCHIP, "EE Console"), FSUI_CSTR("Writes debug messages from the game's EE code to the console."), "Logging", "EnableEEConsole", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MICROCHIP, "IOP Console"), FSUI_CSTR("Writes debug messages from the game's IOP code to the console."), "Logging", "EnableIOPConsole", true); DrawToggleSetting( bsi, FSUI_ICONSTR(ICON_FA_COMPACT_DISC, "CDVD Verbose Reads"), FSUI_CSTR("Logs disc reads from games."), "EmuCore", "CdvdVerboseReads", false); } static constexpr const char* s_savestate_compression_type[] = { FSUI_NSTR("Uncompressed"), FSUI_NSTR("Deflate64"), FSUI_NSTR("Zstandard"), FSUI_NSTR("LZMA2"), }; static constexpr const char* s_savestate_compression_ratio[] = { FSUI_NSTR("Low (Fast)"), FSUI_NSTR("Medium (Recommended)"), FSUI_NSTR("High"), FSUI_NSTR("Very High (Slow, Not Recommended)"), }; if (show_advanced_settings) { MenuHeading(FSUI_CSTR("Emotion Engine")); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_TREND_DOWN, "Rounding Mode"), FSUI_CSTR("Determines how the results of floating-point operations are rounded. Some games need specific settings."), "EmuCore/CPU", "FPU.Roundmode", static_cast(FPRoundMode::ChopZero), ee_rounding_mode_settings, std::size(ee_rounding_mode_settings), true); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_DIVIDE, "Division Rounding Mode"), FSUI_CSTR("Determines how the results of floating-point division is rounded. Some games need specific settings."), "EmuCore/CPU", "FPUDiv.Roundmode", static_cast(FPRoundMode::Nearest), ee_rounding_mode_settings, std::size(ee_rounding_mode_settings), true); DrawClampingModeSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_TURN_DOWN, "Clamping Mode"), FSUI_CSTR("Determines how out-of-range floating point numbers are handled. Some games need specific settings."), -1); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MICROCHIP, "Enable EE Recompiler"), FSUI_CSTR("Performs just-in-time binary translation of 64-bit MIPS-IV machine code to native code."), "EmuCore/CPU/Recompiler", "EnableEE", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BUCKET, "Enable EE Cache"), FSUI_CSTR("Enables simulation of the EE's cache. Slow."), "EmuCore/CPU/Recompiler", "EnableEECache", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROWS_SPIN, "Enable INTC Spin Detection"), FSUI_CSTR("Huge speedup for some games, with almost no compatibility side effects."), "EmuCore/Speedhacks", "IntcStat", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROWS_SPIN, "Enable Wait Loop Detection"), FSUI_CSTR("Moderate speedup for some games, with no known side effects."), "EmuCore/Speedhacks", "WaitLoop", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MEMORY, "Enable Fast Memory Access"), FSUI_CSTR("Uses backpatching to avoid register flushing on every memory access."), "EmuCore/CPU/Recompiler", "EnableFastmem", true); MenuHeading(FSUI_CSTR("Vector Units")); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_TREND_DOWN, "VU0 Rounding Mode"), FSUI_CSTR("Determines how the results of floating-point operations are rounded. Some games need specific settings."), "EmuCore/CPU", "VU0.Roundmode", static_cast(FPRoundMode::ChopZero), ee_rounding_mode_settings, std::size(ee_rounding_mode_settings), true); DrawClampingModeSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_TURN_DOWN, "VU0 Clamping Mode"), FSUI_CSTR("Determines how out-of-range floating point numbers are handled. Some games need specific settings."), 0); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_TREND_DOWN, "VU1 Rounding Mode"), FSUI_CSTR("Determines how the results of floating-point operations are rounded. Some games need specific settings."), "EmuCore/CPU", "VU1.Roundmode", static_cast(FPRoundMode::ChopZero), ee_rounding_mode_settings, std::size(ee_rounding_mode_settings), true); DrawClampingModeSetting(bsi, FSUI_ICONSTR(ICON_FA_ARROW_TURN_DOWN, "VU1 Clamping Mode"), FSUI_CSTR("Determines how out-of-range floating point numbers are handled. Some games need specific settings."), 1); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MICROCHIP, "Enable VU0 Recompiler (Micro Mode)"), FSUI_CSTR("New Vector Unit recompiler with much improved compatibility. Recommended."), "EmuCore/CPU/Recompiler", "EnableVU0", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MICROCHIP, "Enable VU1 Recompiler"), FSUI_CSTR("New Vector Unit recompiler with much improved compatibility. Recommended."), "EmuCore/CPU/Recompiler", "EnableVU1", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FLAG, "Enable VU Flag Optimization"), FSUI_CSTR("Good speedup and high compatibility, may cause graphical errors."), "EmuCore/Speedhacks", "vuFlagHack", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_CLOCK, "Enable Instant VU1"), FSUI_CSTR("Runs VU1 instantly. Provides a modest speed improvement in most games. Safe for most games, but a few games may exhibit graphical errors."), "EmuCore/Speedhacks", "vu1Instant", true); MenuHeading(FSUI_CSTR("I/O Processor")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_MICROCHIP, "Enable IOP Recompiler"), FSUI_CSTR("Performs just-in-time binary translation of 32-bit MIPS-I machine code to native code."), "EmuCore/CPU/Recompiler", "EnableIOP", true); MenuHeading(FSUI_CSTR("Save State Management")); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_BOX_OPEN, "Compression Method"), FSUI_CSTR("Sets the compression algorithm for savestate."), "EmuCore", "SavestateCompressionType", static_cast(SavestateCompressionMethod::Zstandard), s_savestate_compression_type, std::size(s_savestate_compression_type), true); DrawIntListSetting(bsi, FSUI_ICONSTR(ICON_FA_COMPRESS, "Compression Level"), FSUI_CSTR("Sets the compression level for savestate."), "EmuCore", "SavestateCompressionRatio", static_cast(SavestateCompressionLevel::Medium), s_savestate_compression_ratio, std::size(s_savestate_compression_ratio), true); MenuHeading(FSUI_CSTR("Graphics")); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_BUG, "Use Debug Device"), FSUI_CSTR("Enables API-level validation of graphics commands."), "EmuCore/GS", "UseDebugDevice", false); } EndMenuButtons(); } void FullscreenUI::DrawPatchesOrCheatsSettingsPage(bool cheats) { SettingsInterface* bsi = GetEditingSettingsInterface(); const std::vector& patch_list = cheats ? s_game_cheats_list : s_game_patch_list; std::vector& enable_list = cheats ? s_enabled_game_cheat_cache : s_enabled_game_patch_cache; const char* section = cheats ? Patch::CHEATS_CONFIG_SECTION : Patch::PATCHES_CONFIG_SECTION; const bool master_enable = cheats ? GetEffectiveBoolSetting(bsi, "EmuCore", "EnableCheats", false) : true; BeginMenuButtons(); if (cheats) { MenuHeading(FSUI_CSTR("Settings")); DrawToggleSetting( bsi, FSUI_CSTR("Enable Cheats"), FSUI_CSTR("Enables loading cheats from pnach files."), "EmuCore", "EnableCheats", false); if (patch_list.empty()) { ActiveButton( FSUI_CSTR("No cheats are available for this game."), false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); } else { MenuHeading(FSUI_CSTR("Cheat Codes")); } } else { if (patch_list.empty()) { ActiveButton( FSUI_CSTR("No patches are available for this game."), false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); } else { MenuHeading(FSUI_CSTR("Game Patches")); } } for (const Patch::PatchInfo& pi : patch_list) { const auto enable_it = std::find(enable_list.begin(), enable_list.end(), pi.name); bool state = (enable_it != enable_list.end()); if (ToggleButton(pi.name.c_str(), pi.description.c_str(), &state, master_enable)) { if (state) { bsi->AddToStringList(section, Patch::PATCH_ENABLE_CONFIG_KEY, pi.name.c_str()); enable_list.push_back(pi.name); } else { bsi->RemoveFromStringList(section, Patch::PATCH_ENABLE_CONFIG_KEY, pi.name.c_str()); enable_list.erase(enable_it); } SetSettingsChanged(bsi); } } if (cheats && s_game_cheat_unlabelled_count > 0) { ActiveButton(SmallString::from_format(master_enable ? FSUI_FSTR("{} unlabelled patch codes will automatically activate.") : FSUI_FSTR("{} unlabelled patch codes found but not enabled."), s_game_cheat_unlabelled_count), false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); } if (!patch_list.empty() || (cheats && s_game_cheat_unlabelled_count > 0)) { ActiveButton( cheats ? FSUI_CSTR("Activating cheats can cause unpredictable behavior, crashing, soft-locks, or broken saved games.") : FSUI_CSTR("Activating game patches can cause unpredictable behavior, crashing, soft-locks, or broken saved games."), false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); ActiveButton( FSUI_CSTR("Use patches at your own risk, the PCSX2 team will provide no support for users who have enabled game patches."), false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); } EndMenuButtons(); } void FullscreenUI::DrawGameFixesSettingsPage() { SettingsInterface* bsi = GetEditingSettingsInterface(); BeginMenuButtons(); MenuHeading(FSUI_CSTR("Game Fixes")); ActiveButton( FSUI_CSTR("Game fixes should not be modified unless you are aware of what each option does and the implications of doing so."), false, false, ImGuiFullscreen::LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY); DrawToggleSetting(bsi, FSUI_CSTR("FPU Multiply Hack"), FSUI_CSTR("For Tales of Destiny."), "EmuCore/Gamefixes", "FpuMulHack", false); DrawToggleSetting(bsi, FSUI_CSTR("Use Software Renderer For FMVs"), FSUI_CSTR("Needed for some games with complex FMV rendering."), "EmuCore/Gamefixes", "SoftwareRendererFMVHack", false); DrawToggleSetting(bsi, FSUI_CSTR("Skip MPEG Hack"), FSUI_CSTR("Skips videos/FMVs in games to avoid game hanging/freezes."), "EmuCore/Gamefixes", "SkipMPEGHack", false); DrawToggleSetting( bsi, FSUI_CSTR("Preload TLB Hack"), FSUI_CSTR("To avoid TLB miss on Goemon."), "EmuCore/Gamefixes", "GoemonTlbHack", false); DrawToggleSetting(bsi, FSUI_CSTR("EE Timing Hack"), FSUI_CSTR("General-purpose timing hack. Known to affect following games: Digital Devil Saga, SSX."), "EmuCore/Gamefixes", "EETimingHack", false); DrawToggleSetting(bsi, FSUI_CSTR("Instant DMA Hack"), FSUI_CSTR("Good for cache emulation problems. Known to affect following games: Fire Pro Wrestling Z."), "EmuCore/Gamefixes", "InstantDMAHack", false); DrawToggleSetting(bsi, FSUI_CSTR("OPH Flag Hack"), FSUI_CSTR("Known to affect following games: Bleach Blade Battlers, Growlanser II and III, Wizardry."), "EmuCore/Gamefixes", "OPHFlagHack", false); DrawToggleSetting( bsi, FSUI_CSTR("Emulate GIF FIFO"), FSUI_CSTR("Correct but slower. Known to affect the following games: FIFA Street 2."), "EmuCore/Gamefixes", "GIFFIFOHack", false); DrawToggleSetting(bsi, FSUI_CSTR("DMA Busy Hack"), FSUI_CSTR("Known to affect following games: Mana Khemia 1, Metal Saga, Pilot Down Behind Enemy Lines."), "EmuCore/Gamefixes", "DMABusyHack", false); DrawToggleSetting(bsi, FSUI_CSTR("Delay VIF1 Stalls"), FSUI_CSTR("For SOCOM 2 HUD and Spy Hunter loading hang."), "EmuCore/Gamefixes", "VIF1StallHack", false); DrawToggleSetting(bsi, FSUI_CSTR("Emulate VIF FIFO"), FSUI_CSTR("Simulate VIF1 FIFO read ahead. Known to affect following games: Test Drive Unlimited, Transformers."), "EmuCore/Gamefixes", "VIFFIFOHack", false); DrawToggleSetting(bsi, FSUI_CSTR("Full VU0 Synchronization"), FSUI_CSTR("Forces tight VU0 sync on every COP2 instruction."), "EmuCore/Gamefixes", "FullVU0SyncHack", false); DrawToggleSetting(bsi, FSUI_CSTR("VU I Bit Hack"), FSUI_CSTR("Avoids constant recompilation in some games. Known to affect the following games: Scarface The World is Yours, Crash Tag Team Racing."), "EmuCore/Gamefixes", "IbitHack", false); DrawToggleSetting(bsi, FSUI_CSTR("VU Add Hack"), FSUI_CSTR("For Tri-Ace Games: Star Ocean 3, Radiata Stories, Valkyrie Profile 2."), "EmuCore/Gamefixes", "VuAddSubHack", false); DrawToggleSetting(bsi, FSUI_CSTR("VU Overflow Hack"), FSUI_CSTR("To check for possible float overflows (Superman Returns)."), "EmuCore/Gamefixes", "VUOverflowHack", false); DrawToggleSetting(bsi, FSUI_CSTR("VU Sync"), FSUI_CSTR("Run behind. To avoid sync problems when reading or writing VU registers."), "EmuCore/Gamefixes", "VUSyncHack", false); DrawToggleSetting(bsi, FSUI_CSTR("VU XGKick Sync"), FSUI_CSTR("Use accurate timing for VU XGKicks (slower)."), "EmuCore/Gamefixes", "XgKickHack", false); DrawToggleSetting(bsi, FSUI_CSTR("Force Blit Internal FPS Detection"), FSUI_CSTR("Use alternative method to calculate internal FPS to avoid false readings in some games."), "EmuCore/Gamefixes", "BlitInternalFPSHack", false); EndMenuButtons(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Translation String Area // To avoid having to type T_RANSLATE("FullscreenUI", ...) everywhere, we use the shorter macros in the internal // header file, then preprocess and generate a bunch of noops here to define the strings. Sadly that means // the view in Linguist is gonna suck, but you can search the file for the string for more context. //////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if 0 // TRANSLATION-STRING-AREA-BEGIN TRANSLATE_NOOP("FullscreenUI", "Use Global Setting"); TRANSLATE_NOOP("FullscreenUI", "Automatic binding failed, no devices are available."); TRANSLATE_NOOP("FullscreenUI", "Game title copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "Game serial copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "Game CRC copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "Game type copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "Game region copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "Game compatibility copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "Game path copied to clipboard."); TRANSLATE_NOOP("FullscreenUI", "None"); TRANSLATE_NOOP("FullscreenUI", "Automatic"); TRANSLATE_NOOP("FullscreenUI", "Browse..."); TRANSLATE_NOOP("FullscreenUI", "Create New..."); TRANSLATE_NOOP("FullscreenUI", "Enter custom HDD size in gigabytes (40–2000):"); TRANSLATE_NOOP("FullscreenUI", "Invalid size. Please enter a number between 40 and 2000."); TRANSLATE_NOOP("FullscreenUI", "HDD size must be between 40 GB and 2000 GB."); TRANSLATE_NOOP("FullscreenUI", "Enter the name for the new memory card."); TRANSLATE_NOOP("FullscreenUI", "Memory card name cannot be empty."); TRANSLATE_NOOP("FullscreenUI", "PS2 (8MB)"); TRANSLATE_NOOP("FullscreenUI", "PS2 (16MB)"); TRANSLATE_NOOP("FullscreenUI", "PS2 (32MB)"); TRANSLATE_NOOP("FullscreenUI", "PS2 (64MB)"); TRANSLATE_NOOP("FullscreenUI", "PS1 (128KB)"); TRANSLATE_NOOP("FullscreenUI", "Folder"); TRANSLATE_NOOP("FullscreenUI", "Yes - Enable NTFS compression"); TRANSLATE_NOOP("FullscreenUI", "No - Disable NTFS compression"); TRANSLATE_NOOP("FullscreenUI", "Failed to create the Memory Card, the log may contain more information."); TRANSLATE_NOOP("FullscreenUI", "Are you sure you want to restore the default controller configuration?\n\nAll shared bindings and configuration will be lost, but your input profiles will remain.\n\nYou cannot undo this action."); TRANSLATE_NOOP("FullscreenUI", "Controller settings reset to default."); TRANSLATE_NOOP("FullscreenUI", "No input profiles available."); TRANSLATE_NOOP("FullscreenUI", "Custom input profiles are used to override the Shared input profile for specific games.\n\nTo apply a custom input profile to a game, go to its Game Properties, then change the 'Input Profile' on the Summary tab.\n\nEnter the name for the new input profile:"); TRANSLATE_NOOP("FullscreenUI", "Are you sure you want to restore the default settings? Any preferences will be lost."); TRANSLATE_NOOP("FullscreenUI", "Settings reset to defaults."); TRANSLATE_NOOP("FullscreenUI", "-"); TRANSLATE_NOOP("FullscreenUI", "No Binding"); TRANSLATE_NOOP("FullscreenUI", "Setting %s binding %s."); TRANSLATE_NOOP("FullscreenUI", "Push a controller button or axis now."); TRANSLATE_NOOP("FullscreenUI", "Timing out in %.0f seconds..."); TRANSLATE_NOOP("FullscreenUI", "Unknown"); TRANSLATE_NOOP("FullscreenUI", "OK"); TRANSLATE_NOOP("FullscreenUI", "Enter the DNS server address"); TRANSLATE_NOOP("FullscreenUI", "Enter the Gateway address"); TRANSLATE_NOOP("FullscreenUI", "Enter the Subnet Mask"); TRANSLATE_NOOP("FullscreenUI", "Enter the PS2 IP address"); TRANSLATE_NOOP("FullscreenUI", "Enter the IP address"); TRANSLATE_NOOP("FullscreenUI", "Select Device"); TRANSLATE_NOOP("FullscreenUI", "Details"); TRANSLATE_NOOP("FullscreenUI", "The selected input profile will be used for this game."); TRANSLATE_NOOP("FullscreenUI", "Shared"); TRANSLATE_NOOP("FullscreenUI", "Input Profile"); TRANSLATE_NOOP("FullscreenUI", "Options"); TRANSLATE_NOOP("FullscreenUI", "Copies the current global settings to this game."); TRANSLATE_NOOP("FullscreenUI", "Clears all settings set for this game."); TRANSLATE_NOOP("FullscreenUI", "Appearance"); TRANSLATE_NOOP("FullscreenUI", "Selects the color style to be used for Big Picture Mode."); TRANSLATE_NOOP("FullscreenUI", "When Big Picture mode is started, the game list will be displayed instead of the main menu."); TRANSLATE_NOOP("FullscreenUI", "Show a save state selector UI when switching slots instead of showing a notification bubble."); TRANSLATE_NOOP("FullscreenUI", "Background"); TRANSLATE_NOOP("FullscreenUI", "Select a custom background image to use in Big Picture Mode menus.\n\nSupported formats: PNG, JPG, JPEG, BMP."); TRANSLATE_NOOP("FullscreenUI", "Removes the custom background image."); TRANSLATE_NOOP("FullscreenUI", "Sets the transparency of the custom background image."); TRANSLATE_NOOP("FullscreenUI", "Select how to display the background image."); TRANSLATE_NOOP("FullscreenUI", "Behaviour"); TRANSLATE_NOOP("FullscreenUI", "Prevents the screen saver from activating and the host from sleeping while emulation is running."); TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a game is started."); TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back."); TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a controller with bindings is disconnected."); TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you open the quick menu, and unpauses when you close it."); TRANSLATE_NOOP("FullscreenUI", "Display a modal dialog when a save state load/save operation fails."); TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed."); TRANSLATE_NOOP("FullscreenUI", "Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left off next time."); TRANSLATE_NOOP("FullscreenUI", "Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix"); TRANSLATE_NOOP("FullscreenUI", "Integration"); TRANSLATE_NOOP("FullscreenUI", "Shows the game you are currently playing as part of your profile on Discord."); TRANSLATE_NOOP("FullscreenUI", "Game Display"); TRANSLATE_NOOP("FullscreenUI", "Automatically switches to fullscreen mode when a game is started."); TRANSLATE_NOOP("FullscreenUI", "Switches between full screen and windowed when the window is double-clicked."); TRANSLATE_NOOP("FullscreenUI", "Hides the mouse pointer/cursor when the emulator is in fullscreen mode."); TRANSLATE_NOOP("FullscreenUI", "Automatically starts Big Picture Mode instead of the regular Qt interface when PCSX2 launches."); TRANSLATE_NOOP("FullscreenUI", "On-Screen Display"); TRANSLATE_NOOP("FullscreenUI", "Determines how large the on-screen messages and monitors are."); TRANSLATE_NOOP("FullscreenUI", "%d%%"); TRANSLATE_NOOP("FullscreenUI", "Determines where on-screen display messages are positioned."); TRANSLATE_NOOP("FullscreenUI", "Determines where performance statistics are positioned."); TRANSLATE_NOOP("FullscreenUI", "Shows the current PCSX2 version."); TRANSLATE_NOOP("FullscreenUI", "Shows the current emulation speed of the system as a percentage."); TRANSLATE_NOOP("FullscreenUI", "Shows the number of internal video frames displayed per second by the system."); TRANSLATE_NOOP("FullscreenUI", "Shows the number of Vsyncs performed per second by the system."); TRANSLATE_NOOP("FullscreenUI", "Shows the internal resolution of the game."); TRANSLATE_NOOP("FullscreenUI", "Shows the current system CPU and GPU information."); TRANSLATE_NOOP("FullscreenUI", "Shows statistics about the emulated GS such as primitives and draw calls."); TRANSLATE_NOOP("FullscreenUI", "Shows the host's CPU utilization based on threads."); TRANSLATE_NOOP("FullscreenUI", "Shows the host's GPU utilization."); TRANSLATE_NOOP("FullscreenUI", "Shows indicators when fast forwarding, pausing, and other abnormal states are active."); TRANSLATE_NOOP("FullscreenUI", "Shows a visual history of frame times."); TRANSLATE_NOOP("FullscreenUI", "Shows the current configuration in the bottom-right corner of the display."); TRANSLATE_NOOP("FullscreenUI", "Shows the amount of currently active patches/cheats on the bottom-right corner of the display."); TRANSLATE_NOOP("FullscreenUI", "Shows the current controller state of the system in the bottom-left corner of the display."); TRANSLATE_NOOP("FullscreenUI", "Shows the status of the currently active video capture."); TRANSLATE_NOOP("FullscreenUI", "Shows the status of the currently active input recording."); TRANSLATE_NOOP("FullscreenUI", "Shows the number of dumped and loaded texture replacements on the OSD."); TRANSLATE_NOOP("FullscreenUI", "Displays warnings when settings are enabled which may break games."); TRANSLATE_NOOP("FullscreenUI", "Operations"); TRANSLATE_NOOP("FullscreenUI", "Resets configuration to defaults (excluding controller settings)."); TRANSLATE_NOOP("FullscreenUI", "BIOS Configuration"); TRANSLATE_NOOP("FullscreenUI", "Changes the BIOS image used to start future sessions."); TRANSLATE_NOOP("FullscreenUI", "BIOS Selection"); TRANSLATE_NOOP("FullscreenUI", "Fast Boot Options"); TRANSLATE_NOOP("FullscreenUI", "Skips the intro screen, and bypasses region checks."); TRANSLATE_NOOP("FullscreenUI", "Speed Control"); TRANSLATE_NOOP("FullscreenUI", "Sets the speed when running without fast forwarding."); TRANSLATE_NOOP("FullscreenUI", "Sets the speed when using the fast forward hotkey."); TRANSLATE_NOOP("FullscreenUI", "Sets the speed when using the slow motion hotkey."); TRANSLATE_NOOP("FullscreenUI", "System Settings"); TRANSLATE_NOOP("FullscreenUI", "Underclocks or overclocks the emulated Emotion Engine CPU."); TRANSLATE_NOOP("FullscreenUI", "Makes the emulated Emotion Engine skip cycles. Helps a small subset of games like SOTC. Most of the time it's harmful to performance."); TRANSLATE_NOOP("FullscreenUI", "Generally a speedup on CPUs with 4 or more cores. Safe for most games, but a few are incompatible and may hang."); TRANSLATE_NOOP("FullscreenUI", "Pins emulation threads to CPU cores to potentially improve performance/frame time variance."); TRANSLATE_NOOP("FullscreenUI", "Enables loading cheats from pnach files."); TRANSLATE_NOOP("FullscreenUI", "Enables access to files from the host: namespace in the virtual machine."); TRANSLATE_NOOP("FullscreenUI", "Fast disc access, less loading times. Not recommended."); TRANSLATE_NOOP("FullscreenUI", "Loads the disc image into RAM before starting the virtual machine."); TRANSLATE_NOOP("FullscreenUI", "Frame Pacing/Latency Control"); TRANSLATE_NOOP("FullscreenUI", "Sets the number of frames which can be queued."); TRANSLATE_NOOP("FullscreenUI", "Synchronize EE and GS threads after each frame. Lowest input latency, but increases system requirements."); TRANSLATE_NOOP("FullscreenUI", "Synchronizes frame presentation with host refresh."); TRANSLATE_NOOP("FullscreenUI", "Speeds up emulation so that the guest refresh rate matches the host."); TRANSLATE_NOOP("FullscreenUI", "Disables PCSX2's internal frame timing, and uses host vsync instead."); TRANSLATE_NOOP("FullscreenUI", "Graphics API"); TRANSLATE_NOOP("FullscreenUI", "Selects the API used to render the emulated GS."); TRANSLATE_NOOP("FullscreenUI", "Display"); TRANSLATE_NOOP("FullscreenUI", "Selects the aspect ratio to display the game content at."); TRANSLATE_NOOP("FullscreenUI", "Selects the aspect ratio for display when a FMV is detected as playing."); TRANSLATE_NOOP("FullscreenUI", "Selects the algorithm used to convert the PS2's interlaced output to progressive for display."); TRANSLATE_NOOP("FullscreenUI", "Determines the resolution at which screenshots will be saved."); TRANSLATE_NOOP("FullscreenUI", "Selects the format which will be used to save screenshots."); TRANSLATE_NOOP("FullscreenUI", "Selects the quality at which screenshots will be compressed."); TRANSLATE_NOOP("FullscreenUI", "Increases or decreases the virtual picture size vertically."); TRANSLATE_NOOP("FullscreenUI", "Crops the image, while respecting aspect ratio."); TRANSLATE_NOOP("FullscreenUI", "%dpx"); TRANSLATE_NOOP("FullscreenUI", "Enables loading widescreen patches from pnach files."); TRANSLATE_NOOP("FullscreenUI", "Enables loading no-interlacing patches from pnach files."); TRANSLATE_NOOP("FullscreenUI", "Smooths out the image when upscaling the console to the screen."); TRANSLATE_NOOP("FullscreenUI", "Adds padding to the display area to ensure that the ratio between pixels on the host to pixels in the console is an integer number. May result in a sharper image in some 2D games."); TRANSLATE_NOOP("FullscreenUI", "Enables PCRTC Offsets which position the screen as the game requests."); TRANSLATE_NOOP("FullscreenUI", "Enables the option to show the overscan area on games which draw more than the safe area of the screen."); TRANSLATE_NOOP("FullscreenUI", "Enables internal Anti-Blur hacks. Less accurate to PS2 rendering but will make a lot of games look less blurry."); TRANSLATE_NOOP("FullscreenUI", "Rendering"); TRANSLATE_NOOP("FullscreenUI", "Multiplies the render resolution by the specified factor (upscaling)."); TRANSLATE_NOOP("FullscreenUI", "Selects where bilinear filtering is utilized when rendering textures."); TRANSLATE_NOOP("FullscreenUI", "Selects where trilinear filtering is utilized when rendering textures."); TRANSLATE_NOOP("FullscreenUI", "Selects where anisotropic filtering is utilized when rendering textures."); TRANSLATE_NOOP("FullscreenUI", "Selects the type of dithering applies when the game requests it."); TRANSLATE_NOOP("FullscreenUI", "Determines the level of accuracy when emulating blend modes not supported by the host graphics API."); TRANSLATE_NOOP("FullscreenUI", "Enables emulation of the GS's texture mipmapping."); TRANSLATE_NOOP("FullscreenUI", "Number of threads to use in addition to the main GS thread for rasterization."); TRANSLATE_NOOP("FullscreenUI", "Force a primitive flush when a framebuffer is also an input texture."); TRANSLATE_NOOP("FullscreenUI", "Enables emulation of the GS's edge anti-aliasing (AA1)."); TRANSLATE_NOOP("FullscreenUI", "Hardware Fixes"); TRANSLATE_NOOP("FullscreenUI", "Disables automatic hardware fixes, allowing you to set fixes manually."); TRANSLATE_NOOP("FullscreenUI", "CPU Sprite Render Size"); TRANSLATE_NOOP("FullscreenUI", "Uses software renderer to draw texture decompression-like sprites."); TRANSLATE_NOOP("FullscreenUI", "CPU Sprite Render Level"); TRANSLATE_NOOP("FullscreenUI", "Determines filter level for CPU sprite render."); TRANSLATE_NOOP("FullscreenUI", "Software CLUT Render"); TRANSLATE_NOOP("FullscreenUI", "Uses software renderer to draw texture CLUT points/sprites."); TRANSLATE_NOOP("FullscreenUI", "GPU Target CLUT"); TRANSLATE_NOOP("FullscreenUI", "Try to detect when a game is drawing its own color palette and then renders it on the GPU with special handling."); TRANSLATE_NOOP("FullscreenUI", "Skip Draw Start"); TRANSLATE_NOOP("FullscreenUI", "Object range to skip drawing."); TRANSLATE_NOOP("FullscreenUI", "Skip Draw End"); TRANSLATE_NOOP("FullscreenUI", "Auto Flush (Hardware)"); TRANSLATE_NOOP("FullscreenUI", "CPU Framebuffer Conversion"); TRANSLATE_NOOP("FullscreenUI", "Convert 4-bit and 8-bit framebuffer on the CPU instead of the GPU."); TRANSLATE_NOOP("FullscreenUI", "Disable Depth Conversion"); TRANSLATE_NOOP("FullscreenUI", "Disable the support of depth buffers in the texture cache."); TRANSLATE_NOOP("FullscreenUI", "Disable Safe Features"); TRANSLATE_NOOP("FullscreenUI", "This option disables multiple safe features."); TRANSLATE_NOOP("FullscreenUI", "Disable Render Fixes"); TRANSLATE_NOOP("FullscreenUI", "This option disables game-specific render fixes."); TRANSLATE_NOOP("FullscreenUI", "Preload Frame Data"); TRANSLATE_NOOP("FullscreenUI", "Uploads GS data when rendering a new frame to reproduce some effects accurately."); TRANSLATE_NOOP("FullscreenUI", "Disable Partial Invalidation"); TRANSLATE_NOOP("FullscreenUI", "Removes texture cache entries when there is any intersection, rather than only the intersected areas."); TRANSLATE_NOOP("FullscreenUI", "Texture Inside RT"); TRANSLATE_NOOP("FullscreenUI", "Allows the texture cache to reuse as an input texture the inner portion of a previous framebuffer."); TRANSLATE_NOOP("FullscreenUI", "Read Targets When Closing"); TRANSLATE_NOOP("FullscreenUI", "Flushes all targets in the texture cache back to local memory when shutting down."); TRANSLATE_NOOP("FullscreenUI", "Estimate Texture Region"); TRANSLATE_NOOP("FullscreenUI", "Attempts to reduce the texture size when games do not set it themselves (e.g. Snowblind games)."); TRANSLATE_NOOP("FullscreenUI", "GPU Palette Conversion"); TRANSLATE_NOOP("FullscreenUI", "When enabled GPU converts colormap-textures, otherwise the CPU will. It is a trade-off between GPU and CPU."); TRANSLATE_NOOP("FullscreenUI", "Upscaling Fixes"); TRANSLATE_NOOP("FullscreenUI", "Half Pixel Offset"); TRANSLATE_NOOP("FullscreenUI", "Adjusts vertices relative to upscaling."); TRANSLATE_NOOP("FullscreenUI", "Native Scaling"); TRANSLATE_NOOP("FullscreenUI", "Attempt to do rescaling at native resolution."); TRANSLATE_NOOP("FullscreenUI", "Round Sprite"); TRANSLATE_NOOP("FullscreenUI", "Adjusts sprite coordinates."); TRANSLATE_NOOP("FullscreenUI", "Bilinear Dirty Upscale"); TRANSLATE_NOOP("FullscreenUI", "Can smooth out textures due to be bilinear filtered when upscaling. E.g. Brave sun glare."); TRANSLATE_NOOP("FullscreenUI", "Texture Offset X"); TRANSLATE_NOOP("FullscreenUI", "Adjusts target texture offsets."); TRANSLATE_NOOP("FullscreenUI", "Texture Offset Y"); TRANSLATE_NOOP("FullscreenUI", "Align Sprite"); TRANSLATE_NOOP("FullscreenUI", "Fixes issues with upscaling (vertical lines) in some games."); TRANSLATE_NOOP("FullscreenUI", "Merge Sprite"); TRANSLATE_NOOP("FullscreenUI", "Replaces multiple post-processing sprites with a larger single sprite."); TRANSLATE_NOOP("FullscreenUI", "Force Even Sprite Position"); TRANSLATE_NOOP("FullscreenUI", "Lowers the GS precision to avoid gaps between pixels when upscaling. Fixes the text on Wild Arms games."); TRANSLATE_NOOP("FullscreenUI", "Unscaled Palette Texture Draws"); TRANSLATE_NOOP("FullscreenUI", "Can fix some broken effects which rely on pixel perfect precision."); TRANSLATE_NOOP("FullscreenUI", "Texture Replacement"); TRANSLATE_NOOP("FullscreenUI", "Loads replacement textures where available and user-provided."); TRANSLATE_NOOP("FullscreenUI", "Loads replacement textures on a worker thread, reducing microstutter when replacements are enabled."); TRANSLATE_NOOP("FullscreenUI", "Preloads all replacement textures to memory. Not necessary with asynchronous loading."); TRANSLATE_NOOP("FullscreenUI", "Folders"); TRANSLATE_NOOP("FullscreenUI", "Texture Dumping"); TRANSLATE_NOOP("FullscreenUI", "Dumps replaceable textures to disk. Will reduce performance."); TRANSLATE_NOOP("FullscreenUI", "Includes mipmaps when dumping textures."); TRANSLATE_NOOP("FullscreenUI", "Allows texture dumping when FMVs are active. You should not enable this."); TRANSLATE_NOOP("FullscreenUI", "Post-Processing"); TRANSLATE_NOOP("FullscreenUI", "Enables FXAA post-processing shader."); TRANSLATE_NOOP("FullscreenUI", "Enables FidelityFX Contrast Adaptive Sharpening."); TRANSLATE_NOOP("FullscreenUI", "Determines the intensity the sharpening effect in CAS post-processing."); TRANSLATE_NOOP("FullscreenUI", "Filters"); TRANSLATE_NOOP("FullscreenUI", "Enables brightness/contrast/gamma/saturation adjustment."); TRANSLATE_NOOP("FullscreenUI", "Adjusts brightness. 50 is normal."); TRANSLATE_NOOP("FullscreenUI", "Adjusts contrast. 50 is normal."); TRANSLATE_NOOP("FullscreenUI", "Shade Boost Gamma"); TRANSLATE_NOOP("FullscreenUI", "Adjusts gamma. 50 is normal."); TRANSLATE_NOOP("FullscreenUI", "Adjusts saturation. 50 is normal."); TRANSLATE_NOOP("FullscreenUI", "Applies a shader which replicates the visual effects of different styles of television set."); TRANSLATE_NOOP("FullscreenUI", "Advanced"); TRANSLATE_NOOP("FullscreenUI", "Skip Presenting Duplicate Frames"); TRANSLATE_NOOP("FullscreenUI", "Skips displaying frames that don't change in 25/30fps games. Can improve speed, but increase input lag/make frame pacing worse."); TRANSLATE_NOOP("FullscreenUI", "Disable Mailbox Presentation"); TRANSLATE_NOOP("FullscreenUI", "Forces the use of FIFO over Mailbox presentation, i.e. double buffering instead of triple buffering. Usually results in worse frame pacing."); TRANSLATE_NOOP("FullscreenUI", "Extended Upscaling Multipliers"); TRANSLATE_NOOP("FullscreenUI", "Displays additional, very high upscaling multipliers dependent on GPU capability."); TRANSLATE_NOOP("FullscreenUI", "Hardware Download Mode"); TRANSLATE_NOOP("FullscreenUI", "Changes synchronization behavior for GS downloads."); TRANSLATE_NOOP("FullscreenUI", "Allow Exclusive Fullscreen"); TRANSLATE_NOOP("FullscreenUI", "Overrides the driver's heuristics for enabling exclusive fullscreen, or direct flip/scanout."); TRANSLATE_NOOP("FullscreenUI", "Override Texture Barriers"); TRANSLATE_NOOP("FullscreenUI", "Forces texture barrier functionality to the specified value."); TRANSLATE_NOOP("FullscreenUI", "GS Dump Compression"); TRANSLATE_NOOP("FullscreenUI", "Sets the compression algorithm for GS dumps."); TRANSLATE_NOOP("FullscreenUI", "Disable Framebuffer Fetch"); TRANSLATE_NOOP("FullscreenUI", "Prevents the usage of framebuffer fetch when supported by host GPU."); TRANSLATE_NOOP("FullscreenUI", "Disable Shader Cache"); TRANSLATE_NOOP("FullscreenUI", "Prevents the loading and saving of shaders/pipelines to disk."); TRANSLATE_NOOP("FullscreenUI", "Disable Vertex Shader Expand"); TRANSLATE_NOOP("FullscreenUI", "Falls back to the CPU for expanding sprites/lines."); TRANSLATE_NOOP("FullscreenUI", "Texture Preloading"); TRANSLATE_NOOP("FullscreenUI", "Uploads full textures to the GPU on use, rather than only the utilized regions. Can improve performance in some games."); TRANSLATE_NOOP("FullscreenUI", "NTSC Frame Rate"); TRANSLATE_NOOP("FullscreenUI", "Determines what frame rate NTSC games run at."); TRANSLATE_NOOP("FullscreenUI", "PAL Frame Rate"); TRANSLATE_NOOP("FullscreenUI", "Determines what frame rate PAL games run at."); TRANSLATE_NOOP("FullscreenUI", "Audio Control"); TRANSLATE_NOOP("FullscreenUI", "Controls the volume of the audio played on the host at normal speed."); TRANSLATE_NOOP("FullscreenUI", "Controls the volume of the audio played on the host when fast forwarding."); TRANSLATE_NOOP("FullscreenUI", "Prevents the emulator from producing any audible sound."); TRANSLATE_NOOP("FullscreenUI", "Backend Settings"); TRANSLATE_NOOP("FullscreenUI", "Determines how audio frames produced by the emulator are submitted to the host."); TRANSLATE_NOOP("FullscreenUI", "Determines how audio is expanded from stereo to surround for supported games."); TRANSLATE_NOOP("FullscreenUI", "Changes when SPU samples are generated relative to system emulation."); TRANSLATE_NOOP("FullscreenUI", "Determines the amount of audio buffered before being pulled by the host API."); TRANSLATE_NOOP("FullscreenUI", "%d ms"); TRANSLATE_NOOP("FullscreenUI", "Determines how much latency there is between the audio being picked up by the host API, and played through speakers."); TRANSLATE_NOOP("FullscreenUI", "When enabled, the minimum supported output latency will be used for the host API."); TRANSLATE_NOOP("FullscreenUI", "Settings and Operations"); TRANSLATE_NOOP("FullscreenUI", "Creates a new memory card file or folder."); TRANSLATE_NOOP("FullscreenUI", "Simulates a larger memory card by filtering saves only to the current game."); TRANSLATE_NOOP("FullscreenUI", "If not set, this card will be considered unplugged."); TRANSLATE_NOOP("FullscreenUI", "The selected memory card image will be used for this slot."); TRANSLATE_NOOP("FullscreenUI", "Removes the current card from the slot."); TRANSLATE_NOOP("FullscreenUI", "Network Adapter"); TRANSLATE_NOOP("FullscreenUI", "Enables the network adapter for online functionality and LAN play."); TRANSLATE_NOOP("FullscreenUI", "Determines the simulated Ethernet adapter type."); TRANSLATE_NOOP("FullscreenUI", "Network adapter to use for PS2 network emulation."); TRANSLATE_NOOP("FullscreenUI", "When enabled, DHCP packets will be intercepted and replaced with internal responses."); TRANSLATE_NOOP("FullscreenUI", "Network Configuration"); TRANSLATE_NOOP("FullscreenUI", "IP address for the PS2 virtual network adapter."); TRANSLATE_NOOP("FullscreenUI", "Automatically determine the subnet mask based on the IP address class."); TRANSLATE_NOOP("FullscreenUI", "Subnet mask for the PS2 virtual network adapter."); TRANSLATE_NOOP("FullscreenUI", "Automatically determine the gateway address based on the IP address."); TRANSLATE_NOOP("FullscreenUI", "Gateway address for the PS2 virtual network adapter."); TRANSLATE_NOOP("FullscreenUI", "Determines how primary DNS requests are handled."); TRANSLATE_NOOP("FullscreenUI", "Primary DNS server address for the PS2 virtual network adapter."); TRANSLATE_NOOP("FullscreenUI", "Determines how secondary DNS requests are handled."); TRANSLATE_NOOP("FullscreenUI", "Secondary DNS server address for the PS2 virtual network adapter."); TRANSLATE_NOOP("FullscreenUI", "Internal HDD"); TRANSLATE_NOOP("FullscreenUI", "Enables the internal Hard Disk Drive for expanded storage."); TRANSLATE_NOOP("FullscreenUI", "Changes the HDD image used for PS2 internal storage."); TRANSLATE_NOOP("FullscreenUI", "HDD Image Selection"); TRANSLATE_NOOP("FullscreenUI", "Configuration"); TRANSLATE_NOOP("FullscreenUI", "Replaces these settings with a previously saved input profile."); TRANSLATE_NOOP("FullscreenUI", "Stores the current settings to an input profile."); TRANSLATE_NOOP("FullscreenUI", "Resets all configuration to defaults (including bindings)."); TRANSLATE_NOOP("FullscreenUI", "Input Sources"); TRANSLATE_NOOP("FullscreenUI", "The SDL input source supports most controllers."); TRANSLATE_NOOP("FullscreenUI", "Provides vibration and LED control support over Bluetooth."); TRANSLATE_NOOP("FullscreenUI", "Enable/Disable the Player LED on DualSense controllers."); TRANSLATE_NOOP("FullscreenUI", "Allow SDL to use raw access to input devices."); TRANSLATE_NOOP("FullscreenUI", "The XInput source provides support for XBox 360/XBox One/XBox Series controllers."); TRANSLATE_NOOP("FullscreenUI", "Multitap"); TRANSLATE_NOOP("FullscreenUI", "Enables an additional three controller slots. Not supported in all games."); TRANSLATE_NOOP("FullscreenUI", "Attempts to map the selected port to a chosen controller."); TRANSLATE_NOOP("FullscreenUI", "Trigger"); TRANSLATE_NOOP("FullscreenUI", "Toggles the macro when the button is pressed, instead of held."); TRANSLATE_NOOP("FullscreenUI", "Determines the frequency at which the macro will toggle the buttons on and off (aka auto fire)."); TRANSLATE_NOOP("FullscreenUI", "Determines how much pressure is simulated when macro is active."); TRANSLATE_NOOP("FullscreenUI", "Determines the pressure required to activate the macro."); TRANSLATE_NOOP("FullscreenUI", "Toggle every %d frames"); TRANSLATE_NOOP("FullscreenUI", "Clears all bindings for this USB controller."); TRANSLATE_NOOP("FullscreenUI", "Data Save Locations"); TRANSLATE_NOOP("FullscreenUI", "Changing these options may cause games to become non-functional. Modify at your own risk, the PCSX2 team will not provide support for configurations with these settings changed."); TRANSLATE_NOOP("FullscreenUI", "Logging"); TRANSLATE_NOOP("FullscreenUI", "Writes log messages to the system console (console window/standard output)."); TRANSLATE_NOOP("FullscreenUI", "Writes log messages to emulog.txt."); TRANSLATE_NOOP("FullscreenUI", "Writes dev log messages to log sinks."); TRANSLATE_NOOP("FullscreenUI", "Writes timestamps alongside log messages."); TRANSLATE_NOOP("FullscreenUI", "Writes debug messages from the game's EE code to the console."); TRANSLATE_NOOP("FullscreenUI", "Writes debug messages from the game's IOP code to the console."); TRANSLATE_NOOP("FullscreenUI", "Logs disc reads from games."); TRANSLATE_NOOP("FullscreenUI", "Emotion Engine"); TRANSLATE_NOOP("FullscreenUI", "Determines how the results of floating-point operations are rounded. Some games need specific settings."); TRANSLATE_NOOP("FullscreenUI", "Determines how the results of floating-point division is rounded. Some games need specific settings."); TRANSLATE_NOOP("FullscreenUI", "Determines how out-of-range floating point numbers are handled. Some games need specific settings."); TRANSLATE_NOOP("FullscreenUI", "Performs just-in-time binary translation of 64-bit MIPS-IV machine code to native code."); TRANSLATE_NOOP("FullscreenUI", "Enables simulation of the EE's cache. Slow."); TRANSLATE_NOOP("FullscreenUI", "Huge speedup for some games, with almost no compatibility side effects."); TRANSLATE_NOOP("FullscreenUI", "Moderate speedup for some games, with no known side effects."); TRANSLATE_NOOP("FullscreenUI", "Uses backpatching to avoid register flushing on every memory access."); TRANSLATE_NOOP("FullscreenUI", "Vector Units"); TRANSLATE_NOOP("FullscreenUI", "New Vector Unit recompiler with much improved compatibility. Recommended."); TRANSLATE_NOOP("FullscreenUI", "Good speedup and high compatibility, may cause graphical errors."); TRANSLATE_NOOP("FullscreenUI", "Runs VU1 instantly. Provides a modest speed improvement in most games. Safe for most games, but a few games may exhibit graphical errors."); TRANSLATE_NOOP("FullscreenUI", "I/O Processor"); TRANSLATE_NOOP("FullscreenUI", "Performs just-in-time binary translation of 32-bit MIPS-I machine code to native code."); TRANSLATE_NOOP("FullscreenUI", "Save State Management"); TRANSLATE_NOOP("FullscreenUI", "Sets the compression algorithm for savestate."); TRANSLATE_NOOP("FullscreenUI", "Sets the compression level for savestate."); TRANSLATE_NOOP("FullscreenUI", "Graphics"); TRANSLATE_NOOP("FullscreenUI", "Enables API-level validation of graphics commands."); TRANSLATE_NOOP("FullscreenUI", "Settings"); TRANSLATE_NOOP("FullscreenUI", "Enable Cheats"); TRANSLATE_NOOP("FullscreenUI", "No cheats are available for this game."); TRANSLATE_NOOP("FullscreenUI", "Cheat Codes"); TRANSLATE_NOOP("FullscreenUI", "No patches are available for this game."); TRANSLATE_NOOP("FullscreenUI", "Game Patches"); TRANSLATE_NOOP("FullscreenUI", "Activating cheats can cause unpredictable behavior, crashing, soft-locks, or broken saved games."); TRANSLATE_NOOP("FullscreenUI", "Activating game patches can cause unpredictable behavior, crashing, soft-locks, or broken saved games."); TRANSLATE_NOOP("FullscreenUI", "Use patches at your own risk, the PCSX2 team will provide no support for users who have enabled game patches."); TRANSLATE_NOOP("FullscreenUI", "Game Fixes"); TRANSLATE_NOOP("FullscreenUI", "Game fixes should not be modified unless you are aware of what each option does and the implications of doing so."); TRANSLATE_NOOP("FullscreenUI", "FPU Multiply Hack"); TRANSLATE_NOOP("FullscreenUI", "For Tales of Destiny."); TRANSLATE_NOOP("FullscreenUI", "Use Software Renderer For FMVs"); TRANSLATE_NOOP("FullscreenUI", "Needed for some games with complex FMV rendering."); TRANSLATE_NOOP("FullscreenUI", "Skip MPEG Hack"); TRANSLATE_NOOP("FullscreenUI", "Skips videos/FMVs in games to avoid game hanging/freezes."); TRANSLATE_NOOP("FullscreenUI", "Preload TLB Hack"); TRANSLATE_NOOP("FullscreenUI", "To avoid TLB miss on Goemon."); TRANSLATE_NOOP("FullscreenUI", "EE Timing Hack"); TRANSLATE_NOOP("FullscreenUI", "General-purpose timing hack. Known to affect following games: Digital Devil Saga, SSX."); TRANSLATE_NOOP("FullscreenUI", "Instant DMA Hack"); TRANSLATE_NOOP("FullscreenUI", "Good for cache emulation problems. Known to affect following games: Fire Pro Wrestling Z."); TRANSLATE_NOOP("FullscreenUI", "OPH Flag Hack"); TRANSLATE_NOOP("FullscreenUI", "Known to affect following games: Bleach Blade Battlers, Growlanser II and III, Wizardry."); TRANSLATE_NOOP("FullscreenUI", "Emulate GIF FIFO"); TRANSLATE_NOOP("FullscreenUI", "Correct but slower. Known to affect the following games: FIFA Street 2."); TRANSLATE_NOOP("FullscreenUI", "DMA Busy Hack"); TRANSLATE_NOOP("FullscreenUI", "Known to affect following games: Mana Khemia 1, Metal Saga, Pilot Down Behind Enemy Lines."); TRANSLATE_NOOP("FullscreenUI", "Delay VIF1 Stalls"); TRANSLATE_NOOP("FullscreenUI", "For SOCOM 2 HUD and Spy Hunter loading hang."); TRANSLATE_NOOP("FullscreenUI", "Emulate VIF FIFO"); TRANSLATE_NOOP("FullscreenUI", "Simulate VIF1 FIFO read ahead. Known to affect following games: Test Drive Unlimited, Transformers."); TRANSLATE_NOOP("FullscreenUI", "Full VU0 Synchronization"); TRANSLATE_NOOP("FullscreenUI", "Forces tight VU0 sync on every COP2 instruction."); TRANSLATE_NOOP("FullscreenUI", "VU I Bit Hack"); TRANSLATE_NOOP("FullscreenUI", "Avoids constant recompilation in some games. Known to affect the following games: Scarface The World is Yours, Crash Tag Team Racing."); TRANSLATE_NOOP("FullscreenUI", "VU Add Hack"); TRANSLATE_NOOP("FullscreenUI", "For Tri-Ace Games: Star Ocean 3, Radiata Stories, Valkyrie Profile 2."); TRANSLATE_NOOP("FullscreenUI", "VU Overflow Hack"); TRANSLATE_NOOP("FullscreenUI", "To check for possible float overflows (Superman Returns)."); TRANSLATE_NOOP("FullscreenUI", "VU Sync"); TRANSLATE_NOOP("FullscreenUI", "Run behind. To avoid sync problems when reading or writing VU registers."); TRANSLATE_NOOP("FullscreenUI", "VU XGKick Sync"); TRANSLATE_NOOP("FullscreenUI", "Use accurate timing for VU XGKicks (slower)."); TRANSLATE_NOOP("FullscreenUI", "Force Blit Internal FPS Detection"); TRANSLATE_NOOP("FullscreenUI", "Use alternative method to calculate internal FPS to avoid false readings in some games."); TRANSLATE_NOOP("FullscreenUI", "{0}/{1}/{2}/{3}"); TRANSLATE_NOOP("FullscreenUI", "Automatic mapping completed for {}."); TRANSLATE_NOOP("FullscreenUI", "Automatic mapping failed for {}."); TRANSLATE_NOOP("FullscreenUI", "Game settings initialized with global settings for '{}'."); TRANSLATE_NOOP("FullscreenUI", "Game settings have been cleared for '{}'."); TRANSLATE_NOOP("FullscreenUI", "Uses {} as confirm when using a controller."); TRANSLATE_NOOP("FullscreenUI", "Swaps both {}/{} (When Swap OK/Cancel is set to automatic) and {}/{} buttons"); TRANSLATE_NOOP("FullscreenUI", "Slot {}"); TRANSLATE_NOOP("FullscreenUI", "{} (Current)"); TRANSLATE_NOOP("FullscreenUI", "{} (Folder)"); TRANSLATE_NOOP("FullscreenUI", "Selected HDD image: {}"); TRANSLATE_NOOP("FullscreenUI", "HDD image '{}' already exists. Do you want to overwrite it?"); TRANSLATE_NOOP("FullscreenUI", "Failed to create the Memory Card, because the name '{}' contains one or more invalid characters."); TRANSLATE_NOOP("FullscreenUI", "Failed to create the Memory Card, because another card with the name '{}' already exists."); TRANSLATE_NOOP("FullscreenUI", "Memory Card '{}' created."); TRANSLATE_NOOP("FullscreenUI", "Failed to load '{}'."); TRANSLATE_NOOP("FullscreenUI", "Input profile '{}' loaded."); TRANSLATE_NOOP("FullscreenUI", "Input profile '{}' saved."); TRANSLATE_NOOP("FullscreenUI", "Failed to save input profile '{}'."); TRANSLATE_NOOP("FullscreenUI", "Port {} Controller Type"); TRANSLATE_NOOP("FullscreenUI", "Select Macro {} Binds"); TRANSLATE_NOOP("FullscreenUI", "{} Frames"); TRANSLATE_NOOP("FullscreenUI", "Port {} Device"); TRANSLATE_NOOP("FullscreenUI", "Port {} Subtype"); TRANSLATE_NOOP("FullscreenUI", "{} unlabelled patch codes will automatically activate."); TRANSLATE_NOOP("FullscreenUI", "{} unlabelled patch codes found but not enabled."); TRANSLATE_NOOP("FullscreenUI", "Left: "); TRANSLATE_NOOP("FullscreenUI", "Top: "); TRANSLATE_NOOP("FullscreenUI", "Right: "); TRANSLATE_NOOP("FullscreenUI", "Bottom: "); TRANSLATE_NOOP("FullscreenUI", "Summary"); TRANSLATE_NOOP("FullscreenUI", "Interface Settings"); TRANSLATE_NOOP("FullscreenUI", "BIOS Settings"); TRANSLATE_NOOP("FullscreenUI", "Emulation Settings"); TRANSLATE_NOOP("FullscreenUI", "Graphics Settings"); TRANSLATE_NOOP("FullscreenUI", "Audio Settings"); TRANSLATE_NOOP("FullscreenUI", "Memory Card Settings"); TRANSLATE_NOOP("FullscreenUI", "Network & HDD Settings"); TRANSLATE_NOOP("FullscreenUI", "Folder Settings"); TRANSLATE_NOOP("FullscreenUI", "Achievements Settings"); TRANSLATE_NOOP("FullscreenUI", "Controller Settings"); TRANSLATE_NOOP("FullscreenUI", "Hotkey Settings"); TRANSLATE_NOOP("FullscreenUI", "Advanced Settings"); TRANSLATE_NOOP("FullscreenUI", "Patches"); TRANSLATE_NOOP("FullscreenUI", "Cheats"); TRANSLATE_NOOP("FullscreenUI", "Dark"); TRANSLATE_NOOP("FullscreenUI", "Light"); TRANSLATE_NOOP("FullscreenUI", "Grey Matter"); TRANSLATE_NOOP("FullscreenUI", "Untouched Lagoon"); TRANSLATE_NOOP("FullscreenUI", "Baby Pastel"); TRANSLATE_NOOP("FullscreenUI", "Pizza Time!"); TRANSLATE_NOOP("FullscreenUI", "PCSX2 Blue"); TRANSLATE_NOOP("FullscreenUI", "Scarlet Devil"); TRANSLATE_NOOP("FullscreenUI", "Violet Angel"); TRANSLATE_NOOP("FullscreenUI", "Cobalt Sky"); TRANSLATE_NOOP("FullscreenUI", "AMOLED"); TRANSLATE_NOOP("FullscreenUI", "Fit"); TRANSLATE_NOOP("FullscreenUI", "Fill"); TRANSLATE_NOOP("FullscreenUI", "Stretch"); TRANSLATE_NOOP("FullscreenUI", "Center"); TRANSLATE_NOOP("FullscreenUI", "Tile"); TRANSLATE_NOOP("FullscreenUI", "Enabled"); TRANSLATE_NOOP("FullscreenUI", "Disabled"); TRANSLATE_NOOP("FullscreenUI", "Top Left"); TRANSLATE_NOOP("FullscreenUI", "Top Center"); TRANSLATE_NOOP("FullscreenUI", "Top Right"); TRANSLATE_NOOP("FullscreenUI", "Center Left"); TRANSLATE_NOOP("FullscreenUI", "Center Right"); TRANSLATE_NOOP("FullscreenUI", "Bottom Left"); TRANSLATE_NOOP("FullscreenUI", "Bottom Center"); TRANSLATE_NOOP("FullscreenUI", "Bottom Right"); TRANSLATE_NOOP("FullscreenUI", "2% [1 FPS (NTSC) / 1 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "10% [6 FPS (NTSC) / 5 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "25% [15 FPS (NTSC) / 12 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "50% [30 FPS (NTSC) / 25 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "75% [45 FPS (NTSC) / 37 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "90% [54 FPS (NTSC) / 45 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "100% [60 FPS (NTSC) / 50 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "110% [66 FPS (NTSC) / 55 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "120% [72 FPS (NTSC) / 60 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "150% [90 FPS (NTSC) / 75 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "175% [105 FPS (NTSC) / 87 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "200% [120 FPS (NTSC) / 100 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "300% [180 FPS (NTSC) / 150 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "400% [240 FPS (NTSC) / 200 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "500% [300 FPS (NTSC) / 250 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "1000% [600 FPS (NTSC) / 500 FPS (PAL)]"); TRANSLATE_NOOP("FullscreenUI", "50% Speed"); TRANSLATE_NOOP("FullscreenUI", "60% Speed"); TRANSLATE_NOOP("FullscreenUI", "75% Speed"); TRANSLATE_NOOP("FullscreenUI", "100% Speed (Default)"); TRANSLATE_NOOP("FullscreenUI", "130% Speed"); TRANSLATE_NOOP("FullscreenUI", "180% Speed"); TRANSLATE_NOOP("FullscreenUI", "300% Speed"); TRANSLATE_NOOP("FullscreenUI", "Normal (Default)"); TRANSLATE_NOOP("FullscreenUI", "Mild Underclock"); TRANSLATE_NOOP("FullscreenUI", "Moderate Underclock"); TRANSLATE_NOOP("FullscreenUI", "Maximum Underclock"); TRANSLATE_NOOP("FullscreenUI", "0 Frames (Hard Sync)"); TRANSLATE_NOOP("FullscreenUI", "1 Frame"); TRANSLATE_NOOP("FullscreenUI", "2 Frames"); TRANSLATE_NOOP("FullscreenUI", "3 Frames"); TRANSLATE_NOOP("FullscreenUI", "Extra + Preserve Sign"); TRANSLATE_NOOP("FullscreenUI", "Full"); TRANSLATE_NOOP("FullscreenUI", "Extra"); TRANSLATE_NOOP("FullscreenUI", "Automatic (Default)"); TRANSLATE_NOOP("FullscreenUI", "Direct3D 11 (Legacy)"); TRANSLATE_NOOP("FullscreenUI", "Direct3D 12"); TRANSLATE_NOOP("FullscreenUI", "OpenGL"); TRANSLATE_NOOP("FullscreenUI", "Vulkan"); TRANSLATE_NOOP("FullscreenUI", "Metal"); TRANSLATE_NOOP("FullscreenUI", "Software Renderer"); TRANSLATE_NOOP("FullscreenUI", "Null"); TRANSLATE_NOOP("FullscreenUI", "Off"); TRANSLATE_NOOP("FullscreenUI", "Bilinear (Smooth)"); TRANSLATE_NOOP("FullscreenUI", "Bilinear (Sharp)"); TRANSLATE_NOOP("FullscreenUI", "No Deinterlacing"); TRANSLATE_NOOP("FullscreenUI", "Weave (Top Field First, Sawtooth)"); TRANSLATE_NOOP("FullscreenUI", "Weave (Bottom Field First, Sawtooth)"); TRANSLATE_NOOP("FullscreenUI", "Bob (Top Field First)"); TRANSLATE_NOOP("FullscreenUI", "Bob (Bottom Field First)"); TRANSLATE_NOOP("FullscreenUI", "Blend (Top Field First, Half FPS)"); TRANSLATE_NOOP("FullscreenUI", "Blend (Bottom Field First, Half FPS)"); TRANSLATE_NOOP("FullscreenUI", "Adaptive (Top Field First)"); TRANSLATE_NOOP("FullscreenUI", "Adaptive (Bottom Field First)"); TRANSLATE_NOOP("FullscreenUI", "Native (PS2)"); TRANSLATE_NOOP("FullscreenUI", "2x Native (~720px/HD)"); TRANSLATE_NOOP("FullscreenUI", "3x Native (~1080px/FHD)"); TRANSLATE_NOOP("FullscreenUI", "4x Native (~1440px/QHD)"); TRANSLATE_NOOP("FullscreenUI", "5x Native (~1800px/QHD+)"); TRANSLATE_NOOP("FullscreenUI", "6x Native (~2160px/4K UHD)"); TRANSLATE_NOOP("FullscreenUI", "7x Native (~2520px)"); TRANSLATE_NOOP("FullscreenUI", "8x Native (~2880px/5K UHD)"); TRANSLATE_NOOP("FullscreenUI", "9x Native (~3240px)"); TRANSLATE_NOOP("FullscreenUI", "10x Native (~3600px/6K UHD)"); TRANSLATE_NOOP("FullscreenUI", "11x Native (~3960px)"); TRANSLATE_NOOP("FullscreenUI", "12x Native (~4320px/8K UHD)"); TRANSLATE_NOOP("FullscreenUI", "Nearest"); TRANSLATE_NOOP("FullscreenUI", "Bilinear (Forced)"); TRANSLATE_NOOP("FullscreenUI", "Bilinear (PS2)"); TRANSLATE_NOOP("FullscreenUI", "Bilinear (Forced excluding sprite)"); TRANSLATE_NOOP("FullscreenUI", "Off (None)"); TRANSLATE_NOOP("FullscreenUI", "Trilinear (PS2)"); TRANSLATE_NOOP("FullscreenUI", "Trilinear (Forced)"); TRANSLATE_NOOP("FullscreenUI", "Scaled"); TRANSLATE_NOOP("FullscreenUI", "Unscaled (Default)"); TRANSLATE_NOOP("FullscreenUI", "Force 32bit"); TRANSLATE_NOOP("FullscreenUI", "Minimum"); TRANSLATE_NOOP("FullscreenUI", "Basic (Recommended)"); TRANSLATE_NOOP("FullscreenUI", "Medium"); TRANSLATE_NOOP("FullscreenUI", "High"); TRANSLATE_NOOP("FullscreenUI", "Full (Slow)"); TRANSLATE_NOOP("FullscreenUI", "Maximum (Very Slow)"); TRANSLATE_NOOP("FullscreenUI", "Off (Default)"); TRANSLATE_NOOP("FullscreenUI", "2x"); TRANSLATE_NOOP("FullscreenUI", "4x"); TRANSLATE_NOOP("FullscreenUI", "8x"); TRANSLATE_NOOP("FullscreenUI", "16x"); TRANSLATE_NOOP("FullscreenUI", "Partial"); TRANSLATE_NOOP("FullscreenUI", "Full (Hash Cache)"); TRANSLATE_NOOP("FullscreenUI", "Force Disabled"); TRANSLATE_NOOP("FullscreenUI", "Force Enabled"); TRANSLATE_NOOP("FullscreenUI", "Accurate (Recommended)"); TRANSLATE_NOOP("FullscreenUI", "Disable Readbacks (Synchronize GS Thread)"); TRANSLATE_NOOP("FullscreenUI", "Unsynchronized (Non-Deterministic)"); TRANSLATE_NOOP("FullscreenUI", "Disabled (Ignore Transfers)"); TRANSLATE_NOOP("FullscreenUI", "Display Resolution (Aspect Corrected)"); TRANSLATE_NOOP("FullscreenUI", "Internal Resolution (Aspect Corrected)"); TRANSLATE_NOOP("FullscreenUI", "Internal Resolution (No Aspect Correction)"); TRANSLATE_NOOP("FullscreenUI", "PNG"); TRANSLATE_NOOP("FullscreenUI", "JPEG"); TRANSLATE_NOOP("FullscreenUI", "WebP"); TRANSLATE_NOOP("FullscreenUI", "0 (Disabled)"); TRANSLATE_NOOP("FullscreenUI", "1 (64 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "2 (128 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "3 (192 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "4 (256 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "5 (320 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "6 (384 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "7 (448 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "8 (512 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "9 (576 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "10 (640 Max Width)"); TRANSLATE_NOOP("FullscreenUI", "Sprites Only"); TRANSLATE_NOOP("FullscreenUI", "Sprites/Triangles"); TRANSLATE_NOOP("FullscreenUI", "Blended Sprites/Triangles"); TRANSLATE_NOOP("FullscreenUI", "1 (Normal)"); TRANSLATE_NOOP("FullscreenUI", "2 (Aggressive)"); TRANSLATE_NOOP("FullscreenUI", "Inside Target"); TRANSLATE_NOOP("FullscreenUI", "Merge Targets"); TRANSLATE_NOOP("FullscreenUI", "Normal (Vertex)"); TRANSLATE_NOOP("FullscreenUI", "Special (Texture)"); TRANSLATE_NOOP("FullscreenUI", "Special (Texture - Aggressive)"); TRANSLATE_NOOP("FullscreenUI", "Align to Native"); TRANSLATE_NOOP("FullscreenUI", "Align to Native - with Texture Offset"); TRANSLATE_NOOP("FullscreenUI", "Normal"); TRANSLATE_NOOP("FullscreenUI", "Aggressive"); TRANSLATE_NOOP("FullscreenUI", "Normal (Maintain Upscale)"); TRANSLATE_NOOP("FullscreenUI", "Aggressive (Maintain Upscale)"); TRANSLATE_NOOP("FullscreenUI", "Half"); TRANSLATE_NOOP("FullscreenUI", "Force Bilinear"); TRANSLATE_NOOP("FullscreenUI", "Force Nearest"); TRANSLATE_NOOP("FullscreenUI", "Disabled (Default)"); TRANSLATE_NOOP("FullscreenUI", "Enabled (Sprites Only)"); TRANSLATE_NOOP("FullscreenUI", "Enabled (All Primitives)"); TRANSLATE_NOOP("FullscreenUI", "Enabled (Exact Match)"); TRANSLATE_NOOP("FullscreenUI", "Enabled (Check Inside Target)"); TRANSLATE_NOOP("FullscreenUI", "None (Default)"); TRANSLATE_NOOP("FullscreenUI", "Sharpen Only (Internal Resolution)"); TRANSLATE_NOOP("FullscreenUI", "Sharpen and Resize (Display Resolution)"); TRANSLATE_NOOP("FullscreenUI", "Scanline Filter"); TRANSLATE_NOOP("FullscreenUI", "Diagonal Filter"); TRANSLATE_NOOP("FullscreenUI", "Triangular Filter"); TRANSLATE_NOOP("FullscreenUI", "Wave Filter"); TRANSLATE_NOOP("FullscreenUI", "Lottes CRT"); TRANSLATE_NOOP("FullscreenUI", "4xRGSS"); TRANSLATE_NOOP("FullscreenUI", "NxAGSS"); TRANSLATE_NOOP("FullscreenUI", "Uncompressed"); TRANSLATE_NOOP("FullscreenUI", "LZMA (xz)"); TRANSLATE_NOOP("FullscreenUI", "Zstandard (zst)"); TRANSLATE_NOOP("FullscreenUI", "PS1"); TRANSLATE_NOOP("FullscreenUI", "Manual"); TRANSLATE_NOOP("FullscreenUI", "Auto"); TRANSLATE_NOOP("FullscreenUI", "Internal"); TRANSLATE_NOOP("FullscreenUI", "Negative"); TRANSLATE_NOOP("FullscreenUI", "Positive"); TRANSLATE_NOOP("FullscreenUI", "Chop/Zero (Default)"); TRANSLATE_NOOP("FullscreenUI", "Deflate64"); TRANSLATE_NOOP("FullscreenUI", "Zstandard"); TRANSLATE_NOOP("FullscreenUI", "LZMA2"); TRANSLATE_NOOP("FullscreenUI", "Low (Fast)"); TRANSLATE_NOOP("FullscreenUI", "Medium (Recommended)"); TRANSLATE_NOOP("FullscreenUI", "Very High (Slow, Not Recommended)"); TRANSLATE_NOOP("FullscreenUI", "Clear Binding"); TRANSLATE_NOOP("FullscreenUI", "Default"); TRANSLATE_NOOP("FullscreenUI", "Change Page"); TRANSLATE_NOOP("FullscreenUI", "Navigate"); TRANSLATE_NOOP("FullscreenUI", "Select"); TRANSLATE_NOOP("FullscreenUI", "Back"); TRANSLATE_NOOP("FullscreenUI", "Frequency"); TRANSLATE_NOOP("FullscreenUI", "Set Input Binding"); TRANSLATE_NOOP("FullscreenUI", "Title"); TRANSLATE_NOOP("FullscreenUI", "Serial"); TRANSLATE_NOOP("FullscreenUI", "CRC"); TRANSLATE_NOOP("FullscreenUI", "Type"); TRANSLATE_NOOP("FullscreenUI", "Region"); TRANSLATE_NOOP("FullscreenUI", "Compatibility Rating"); TRANSLATE_NOOP("FullscreenUI", "Path"); TRANSLATE_NOOP("FullscreenUI", "Disc Path"); TRANSLATE_NOOP("FullscreenUI", "Select Disc Path"); TRANSLATE_NOOP("FullscreenUI", "Cannot show details for games which were not scanned in the game list."); TRANSLATE_NOOP("FullscreenUI", "Copy Settings"); TRANSLATE_NOOP("FullscreenUI", "Clear Settings"); TRANSLATE_NOOP("FullscreenUI", "Theme"); TRANSLATE_NOOP("FullscreenUI", "Default To Game List"); TRANSLATE_NOOP("FullscreenUI", "Use Save State Selector"); TRANSLATE_NOOP("FullscreenUI", "Background Image"); TRANSLATE_NOOP("FullscreenUI", "Select Background Image"); TRANSLATE_NOOP("FullscreenUI", "Clear Background Image"); TRANSLATE_NOOP("FullscreenUI", "Background Opacity"); TRANSLATE_NOOP("FullscreenUI", "Background Mode"); TRANSLATE_NOOP("FullscreenUI", "Inhibit Screensaver"); TRANSLATE_NOOP("FullscreenUI", "Pause On Start"); TRANSLATE_NOOP("FullscreenUI", "Pause On Focus Loss"); TRANSLATE_NOOP("FullscreenUI", "Pause On Controller Disconnection"); TRANSLATE_NOOP("FullscreenUI", "Pause On Menu"); TRANSLATE_NOOP("FullscreenUI", "Prompt On State Load/Save Failure"); TRANSLATE_NOOP("FullscreenUI", "Confirm Shutdown"); TRANSLATE_NOOP("FullscreenUI", "Save State On Shutdown"); TRANSLATE_NOOP("FullscreenUI", "Create Save State Backups"); TRANSLATE_NOOP("FullscreenUI", "Swap OK/Cancel in Big Picture Mode"); TRANSLATE_NOOP("FullscreenUI", "Use Legacy Nintendo Layout in Big Picture Mode"); TRANSLATE_NOOP("FullscreenUI", "Enable Discord Presence"); TRANSLATE_NOOP("FullscreenUI", "Start Fullscreen"); TRANSLATE_NOOP("FullscreenUI", "Double-Click Toggles Fullscreen"); TRANSLATE_NOOP("FullscreenUI", "Hide Cursor In Fullscreen"); TRANSLATE_NOOP("FullscreenUI", "Start Big Picture UI"); TRANSLATE_NOOP("FullscreenUI", "OSD Scale"); TRANSLATE_NOOP("FullscreenUI", "OSD Messages Position"); TRANSLATE_NOOP("FullscreenUI", "OSD Performance Position"); TRANSLATE_NOOP("FullscreenUI", "Show PCSX2 Version"); TRANSLATE_NOOP("FullscreenUI", "Show Speed"); TRANSLATE_NOOP("FullscreenUI", "Show FPS"); TRANSLATE_NOOP("FullscreenUI", "Show VPS"); TRANSLATE_NOOP("FullscreenUI", "Show Resolution"); TRANSLATE_NOOP("FullscreenUI", "Show Hardware Info"); TRANSLATE_NOOP("FullscreenUI", "Show GS Statistics"); TRANSLATE_NOOP("FullscreenUI", "Show CPU Usage"); TRANSLATE_NOOP("FullscreenUI", "Show GPU Usage"); TRANSLATE_NOOP("FullscreenUI", "Show Status Indicators"); TRANSLATE_NOOP("FullscreenUI", "Show Frame Times"); TRANSLATE_NOOP("FullscreenUI", "Show Settings"); TRANSLATE_NOOP("FullscreenUI", "Show Patches"); TRANSLATE_NOOP("FullscreenUI", "Show Inputs"); TRANSLATE_NOOP("FullscreenUI", "Show Video Capture Status"); TRANSLATE_NOOP("FullscreenUI", "Show Input Recording Status"); TRANSLATE_NOOP("FullscreenUI", "Show Texture Replacement Status"); TRANSLATE_NOOP("FullscreenUI", "Warn About Unsafe Settings"); TRANSLATE_NOOP("FullscreenUI", "Reset Settings"); TRANSLATE_NOOP("FullscreenUI", "Change Search Directory"); TRANSLATE_NOOP("FullscreenUI", "Fast Boot"); TRANSLATE_NOOP("FullscreenUI", "Normal Speed"); TRANSLATE_NOOP("FullscreenUI", "Fast Forward Speed"); TRANSLATE_NOOP("FullscreenUI", "Slow Motion Speed"); TRANSLATE_NOOP("FullscreenUI", "EE Cycle Rate"); TRANSLATE_NOOP("FullscreenUI", "EE Cycle Skipping"); TRANSLATE_NOOP("FullscreenUI", "Enable MTVU (Multi-Threaded VU1)"); TRANSLATE_NOOP("FullscreenUI", "Thread Pinning"); TRANSLATE_NOOP("FullscreenUI", "Enable Host Filesystem"); TRANSLATE_NOOP("FullscreenUI", "Enable Fast CDVD"); TRANSLATE_NOOP("FullscreenUI", "Enable CDVD Precaching"); TRANSLATE_NOOP("FullscreenUI", "Maximum Frame Latency"); TRANSLATE_NOOP("FullscreenUI", "Optimal Frame Pacing"); TRANSLATE_NOOP("FullscreenUI", "Vertical Sync (VSync)"); TRANSLATE_NOOP("FullscreenUI", "Sync to Host Refresh Rate"); TRANSLATE_NOOP("FullscreenUI", "Use Host VSync Timing"); TRANSLATE_NOOP("FullscreenUI", "Aspect Ratio"); TRANSLATE_NOOP("FullscreenUI", "FMV Aspect Ratio Override"); TRANSLATE_NOOP("FullscreenUI", "Deinterlacing"); TRANSLATE_NOOP("FullscreenUI", "Screenshot Size"); TRANSLATE_NOOP("FullscreenUI", "Screenshot Format"); TRANSLATE_NOOP("FullscreenUI", "Screenshot Quality"); TRANSLATE_NOOP("FullscreenUI", "Vertical Stretch"); TRANSLATE_NOOP("FullscreenUI", "Crop"); TRANSLATE_NOOP("FullscreenUI", "Enable Widescreen Patches"); TRANSLATE_NOOP("FullscreenUI", "Enable No-Interlacing Patches"); TRANSLATE_NOOP("FullscreenUI", "Bilinear Upscaling"); TRANSLATE_NOOP("FullscreenUI", "Integer Upscaling"); TRANSLATE_NOOP("FullscreenUI", "Screen Offsets"); TRANSLATE_NOOP("FullscreenUI", "Show Overscan"); TRANSLATE_NOOP("FullscreenUI", "Anti-Blur"); TRANSLATE_NOOP("FullscreenUI", "Internal Resolution"); TRANSLATE_NOOP("FullscreenUI", "Bilinear Filtering"); TRANSLATE_NOOP("FullscreenUI", "Trilinear Filtering"); TRANSLATE_NOOP("FullscreenUI", "Anisotropic Filtering"); TRANSLATE_NOOP("FullscreenUI", "Dithering"); TRANSLATE_NOOP("FullscreenUI", "Blending Accuracy"); TRANSLATE_NOOP("FullscreenUI", "Mipmapping"); TRANSLATE_NOOP("FullscreenUI", "Software Rendering Threads"); TRANSLATE_NOOP("FullscreenUI", "Auto Flush (Software)"); TRANSLATE_NOOP("FullscreenUI", "Edge AA (AA1)"); TRANSLATE_NOOP("FullscreenUI", "Manual Hardware Fixes"); TRANSLATE_NOOP("FullscreenUI", "Load Textures"); TRANSLATE_NOOP("FullscreenUI", "Asynchronous Texture Loading"); TRANSLATE_NOOP("FullscreenUI", "Precache Replacements"); TRANSLATE_NOOP("FullscreenUI", "Replacements Directory"); TRANSLATE_NOOP("FullscreenUI", "Dump Textures"); TRANSLATE_NOOP("FullscreenUI", "Dump Mipmaps"); TRANSLATE_NOOP("FullscreenUI", "Dump FMV Textures"); TRANSLATE_NOOP("FullscreenUI", "FXAA"); TRANSLATE_NOOP("FullscreenUI", "Contrast Adaptive Sharpening"); TRANSLATE_NOOP("FullscreenUI", "CAS Sharpness"); TRANSLATE_NOOP("FullscreenUI", "Shade Boost"); TRANSLATE_NOOP("FullscreenUI", "Shade Boost Brightness"); TRANSLATE_NOOP("FullscreenUI", "Shade Boost Contrast"); TRANSLATE_NOOP("FullscreenUI", "Shade Boost Saturation"); TRANSLATE_NOOP("FullscreenUI", "TV Shaders"); TRANSLATE_NOOP("FullscreenUI", "Standard Volume"); TRANSLATE_NOOP("FullscreenUI", "Fast Forward Volume"); TRANSLATE_NOOP("FullscreenUI", "Mute All Sound"); TRANSLATE_NOOP("FullscreenUI", "Audio Backend"); TRANSLATE_NOOP("FullscreenUI", "Expansion"); TRANSLATE_NOOP("FullscreenUI", "Synchronization"); TRANSLATE_NOOP("FullscreenUI", "Buffer Size"); TRANSLATE_NOOP("FullscreenUI", "Output Latency"); TRANSLATE_NOOP("FullscreenUI", "Minimal Output Latency"); TRANSLATE_NOOP("FullscreenUI", "Create Memory Card"); TRANSLATE_NOOP("FullscreenUI", "Memory Card Directory"); TRANSLATE_NOOP("FullscreenUI", "Folder Memory Card Filter"); TRANSLATE_NOOP("FullscreenUI", "Enable Network Adapter"); TRANSLATE_NOOP("FullscreenUI", "Ethernet Device Type"); TRANSLATE_NOOP("FullscreenUI", "Ethernet Device"); TRANSLATE_NOOP("FullscreenUI", "Intercept DHCP"); TRANSLATE_NOOP("FullscreenUI", "Address"); TRANSLATE_NOOP("FullscreenUI", "Auto Subnet Mask"); TRANSLATE_NOOP("FullscreenUI", "Subnet Mask"); TRANSLATE_NOOP("FullscreenUI", "Auto Gateway"); TRANSLATE_NOOP("FullscreenUI", "Gateway Address"); TRANSLATE_NOOP("FullscreenUI", "DNS1 Mode"); TRANSLATE_NOOP("FullscreenUI", "DNS1 Address"); TRANSLATE_NOOP("FullscreenUI", "DNS2 Mode"); TRANSLATE_NOOP("FullscreenUI", "DNS2 Address"); TRANSLATE_NOOP("FullscreenUI", "Enable HDD"); TRANSLATE_NOOP("FullscreenUI", "Select HDD Image File"); TRANSLATE_NOOP("FullscreenUI", "Select HDD Size"); TRANSLATE_NOOP("FullscreenUI", "Custom HDD Size"); TRANSLATE_NOOP("FullscreenUI", "Create"); TRANSLATE_NOOP("FullscreenUI", "File Already Exists"); TRANSLATE_NOOP("FullscreenUI", "Memory Card Type"); TRANSLATE_NOOP("FullscreenUI", "Use NTFS Compression?"); TRANSLATE_NOOP("FullscreenUI", "Reset Controller Settings"); TRANSLATE_NOOP("FullscreenUI", "Load Profile"); TRANSLATE_NOOP("FullscreenUI", "Save Profile"); TRANSLATE_NOOP("FullscreenUI", "Enable SDL Input Source"); TRANSLATE_NOOP("FullscreenUI", "SDL DualShock 4 / DualSense Enhanced Mode"); TRANSLATE_NOOP("FullscreenUI", "SDL DualSense Player LED"); TRANSLATE_NOOP("FullscreenUI", "SDL Raw Input"); TRANSLATE_NOOP("FullscreenUI", "Enable XInput Input Source"); TRANSLATE_NOOP("FullscreenUI", "Enable Console Port 1 Multitap"); TRANSLATE_NOOP("FullscreenUI", "Enable Console Port 2 Multitap"); TRANSLATE_NOOP("FullscreenUI", "Controller Port {}{}"); TRANSLATE_NOOP("FullscreenUI", "Controller Port {}"); TRANSLATE_NOOP("FullscreenUI", "Controller Type"); TRANSLATE_NOOP("FullscreenUI", "Automatic Mapping"); TRANSLATE_NOOP("FullscreenUI", "Controller Port {}{} Macros"); TRANSLATE_NOOP("FullscreenUI", "Controller Port {} Macros"); TRANSLATE_NOOP("FullscreenUI", "Macro Button {}"); TRANSLATE_NOOP("FullscreenUI", "Buttons"); TRANSLATE_NOOP("FullscreenUI", "Press To Toggle"); TRANSLATE_NOOP("FullscreenUI", "Pressure"); TRANSLATE_NOOP("FullscreenUI", "Deadzone"); TRANSLATE_NOOP("FullscreenUI", "Controller Port {}{} Settings"); TRANSLATE_NOOP("FullscreenUI", "Controller Port {} Settings"); TRANSLATE_NOOP("FullscreenUI", "USB Port {}"); TRANSLATE_NOOP("FullscreenUI", "Device Type"); TRANSLATE_NOOP("FullscreenUI", "Device Subtype"); TRANSLATE_NOOP("FullscreenUI", "{} Bindings"); TRANSLATE_NOOP("FullscreenUI", "Clear Bindings"); TRANSLATE_NOOP("FullscreenUI", "{} Settings"); TRANSLATE_NOOP("FullscreenUI", "Cache Directory"); TRANSLATE_NOOP("FullscreenUI", "Covers Directory"); TRANSLATE_NOOP("FullscreenUI", "Snapshots Directory"); TRANSLATE_NOOP("FullscreenUI", "Save States Directory"); TRANSLATE_NOOP("FullscreenUI", "Game Settings Directory"); TRANSLATE_NOOP("FullscreenUI", "Input Profile Directory"); TRANSLATE_NOOP("FullscreenUI", "Cheats Directory"); TRANSLATE_NOOP("FullscreenUI", "Patches Directory"); TRANSLATE_NOOP("FullscreenUI", "Texture Replacements Directory"); TRANSLATE_NOOP("FullscreenUI", "Video Dumping Directory"); TRANSLATE_NOOP("FullscreenUI", "Show Advanced Settings"); TRANSLATE_NOOP("FullscreenUI", "System Console"); TRANSLATE_NOOP("FullscreenUI", "File Logging"); TRANSLATE_NOOP("FullscreenUI", "Verbose Logging"); TRANSLATE_NOOP("FullscreenUI", "Log Timestamps"); TRANSLATE_NOOP("FullscreenUI", "EE Console"); TRANSLATE_NOOP("FullscreenUI", "IOP Console"); TRANSLATE_NOOP("FullscreenUI", "CDVD Verbose Reads"); TRANSLATE_NOOP("FullscreenUI", "Rounding Mode"); TRANSLATE_NOOP("FullscreenUI", "Division Rounding Mode"); TRANSLATE_NOOP("FullscreenUI", "Clamping Mode"); TRANSLATE_NOOP("FullscreenUI", "Enable EE Recompiler"); TRANSLATE_NOOP("FullscreenUI", "Enable EE Cache"); TRANSLATE_NOOP("FullscreenUI", "Enable INTC Spin Detection"); TRANSLATE_NOOP("FullscreenUI", "Enable Wait Loop Detection"); TRANSLATE_NOOP("FullscreenUI", "Enable Fast Memory Access"); TRANSLATE_NOOP("FullscreenUI", "VU0 Rounding Mode"); TRANSLATE_NOOP("FullscreenUI", "VU0 Clamping Mode"); TRANSLATE_NOOP("FullscreenUI", "VU1 Rounding Mode"); TRANSLATE_NOOP("FullscreenUI", "VU1 Clamping Mode"); TRANSLATE_NOOP("FullscreenUI", "Enable VU0 Recompiler (Micro Mode)"); TRANSLATE_NOOP("FullscreenUI", "Enable VU1 Recompiler"); TRANSLATE_NOOP("FullscreenUI", "Enable VU Flag Optimization"); TRANSLATE_NOOP("FullscreenUI", "Enable Instant VU1"); TRANSLATE_NOOP("FullscreenUI", "Enable IOP Recompiler"); TRANSLATE_NOOP("FullscreenUI", "Compression Method"); TRANSLATE_NOOP("FullscreenUI", "Compression Level"); TRANSLATE_NOOP("FullscreenUI", "Use Debug Device"); TRANSLATE_NOOP("FullscreenUI", "Memory Card Enabled"); TRANSLATE_NOOP("FullscreenUI", "Card Name"); TRANSLATE_NOOP("FullscreenUI", "Eject Card"); // TRANSLATION-STRING-AREA-END #endif