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:
Henrik Rydgård authored and GitHub committed 2026-10-25 16:25:30 +01:00
commit 588d2e5745
17 files changed
+1231 -919

No files matched your search

+9 -2
View File
@@ -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
View File
@@ -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) {
+182
View File
@@ -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));
}
}
+161
View File
@@ -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();
}
}
}
+381
View File
@@ -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);
});
}
+37
View File
@@ -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);
+270
View File
@@ -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);
}
}
+60
View File
@@ -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()));
});
}
+50
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+9 -2
View File
@@ -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" />
+26 -2
View File
@@ -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>
+7 -1
View File
@@ -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 \
+1 -1
View File
@@ -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`