mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-13 17:49:29 +01:00
Merge pull request #22773 from hrydgard/settings-pages-moves
Settings: Move the settings pages to a file each, and rename DeveloperToolsScreen
This commit is contained in:
17 files changed
+1231
-919
No files matched your search
+9
-2
@@ -63,6 +63,13 @@ list(APPEND UISource
|
||||
TabbedDialogScreen.cpp
|
||||
SettingsPage.h
|
||||
SettingsPage.cpp
|
||||
Settings/MainSettingsPages.h
|
||||
Settings/GraphicsPage.cpp
|
||||
Settings/ControlsPage.cpp
|
||||
Settings/AudioPage.cpp
|
||||
Settings/NetworkingPage.cpp
|
||||
Settings/ToolsPage.cpp
|
||||
Settings/VRPage.cpp
|
||||
SettingsPagesDialogScreen.h
|
||||
SettingsPagesDialogScreen.cpp
|
||||
GameScreen.h
|
||||
@@ -71,8 +78,8 @@ list(APPEND UISource
|
||||
GamePacker.cpp
|
||||
GameSettingsScreen.h
|
||||
GameSettingsScreen.cpp
|
||||
DeveloperToolsScreen.h
|
||||
DeveloperToolsScreen.cpp
|
||||
DeveloperSettingsPages.h
|
||||
DeveloperSettingsPages.cpp
|
||||
DriverManagerScreen.h
|
||||
DriverManagerScreen.cpp
|
||||
GPUDriverTestScreen.h
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include "Core/Util/PathUtil.h"
|
||||
#include "Core/FileSystems/VirtualDiscFileSystem.h"
|
||||
#include "UI/GPUDriverTestScreen.h"
|
||||
#include "UI/DeveloperToolsScreen.h"
|
||||
#include "UI/DeveloperSettingsPages.h"
|
||||
#include "UI/DevScreens.h"
|
||||
#include "UI/DriverManagerScreen.h"
|
||||
#include "UI/DisplayLayoutScreen.h"
|
||||
File renamed without changes.
+2
-906
@@ -44,12 +44,13 @@
|
||||
#include "Common/UI/PopupScreens.h"
|
||||
#include "UI/EmuScreen.h"
|
||||
#include "UI/GameSettingsScreen.h"
|
||||
#include "UI/Settings/MainSettingsPages.h"
|
||||
#include "UI/SettingsPage.h"
|
||||
#include "UI/GameInfoCache.h"
|
||||
#include "UI/GamepadEmu.h"
|
||||
#include "UI/ControlMappingScreen.h"
|
||||
#include "UI/DevScreens.h"
|
||||
#include "UI/DeveloperToolsScreen.h"
|
||||
#include "UI/DeveloperSettingsPages.h"
|
||||
#include "UI/DisplayLayoutScreen.h"
|
||||
#include "UI/FirmwareScreen.h"
|
||||
#include "UI/RemoteISOScreen.h"
|
||||
@@ -173,32 +174,6 @@ void GameSettingsScreen::PreCreateViews() {
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool UsingHardwareTextureScaling() {
|
||||
return g_Config.bTexHardwareScaling && (GetGPUBackend() == GPUBackend::VULKAN || GetGPUBackend() == GPUBackend::METAL) && !g_Config.bSoftwareRendering;
|
||||
}
|
||||
|
||||
static std::string TextureTranslateName(std::string_view value) {
|
||||
const TextureShaderInfo *info = GetTextureShaderInfo(value);
|
||||
if (info) {
|
||||
auto ts = GetI18NCategory(I18NCat::TEXTURESHADERS);
|
||||
return std::string(ts->T(value, info->name.c_str()));
|
||||
} else {
|
||||
return std::string(value);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string *GPUDeviceNameSetting() {
|
||||
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
|
||||
return &g_Config.sVulkanDevice;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (g_Config.iGPUBackend == (int)GPUBackend::DIRECT3D11) {
|
||||
return &g_Config.sD3D11Device;
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
|
||||
// Works out where the memstick is (installed.txt next to the exe means My Documents or a custom
|
||||
// folder), and which of the two checkboxes can be changed.
|
||||
@@ -244,14 +219,6 @@ void GameSettingsScreen::CheckMemstickInstallState() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// The tabs other than System, which needs more of the screen.
|
||||
static void BuildGraphicsSettings(SettingsPage *page);
|
||||
static void BuildControlsSettings(SettingsPage *page);
|
||||
static void BuildAudioSettings(SettingsPage *page);
|
||||
static void BuildNetworkingSettings(SettingsPage *page);
|
||||
static void BuildToolsSettings(SettingsPage *page);
|
||||
static void BuildVRSettings(SettingsPage *page);
|
||||
|
||||
const std::vector<GameSettingsScreen::PageDef> &GameSettingsScreen::PageDefs() {
|
||||
static const std::vector<PageDef> pages = {
|
||||
{ "GameSettingsGraphics", "Graphics", "I_DISPLAY", "graphics", I18NCat::GRAPHICS, &BuildGraphicsSettings },
|
||||
@@ -286,850 +253,6 @@ void GameSettingsScreen::CreateTabs() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make this generic
|
||||
extern int DefaultDepthRaster();
|
||||
|
||||
static void OnRenderingBackend(SettingsPageHost *host) {
|
||||
// It only makes sense to show the restart prompt if the backend was actually changed.
|
||||
if (g_Config.iGPUBackend != (int)GetGPUBackend()) {
|
||||
host->RestartOrDo([]() {
|
||||
g_Config.iGPUBackend = (int)GetGPUBackend();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void OnRenderingDevice(SettingsPageHost *host) {
|
||||
// It only makes sense to show the restart prompt if the device was actually changed.
|
||||
std::string *deviceNameSetting = GPUDeviceNameSetting();
|
||||
if (deviceNameSetting && *deviceNameSetting != GetGPUBackendDevice()) {
|
||||
host->RestartOrDo([host]() {
|
||||
std::string *deviceNameSetting = GPUDeviceNameSetting();
|
||||
if (deviceNameSetting)
|
||||
*deviceNameSetting = GetGPUBackendDevice();
|
||||
// Needed to redraw the setting.
|
||||
host->RecreatePageViews();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void BuildGraphicsSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
SettingsPageHost *host = page->Host();
|
||||
|
||||
Draw::DrawContext *draw = host->PageScreenManager()->getDrawContext();
|
||||
int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE);
|
||||
|
||||
page->Header("Rendering Mode");
|
||||
|
||||
#if !PPSSPP_PLATFORM(UWP)
|
||||
page->Setting(&g_Config.iGPUBackend).Setup([host](View *view) {
|
||||
PopupMultiChoice *renderingBackendChoice = static_cast<PopupMultiChoice *>(view);
|
||||
renderingBackendChoice->SetPreOpenCallback([host](UI::PopupMultiChoice *choice) {
|
||||
// Don't filter until the last possible moment, since it involves trying to initialize Vulkan, if we were
|
||||
// started in OpenGL mode on Android.
|
||||
choice->HideChoice(1);
|
||||
choice->OnChoice.Add([host](UI::EventParams &) {
|
||||
OnRenderingBackend(host);
|
||||
});
|
||||
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL))
|
||||
choice->HideChoice((int)GPUBackend::OPENGL);
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11))
|
||||
choice->HideChoice((int)GPUBackend::DIRECT3D11);
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::VULKAN))
|
||||
choice->HideChoice((int)GPUBackend::VULKAN);
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::METAL))
|
||||
choice->HideChoice((int)GPUBackend::METAL);
|
||||
});
|
||||
|
||||
if (!IsFirstInstance()) {
|
||||
// If we're not the first instance, can't save the setting, and it requires a restart, so...
|
||||
renderingBackendChoice->SetEnabled(false);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
#if (PPSSPP_PLATFORM(IOS) && !PPSSPP_PLATFORM(TVOS)) || PPSSPP_PLATFORM(ANDROID)
|
||||
// Showing the game there needs a second swapchain. Otherwise the system mirrors the screen.
|
||||
page->Setting(&g_Config.iExternalDisplay).EnabledFunc([draw] {
|
||||
return draw->GetDeviceCaps().multipleSwapchains;
|
||||
}).OnChange([previous = g_Config.iExternalDisplay](UI::EventParams &e) mutable {
|
||||
// Picking the current value again would rebuild the TV's output for nothing (iOS starts over on a change).
|
||||
if (g_Config.iExternalDisplay == previous) {
|
||||
return;
|
||||
}
|
||||
previous = g_Config.iExternalDisplay;
|
||||
System_Notify(SystemNotification::EXTERNAL_DISPLAY_CHANGED);
|
||||
});
|
||||
#endif
|
||||
|
||||
// Backends that don't allow a device choice will only expose one device.
|
||||
if (draw->GetDeviceList().size() > 1) {
|
||||
std::string *deviceNameSetting = GPUDeviceNameSetting();
|
||||
if (deviceNameSetting) {
|
||||
page->Setting(deviceNameSetting, draw->GetDeviceList()).OnChange([host](UI::EventParams &e) {
|
||||
OnRenderingDevice(host);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
page->Setting(&g_Config.iInternalResolution).EnabledFunc([] {
|
||||
return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects;
|
||||
});
|
||||
|
||||
if (deviceType != DEVICE_TYPE_VR) {
|
||||
page->Setting(&g_Config.bSoftwareRendering).EnabledFunc([] {
|
||||
return !PSP_IsInited();
|
||||
});
|
||||
}
|
||||
|
||||
if (draw->GetDeviceCaps().multiSampleLevelsMask != 1) {
|
||||
page->Setting(&g_Config.iMultiSampleLevel).EnabledFunc([] {
|
||||
return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects;
|
||||
}).Setup([draw](View *view) {
|
||||
PopupMultiChoice *msaaChoice = static_cast<PopupMultiChoice *>(view);
|
||||
if (g_Config.iMultiSampleLevel > 1 && draw->GetDeviceCaps().isTilingGPU) {
|
||||
msaaChoice->SetIconRight(ImageID("I_WARNING"), 0.7f);
|
||||
}
|
||||
// Hide unsupported levels.
|
||||
for (int i = 1; i < msaaChoice->NumChoices(); i++) {
|
||||
if ((draw->GetDeviceCaps().multiSampleLevelsMask & (1 << i)) == 0) {
|
||||
msaaChoice->HideChoice(i);
|
||||
} else if (i > 0 && draw->GetDeviceCaps().isTilingGPU) {
|
||||
msaaChoice->SetChoiceIcon(i, ImageID("I_WARNING"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
if ((deviceType != DEVICE_TYPE_TV) && (deviceType != DEVICE_TYPE_VR)) {
|
||||
int max_res = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 2;
|
||||
if (max_res == 3)
|
||||
max_res = 4; // At least allow 2x
|
||||
page->Setting(&g_Config.iAndroidHwScale).Setup([max_res](View *view) {
|
||||
// Hide the scales the display is too small for.
|
||||
PopupMultiChoice *choice = static_cast<PopupMultiChoice *>(view);
|
||||
for (int i = max_res; i < choice->NumChoices(); i++) {
|
||||
choice->HideChoice(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
||||
|
||||
page->Setting(&g_Config.bReplaceTextures);
|
||||
|
||||
page->Header("Display");
|
||||
|
||||
if (deviceType != DEVICE_TYPE_VR) {
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
page->Setting(&g_Config.bFullScreen);
|
||||
if (draw->GetDeviceCaps().fullScreenExclusiveSupported) {
|
||||
page->Setting(&g_Config.bAllowFullScreenExclusive).EnabledFunc([] {
|
||||
return g_Config.bFullScreen && !g_Config.bFullScreenMulti;
|
||||
}).OnChange([host](UI::EventParams &e) {
|
||||
host->RestartOrDo([host]() {
|
||||
g_Config.bAllowFullScreenExclusive = !g_Config.bAllowFullScreenExclusive;
|
||||
host->RecreatePageViews();
|
||||
});
|
||||
});
|
||||
}
|
||||
if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) {
|
||||
page->Setting(&g_Config.bFullScreenMulti).EnabledFunc([] {
|
||||
return g_Config.bFullScreen && !g_Config.bAllowFullScreenExclusive;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
// Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc.
|
||||
page->Choice("Display layout & effects").OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new DisplayLayoutScreen(host->PageGamePath()));
|
||||
});
|
||||
}
|
||||
|
||||
// If only one mode is supported (like FIFO on iOS), no need to show the options.
|
||||
if (CountSetBits((u32)draw->GetDeviceCaps().presentModesSupported) > 1) {
|
||||
// Immediate means non-synchronized, tearing.
|
||||
if (draw->GetDeviceCaps().presentModesSupported & Draw::PresentMode::IMMEDIATE) {
|
||||
page->Setting(&g_Config.bVSync).OnChange([](UI::EventParams &e) {
|
||||
NativeResized(); // TODO: Remove
|
||||
});
|
||||
}
|
||||
if (draw->GetDeviceCaps().presentModesSupported & Draw::PresentMode::MAILBOX) {
|
||||
SettingItem &lowLatency = page->Setting(&g_Config.bLowLatencyPresent).OnChange([](UI::EventParams &e) {
|
||||
NativeResized(); // TODO: Remove
|
||||
});
|
||||
|
||||
// If the immediate mode is supported, we can tie low latency present to VSync.
|
||||
if (draw->GetDeviceCaps().presentModesSupported & Draw::PresentMode::IMMEDIATE) {
|
||||
lowLatency.Enabled(&g_Config.bVSync);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page->Header("Frame Rate Control");
|
||||
|
||||
page->Setting(&g_Config.iAltSpeedPercent1);
|
||||
page->Setting(&g_Config.iAltSpeedPercent2);
|
||||
if (KeyMap::InputMappingsFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, true)) {
|
||||
page->Setting(&g_Config.iAnalogAltSpeedPercent);
|
||||
}
|
||||
|
||||
page->Header({ I18NCat::GRAPHICS, "Speed Hacks", "Speed Hacks (can cause rendering errors!)" });
|
||||
|
||||
page->Setting(&g_Config.iFrameSkip).EnabledFunc([] {
|
||||
return !g_Config.bAutoFrameSkip;
|
||||
}).Setup([](View *view) {
|
||||
PopupMultiChoice *choice = static_cast<PopupMultiChoice *>(view);
|
||||
choice->SetChoicesUntranslated(1, choice->NumChoices() - 1);
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.bAutoFrameSkip);
|
||||
|
||||
page->Setting(&g_Config.bSkipBufferEffects).Disabled(&g_Config.bSoftwareRendering);
|
||||
page->Hint({ I18NCat::GRAPHICS, "RenderingMode NonBuffered Tip", "Faster, but graphics may be missing in some games" });
|
||||
|
||||
page->Setting(&g_Config.iSkipGPUReadbackMode).Disabled(&g_Config.bSoftwareRendering).Setup([](View *view) {
|
||||
static_cast<PopupMultiChoice *>(view)->SetDefault(0);
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.iDepthRasterMode).Disabled(&g_Config.bSoftwareRendering).Setup([](View *view) {
|
||||
PopupMultiChoice *depthRasterMode = static_cast<PopupMultiChoice *>(view);
|
||||
depthRasterMode->SetChoiceIcon(3, ImageID("I_WARNING")); // It's a performance trap.
|
||||
depthRasterMode->SetDefault(DefaultDepthRaster());
|
||||
if (g_Config.iDepthRasterMode != 3)
|
||||
depthRasterMode->HideChoice(3);
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.iBloomHack).EnabledFunc([] {
|
||||
return !g_Config.bSoftwareRendering && g_Config.iInternalResolution != 1;
|
||||
});
|
||||
page->Hint("Reduces artifacts");
|
||||
|
||||
page->Header("Performance");
|
||||
page->Setting(&g_Config.bRenderDuplicateFrames).EnabledFunc([] {
|
||||
return !g_Config.bSkipBufferEffects && g_Config.iFrameSkip == 0;
|
||||
});
|
||||
page->Hint({ I18NCat::GRAPHICS, "RenderDuplicateFrames Tip", "Can make framerate smoother in games that run at lower framerates" });
|
||||
|
||||
if (draw->GetDeviceCaps().setMaxFrameLatencySupported) {
|
||||
// Changing it needs a restart, so the value in use is the one the page was built with.
|
||||
page->Setting(&g_Config.iInflightFrames).OnChange([host, previous = g_Config.iInflightFrames](UI::EventParams &e) {
|
||||
if (g_Config.iInflightFrames != previous) {
|
||||
host->RestartOrDo([previous]() {
|
||||
g_Config.iInflightFrames = previous;
|
||||
});
|
||||
}
|
||||
});
|
||||
page->Hint("Faster, input lag"); // TODO: This hint could use improvement.
|
||||
}
|
||||
|
||||
page->Header("Texture upscaling");
|
||||
|
||||
if (GetGPUBackend() == GPUBackend::VULKAN || GetGPUBackend() == GPUBackend::METAL) {
|
||||
page->Custom("GPU texture upscaler (fast)", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
ChoiceWithValueDisplay *textureShaderChoice = parent->Add(new ChoiceWithValueDisplay(&g_Config.sTextureShaderName, gr->T("GPU texture upscaler (fast)"), &TextureTranslateName));
|
||||
textureShaderChoice->OnClick.Add([host](UI::EventParams &e) {
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
auto shaderScreen = new TextureShaderScreen(gr->T("GPU texture upscaler (fast)"));
|
||||
shaderScreen->OnChoice.Add([host](UI::EventParams &e) {
|
||||
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
||||
host->RecreatePageViews(); // Update setting name
|
||||
g_Config.bTexHardwareScaling = g_Config.sTextureShaderName != "Off";
|
||||
});
|
||||
if (e.v)
|
||||
shaderScreen->SetPopupOrigin(e.v);
|
||||
host->PageScreenManager()->push(shaderScreen);
|
||||
});
|
||||
return textureShaderChoice;
|
||||
}).Disabled(&g_Config.bSoftwareRendering);
|
||||
}
|
||||
|
||||
page->Setting(&g_Config.iTexScalingType).EnabledFunc([]() {
|
||||
return !g_Config.bSoftwareRendering && !UsingHardwareTextureScaling();
|
||||
});
|
||||
page->Setting(&g_Config.iTexScalingLevel).EnabledFunc([]() {
|
||||
return !g_Config.bSoftwareRendering && !UsingHardwareTextureScaling();
|
||||
});
|
||||
page->Hint({ I18NCat::GRAPHICS, "UpscaleLevel Tip", "CPU heavy - some scaling may be delayed to avoid stutter" });
|
||||
|
||||
page->Setting(&g_Config.bTexDeposterize).EnabledFunc([]() {
|
||||
return !g_Config.bSoftwareRendering && !UsingHardwareTextureScaling();
|
||||
});
|
||||
page->Hint({ I18NCat::GRAPHICS, "Deposterize Tip", "Fixes visual banding glitches in upscaled textures" });
|
||||
|
||||
page->Header("Texture Filtering");
|
||||
|
||||
page->Setting(&g_Config.iAnisotropyLevel).Disabled(&g_Config.bSoftwareRendering);
|
||||
|
||||
page->Setting(&g_Config.iTexFiltering).Disabled(&g_Config.bSoftwareRendering);
|
||||
|
||||
page->Setting(&g_Config.bSmart2DTexFiltering).Disabled(&g_Config.bSoftwareRendering);
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
|
||||
bool showCardboardSettings = deviceType != DEVICE_TYPE_VR;
|
||||
#else
|
||||
// If you enabled it through the ini, you can see this. Useful for testing.
|
||||
bool showCardboardSettings = config.bEnableCardboardVR;
|
||||
#endif
|
||||
if (showCardboardSettings) {
|
||||
page->Header("Cardboard VR Settings");
|
||||
page->Setting(&config.bEnableCardboardVR);
|
||||
page->Setting(&config.iCardboardScreenSize).Enabled(&config.bEnableCardboardVR);
|
||||
page->Setting(&config.iCardboardXShift).Enabled(&config.bEnableCardboardVR);
|
||||
page->Setting(&config.iCardboardYShift).Enabled(&config.bEnableCardboardVR);
|
||||
}
|
||||
|
||||
page->Header("Overlay Information");
|
||||
auto addStatusFlag = [page](ShowStatusFlags flag, const char *text) {
|
||||
page->Custom(text, [flag, text](UI::ViewGroup *parent) -> UI::View * {
|
||||
return parent->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)flag, T(I18NCat::GRAPHICS, text)));
|
||||
});
|
||||
};
|
||||
addStatusFlag(ShowStatusFlags::FPS_COUNTER, "Show FPS Counter");
|
||||
addStatusFlag(ShowStatusFlags::SPEED_COUNTER, "Show Speed");
|
||||
if (System_GetPropertyBool(SYSPROP_CAN_READ_BATTERY_PERCENTAGE)) {
|
||||
addStatusFlag(ShowStatusFlags::BATTERY_PERCENT, "Show Battery %");
|
||||
}
|
||||
page->Custom({ I18NCat::DEVELOPER, "Debug overlay" }, [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
AddOverlayList(parent, host->PageScreenManager());
|
||||
return parent->GetViewByIndex(parent->GetNumSubviews() - 1);
|
||||
});
|
||||
}
|
||||
|
||||
static void BuildAudioSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
|
||||
#if PPSSPP_PLATFORM(IOS)
|
||||
page->Setting(&g_Config.bAudioRespectSilentMode).Enabled(&g_Config.bEnableSound);
|
||||
#endif
|
||||
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
|
||||
page->Setting(&g_Config.bAudioMixWithOthers).Enabled(&g_Config.bEnableSound);
|
||||
#endif
|
||||
page->Header("Audio playback");
|
||||
|
||||
page->Setting(&g_Config.iAudioPlaybackMode);
|
||||
page->Setting(&g_Config.bFillAudioGaps).EnabledFunc([]() {
|
||||
return g_Config.iAudioPlaybackMode == (int)AudioSyncMode::GRANULAR;
|
||||
});
|
||||
|
||||
page->Header("Game volume");
|
||||
|
||||
// This is here because it now only applies to in-game. Muting the menu sounds is separate.
|
||||
page->Setting(&g_Config.bEnableSound);
|
||||
|
||||
page->Setting(&g_Config.iGameVolume).Enabled(&g_Config.bEnableSound);
|
||||
page->Setting(&g_Config.iReverbVolume).Enabled(&g_Config.bEnableSound);
|
||||
page->Setting(&g_Config.iAltSpeedVolume).Enabled(&g_Config.bEnableSound);
|
||||
page->Setting(&g_Config.iAchievementVolume).Enabled(&g_Config.bEnableSound).OnChange([](EventParams &e) {
|
||||
// Audio preview
|
||||
float achievementVolume = Volume100ToMultiplier(g_Config.iAchievementVolume);
|
||||
g_BackgroundAudio.SFX().Play(UI::UISound::ACHIEVEMENT_UNLOCKED, achievementVolume);
|
||||
});
|
||||
|
||||
page->Header();
|
||||
|
||||
page->Setting(&g_Config.bUISound);
|
||||
page->Setting(&g_Config.iUIVolume).LiveUpdate().Enabled(&g_Config.bUISound).OnChange([](EventParams &e) {
|
||||
static double lastTimePlayed = 0.0;
|
||||
double now = time_now_d();
|
||||
if (now - lastTimePlayed < 0.1) {
|
||||
return; // Don't play if we just played one, to avoid spamming when dragging.
|
||||
}
|
||||
lastTimePlayed = now;
|
||||
// Audio preview
|
||||
PlayUISound(UI::UISound::CONFIRM);
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.iGamePreviewVolume);
|
||||
|
||||
bool sdlAudio = false;
|
||||
|
||||
#if defined(SDL)
|
||||
page->Header("Audio backend");
|
||||
std::vector<std::string> audioDeviceList;
|
||||
SplitString(System_GetProperty(SYSPROP_AUDIO_DEVICE_LIST), '\0', audioDeviceList);
|
||||
audioDeviceList.insert(audioDeviceList.begin(), std::string(T(I18NCat::AUDIO, "Auto")));
|
||||
page->Setting(&g_Config.sAudioDevice, std::move(audioDeviceList)).OnChange([](EventParams &e) {
|
||||
if (g_Config.sAudioDevice == T(I18NCat::AUDIO, "Auto")) {
|
||||
g_Config.sAudioDevice.clear();
|
||||
}
|
||||
System_Notify(SystemNotification::AUDIO_RESET_DEVICE);
|
||||
});
|
||||
sdlAudio = true;
|
||||
|
||||
static const int bufferSizes[] = {128, 256, 512, 1024, 2048};
|
||||
page->IntSlider(&g_Config.iSDLAudioBufferSize, 0, 2048, "Buffer size").Default(256).RestrictTo(bufferSizes, ARRAY_SIZE(bufferSizes));
|
||||
page->Hint({ I18NCat::DIALOG, "This change will not take effect until PPSSPP is restarted." });
|
||||
#endif
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
extern AudioBackend *g_audioBackend;
|
||||
|
||||
std::vector<std::string> audioDeviceNames;
|
||||
std::vector<std::string> audioDeviceIds;
|
||||
|
||||
std::vector<AudioDeviceDesc> deviceDescs;
|
||||
g_audioBackend->EnumerateDevices(&deviceDescs);
|
||||
if (!deviceDescs.empty()) {
|
||||
page->Header("Audio backend");
|
||||
for (auto &desc : deviceDescs) {
|
||||
audioDeviceNames.push_back(desc.name);
|
||||
audioDeviceIds.push_back(desc.uniqueId);
|
||||
}
|
||||
|
||||
audioDeviceNames.insert(audioDeviceNames.begin(), std::string(T(I18NCat::AUDIO, "Auto")));
|
||||
audioDeviceIds.insert(audioDeviceIds.begin(), "");
|
||||
|
||||
page->Setting(&g_Config.sAudioDevice, std::move(audioDeviceNames), std::move(audioDeviceIds)).OnChange([](EventParams &) {
|
||||
bool reverted;
|
||||
if (g_audioBackend->InitOutputDevice(g_Config.sAudioDevice, LatencyMode::Aggressive, &reverted)) {
|
||||
if (reverted) {
|
||||
WARN_LOG(Log::Audio, "Unexpected: After a direct choice, audio device reverted to default. '%s'", g_Config.sAudioDevice.c_str());
|
||||
}
|
||||
} else {
|
||||
WARN_LOG(Log::Audio, "InitOutputDevice failed");
|
||||
}
|
||||
});
|
||||
page->Setting(&g_Config.bAutoSwitchAudioDevice).EnabledFunc([]()->bool {
|
||||
return g_Config.sAudioDevice.empty();
|
||||
});
|
||||
}
|
||||
|
||||
#else
|
||||
if (sdlAudio) {
|
||||
page->Setting(&g_Config.bAutoSwitchAudioDevice);
|
||||
} else {
|
||||
page->Header("Audio backend");
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
page->Setting(&g_Config.bExtraAudioBuffering);
|
||||
|
||||
auto restartAudio = [](UI::EventParams &) {
|
||||
AndroidAudio_Restart(g_audioState);
|
||||
};
|
||||
// AAudio isn't stable before Android 8.1, so there it's always OpenSL ES.
|
||||
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 27) {
|
||||
page->Setting(&g_Config.iAndroidAudioApi).OnChange(restartAudio);
|
||||
page->Hint({ I18NCat::AUDIO, "AudioApiHint", "Try the other one if you have no sound or other audio problems." });
|
||||
|
||||
page->Setting(&g_Config.bAndroidAudioMMap).OnChange(restartAudio).EnabledFunc([]() {
|
||||
return g_Config.iAndroidAudioApi == (int)AndroidAudioApi::AAUDIO;
|
||||
});
|
||||
page->Hint({ I18NCat::AUDIO, "AudioMMapHint", "Lowest audio delay. On some devices, it causes silence over Bluetooth or other connected audio devices. Turn it off if you get no sound." });
|
||||
}
|
||||
// Show Oboe debug info
|
||||
const std::string audioErrorStr = AndroidAudio_GetErrorString(g_audioState);
|
||||
if (!audioErrorStr.empty()) {
|
||||
page->Info("Audio Error", audioErrorStr);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::vector<std::string> micList = Microphone::getDeviceList();
|
||||
if (!micList.empty()) {
|
||||
page->Header("Microphone");
|
||||
std::vector<std::string> micValues = micList;
|
||||
micList.emplace(micList.begin(), T(I18NCat::AUDIO, "Auto"));
|
||||
micValues.insert(micValues.begin(), "");
|
||||
page->Setting(&g_Config.sMicDevice, std::move(micList), std::move(micValues));
|
||||
}
|
||||
}
|
||||
|
||||
static void BuildControlsSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
SettingsPageHost *host = page->Host();
|
||||
|
||||
int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE);
|
||||
|
||||
page->Header({ I18NCat::MAINSETTINGS, "Controls" });
|
||||
page->Choice("Control mapping").OnClick([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new ControlMappingScreen(host->PageGamePath()));
|
||||
});
|
||||
page->Choice("Calibrate analog stick").OnClick([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new AnalogCalibrationScreen(host->PageGamePath()));
|
||||
});
|
||||
|
||||
#if (PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)) || (PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID))
|
||||
page->Setting(&g_Config.bSystemControls);
|
||||
#endif
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
page->Setting(&g_Config.bGamepadOnlyFocused);
|
||||
#endif
|
||||
|
||||
if (System_GetPropertyBool(SYSPROP_HAS_ACCELEROMETER)) {
|
||||
page->Custom("Tilt control setup", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
// Show the tilt type on the item.
|
||||
Choice *customizeTilt = parent->Add(new ChoiceWithCallbackValueDisplay(T(I18NCat::CONTROLS, "Tilt control setup"), []() -> std::string {
|
||||
if (g_Config.bTiltInputEnabled && (u32)g_Config.iTiltInputType < (u32)g_numTiltTypes) {
|
||||
auto co = GetI18NCategory(I18NCat::CONTROLS);
|
||||
return std::string(co->T(g_tiltTypes[g_Config.iTiltInputType]));
|
||||
} else {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
return std::string(di->T("Disabled"));
|
||||
}
|
||||
}));
|
||||
customizeTilt->OnClick.Add([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new TiltAnalogSettingsScreen(host->PageGamePath()));
|
||||
});
|
||||
return customizeTilt;
|
||||
});
|
||||
} else if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) { // TODO: This seems like a regression
|
||||
page->Setting(&g_Config.bHapticFeedback);
|
||||
}
|
||||
|
||||
page->Header("Analog to digital mapping");
|
||||
page->Setting(&g_Config.fAnalogTriggerThreshold);
|
||||
page->Setting(&g_Config.fAnalogStickThreshold);
|
||||
|
||||
// TVs don't have touch control, at least not yet.
|
||||
if ((deviceType != DEVICE_TYPE_TV) && (deviceType != DEVICE_TYPE_VR)) {
|
||||
page->Header("On-screen touch controls");
|
||||
page->Setting(&g_Config.bShowTouchControls);
|
||||
page->Choice("Edit touch control layout").OnClick([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new TouchControlLayoutScreen(host->PageGamePath()));
|
||||
}).Enabled(&g_Config.bShowTouchControls);
|
||||
page->Choice("Gesture mapping").OnClick([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new GestureMappingScreen(host->PageGamePath()));
|
||||
}).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
page->Setting(&g_Config.iTouchButtonStyle).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
page->Setting(&g_Config.iTouchButtonOpacity).Enabled(&g_Config.bShowTouchControls);
|
||||
page->Setting(&g_Config.iTouchButtonHideSeconds).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
page->Setting(&g_Config.bTouchGliding).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
TouchControlConfig &touch = g_Config.GetTouchControlsConfig(g_display.GetDeviceOrientation());
|
||||
|
||||
// Hide stick background, useful when increasing the size
|
||||
page->Setting(&touch.bHideStickBackground).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
// Sticky D-pad.
|
||||
page->Setting(&g_Config.bStickyTouchDPad).Enabled(&g_Config.bShowTouchControls);
|
||||
page->Hint("Easier sweeping movements");
|
||||
|
||||
// Re-centers itself to the touch location on touch-down.
|
||||
page->Setting(&g_Config.bAutoCenterTouchAnalog).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
|
||||
page->Setting(&g_Config.bHapticFeedback);
|
||||
}
|
||||
|
||||
// The pause button is now a regular on-screen button.
|
||||
|
||||
page->Setting(&g_Config.bDisableDpadDiagonals).Enabled(&g_Config.bShowTouchControls);
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
page->Header("Control input sources");
|
||||
page->Setting(&g_Config.bAllowHIDInput);
|
||||
page->Setting(&g_Config.bAllowXInput);
|
||||
page->Setting(&g_Config.bAllowDInput);
|
||||
#endif
|
||||
|
||||
if (deviceType != DEVICE_TYPE_VR) {
|
||||
page->Header({ I18NCat::CONTROLS, "Keyboard", "Keyboard Control Settings" });
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
page->Setting(&g_Config.bIgnoreWindowsKey);
|
||||
#endif
|
||||
page->Setting(&g_Config.fAnalogLimiterDeadzone);
|
||||
page->Hint({ I18NCat::CONTROLS, "AnalogLimiter Tip", "When the analog limiter button is pressed" });
|
||||
page->Setting(&g_Config.iRapidFireInterval);
|
||||
#if PPSSPP_PLATFORM(WINDOWS) || defined(SDL) || PPSSPP_PLATFORM(ANDROID)
|
||||
bool enableMouseSettings = true;
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) < 12) {
|
||||
enableMouseSettings = false;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
bool enableMouseSettings = false;
|
||||
#endif
|
||||
if (enableMouseSettings) {
|
||||
// The mousewheel button-release setting is independent of actual mouse delta control.
|
||||
page->Header({ I18NCat::CONTROLS, "Mouse", "Mouse settings" });
|
||||
page->Setting(&g_Config.iMouseWheelUpDelayMs);
|
||||
|
||||
page->Setting(&g_Config.bMouseControl);
|
||||
page->Hint({ I18NCat::CONTROLS, "MouseControl Tip", "You can now map mouse in control mapping screen by pressing the 'M' icon." });
|
||||
|
||||
#if !PPSSPP_PLATFORM(ANDROID)
|
||||
page->Setting(&g_Config.bMouseConfine).Enabled(&g_Config.bMouseControl);
|
||||
#endif
|
||||
page->Setting(&g_Config.fMouseSensitivity).Enabled(&g_Config.bMouseControl).LiveUpdate();
|
||||
page->Setting(&g_Config.fMouseSmoothing).Enabled(&g_Config.bMouseControl).LiveUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compound view just like the audio file choosers
|
||||
class MacAddressChooser : public UI::LinearLayout {
|
||||
public:
|
||||
MacAddressChooser(RequesterToken token, Path gamePath, std::string *value, std::string_view title, ScreenManager *screenManager, UI::LayoutParams *layoutParams = nullptr);
|
||||
};
|
||||
|
||||
MacAddressChooser::MacAddressChooser(RequesterToken token, Path gamePath, std::string *value, std::string_view title, ScreenManager *screenManager, UI::LayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams) {
|
||||
using namespace UI;
|
||||
SetSpacing(5.0f);
|
||||
if (!layoutParams) {
|
||||
layoutParams_->width = FILL_PARENT;
|
||||
layoutParams_->height = ITEM_HEIGHT;
|
||||
}
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
|
||||
std::string initialValue = *value;
|
||||
Add(new PopupTextInputChoice(token, value, title, g_Config.sMACAddress, 17, screenManager, new LinearLayoutParams(1.0f)))->OnChange.Add([=](UI::EventParams &e) {
|
||||
// Validate the chosen address, and restore to initialValue if bad.
|
||||
if (g_Config.sMACAddress.size() != 17) {
|
||||
// TODO: Alert the user
|
||||
*value = initialValue;
|
||||
}
|
||||
});
|
||||
Add(new Choice(n->T("Randomize"), new LinearLayoutParams(WRAP_CONTENT, ITEM_HEIGHT)))->OnClick.Add([=](UI::EventParams &) {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
|
||||
std::string_view confirmMessage = n->T("ChangeMacSaveConfirm", "Generate a new MAC address?");
|
||||
std::string_view warningMessage = n->T("ChangeMacSaveWarning", "Some games verify the MAC address when loading savedata, so this may break old saves.");
|
||||
std::string combined = g_Config.sMACAddress + "\n\n" + std::string(confirmMessage) + "\n\n" + std::string(warningMessage);
|
||||
|
||||
auto confirmScreen = new MessagePopupScreen(
|
||||
title,
|
||||
combined, di->T("Yes"), di->T("No"),
|
||||
[](bool success) {
|
||||
if (success) {
|
||||
g_Config.sMACAddress = CreateRandMAC();
|
||||
}
|
||||
});
|
||||
screenManager->push(confirmScreen);
|
||||
});
|
||||
}
|
||||
|
||||
// The nickname is shown on both the Networking and System tabs.
|
||||
static UI::View *AddNicknameChoice(SettingsPageHost *host, UI::ViewGroup *parent) {
|
||||
using namespace UI;
|
||||
|
||||
auto sy = GetI18NCategory(I18NCat::SYSTEM);
|
||||
PopupTextInputChoice *nickname = parent->Add(new PopupTextInputChoice(host->PageRequesterToken(), &g_Config.sNickName, sy->T("Nickname"), "", 32, host->PageScreenManager()));
|
||||
if (g_Config.sNickName == "PPSSPP") {
|
||||
nickname->SetIconRight(ImageID("I_WARNING"));
|
||||
}
|
||||
nickname->OnChange.Add([host](UI::EventParams &e) {
|
||||
// Copy to infrastructure name if valid and not already set.
|
||||
if (g_Config.sInfrastructureUsername.empty()) {
|
||||
if (g_Config.sNickName == SanitizeString(g_Config.sNickName, StringRestriction::AlphaNumDashUnderscore, 3, 16)) {
|
||||
g_Config.sInfrastructureUsername = g_Config.sNickName;
|
||||
}
|
||||
}
|
||||
// Updates the warning icon, and the username notice on the Networking tab.
|
||||
host->RecreatePageViews();
|
||||
});
|
||||
return nickname;
|
||||
}
|
||||
|
||||
static void BuildNetworkingSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
SettingsPageHost *host = page->Host();
|
||||
|
||||
page->Header({ I18NCat::MAINSETTINGS, "Networking" });
|
||||
|
||||
page->Choice("Quick start guide for multiplayer", ImageID("I_LINK_OUT")).OnClick([](EventParams &e) {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
std::string url(n->T("MultiplayerQuickStartURL", "https://www.ppsspp.org/docs/multiplayer/quickstart/"));
|
||||
System_LaunchUrl(LaunchUrlType::BROWSER_URL, url);
|
||||
});
|
||||
|
||||
// Ad hoc play, the built-in server and UPnP all talk to the local network.
|
||||
auto requestLocalNetwork = [](UI::EventParams &e) {
|
||||
CheckBox *checkBox = static_cast<CheckBox *>(e.v);
|
||||
if (checkBox->Toggled()) {
|
||||
System_RequestLocalNetworkPermission();
|
||||
}
|
||||
};
|
||||
|
||||
page->Setting(&g_Config.bEnableWlan).OnChange(requestLocalNetwork);
|
||||
page->Custom("MAC address", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
return parent->Add(new MacAddressChooser(host->PageRequesterToken(), host->PageGamePath(), &g_Config.sMACAddress, T(I18NCat::NETWORKING, "MAC address"), host->PageScreenManager()));
|
||||
});
|
||||
|
||||
page->Header("Ad Hoc multiplayer");
|
||||
|
||||
page->Custom("Ad hoc server address", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
auto launchAdhocServerScreen = [host](UI::EventParams &) {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
host->PageScreenManager()->push(new AdhocServerScreen(&g_Config.sProAdhocServer, n->T("Ad hoc server address")));
|
||||
};
|
||||
|
||||
if (AdhocServerNameIsCustom()) {
|
||||
LinearLayout *serverRow = parent->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
|
||||
serverRow->SetSpacing(0.0f);
|
||||
serverRow->Add(new ChoiceWithValueDisplay(&g_Config.sProAdhocServer, n->T("Ad hoc server address"), I18NCat::NONE, new LinearLayoutParams(1.0f)))->OnClick.Add(launchAdhocServerScreen);
|
||||
serverRow->Add(new Choice(ImageID("I_EDIT_TEXT"), new LinearLayoutParams(ITEM_HEIGHT, ITEM_HEIGHT)))->OnClick.Add([host](UI::EventParams &) {
|
||||
AskToEditCurrentServer(host->PageRequesterToken(), host->PageScreenManager());
|
||||
});
|
||||
return serverRow;
|
||||
}
|
||||
|
||||
AdhocServerListEntry entry;
|
||||
if (!g_Config.sProAdhocServer.empty() && AdhocGetServerByHost(g_Config.sProAdhocServer, &entry)) {
|
||||
Choice *choice = parent->Add(new ChoiceWithFixedValueDisplay(ApplySafeSubstitutions("%1 (%2)", entry.name, entry.host), n->T("Ad hoc server address")));
|
||||
choice->OnClick.Add(launchAdhocServerScreen);
|
||||
return choice;
|
||||
}
|
||||
// This case happens when updating from a previous version, as well as clicking on one of the local addresses
|
||||
Choice *choice = parent->Add(new ChoiceWithFixedValueDisplay(g_Config.sProAdhocServer, n->T("Ad hoc server address")));
|
||||
choice->OnClick.Add(launchAdhocServerScreen);
|
||||
return choice;
|
||||
});
|
||||
|
||||
AdhocServerListEntry serverEntry;
|
||||
if (!AdhocServerNameIsCustom() && !g_Config.sProAdhocServer.empty() && AdhocGetServerByHost(g_Config.sProAdhocServer, &serverEntry)) {
|
||||
page->Custom("Server status: %1", [host, serverEntry](UI::ViewGroup *parent) -> UI::View * {
|
||||
Choice *status = parent->Add(new Choice(ApplySafeSubstitutions(T(I18NCat::NETWORKING, "Server status: %1"), serverEntry.name)));
|
||||
status->SetIconLeft(ImageID("I_INFO"));
|
||||
status->OnClick.Add([host, serverEntry](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new AdhocServerInfoScreen(serverEntry));
|
||||
});
|
||||
return status;
|
||||
});
|
||||
}
|
||||
|
||||
page->Setting(&g_Config.iAdhocServerRelayMode).EnabledFunc([] {
|
||||
return !PSP_IsInited();
|
||||
});
|
||||
page->Hint({ I18NCat::NETWORKING, "PacketRelayHint", "Available on servers that provide 'aemu_postoffice' packet relay, like socom.cc. Disable this for LAN or VPN play. Can be more reliable, but sometimes slower." });
|
||||
|
||||
page->Custom({ I18NCat::SYSTEM, "Nickname" }, [host](UI::ViewGroup *parent) {
|
||||
return AddNicknameChoice(host, parent);
|
||||
});
|
||||
page->Hint("Try to pick a unique nickname for ad hoc play");
|
||||
|
||||
page->Setting(&g_Config.bEnableAdhocServer).OnChange(requestLocalNetwork);
|
||||
|
||||
page->Setting(&g_Config.bAdhocUseUdp).EnabledFunc([] {
|
||||
return !PSP_IsInited();
|
||||
});
|
||||
page->Hint("Try switching between TCP/UDP if you suffer frequent adhoc server disconnects. Some network environments favor TCP and some UDP.");
|
||||
|
||||
page->Setting(&g_Config.bAdhocRelayModeEnetPdpReliable).EnabledFunc([] {
|
||||
return !PSP_IsInited() && g_Config.bAdhocUseUdp;
|
||||
});
|
||||
page->Hint("When disabled, packet loss on datagram adhoc sockets will be exposed to game's netcode. Keep this enabled if you don't know what that means.");
|
||||
|
||||
page->Header("Infrastructure");
|
||||
if (g_Config.sInfrastructureUsername.empty()) {
|
||||
page->Custom("To play in Infrastructure Mode, you must enter a username", [](UI::ViewGroup *parent) -> UI::View * {
|
||||
NoticeView *notice = parent->Add(new NoticeView(NoticeLevel::WARN, T(I18NCat::NETWORKING, "To play in Infrastructure Mode, you must enter a username"), ""));
|
||||
notice->SetWrapText(true);
|
||||
return notice;
|
||||
});
|
||||
}
|
||||
page->Custom({ I18NCat::DIALOG, "Username" }, [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
PopupTextInputChoice *usernameChoice = parent->Add(new PopupTextInputChoice(host->PageRequesterToken(), &g_Config.sInfrastructureUsername, T(I18NCat::DIALOG, "Username"), "", 16, host->PageScreenManager()));
|
||||
usernameChoice->SetRestriction(StringRestriction::AlphaNumDashUnderscore, 3);
|
||||
usernameChoice->OnChange.Add([host](UI::EventParams &e) {
|
||||
host->RecreatePageViews();
|
||||
});
|
||||
return usernameChoice;
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.bInfrastructureAutoDNS);
|
||||
page->Custom("DNS server", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
return parent->Add(new PopupTextInputChoice(host->PageRequesterToken(), &g_Config.sInfrastructureDNSServer, T(I18NCat::NETWORKING, "DNS server"), "", 32, host->PageScreenManager()));
|
||||
}).Disabled(&g_Config.bInfrastructureAutoDNS);
|
||||
|
||||
page->Header("UPnP (port-forwarding)");
|
||||
// Only togglable outside a game - sceNet latches settings like UPnPUseOriginalPort at boot,
|
||||
// and a game that's already mapped its ports wouldn't cope with them disappearing.
|
||||
page->Setting(&g_Config.bEnableUPnP).EnabledFunc([] {
|
||||
return !PSP_IsInited();
|
||||
}).OnChange([requestLocalNetwork](UI::EventParams &e) {
|
||||
requestLocalNetwork(e);
|
||||
// Wake the UPnP service thread so it connects (or tears its mappings back down) right
|
||||
// away, instead of waiting for a port request that may never come.
|
||||
UPnP_Notify();
|
||||
});
|
||||
page->Setting(&g_Config.bUPnPUseOriginalPort).Enabled(&g_Config.bEnableUPnP);
|
||||
page->Hint({ I18NCat::NETWORKING, "UseOriginalPort Tip", "May not work for all devices or games, see wiki." });
|
||||
|
||||
page->Header("Chat");
|
||||
page->Setting(&g_Config.bEnableNetworkChat);
|
||||
page->Setting(&g_Config.iChatButtonPosition).Enabled(&g_Config.bEnableNetworkChat);
|
||||
page->Setting(&g_Config.iChatScreenPosition).Enabled(&g_Config.bEnableNetworkChat);
|
||||
page->Setting(&g_Config.bChatTimestamps).Enabled(&g_Config.bEnableNetworkChat);
|
||||
|
||||
page->Header("Quick chat");
|
||||
page->Setting(&g_Config.bEnableQuickChat).Enabled(&g_Config.bEnableNetworkChat);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
page->Custom("Quick chat %1", [host, i](UI::ViewGroup *parent) -> UI::View * {
|
||||
return parent->Add(new PopupTextInputChoice(host->PageRequesterToken(), &g_Config.sQuickChat[i], ApplySafeSubstitutions(T(I18NCat::NETWORKING, "Quick chat %1"), i + 1), "", 32, host->PageScreenManager()));
|
||||
}).EnabledFunc([] {
|
||||
return g_Config.bEnableQuickChat && g_Config.bEnableNetworkChat;
|
||||
});
|
||||
}
|
||||
|
||||
page->Header({ I18NCat::NETWORKING, "Misc", "Misc (default = compatibility)" });
|
||||
page->Choice("Open PPSSPP Multiplayer Wiki Page", ImageID("I_LINK_OUT")).OnClick([](EventParams &e) {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
std::string url(n->T("MultiplayerHowToURL", "https://github.com/hrydgard/ppsspp/wiki/How-to-play-multiplayer-games-with-PPSSPP"));
|
||||
System_LaunchUrl(LaunchUrlType::BROWSER_URL, url);
|
||||
});
|
||||
static const char *wlanChannels[] = {"Auto", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"};
|
||||
page->Setting(&g_Config.iWlanAdhocChannel).Setup([](View *view) {
|
||||
PopupMultiChoice *wlanChannelChoice = static_cast<PopupMultiChoice *>(view);
|
||||
wlanChannelChoice->SetChoicesUntranslated(1, (int)ARRAY_SIZE(wlanChannels) - 1);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
wlanChannelChoice->HideChoice(i + 2);
|
||||
wlanChannelChoice->HideChoice(i + 7);
|
||||
}
|
||||
});
|
||||
page->Setting(&g_Config.iPortOffset);
|
||||
page->Hint("PortOffsetHint");
|
||||
page->Setting(&g_Config.iMinTimeout);
|
||||
page->Setting(&g_Config.bForcedFirstConnect);
|
||||
page->Setting(&g_Config.bAllowSpeedControlWhileConnected);
|
||||
if (Discord::IsAvailable()) {
|
||||
page->Setting(&g_Config.bDiscordRichPresence);
|
||||
}
|
||||
}
|
||||
|
||||
static void BuildToolsSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
SettingsPageHost *host = page->Host();
|
||||
|
||||
page->Header("Tools");
|
||||
|
||||
const bool showRetroAchievements = System_GetPropertyInt(SYSPROP_DEVICE_TYPE) != DEVICE_TYPE_VR;
|
||||
if (showRetroAchievements) {
|
||||
page->Choice({ I18NCat::SYSTEM, "RetroAchievements" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new RetroAchievementsSettingsScreen(host->PageGamePath()));
|
||||
}).Setup([](View *view) {
|
||||
static_cast<Choice *>(view)->SetIconRight(ImageID("I_RETROACHIEVEMENTS_LOGO"));
|
||||
});
|
||||
}
|
||||
|
||||
// These were moved here so use the wrong translation objects, to avoid having to change all inis... This isn't a sustainable situation :P
|
||||
page->Choice({ I18NCat::SAVEDATA, "Savedata Manager" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new SavedataScreen(host->PageGamePath()));
|
||||
});
|
||||
page->Choice({ I18NCat::DEVELOPER, "System Information" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new SystemInfoScreen(host->PageGamePath()));
|
||||
});
|
||||
page->Link({ I18NCat::SYSTEM, "Developer Tools" }, I18NCat::DEVELOPER, &BuildDeveloperToolsPage);
|
||||
page->Choice({ I18NCat::REMOTEISO, "Remote disc streaming" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new RemoteISOScreen(host->PageGamePath()));
|
||||
});
|
||||
page->Choice({ I18NCat::SYSTEM, "PSP Firmware" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new FirmwareScreen(host->PageGamePath()));
|
||||
});
|
||||
}
|
||||
|
||||
void GameSettingsScreen::BuildSystemSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
|
||||
@@ -1403,33 +526,6 @@ void GameSettingsScreen::BuildSystemSettings(SettingsPage *page) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static void BuildVRSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
|
||||
int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE);
|
||||
|
||||
if (deviceType == DEVICE_TYPE_VR) {
|
||||
page->Header("Virtual reality");
|
||||
page->Setting(&g_Config.bEnableVR);
|
||||
page->Setting(&g_Config.bEnable6DoF);
|
||||
page->Setting(&g_Config.bEnableStereo);
|
||||
page->Setting(&g_Config.bEnableImmersiveVR);
|
||||
if (IsPassthroughSupported()) {
|
||||
page->Setting(&g_Config.bPassthrough);
|
||||
}
|
||||
page->Setting(&g_Config.bForce72Hz);
|
||||
}
|
||||
|
||||
page->Header("VR camera");
|
||||
if (deviceType == DEVICE_TYPE_VR) {
|
||||
page->Setting(&g_Config.fCanvasDistance);
|
||||
page->Setting(&g_Config.fCanvas3DDistance);
|
||||
}
|
||||
page->Setting(&g_Config.fFieldOfViewPercentage);
|
||||
page->Setting(&g_Config.bRescaleHUD);
|
||||
page->Setting(&g_Config.fHeadUpDisplayScale).Enabled(&g_Config.bRescaleHUD);
|
||||
page->Setting(&g_Config.bManualForceVR);
|
||||
}
|
||||
void GameSettingsScreen::OnImmersiveModeChange(UI::EventParams &e) {
|
||||
System_Notify(SystemNotification::IMMERSIVE_MODE_CHANGE);
|
||||
if (g_Config.iAndroidHwScale != 0) {
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#include "Common/Audio/AudioBackend.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/TimeUtil.h"
|
||||
#include "Common/UI/Root.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
#include "Core/HLE/sceUsbMic.h"
|
||||
#include "UI/BackgroundAudio.h"
|
||||
#include "UI/SettingsPage.h"
|
||||
#include "UI/Settings/MainSettingsPages.h"
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
#include "android/jni/AndroidAudio.h"
|
||||
|
||||
extern AndroidAudioState *g_audioState;
|
||||
#endif
|
||||
|
||||
void BuildAudioSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
|
||||
#if PPSSPP_PLATFORM(IOS)
|
||||
page->Setting(&g_Config.bAudioRespectSilentMode).Enabled(&g_Config.bEnableSound);
|
||||
#endif
|
||||
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
|
||||
page->Setting(&g_Config.bAudioMixWithOthers).Enabled(&g_Config.bEnableSound);
|
||||
#endif
|
||||
page->Header("Audio playback");
|
||||
|
||||
page->Setting(&g_Config.iAudioPlaybackMode);
|
||||
page->Setting(&g_Config.bFillAudioGaps).EnabledFunc([]() {
|
||||
return g_Config.iAudioPlaybackMode == (int)AudioSyncMode::GRANULAR;
|
||||
});
|
||||
|
||||
page->Header("Game volume");
|
||||
|
||||
// This is here because it now only applies to in-game. Muting the menu sounds is separate.
|
||||
page->Setting(&g_Config.bEnableSound);
|
||||
|
||||
page->Setting(&g_Config.iGameVolume).Enabled(&g_Config.bEnableSound);
|
||||
page->Setting(&g_Config.iReverbVolume).Enabled(&g_Config.bEnableSound);
|
||||
page->Setting(&g_Config.iAltSpeedVolume).Enabled(&g_Config.bEnableSound);
|
||||
page->Setting(&g_Config.iAchievementVolume).Enabled(&g_Config.bEnableSound).OnChange([](EventParams &e) {
|
||||
// Audio preview
|
||||
float achievementVolume = Volume100ToMultiplier(g_Config.iAchievementVolume);
|
||||
g_BackgroundAudio.SFX().Play(UI::UISound::ACHIEVEMENT_UNLOCKED, achievementVolume);
|
||||
});
|
||||
|
||||
page->Header();
|
||||
|
||||
page->Setting(&g_Config.bUISound);
|
||||
page->Setting(&g_Config.iUIVolume).LiveUpdate().Enabled(&g_Config.bUISound).OnChange([](EventParams &e) {
|
||||
static double lastTimePlayed = 0.0;
|
||||
double now = time_now_d();
|
||||
if (now - lastTimePlayed < 0.1) {
|
||||
return; // Don't play if we just played one, to avoid spamming when dragging.
|
||||
}
|
||||
lastTimePlayed = now;
|
||||
// Audio preview
|
||||
PlayUISound(UI::UISound::CONFIRM);
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.iGamePreviewVolume);
|
||||
|
||||
bool sdlAudio = false;
|
||||
|
||||
#if defined(SDL)
|
||||
page->Header("Audio backend");
|
||||
std::vector<std::string> audioDeviceList;
|
||||
SplitString(System_GetProperty(SYSPROP_AUDIO_DEVICE_LIST), '\0', audioDeviceList);
|
||||
audioDeviceList.insert(audioDeviceList.begin(), std::string(T(I18NCat::AUDIO, "Auto")));
|
||||
page->Setting(&g_Config.sAudioDevice, std::move(audioDeviceList)).OnChange([](EventParams &e) {
|
||||
if (g_Config.sAudioDevice == T(I18NCat::AUDIO, "Auto")) {
|
||||
g_Config.sAudioDevice.clear();
|
||||
}
|
||||
System_Notify(SystemNotification::AUDIO_RESET_DEVICE);
|
||||
});
|
||||
sdlAudio = true;
|
||||
|
||||
static const int bufferSizes[] = {128, 256, 512, 1024, 2048};
|
||||
page->IntSlider(&g_Config.iSDLAudioBufferSize, 0, 2048, "Buffer size").Default(256).RestrictTo(bufferSizes, ARRAY_SIZE(bufferSizes));
|
||||
page->Hint({ I18NCat::DIALOG, "This change will not take effect until PPSSPP is restarted." });
|
||||
#endif
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
extern AudioBackend *g_audioBackend;
|
||||
|
||||
std::vector<std::string> audioDeviceNames;
|
||||
std::vector<std::string> audioDeviceIds;
|
||||
|
||||
std::vector<AudioDeviceDesc> deviceDescs;
|
||||
g_audioBackend->EnumerateDevices(&deviceDescs);
|
||||
if (!deviceDescs.empty()) {
|
||||
page->Header("Audio backend");
|
||||
for (auto &desc : deviceDescs) {
|
||||
audioDeviceNames.push_back(desc.name);
|
||||
audioDeviceIds.push_back(desc.uniqueId);
|
||||
}
|
||||
|
||||
audioDeviceNames.insert(audioDeviceNames.begin(), std::string(T(I18NCat::AUDIO, "Auto")));
|
||||
audioDeviceIds.insert(audioDeviceIds.begin(), "");
|
||||
|
||||
page->Setting(&g_Config.sAudioDevice, std::move(audioDeviceNames), std::move(audioDeviceIds)).OnChange([](EventParams &) {
|
||||
bool reverted;
|
||||
if (g_audioBackend->InitOutputDevice(g_Config.sAudioDevice, LatencyMode::Aggressive, &reverted)) {
|
||||
if (reverted) {
|
||||
WARN_LOG(Log::Audio, "Unexpected: After a direct choice, audio device reverted to default. '%s'", g_Config.sAudioDevice.c_str());
|
||||
}
|
||||
} else {
|
||||
WARN_LOG(Log::Audio, "InitOutputDevice failed");
|
||||
}
|
||||
});
|
||||
page->Setting(&g_Config.bAutoSwitchAudioDevice).EnabledFunc([]()->bool {
|
||||
return g_Config.sAudioDevice.empty();
|
||||
});
|
||||
}
|
||||
|
||||
#else
|
||||
if (sdlAudio) {
|
||||
page->Setting(&g_Config.bAutoSwitchAudioDevice);
|
||||
} else {
|
||||
page->Header("Audio backend");
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
page->Setting(&g_Config.bExtraAudioBuffering);
|
||||
|
||||
auto restartAudio = [](UI::EventParams &) {
|
||||
AndroidAudio_Restart(g_audioState);
|
||||
};
|
||||
// AAudio isn't stable before Android 8.1, so there it's always OpenSL ES.
|
||||
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 27) {
|
||||
page->Setting(&g_Config.iAndroidAudioApi).OnChange(restartAudio);
|
||||
page->Hint({ I18NCat::AUDIO, "AudioApiHint", "Try the other one if you have no sound or other audio problems." });
|
||||
|
||||
page->Setting(&g_Config.bAndroidAudioMMap).OnChange(restartAudio).EnabledFunc([]() {
|
||||
return g_Config.iAndroidAudioApi == (int)AndroidAudioApi::AAUDIO;
|
||||
});
|
||||
page->Hint({ I18NCat::AUDIO, "AudioMMapHint", "Lowest audio delay. On some devices, it causes silence over Bluetooth or other connected audio devices. Turn it off if you get no sound." });
|
||||
}
|
||||
// Show Oboe debug info
|
||||
const std::string audioErrorStr = AndroidAudio_GetErrorString(g_audioState);
|
||||
if (!audioErrorStr.empty()) {
|
||||
page->Info("Audio Error", audioErrorStr);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::vector<std::string> micList = Microphone::getDeviceList();
|
||||
if (!micList.empty()) {
|
||||
page->Header("Microphone");
|
||||
std::vector<std::string> micValues = micList;
|
||||
micList.emplace(micList.begin(), T(I18NCat::AUDIO, "Auto"));
|
||||
micValues.insert(micValues.begin(), "");
|
||||
page->Setting(&g_Config.sMicDevice, std::move(micList), std::move(micValues));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/System/Display.h"
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/UI/ScreenManager.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
#include "UI/ControlMappingScreen.h"
|
||||
#include "UI/GameSettingsScreen.h"
|
||||
#include "UI/SettingsPage.h"
|
||||
#include "UI/Settings/MainSettingsPages.h"
|
||||
#include "UI/TiltAnalogSettingsScreen.h"
|
||||
#include "UI/TouchControlLayoutScreen.h"
|
||||
|
||||
void BuildControlsSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
SettingsPageHost *host = page->Host();
|
||||
|
||||
int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE);
|
||||
|
||||
page->Header({ I18NCat::MAINSETTINGS, "Controls" });
|
||||
page->Choice("Control mapping").OnClick([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new ControlMappingScreen(host->PageGamePath()));
|
||||
});
|
||||
page->Choice("Calibrate analog stick").OnClick([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new AnalogCalibrationScreen(host->PageGamePath()));
|
||||
});
|
||||
|
||||
#if (PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)) || (PPSSPP_PLATFORM(LINUX) && !PPSSPP_PLATFORM(ANDROID))
|
||||
page->Setting(&g_Config.bSystemControls);
|
||||
#endif
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
page->Setting(&g_Config.bGamepadOnlyFocused);
|
||||
#endif
|
||||
|
||||
if (System_GetPropertyBool(SYSPROP_HAS_ACCELEROMETER)) {
|
||||
page->Custom("Tilt control setup", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
// Show the tilt type on the item.
|
||||
Choice *customizeTilt = parent->Add(new ChoiceWithCallbackValueDisplay(T(I18NCat::CONTROLS, "Tilt control setup"), []() -> std::string {
|
||||
if (g_Config.bTiltInputEnabled && (u32)g_Config.iTiltInputType < (u32)g_numTiltTypes) {
|
||||
auto co = GetI18NCategory(I18NCat::CONTROLS);
|
||||
return std::string(co->T(g_tiltTypes[g_Config.iTiltInputType]));
|
||||
} else {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
return std::string(di->T("Disabled"));
|
||||
}
|
||||
}));
|
||||
customizeTilt->OnClick.Add([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new TiltAnalogSettingsScreen(host->PageGamePath()));
|
||||
});
|
||||
return customizeTilt;
|
||||
});
|
||||
} else if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_VR) { // TODO: This seems like a regression
|
||||
page->Setting(&g_Config.bHapticFeedback);
|
||||
}
|
||||
|
||||
page->Header("Analog to digital mapping");
|
||||
page->Setting(&g_Config.fAnalogTriggerThreshold);
|
||||
page->Setting(&g_Config.fAnalogStickThreshold);
|
||||
|
||||
// TVs don't have touch control, at least not yet.
|
||||
if ((deviceType != DEVICE_TYPE_TV) && (deviceType != DEVICE_TYPE_VR)) {
|
||||
page->Header("On-screen touch controls");
|
||||
page->Setting(&g_Config.bShowTouchControls);
|
||||
page->Choice("Edit touch control layout").OnClick([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new TouchControlLayoutScreen(host->PageGamePath()));
|
||||
}).Enabled(&g_Config.bShowTouchControls);
|
||||
page->Choice("Gesture mapping").OnClick([host](UI::EventParams &e) {
|
||||
host->PageScreenManager()->push(new GestureMappingScreen(host->PageGamePath()));
|
||||
}).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
page->Setting(&g_Config.iTouchButtonStyle).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
page->Setting(&g_Config.iTouchButtonOpacity).Enabled(&g_Config.bShowTouchControls);
|
||||
page->Setting(&g_Config.iTouchButtonHideSeconds).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
page->Setting(&g_Config.bTouchGliding).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
TouchControlConfig &touch = g_Config.GetTouchControlsConfig(g_display.GetDeviceOrientation());
|
||||
|
||||
// Hide stick background, useful when increasing the size
|
||||
page->Setting(&touch.bHideStickBackground).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
// Sticky D-pad.
|
||||
page->Setting(&g_Config.bStickyTouchDPad).Enabled(&g_Config.bShowTouchControls);
|
||||
page->Hint("Easier sweeping movements");
|
||||
|
||||
// Re-centers itself to the touch location on touch-down.
|
||||
page->Setting(&g_Config.bAutoCenterTouchAnalog).Enabled(&g_Config.bShowTouchControls);
|
||||
|
||||
if (System_GetPropertyInt(SYSPROP_DEVICE_TYPE) == DEVICE_TYPE_MOBILE) {
|
||||
page->Setting(&g_Config.bHapticFeedback);
|
||||
}
|
||||
|
||||
// The pause button is now a regular on-screen button.
|
||||
|
||||
page->Setting(&g_Config.bDisableDpadDiagonals).Enabled(&g_Config.bShowTouchControls);
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(WINDOWS)
|
||||
page->Header("Control input sources");
|
||||
page->Setting(&g_Config.bAllowHIDInput);
|
||||
page->Setting(&g_Config.bAllowXInput);
|
||||
page->Setting(&g_Config.bAllowDInput);
|
||||
#endif
|
||||
|
||||
if (deviceType != DEVICE_TYPE_VR) {
|
||||
page->Header({ I18NCat::CONTROLS, "Keyboard", "Keyboard Control Settings" });
|
||||
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
||||
page->Setting(&g_Config.bIgnoreWindowsKey);
|
||||
#endif
|
||||
page->Setting(&g_Config.fAnalogLimiterDeadzone);
|
||||
page->Hint({ I18NCat::CONTROLS, "AnalogLimiter Tip", "When the analog limiter button is pressed" });
|
||||
page->Setting(&g_Config.iRapidFireInterval);
|
||||
#if PPSSPP_PLATFORM(WINDOWS) || defined(SDL) || PPSSPP_PLATFORM(ANDROID)
|
||||
bool enableMouseSettings = true;
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) < 12) {
|
||||
enableMouseSettings = false;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
bool enableMouseSettings = false;
|
||||
#endif
|
||||
if (enableMouseSettings) {
|
||||
// The mousewheel button-release setting is independent of actual mouse delta control.
|
||||
page->Header({ I18NCat::CONTROLS, "Mouse", "Mouse settings" });
|
||||
page->Setting(&g_Config.iMouseWheelUpDelayMs);
|
||||
|
||||
page->Setting(&g_Config.bMouseControl);
|
||||
page->Hint({ I18NCat::CONTROLS, "MouseControl Tip", "You can now map mouse in control mapping screen by pressing the 'M' icon." });
|
||||
|
||||
#if !PPSSPP_PLATFORM(ANDROID)
|
||||
page->Setting(&g_Config.bMouseConfine).Enabled(&g_Config.bMouseControl);
|
||||
#endif
|
||||
page->Setting(&g_Config.fMouseSensitivity).Enabled(&g_Config.bMouseControl).LiveUpdate();
|
||||
page->Setting(&g_Config.fMouseSmoothing).Enabled(&g_Config.bMouseControl).LiveUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/GPU/thin3d.h"
|
||||
#include "Common/System/Display.h"
|
||||
#include "Common/System/NativeApp.h"
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/UI/PopupScreens.h"
|
||||
#include "Common/UI/ScreenManager.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
#include "Core/Instance.h"
|
||||
#include "Core/KeyMap.h"
|
||||
#include "Core/System.h"
|
||||
#include "GPU/Common/PostShader.h"
|
||||
#include "UI/DevScreens.h"
|
||||
#include "UI/DisplayLayoutScreen.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "UI/SettingsPage.h"
|
||||
#include "UI/Settings/MainSettingsPages.h"
|
||||
|
||||
static bool UsingHardwareTextureScaling() {
|
||||
return g_Config.bTexHardwareScaling && (GetGPUBackend() == GPUBackend::VULKAN || GetGPUBackend() == GPUBackend::METAL) && !g_Config.bSoftwareRendering;
|
||||
}
|
||||
|
||||
static std::string TextureTranslateName(std::string_view value) {
|
||||
const TextureShaderInfo *info = GetTextureShaderInfo(value);
|
||||
if (info) {
|
||||
auto ts = GetI18NCategory(I18NCat::TEXTURESHADERS);
|
||||
return std::string(ts->T(value, info->name.c_str()));
|
||||
} else {
|
||||
return std::string(value);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string *GPUDeviceNameSetting() {
|
||||
if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
|
||||
return &g_Config.sVulkanDevice;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
if (g_Config.iGPUBackend == (int)GPUBackend::DIRECT3D11) {
|
||||
return &g_Config.sD3D11Device;
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO: Make this generic
|
||||
extern int DefaultDepthRaster();
|
||||
|
||||
static void OnRenderingBackend(SettingsPageHost *host) {
|
||||
// It only makes sense to show the restart prompt if the backend was actually changed.
|
||||
if (g_Config.iGPUBackend != (int)GetGPUBackend()) {
|
||||
host->RestartOrDo([]() {
|
||||
g_Config.iGPUBackend = (int)GetGPUBackend();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
static void OnRenderingDevice(SettingsPageHost *host) {
|
||||
// It only makes sense to show the restart prompt if the device was actually changed.
|
||||
std::string *deviceNameSetting = GPUDeviceNameSetting();
|
||||
if (deviceNameSetting && *deviceNameSetting != GetGPUBackendDevice()) {
|
||||
host->RestartOrDo([host]() {
|
||||
std::string *deviceNameSetting = GPUDeviceNameSetting();
|
||||
if (deviceNameSetting)
|
||||
*deviceNameSetting = GetGPUBackendDevice();
|
||||
// Needed to redraw the setting.
|
||||
host->RecreatePageViews();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void BuildGraphicsSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
SettingsPageHost *host = page->Host();
|
||||
|
||||
Draw::DrawContext *draw = host->PageScreenManager()->getDrawContext();
|
||||
int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE);
|
||||
|
||||
page->Header("Rendering Mode");
|
||||
|
||||
#if !PPSSPP_PLATFORM(UWP)
|
||||
page->Setting(&g_Config.iGPUBackend).Setup([host](View *view) {
|
||||
PopupMultiChoice *renderingBackendChoice = static_cast<PopupMultiChoice *>(view);
|
||||
renderingBackendChoice->SetPreOpenCallback([host](UI::PopupMultiChoice *choice) {
|
||||
// Don't filter until the last possible moment, since it involves trying to initialize Vulkan, if we were
|
||||
// started in OpenGL mode on Android.
|
||||
choice->HideChoice(1);
|
||||
choice->OnChoice.Add([host](UI::EventParams &) {
|
||||
OnRenderingBackend(host);
|
||||
});
|
||||
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL))
|
||||
choice->HideChoice((int)GPUBackend::OPENGL);
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11))
|
||||
choice->HideChoice((int)GPUBackend::DIRECT3D11);
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::VULKAN))
|
||||
choice->HideChoice((int)GPUBackend::VULKAN);
|
||||
if (!g_Config.IsBackendEnabled(GPUBackend::METAL))
|
||||
choice->HideChoice((int)GPUBackend::METAL);
|
||||
});
|
||||
|
||||
if (!IsFirstInstance()) {
|
||||
// If we're not the first instance, can't save the setting, and it requires a restart, so...
|
||||
renderingBackendChoice->SetEnabled(false);
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
#if (PPSSPP_PLATFORM(IOS) && !PPSSPP_PLATFORM(TVOS)) || PPSSPP_PLATFORM(ANDROID)
|
||||
// Showing the game there needs a second swapchain. Otherwise the system mirrors the screen.
|
||||
page->Setting(&g_Config.iExternalDisplay).EnabledFunc([draw] {
|
||||
return draw->GetDeviceCaps().multipleSwapchains;
|
||||
}).OnChange([previous = g_Config.iExternalDisplay](UI::EventParams &e) mutable {
|
||||
// Picking the current value again would rebuild the TV's output for nothing (iOS starts over on a change).
|
||||
if (g_Config.iExternalDisplay == previous) {
|
||||
return;
|
||||
}
|
||||
previous = g_Config.iExternalDisplay;
|
||||
System_Notify(SystemNotification::EXTERNAL_DISPLAY_CHANGED);
|
||||
});
|
||||
#endif
|
||||
|
||||
// Backends that don't allow a device choice will only expose one device.
|
||||
if (draw->GetDeviceList().size() > 1) {
|
||||
std::string *deviceNameSetting = GPUDeviceNameSetting();
|
||||
if (deviceNameSetting) {
|
||||
page->Setting(deviceNameSetting, draw->GetDeviceList()).OnChange([host](UI::EventParams &e) {
|
||||
OnRenderingDevice(host);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
page->Setting(&g_Config.iInternalResolution).EnabledFunc([] {
|
||||
return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects;
|
||||
});
|
||||
|
||||
if (deviceType != DEVICE_TYPE_VR) {
|
||||
page->Setting(&g_Config.bSoftwareRendering).EnabledFunc([] {
|
||||
return !PSP_IsInited();
|
||||
});
|
||||
}
|
||||
|
||||
if (draw->GetDeviceCaps().multiSampleLevelsMask != 1) {
|
||||
page->Setting(&g_Config.iMultiSampleLevel).EnabledFunc([] {
|
||||
return !g_Config.bSoftwareRendering && !g_Config.bSkipBufferEffects;
|
||||
}).Setup([draw](View *view) {
|
||||
PopupMultiChoice *msaaChoice = static_cast<PopupMultiChoice *>(view);
|
||||
if (g_Config.iMultiSampleLevel > 1 && draw->GetDeviceCaps().isTilingGPU) {
|
||||
msaaChoice->SetIconRight(ImageID("I_WARNING"), 0.7f);
|
||||
}
|
||||
// Hide unsupported levels.
|
||||
for (int i = 1; i < msaaChoice->NumChoices(); i++) {
|
||||
if ((draw->GetDeviceCaps().multiSampleLevelsMask & (1 << i)) == 0) {
|
||||
msaaChoice->HideChoice(i);
|
||||
} else if (i > 0 && draw->GetDeviceCaps().isTilingGPU) {
|
||||
msaaChoice->SetChoiceIcon(i, ImageID("I_WARNING"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
if ((deviceType != DEVICE_TYPE_TV) && (deviceType != DEVICE_TYPE_VR)) {
|
||||
int max_res = std::max(System_GetPropertyInt(SYSPROP_DISPLAY_XRES), System_GetPropertyInt(SYSPROP_DISPLAY_YRES)) / 480 + 2;
|
||||
if (max_res == 3)
|
||||
max_res = 4; // At least allow 2x
|
||||
page->Setting(&g_Config.iAndroidHwScale).Setup([max_res](View *view) {
|
||||
// Hide the scales the display is too small for.
|
||||
PopupMultiChoice *choice = static_cast<PopupMultiChoice *>(view);
|
||||
for (int i = max_res; i < choice->NumChoices(); i++) {
|
||||
choice->HideChoice(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
||||
|
||||
page->Setting(&g_Config.bReplaceTextures);
|
||||
|
||||
page->Header("Display");
|
||||
|
||||
if (deviceType != DEVICE_TYPE_VR) {
|
||||
#if !defined(MOBILE_DEVICE)
|
||||
page->Setting(&g_Config.bFullScreen);
|
||||
if (draw->GetDeviceCaps().fullScreenExclusiveSupported) {
|
||||
page->Setting(&g_Config.bAllowFullScreenExclusive).EnabledFunc([] {
|
||||
return g_Config.bFullScreen && !g_Config.bFullScreenMulti;
|
||||
}).OnChange([host](UI::EventParams &e) {
|
||||
host->RestartOrDo([host]() {
|
||||
g_Config.bAllowFullScreenExclusive = !g_Config.bAllowFullScreenExclusive;
|
||||
host->RecreatePageViews();
|
||||
});
|
||||
});
|
||||
}
|
||||
if (System_GetPropertyInt(SYSPROP_DISPLAY_COUNT) > 1) {
|
||||
page->Setting(&g_Config.bFullScreenMulti).EnabledFunc([] {
|
||||
return g_Config.bFullScreen && !g_Config.bAllowFullScreenExclusive;
|
||||
});
|
||||
}
|
||||
#endif
|
||||
// Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc.
|
||||
page->Choice("Display layout & effects").OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new DisplayLayoutScreen(host->PageGamePath()));
|
||||
});
|
||||
}
|
||||
|
||||
// If only one mode is supported (like FIFO on iOS), no need to show the options.
|
||||
if (CountSetBits((u32)draw->GetDeviceCaps().presentModesSupported) > 1) {
|
||||
// Immediate means non-synchronized, tearing.
|
||||
if (draw->GetDeviceCaps().presentModesSupported & Draw::PresentMode::IMMEDIATE) {
|
||||
page->Setting(&g_Config.bVSync).OnChange([](UI::EventParams &e) {
|
||||
NativeResized(); // TODO: Remove
|
||||
});
|
||||
}
|
||||
if (draw->GetDeviceCaps().presentModesSupported & Draw::PresentMode::MAILBOX) {
|
||||
SettingItem &lowLatency = page->Setting(&g_Config.bLowLatencyPresent).OnChange([](UI::EventParams &e) {
|
||||
NativeResized(); // TODO: Remove
|
||||
});
|
||||
|
||||
// If the immediate mode is supported, we can tie low latency present to VSync.
|
||||
if (draw->GetDeviceCaps().presentModesSupported & Draw::PresentMode::IMMEDIATE) {
|
||||
lowLatency.Enabled(&g_Config.bVSync);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page->Header("Frame Rate Control");
|
||||
|
||||
page->Setting(&g_Config.iAltSpeedPercent1);
|
||||
page->Setting(&g_Config.iAltSpeedPercent2);
|
||||
if (KeyMap::InputMappingsFromPspButton(VIRTKEY_SPEED_ANALOG, nullptr, true)) {
|
||||
page->Setting(&g_Config.iAnalogAltSpeedPercent);
|
||||
}
|
||||
|
||||
page->Header({ I18NCat::GRAPHICS, "Speed Hacks", "Speed Hacks (can cause rendering errors!)" });
|
||||
|
||||
page->Setting(&g_Config.iFrameSkip).EnabledFunc([] {
|
||||
return !g_Config.bAutoFrameSkip;
|
||||
}).Setup([](View *view) {
|
||||
PopupMultiChoice *choice = static_cast<PopupMultiChoice *>(view);
|
||||
choice->SetChoicesUntranslated(1, choice->NumChoices() - 1);
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.bAutoFrameSkip);
|
||||
|
||||
page->Setting(&g_Config.bSkipBufferEffects).Disabled(&g_Config.bSoftwareRendering);
|
||||
page->Hint({ I18NCat::GRAPHICS, "RenderingMode NonBuffered Tip", "Faster, but graphics may be missing in some games" });
|
||||
|
||||
page->Setting(&g_Config.iSkipGPUReadbackMode).Disabled(&g_Config.bSoftwareRendering).Setup([](View *view) {
|
||||
static_cast<PopupMultiChoice *>(view)->SetDefault(0);
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.iDepthRasterMode).Disabled(&g_Config.bSoftwareRendering).Setup([](View *view) {
|
||||
PopupMultiChoice *depthRasterMode = static_cast<PopupMultiChoice *>(view);
|
||||
depthRasterMode->SetChoiceIcon(3, ImageID("I_WARNING")); // It's a performance trap.
|
||||
depthRasterMode->SetDefault(DefaultDepthRaster());
|
||||
if (g_Config.iDepthRasterMode != 3)
|
||||
depthRasterMode->HideChoice(3);
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.iBloomHack).EnabledFunc([] {
|
||||
return !g_Config.bSoftwareRendering && g_Config.iInternalResolution != 1;
|
||||
});
|
||||
page->Hint("Reduces artifacts");
|
||||
|
||||
page->Header("Performance");
|
||||
page->Setting(&g_Config.bRenderDuplicateFrames).EnabledFunc([] {
|
||||
return !g_Config.bSkipBufferEffects && g_Config.iFrameSkip == 0;
|
||||
});
|
||||
page->Hint({ I18NCat::GRAPHICS, "RenderDuplicateFrames Tip", "Can make framerate smoother in games that run at lower framerates" });
|
||||
|
||||
if (draw->GetDeviceCaps().setMaxFrameLatencySupported) {
|
||||
// Changing it needs a restart, so the value in use is the one the page was built with.
|
||||
page->Setting(&g_Config.iInflightFrames).OnChange([host, previous = g_Config.iInflightFrames](UI::EventParams &e) {
|
||||
if (g_Config.iInflightFrames != previous) {
|
||||
host->RestartOrDo([previous]() {
|
||||
g_Config.iInflightFrames = previous;
|
||||
});
|
||||
}
|
||||
});
|
||||
page->Hint("Faster, input lag"); // TODO: This hint could use improvement.
|
||||
}
|
||||
|
||||
page->Header("Texture upscaling");
|
||||
|
||||
if (GetGPUBackend() == GPUBackend::VULKAN || GetGPUBackend() == GPUBackend::METAL) {
|
||||
page->Custom("GPU texture upscaler (fast)", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
ChoiceWithValueDisplay *textureShaderChoice = parent->Add(new ChoiceWithValueDisplay(&g_Config.sTextureShaderName, gr->T("GPU texture upscaler (fast)"), &TextureTranslateName));
|
||||
textureShaderChoice->OnClick.Add([host](UI::EventParams &e) {
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
auto shaderScreen = new TextureShaderScreen(gr->T("GPU texture upscaler (fast)"));
|
||||
shaderScreen->OnChoice.Add([host](UI::EventParams &e) {
|
||||
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
||||
host->RecreatePageViews(); // Update setting name
|
||||
g_Config.bTexHardwareScaling = g_Config.sTextureShaderName != "Off";
|
||||
});
|
||||
if (e.v)
|
||||
shaderScreen->SetPopupOrigin(e.v);
|
||||
host->PageScreenManager()->push(shaderScreen);
|
||||
});
|
||||
return textureShaderChoice;
|
||||
}).Disabled(&g_Config.bSoftwareRendering);
|
||||
}
|
||||
|
||||
page->Setting(&g_Config.iTexScalingType).EnabledFunc([]() {
|
||||
return !g_Config.bSoftwareRendering && !UsingHardwareTextureScaling();
|
||||
});
|
||||
page->Setting(&g_Config.iTexScalingLevel).EnabledFunc([]() {
|
||||
return !g_Config.bSoftwareRendering && !UsingHardwareTextureScaling();
|
||||
});
|
||||
page->Hint({ I18NCat::GRAPHICS, "UpscaleLevel Tip", "CPU heavy - some scaling may be delayed to avoid stutter" });
|
||||
|
||||
page->Setting(&g_Config.bTexDeposterize).EnabledFunc([]() {
|
||||
return !g_Config.bSoftwareRendering && !UsingHardwareTextureScaling();
|
||||
});
|
||||
page->Hint({ I18NCat::GRAPHICS, "Deposterize Tip", "Fixes visual banding glitches in upscaled textures" });
|
||||
|
||||
page->Header("Texture Filtering");
|
||||
|
||||
page->Setting(&g_Config.iAnisotropyLevel).Disabled(&g_Config.bSoftwareRendering);
|
||||
|
||||
page->Setting(&g_Config.iTexFiltering).Disabled(&g_Config.bSoftwareRendering);
|
||||
|
||||
page->Setting(&g_Config.bSmart2DTexFiltering).Disabled(&g_Config.bSoftwareRendering);
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
|
||||
bool showCardboardSettings = deviceType != DEVICE_TYPE_VR;
|
||||
#else
|
||||
// If you enabled it through the ini, you can see this. Useful for testing.
|
||||
bool showCardboardSettings = config.bEnableCardboardVR;
|
||||
#endif
|
||||
if (showCardboardSettings) {
|
||||
page->Header("Cardboard VR Settings");
|
||||
page->Setting(&config.bEnableCardboardVR);
|
||||
page->Setting(&config.iCardboardScreenSize).Enabled(&config.bEnableCardboardVR);
|
||||
page->Setting(&config.iCardboardXShift).Enabled(&config.bEnableCardboardVR);
|
||||
page->Setting(&config.iCardboardYShift).Enabled(&config.bEnableCardboardVR);
|
||||
}
|
||||
|
||||
page->Header("Overlay Information");
|
||||
auto addStatusFlag = [page](ShowStatusFlags flag, const char *text) {
|
||||
page->Custom(text, [flag, text](UI::ViewGroup *parent) -> UI::View * {
|
||||
return parent->Add(new BitCheckBox(&g_Config.iShowStatusFlags, (int)flag, T(I18NCat::GRAPHICS, text)));
|
||||
});
|
||||
};
|
||||
addStatusFlag(ShowStatusFlags::FPS_COUNTER, "Show FPS Counter");
|
||||
addStatusFlag(ShowStatusFlags::SPEED_COUNTER, "Show Speed");
|
||||
if (System_GetPropertyBool(SYSPROP_CAN_READ_BATTERY_PERCENTAGE)) {
|
||||
addStatusFlag(ShowStatusFlags::BATTERY_PERCENT, "Show Battery %");
|
||||
}
|
||||
page->Custom({ I18NCat::DEVELOPER, "Debug overlay" }, [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
AddOverlayList(parent, host->PageScreenManager());
|
||||
return parent->GetViewByIndex(parent->GetNumSubviews() - 1);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace UI {
|
||||
class View;
|
||||
class ViewGroup;
|
||||
}
|
||||
|
||||
class SettingsPage;
|
||||
class SettingsPageHost;
|
||||
|
||||
// The settings screen's tabs, except System, which needs more of the screen.
|
||||
void BuildGraphicsSettings(SettingsPage *page);
|
||||
void BuildControlsSettings(SettingsPage *page);
|
||||
void BuildAudioSettings(SettingsPage *page);
|
||||
void BuildNetworkingSettings(SettingsPage *page);
|
||||
void BuildToolsSettings(SettingsPage *page);
|
||||
void BuildVRSettings(SettingsPage *page);
|
||||
|
||||
// The nickname is shown on both the Networking and System tabs.
|
||||
UI::View *AddNicknameChoice(SettingsPageHost *host, UI::ViewGroup *parent);
|
||||
@@ -0,0 +1,270 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/System/Request.h"
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/UI/Notice.h"
|
||||
#include "Common/UI/PopupScreens.h"
|
||||
#include "Common/UI/ScreenManager.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/UI/ViewGroup.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/HLE/sceNetAdhoc.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/Util/PortManager.h"
|
||||
#include "UI/AdhocServerScreen.h"
|
||||
#include "UI/DiscordIntegration.h"
|
||||
#include "UI/SettingsPage.h"
|
||||
#include "UI/Settings/MainSettingsPages.h"
|
||||
|
||||
// Compound view just like the audio file choosers
|
||||
class MacAddressChooser : public UI::LinearLayout {
|
||||
public:
|
||||
MacAddressChooser(RequesterToken token, Path gamePath, std::string *value, std::string_view title, ScreenManager *screenManager, UI::LayoutParams *layoutParams = nullptr);
|
||||
};
|
||||
|
||||
MacAddressChooser::MacAddressChooser(RequesterToken token, Path gamePath, std::string *value, std::string_view title, ScreenManager *screenManager, UI::LayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams) {
|
||||
using namespace UI;
|
||||
SetSpacing(5.0f);
|
||||
if (!layoutParams) {
|
||||
layoutParams_->width = FILL_PARENT;
|
||||
layoutParams_->height = ITEM_HEIGHT;
|
||||
}
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
|
||||
std::string initialValue = *value;
|
||||
Add(new PopupTextInputChoice(token, value, title, g_Config.sMACAddress, 17, screenManager, new LinearLayoutParams(1.0f)))->OnChange.Add([=](UI::EventParams &e) {
|
||||
// Validate the chosen address, and restore to initialValue if bad.
|
||||
if (g_Config.sMACAddress.size() != 17) {
|
||||
// TODO: Alert the user
|
||||
*value = initialValue;
|
||||
}
|
||||
});
|
||||
Add(new Choice(n->T("Randomize"), new LinearLayoutParams(WRAP_CONTENT, ITEM_HEIGHT)))->OnClick.Add([=](UI::EventParams &) {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
|
||||
std::string_view confirmMessage = n->T("ChangeMacSaveConfirm", "Generate a new MAC address?");
|
||||
std::string_view warningMessage = n->T("ChangeMacSaveWarning", "Some games verify the MAC address when loading savedata, so this may break old saves.");
|
||||
std::string combined = g_Config.sMACAddress + "\n\n" + std::string(confirmMessage) + "\n\n" + std::string(warningMessage);
|
||||
|
||||
auto confirmScreen = new MessagePopupScreen(
|
||||
title,
|
||||
combined, di->T("Yes"), di->T("No"),
|
||||
[](bool success) {
|
||||
if (success) {
|
||||
g_Config.sMACAddress = CreateRandMAC();
|
||||
}
|
||||
});
|
||||
screenManager->push(confirmScreen);
|
||||
});
|
||||
}
|
||||
|
||||
// The nickname is shown on both the Networking and System tabs.
|
||||
UI::View *AddNicknameChoice(SettingsPageHost *host, UI::ViewGroup *parent) {
|
||||
using namespace UI;
|
||||
|
||||
auto sy = GetI18NCategory(I18NCat::SYSTEM);
|
||||
PopupTextInputChoice *nickname = parent->Add(new PopupTextInputChoice(host->PageRequesterToken(), &g_Config.sNickName, sy->T("Nickname"), "", 32, host->PageScreenManager()));
|
||||
if (g_Config.sNickName == "PPSSPP") {
|
||||
nickname->SetIconRight(ImageID("I_WARNING"));
|
||||
}
|
||||
nickname->OnChange.Add([host](UI::EventParams &e) {
|
||||
// Copy to infrastructure name if valid and not already set.
|
||||
if (g_Config.sInfrastructureUsername.empty()) {
|
||||
if (g_Config.sNickName == SanitizeString(g_Config.sNickName, StringRestriction::AlphaNumDashUnderscore, 3, 16)) {
|
||||
g_Config.sInfrastructureUsername = g_Config.sNickName;
|
||||
}
|
||||
}
|
||||
// Updates the warning icon, and the username notice on the Networking tab.
|
||||
host->RecreatePageViews();
|
||||
});
|
||||
return nickname;
|
||||
}
|
||||
|
||||
void BuildNetworkingSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
SettingsPageHost *host = page->Host();
|
||||
|
||||
page->Header({ I18NCat::MAINSETTINGS, "Networking" });
|
||||
|
||||
page->Choice("Quick start guide for multiplayer", ImageID("I_LINK_OUT")).OnClick([](EventParams &e) {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
std::string url(n->T("MultiplayerQuickStartURL", "https://www.ppsspp.org/docs/multiplayer/quickstart/"));
|
||||
System_LaunchUrl(LaunchUrlType::BROWSER_URL, url);
|
||||
});
|
||||
|
||||
// Ad hoc play, the built-in server and UPnP all talk to the local network.
|
||||
auto requestLocalNetwork = [](UI::EventParams &e) {
|
||||
CheckBox *checkBox = static_cast<CheckBox *>(e.v);
|
||||
if (checkBox->Toggled()) {
|
||||
System_RequestLocalNetworkPermission();
|
||||
}
|
||||
};
|
||||
|
||||
page->Setting(&g_Config.bEnableWlan).OnChange(requestLocalNetwork);
|
||||
page->Custom("MAC address", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
return parent->Add(new MacAddressChooser(host->PageRequesterToken(), host->PageGamePath(), &g_Config.sMACAddress, T(I18NCat::NETWORKING, "MAC address"), host->PageScreenManager()));
|
||||
});
|
||||
|
||||
page->Header("Ad Hoc multiplayer");
|
||||
|
||||
page->Custom("Ad hoc server address", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
auto launchAdhocServerScreen = [host](UI::EventParams &) {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
host->PageScreenManager()->push(new AdhocServerScreen(&g_Config.sProAdhocServer, n->T("Ad hoc server address")));
|
||||
};
|
||||
|
||||
if (AdhocServerNameIsCustom()) {
|
||||
LinearLayout *serverRow = parent->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
|
||||
serverRow->SetSpacing(0.0f);
|
||||
serverRow->Add(new ChoiceWithValueDisplay(&g_Config.sProAdhocServer, n->T("Ad hoc server address"), I18NCat::NONE, new LinearLayoutParams(1.0f)))->OnClick.Add(launchAdhocServerScreen);
|
||||
serverRow->Add(new Choice(ImageID("I_EDIT_TEXT"), new LinearLayoutParams(ITEM_HEIGHT, ITEM_HEIGHT)))->OnClick.Add([host](UI::EventParams &) {
|
||||
AskToEditCurrentServer(host->PageRequesterToken(), host->PageScreenManager());
|
||||
});
|
||||
return serverRow;
|
||||
}
|
||||
|
||||
AdhocServerListEntry entry;
|
||||
if (!g_Config.sProAdhocServer.empty() && AdhocGetServerByHost(g_Config.sProAdhocServer, &entry)) {
|
||||
Choice *choice = parent->Add(new ChoiceWithFixedValueDisplay(ApplySafeSubstitutions("%1 (%2)", entry.name, entry.host), n->T("Ad hoc server address")));
|
||||
choice->OnClick.Add(launchAdhocServerScreen);
|
||||
return choice;
|
||||
}
|
||||
// This case happens when updating from a previous version, as well as clicking on one of the local addresses
|
||||
Choice *choice = parent->Add(new ChoiceWithFixedValueDisplay(g_Config.sProAdhocServer, n->T("Ad hoc server address")));
|
||||
choice->OnClick.Add(launchAdhocServerScreen);
|
||||
return choice;
|
||||
});
|
||||
|
||||
AdhocServerListEntry serverEntry;
|
||||
if (!AdhocServerNameIsCustom() && !g_Config.sProAdhocServer.empty() && AdhocGetServerByHost(g_Config.sProAdhocServer, &serverEntry)) {
|
||||
page->Custom("Server status: %1", [host, serverEntry](UI::ViewGroup *parent) -> UI::View * {
|
||||
Choice *status = parent->Add(new Choice(ApplySafeSubstitutions(T(I18NCat::NETWORKING, "Server status: %1"), serverEntry.name)));
|
||||
status->SetIconLeft(ImageID("I_INFO"));
|
||||
status->OnClick.Add([host, serverEntry](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new AdhocServerInfoScreen(serverEntry));
|
||||
});
|
||||
return status;
|
||||
});
|
||||
}
|
||||
|
||||
page->Setting(&g_Config.iAdhocServerRelayMode).EnabledFunc([] {
|
||||
return !PSP_IsInited();
|
||||
});
|
||||
page->Hint({ I18NCat::NETWORKING, "PacketRelayHint", "Available on servers that provide 'aemu_postoffice' packet relay, like socom.cc. Disable this for LAN or VPN play. Can be more reliable, but sometimes slower." });
|
||||
|
||||
page->Custom({ I18NCat::SYSTEM, "Nickname" }, [host](UI::ViewGroup *parent) {
|
||||
return AddNicknameChoice(host, parent);
|
||||
});
|
||||
page->Hint("Try to pick a unique nickname for ad hoc play");
|
||||
|
||||
page->Setting(&g_Config.bEnableAdhocServer).OnChange(requestLocalNetwork);
|
||||
|
||||
page->Setting(&g_Config.bAdhocUseUdp).EnabledFunc([] {
|
||||
return !PSP_IsInited();
|
||||
});
|
||||
page->Hint("Try switching between TCP/UDP if you suffer frequent adhoc server disconnects. Some network environments favor TCP and some UDP.");
|
||||
|
||||
page->Setting(&g_Config.bAdhocRelayModeEnetPdpReliable).EnabledFunc([] {
|
||||
return !PSP_IsInited() && g_Config.bAdhocUseUdp;
|
||||
});
|
||||
page->Hint("When disabled, packet loss on datagram adhoc sockets will be exposed to game's netcode. Keep this enabled if you don't know what that means.");
|
||||
|
||||
page->Header("Infrastructure");
|
||||
if (g_Config.sInfrastructureUsername.empty()) {
|
||||
page->Custom("To play in Infrastructure Mode, you must enter a username", [](UI::ViewGroup *parent) -> UI::View * {
|
||||
NoticeView *notice = parent->Add(new NoticeView(NoticeLevel::WARN, T(I18NCat::NETWORKING, "To play in Infrastructure Mode, you must enter a username"), ""));
|
||||
notice->SetWrapText(true);
|
||||
return notice;
|
||||
});
|
||||
}
|
||||
page->Custom({ I18NCat::DIALOG, "Username" }, [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
PopupTextInputChoice *usernameChoice = parent->Add(new PopupTextInputChoice(host->PageRequesterToken(), &g_Config.sInfrastructureUsername, T(I18NCat::DIALOG, "Username"), "", 16, host->PageScreenManager()));
|
||||
usernameChoice->SetRestriction(StringRestriction::AlphaNumDashUnderscore, 3);
|
||||
usernameChoice->OnChange.Add([host](UI::EventParams &e) {
|
||||
host->RecreatePageViews();
|
||||
});
|
||||
return usernameChoice;
|
||||
});
|
||||
|
||||
page->Setting(&g_Config.bInfrastructureAutoDNS);
|
||||
page->Custom("DNS server", [host](UI::ViewGroup *parent) -> UI::View * {
|
||||
return parent->Add(new PopupTextInputChoice(host->PageRequesterToken(), &g_Config.sInfrastructureDNSServer, T(I18NCat::NETWORKING, "DNS server"), "", 32, host->PageScreenManager()));
|
||||
}).Disabled(&g_Config.bInfrastructureAutoDNS);
|
||||
|
||||
page->Header("UPnP (port-forwarding)");
|
||||
// Only togglable outside a game - sceNet latches settings like UPnPUseOriginalPort at boot,
|
||||
// and a game that's already mapped its ports wouldn't cope with them disappearing.
|
||||
page->Setting(&g_Config.bEnableUPnP).EnabledFunc([] {
|
||||
return !PSP_IsInited();
|
||||
}).OnChange([requestLocalNetwork](UI::EventParams &e) {
|
||||
requestLocalNetwork(e);
|
||||
// Wake the UPnP service thread so it connects (or tears its mappings back down) right
|
||||
// away, instead of waiting for a port request that may never come.
|
||||
UPnP_Notify();
|
||||
});
|
||||
page->Setting(&g_Config.bUPnPUseOriginalPort).Enabled(&g_Config.bEnableUPnP);
|
||||
page->Hint({ I18NCat::NETWORKING, "UseOriginalPort Tip", "May not work for all devices or games, see wiki." });
|
||||
|
||||
page->Header("Chat");
|
||||
page->Setting(&g_Config.bEnableNetworkChat);
|
||||
page->Setting(&g_Config.iChatButtonPosition).Enabled(&g_Config.bEnableNetworkChat);
|
||||
page->Setting(&g_Config.iChatScreenPosition).Enabled(&g_Config.bEnableNetworkChat);
|
||||
page->Setting(&g_Config.bChatTimestamps).Enabled(&g_Config.bEnableNetworkChat);
|
||||
|
||||
page->Header("Quick chat");
|
||||
page->Setting(&g_Config.bEnableQuickChat).Enabled(&g_Config.bEnableNetworkChat);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
page->Custom("Quick chat %1", [host, i](UI::ViewGroup *parent) -> UI::View * {
|
||||
return parent->Add(new PopupTextInputChoice(host->PageRequesterToken(), &g_Config.sQuickChat[i], ApplySafeSubstitutions(T(I18NCat::NETWORKING, "Quick chat %1"), i + 1), "", 32, host->PageScreenManager()));
|
||||
}).EnabledFunc([] {
|
||||
return g_Config.bEnableQuickChat && g_Config.bEnableNetworkChat;
|
||||
});
|
||||
}
|
||||
|
||||
page->Header({ I18NCat::NETWORKING, "Misc", "Misc (default = compatibility)" });
|
||||
page->Choice("Open PPSSPP Multiplayer Wiki Page", ImageID("I_LINK_OUT")).OnClick([](EventParams &e) {
|
||||
auto n = GetI18NCategory(I18NCat::NETWORKING);
|
||||
std::string url(n->T("MultiplayerHowToURL", "https://github.com/hrydgard/ppsspp/wiki/How-to-play-multiplayer-games-with-PPSSPP"));
|
||||
System_LaunchUrl(LaunchUrlType::BROWSER_URL, url);
|
||||
});
|
||||
static const char *wlanChannels[] = {"Auto", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"};
|
||||
page->Setting(&g_Config.iWlanAdhocChannel).Setup([](View *view) {
|
||||
PopupMultiChoice *wlanChannelChoice = static_cast<PopupMultiChoice *>(view);
|
||||
wlanChannelChoice->SetChoicesUntranslated(1, (int)ARRAY_SIZE(wlanChannels) - 1);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
wlanChannelChoice->HideChoice(i + 2);
|
||||
wlanChannelChoice->HideChoice(i + 7);
|
||||
}
|
||||
});
|
||||
page->Setting(&g_Config.iPortOffset);
|
||||
page->Hint("PortOffsetHint");
|
||||
page->Setting(&g_Config.iMinTimeout);
|
||||
page->Setting(&g_Config.bForcedFirstConnect);
|
||||
page->Setting(&g_Config.bAllowSpeedControlWhileConnected);
|
||||
if (Discord::IsAvailable()) {
|
||||
page->Setting(&g_Config.bDiscordRichPresence);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/UI/ScreenManager.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "UI/DeveloperSettingsPages.h"
|
||||
#include "UI/FirmwareScreen.h"
|
||||
#include "UI/RemoteISOScreen.h"
|
||||
#include "UI/RetroAchievementScreens.h"
|
||||
#include "UI/SavedataScreen.h"
|
||||
#include "UI/SettingsPage.h"
|
||||
#include "UI/Settings/MainSettingsPages.h"
|
||||
#include "UI/SystemInfoScreen.h"
|
||||
|
||||
void BuildToolsSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
SettingsPageHost *host = page->Host();
|
||||
|
||||
page->Header("Tools");
|
||||
|
||||
const bool showRetroAchievements = System_GetPropertyInt(SYSPROP_DEVICE_TYPE) != DEVICE_TYPE_VR;
|
||||
if (showRetroAchievements) {
|
||||
page->Choice({ I18NCat::SYSTEM, "RetroAchievements" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new RetroAchievementsSettingsScreen(host->PageGamePath()));
|
||||
}).Setup([](View *view) {
|
||||
static_cast<Choice *>(view)->SetIconRight(ImageID("I_RETROACHIEVEMENTS_LOGO"));
|
||||
});
|
||||
}
|
||||
|
||||
// These were moved here so use the wrong translation objects, to avoid having to change all inis... This isn't a sustainable situation :P
|
||||
page->Choice({ I18NCat::SAVEDATA, "Savedata Manager" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new SavedataScreen(host->PageGamePath()));
|
||||
});
|
||||
page->Choice({ I18NCat::DEVELOPER, "System Information" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new SystemInfoScreen(host->PageGamePath()));
|
||||
});
|
||||
page->Link({ I18NCat::SYSTEM, "Developer Tools" }, I18NCat::DEVELOPER, &BuildDeveloperToolsPage);
|
||||
page->Choice({ I18NCat::REMOTEISO, "Remote disc streaming" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new RemoteISOScreen(host->PageGamePath()));
|
||||
});
|
||||
page->Choice({ I18NCat::SYSTEM, "PSP Firmware" }).OnClick([host](UI::EventParams &) {
|
||||
host->PageScreenManager()->push(new FirmwareScreen(host->PageGamePath()));
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2012- PPSSPP Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0 or later versions.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "Common/System/System.h"
|
||||
#include "Common/VR/PPSSPPVR.h"
|
||||
#include "Core/Config.h"
|
||||
#include "UI/SettingsPage.h"
|
||||
#include "UI/Settings/MainSettingsPages.h"
|
||||
|
||||
void BuildVRSettings(SettingsPage *page) {
|
||||
using namespace UI;
|
||||
|
||||
int deviceType = System_GetPropertyInt(SYSPROP_DEVICE_TYPE);
|
||||
|
||||
if (deviceType == DEVICE_TYPE_VR) {
|
||||
page->Header("Virtual reality");
|
||||
page->Setting(&g_Config.bEnableVR);
|
||||
page->Setting(&g_Config.bEnable6DoF);
|
||||
page->Setting(&g_Config.bEnableStereo);
|
||||
page->Setting(&g_Config.bEnableImmersiveVR);
|
||||
if (IsPassthroughSupported()) {
|
||||
page->Setting(&g_Config.bPassthrough);
|
||||
}
|
||||
page->Setting(&g_Config.bForce72Hz);
|
||||
}
|
||||
|
||||
page->Header("VR camera");
|
||||
if (deviceType == DEVICE_TYPE_VR) {
|
||||
page->Setting(&g_Config.fCanvasDistance);
|
||||
page->Setting(&g_Config.fCanvas3DDistance);
|
||||
}
|
||||
page->Setting(&g_Config.fFieldOfViewPercentage);
|
||||
page->Setting(&g_Config.bRescaleHUD);
|
||||
page->Setting(&g_Config.fHeadUpDisplayScale).Enabled(&g_Config.bRescaleHUD);
|
||||
page->Setting(&g_Config.bManualForceVR);
|
||||
}
|
||||
+9
-2
@@ -36,7 +36,7 @@
|
||||
<ClCompile Include="CustomButtonMappingScreen.cpp" />
|
||||
<ClCompile Include="CwCheatScreen.cpp" />
|
||||
<ClCompile Include="DebugOverlay.cpp" />
|
||||
<ClCompile Include="DeveloperToolsScreen.cpp" />
|
||||
<ClCompile Include="DeveloperSettingsPages.cpp" />
|
||||
<ClCompile Include="DevScreens.cpp" />
|
||||
<ClCompile Include="DiscordIntegration.cpp" />
|
||||
<ClCompile Include="DisplayLayoutScreen.cpp" />
|
||||
@@ -78,6 +78,12 @@
|
||||
<ClCompile Include="SystemInfoScreen.cpp" />
|
||||
<ClCompile Include="TabbedDialogScreen.cpp" />
|
||||
<ClCompile Include="SettingsPage.cpp" />
|
||||
<ClCompile Include="Settings\GraphicsPage.cpp" />
|
||||
<ClCompile Include="Settings\ControlsPage.cpp" />
|
||||
<ClCompile Include="Settings\AudioPage.cpp" />
|
||||
<ClCompile Include="Settings\NetworkingPage.cpp" />
|
||||
<ClCompile Include="Settings\ToolsPage.cpp" />
|
||||
<ClCompile Include="Settings\VRPage.cpp" />
|
||||
<ClCompile Include="SettingsPagesDialogScreen.cpp" />
|
||||
<ClCompile Include="SimpleDialogScreen.cpp" />
|
||||
<ClCompile Include="TiltAnalogSettingsScreen.cpp" />
|
||||
@@ -101,7 +107,7 @@
|
||||
<ClInclude Include="ControlMappingScreen.h" />
|
||||
<ClInclude Include="CustomButtonMappingScreen.h" />
|
||||
<ClInclude Include="DebugOverlay.h" />
|
||||
<ClInclude Include="DeveloperToolsScreen.h" />
|
||||
<ClInclude Include="DeveloperSettingsPages.h" />
|
||||
<ClInclude Include="DevScreens.h" />
|
||||
<ClInclude Include="DiscordIntegration.h" />
|
||||
<ClInclude Include="DisplayLayoutScreen.h" />
|
||||
@@ -143,6 +149,7 @@
|
||||
<ClInclude Include="SystemInfoScreen.h" />
|
||||
<ClInclude Include="TabbedDialogScreen.h" />
|
||||
<ClInclude Include="SettingsPage.h" />
|
||||
<ClInclude Include="Settings\MainSettingsPages.h" />
|
||||
<ClInclude Include="SettingsPagesDialogScreen.h" />
|
||||
<ClInclude Include="TiltAnalogSettingsScreen.h" />
|
||||
<ClInclude Include="TouchControlLayoutScreen.h" />
|
||||
|
||||
+26
-2
@@ -105,6 +105,24 @@
|
||||
<ClCompile Include="SettingsPage.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Settings\GraphicsPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Settings\ControlsPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Settings\AudioPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Settings\NetworkingPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Settings\ToolsPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Settings\VRPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SettingsPagesDialogScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
@@ -141,7 +159,7 @@
|
||||
<ClCompile Include="ImDebugger\ImConsole.cpp">
|
||||
<Filter>ImDebugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DeveloperToolsScreen.cpp">
|
||||
<ClCompile Include="DeveloperSettingsPages.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UIAtlas.cpp" />
|
||||
@@ -275,6 +293,9 @@
|
||||
<ClInclude Include="SettingsPage.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Settings\MainSettingsPages.h">
|
||||
<Filter>Settings</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingsPagesDialogScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
@@ -308,7 +329,7 @@
|
||||
<ClInclude Include="ImDebugger\ImConsole.h">
|
||||
<Filter>ImDebugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DeveloperToolsScreen.h">
|
||||
<ClInclude Include="DeveloperSettingsPages.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UIAtlas.h" />
|
||||
@@ -345,6 +366,9 @@
|
||||
<Filter Include="Screens">
|
||||
<UniqueIdentifier>{faee5dce-633b-4ba6-b19d-ea70ee3c1c38}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Settings">
|
||||
<UniqueIdentifier>{16cf6f47-da0b-421f-99a3-c934d3edc1a4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Views">
|
||||
<UniqueIdentifier>{071baa63-c681-4ad6-945b-e126645d1b55}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<ClInclude Include="..\..\UI\CustomButtonMappingScreen.h" />
|
||||
<ClInclude Include="..\..\UI\CwCheatScreen.h" />
|
||||
<ClInclude Include="..\..\UI\DebugOverlay.h" />
|
||||
<ClInclude Include="..\..\UI\DeveloperToolsScreen.h" />
|
||||
<ClInclude Include="..\..\UI\DeveloperSettingsPages.h" />
|
||||
<ClInclude Include="..\..\UI\DevScreens.h" />
|
||||
<ClInclude Include="..\..\UI\DiscordIntegration.h" />
|
||||
<ClInclude Include="..\..\UI\DisplayLayoutScreen.h" />
|
||||
@@ -126,6 +126,7 @@
|
||||
<ClInclude Include="..\..\UI\SystemInfoScreen.h" />
|
||||
<ClInclude Include="..\..\UI\TabbedDialogScreen.h" />
|
||||
<ClInclude Include="..\..\UI\SettingsPage.h" />
|
||||
<ClInclude Include="..\..\UI\Settings\MainSettingsPages.h" />
|
||||
<ClInclude Include="..\..\UI\SettingsPagesDialogScreen.h" />
|
||||
<ClInclude Include="..\..\UI\RetroAchievementScreens.h" />
|
||||
<ClInclude Include="..\..\UI\Theme.h" />
|
||||
@@ -160,7 +161,7 @@
|
||||
<ClCompile Include="..\..\UI\CustomButtonMappingScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\CwCheatScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\DebugOverlay.cpp" />
|
||||
<ClCompile Include="..\..\UI\DeveloperToolsScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\DeveloperSettingsPages.cpp" />
|
||||
<ClCompile Include="..\..\UI\DevScreens.cpp" />
|
||||
<ClCompile Include="..\..\UI\DiscordIntegration.cpp" />
|
||||
<ClCompile Include="..\..\UI\DisplayLayoutScreen.cpp" />
|
||||
@@ -191,6 +192,12 @@
|
||||
<ClCompile Include="..\..\UI\SystemInfoScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\TabbedDialogScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\SettingsPage.cpp" />
|
||||
<ClCompile Include="..\..\UI\Settings\GraphicsPage.cpp" />
|
||||
<ClCompile Include="..\..\UI\Settings\ControlsPage.cpp" />
|
||||
<ClCompile Include="..\..\UI\Settings\AudioPage.cpp" />
|
||||
<ClCompile Include="..\..\UI\Settings\NetworkingPage.cpp" />
|
||||
<ClCompile Include="..\..\UI\Settings\ToolsPage.cpp" />
|
||||
<ClCompile Include="..\..\UI\Settings\VRPage.cpp" />
|
||||
<ClCompile Include="..\..\UI\SettingsPagesDialogScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\SimpleDialogScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\RetroAchievementScreens.cpp" />
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<ClCompile Include="..\..\UI\CwCheatScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\DeveloperToolsScreen.cpp">
|
||||
<ClCompile Include="..\..\UI\DeveloperSettingsPages.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\DevScreens.cpp">
|
||||
@@ -134,6 +134,24 @@
|
||||
<ClCompile Include="..\..\UI\SettingsPage.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\Settings\GraphicsPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\Settings\ControlsPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\Settings\AudioPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\Settings\NetworkingPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\Settings\ToolsPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\Settings\VRPage.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\UI\SettingsPagesDialogScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
@@ -209,7 +227,7 @@
|
||||
<ClInclude Include="..\..\UI\CwCheatScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\UI\DeveloperToolsScreen.h">
|
||||
<ClInclude Include="..\..\UI\DeveloperSettingsPages.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\UI\DevScreens.h">
|
||||
@@ -296,6 +314,9 @@
|
||||
<ClInclude Include="..\..\UI\SettingsPage.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\UI\Settings\MainSettingsPages.h">
|
||||
<Filter>Settings</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\UI\SettingsPagesDialogScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
@@ -328,5 +349,8 @@
|
||||
<Filter Include="Screens">
|
||||
<UniqueIdentifier>{38b8413d-438d-4197-9db8-7bd123fc7431}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Settings">
|
||||
<UniqueIdentifier>{5898f2e1-ea5b-45dc-a02d-17a4de26650b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1025,6 +1025,12 @@ LOCAL_SRC_FILES := \
|
||||
$(SRC)/UI/MainScreen.cpp \
|
||||
$(SRC)/UI/TabbedDialogScreen.cpp \
|
||||
$(SRC)/UI/SettingsPage.cpp \
|
||||
$(SRC)/UI/Settings/GraphicsPage.cpp \
|
||||
$(SRC)/UI/Settings/ControlsPage.cpp \
|
||||
$(SRC)/UI/Settings/AudioPage.cpp \
|
||||
$(SRC)/UI/Settings/NetworkingPage.cpp \
|
||||
$(SRC)/UI/Settings/ToolsPage.cpp \
|
||||
$(SRC)/UI/Settings/VRPage.cpp \
|
||||
$(SRC)/UI/SettingsPagesDialogScreen.cpp \
|
||||
$(SRC)/UI/AdhocServerScreen.cpp \
|
||||
$(SRC)/UI/SimpleDialogScreen.cpp \
|
||||
@@ -1048,7 +1054,7 @@ LOCAL_SRC_FILES := \
|
||||
$(SRC)/UI/UploadScreen.cpp \
|
||||
$(SRC)/UI/ControlMappingScreen.cpp \
|
||||
$(SRC)/UI/GameSettingsScreen.cpp \
|
||||
$(SRC)/UI/DeveloperToolsScreen.cpp \
|
||||
$(SRC)/UI/DeveloperSettingsPages.cpp \
|
||||
$(SRC)/UI/GPUDriverTestScreen.cpp \
|
||||
$(SRC)/UI/TiltAnalogSettingsScreen.cpp \
|
||||
$(SRC)/UI/TouchControlLayoutScreen.cpp \
|
||||
|
||||
@@ -294,7 +294,7 @@ file - this is just an index.
|
||||
## Enabling it
|
||||
|
||||
- **UI**: Settings > Tools > Developer Tools > "Allow remote debugger"
|
||||
checkbox (`UI/DeveloperToolsScreen.cpp`). The "Local Server Port" slider on
|
||||
checkbox (`UI/DeveloperSettingsPages.cpp`). The "Local Server Port" slider on
|
||||
the Networking screen sets the port (shared with Remote ISO sharing; `0` =
|
||||
auto-pick).
|
||||
- **Config**: `RemoteDebuggerOnStartup=true` in `ppsspp.ini`
|
||||
|
||||
Reference in new issue
Block a user