mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-01 12:07:31 +01:00
These were looked up in a different section from the one with the translation, so they always showed in English (the savedata error messages, "Done!" after moving the memstick, "Switch UMD", "Ask for network permission" and others). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1312 lines
47 KiB
C++
1312 lines
47 KiB
C++
#include "ppsspp_config.h"
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <unordered_map>
|
|
|
|
#include "resource.h"
|
|
|
|
#include "Common/GPU/OpenGL/GLFeatures.h"
|
|
|
|
#include "Common/Data/Text/I18n.h"
|
|
#include "Common/Data/Encoding/Utf8.h"
|
|
#include "Common/System/System.h"
|
|
#include "Common/System/OSD.h"
|
|
#include "Common/System/Request.h"
|
|
#include "Common/System/Display.h"
|
|
#include "Common/File/FileUtil.h"
|
|
#include "Common/Log.h"
|
|
#include "Common/Log/LogManager.h"
|
|
#include "Common/Log/ConsoleListener.h"
|
|
#include "Common/StringUtils.h"
|
|
#if PPSSPP_API(ANY_GL)
|
|
#include "GPU/GLES/TextureCacheGLES.h"
|
|
#include "GPU/GLES/FramebufferManagerGLES.h"
|
|
#endif
|
|
#include "GPU/Common/PostShader.h"
|
|
#include "GPU/Common/TextureScalerCommon.h"
|
|
|
|
#include "Core/Config.h"
|
|
#include "Core/ConfigValues.h"
|
|
#include "Core/FileSystems/MetaFileSystem.h"
|
|
#include "Core/KeyMap.h"
|
|
#include "Core/Screenshot.h"
|
|
#include "Windows/MainWindowMenu.h"
|
|
#include "Windows/MainWindow.h"
|
|
#include "Windows/W32Util/DialogManager.h"
|
|
#include "Windows/W32Util/ShellUtil.h"
|
|
#include "Windows/W32Util/Misc.h"
|
|
#include "Windows/InputBox.h"
|
|
#include "Windows/main.h"
|
|
#include "Windows/W32Util/DarkMode.h"
|
|
|
|
#include "Core/HLE/sceUmd.h"
|
|
#include "Core/HLE/sceNet.h"
|
|
#include "Core/SaveState.h"
|
|
#include "Core/Core.h"
|
|
#include "Core/RetroAchievements.h"
|
|
#include "UI/PauseScreen.h"
|
|
|
|
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
|
|
#include "ext/rcheevos/include/rc_client_raintegration.h"
|
|
#endif
|
|
|
|
namespace MainWindow {
|
|
extern bool noFocusPause;
|
|
std::vector<HMENU> g_topLevelMenus;
|
|
HMENU g_hMenuBackend;
|
|
|
|
static std::unordered_map<int, std::string> initialMenuKeys;
|
|
static std::vector<std::string> availableShaders;
|
|
static std::string menuLanguageID = "";
|
|
static int menuKeymapGeneration = -1;
|
|
std::vector<ShaderInfo> menuShaderInfo;
|
|
|
|
LRESULT CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
void SetIngameMenuItemStates(HMENU menu, const GlobalUIState state) {
|
|
const bool menuEnableBool = state == UISTATE_INGAME || state == UISTATE_EXCEPTION;
|
|
|
|
bool loadStateEnableBool = menuEnableBool;
|
|
bool saveStateEnableBool = menuEnableBool;
|
|
if (Achievements::HardcoreModeActive()) {
|
|
loadStateEnableBool = false;
|
|
if (!g_Config.bAchievementsSaveStateInHardcoreMode) {
|
|
saveStateEnableBool = false;
|
|
}
|
|
}
|
|
|
|
if (!NetworkAllowSaveState()) {
|
|
loadStateEnableBool = false;
|
|
saveStateEnableBool = false;
|
|
}
|
|
|
|
const UINT menuEnable = menuEnableBool ? MF_ENABLED : MF_GRAYED;
|
|
const UINT loadStateEnable = loadStateEnableBool ? MF_ENABLED : MF_GRAYED;
|
|
const UINT saveStateEnable = saveStateEnableBool ? MF_ENABLED : MF_GRAYED;
|
|
const UINT menuInGameEnable = state == UISTATE_INGAME ? MF_ENABLED : MF_GRAYED;
|
|
const UINT umdSwitchEnable = state == UISTATE_INGAME && getUMDReplacePermit() ? MF_ENABLED : MF_GRAYED;
|
|
const UINT debugEnable = !Achievements::HardcoreModeActive() ? MF_ENABLED : MF_GRAYED;
|
|
const UINT debugIngameEnable = (state == UISTATE_INGAME && !Achievements::HardcoreModeActive()) ? MF_ENABLED : MF_GRAYED;
|
|
|
|
EnableMenuItem(menu, ID_FILE_SAVESTATE_SLOT_MENU, saveStateEnable);
|
|
EnableMenuItem(menu, ID_FILE_SAVESTATEFILE, saveStateEnable);
|
|
EnableMenuItem(menu, ID_FILE_LOADSTATEFILE, loadStateEnable);
|
|
EnableMenuItem(menu, ID_FILE_QUICKSAVESTATE, saveStateEnable);
|
|
EnableMenuItem(menu, ID_FILE_QUICKLOADSTATE, loadStateEnable);
|
|
EnableMenuItem(menu, ID_EMULATION_PAUSE, menuEnable);
|
|
EnableMenuItem(menu, ID_EMULATION_STOP, menuEnable);
|
|
EnableMenuItem(menu, ID_EMULATION_RESET, menuEnable);
|
|
EnableMenuItem(menu, ID_EMULATION_SWITCH_UMD, umdSwitchEnable);
|
|
EnableMenuItem(menu, ID_EMULATION_CHAT, g_Config.bEnableNetworkChat ? menuInGameEnable : MF_GRAYED);
|
|
EnableMenuItem(menu, ID_TOGGLE_BREAK, debugIngameEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_LOADMAPFILE, debugIngameEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_SAVEMAPFILE, debugIngameEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_LOADSYMFILE, debugIngameEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_SAVESYMFILE, debugIngameEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_RESETSYMBOLTABLE, debugIngameEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_SHOWDEBUGSTATISTICS, debugEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_EXTRACTFILE, menuEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_MEMORYBASE, menuInGameEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_DISASSEMBLY, debugEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_MEMORYVIEW, debugEnable);
|
|
EnableMenuItem(menu, ID_DEBUG_GEDEBUGGER, debugEnable);
|
|
|
|
// While playing, this pop up doesn't work - and probably doesn't make sense.
|
|
EnableMenuItem(menu, ID_OPTIONS_LANGUAGE, state == UISTATE_INGAME ? MF_GRAYED : MF_ENABLED);
|
|
}
|
|
|
|
static HMENU GetSubmenuById(HMENU menu, int menuID) {
|
|
MENUITEMINFO menuInfo{ sizeof(MENUITEMINFO), MIIM_SUBMENU };
|
|
if (GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo) != FALSE) {
|
|
return menuInfo.hSubMenu;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
static void ClearSubMenu(HMENU menu) {
|
|
const int count = GetMenuItemCount(menu);
|
|
for (int i = count - 1; i >= 0; --i) {
|
|
RemoveMenu(menu, i, MF_BYPOSITION);
|
|
}
|
|
}
|
|
|
|
static std::string GetMenuItemText(HMENU menu, int menuID) {
|
|
MENUITEMINFO menuInfo{ sizeof(menuInfo), MIIM_STRING };
|
|
std::string retVal;
|
|
if (GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo) != FALSE) {
|
|
menuInfo.cch++; // account for null terminator
|
|
std::vector<wchar_t> buffer(menuInfo.cch);
|
|
menuInfo.dwTypeData = buffer.data();
|
|
GetMenuItemInfo(menu, menuID, MF_BYCOMMAND, &menuInfo);
|
|
retVal = ConvertWStringToUTF8(menuInfo.dwTypeData); // note, this is buffer.
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
const std::string &GetMenuItemInitialText(HMENU menu, const int menuID) {
|
|
if (initialMenuKeys.find(menuID) == initialMenuKeys.end()) {
|
|
initialMenuKeys[menuID] = GetMenuItemText(menu, menuID);
|
|
}
|
|
return initialMenuKeys[menuID];
|
|
}
|
|
|
|
void MainMenuInit(HWND hwndMain, HMENU hMenu) {
|
|
MENUINFO info;
|
|
ZeroMemory(&info, sizeof(MENUINFO));
|
|
info.cbSize = sizeof(MENUINFO);
|
|
info.cyMax = 0;
|
|
info.dwStyle = MNS_CHECKORBMP;
|
|
info.fMask = MIM_STYLE;
|
|
g_topLevelMenus.clear();
|
|
for (int i = 0; i < GetMenuItemCount(hMenu); i++) {
|
|
HMENU subMenu = GetSubMenu(hMenu, i);
|
|
SetMenuInfo(subMenu, &info);
|
|
g_topLevelMenus.push_back(subMenu);
|
|
}
|
|
|
|
// Always translate first: translating resets the menu.
|
|
TranslateMenus(hwndMain, hMenu);
|
|
// Don't need to update here, happens later.
|
|
|
|
HMENU helpMenu = GetSubmenuById(hMenu, ID_HELP_MENU);
|
|
if (System_GetPropertyBool(SYSPROP_APP_GOLD)) {
|
|
RemoveMenu(helpMenu, ID_HELP_BUYGOLD, MF_BYCOMMAND);
|
|
}
|
|
|
|
HMENU hMenuOptions = GetSubmenuById(hMenu, ID_OPTIONS_MENU);
|
|
g_hMenuBackend = GetSubmenuById(hMenuOptions, ID_OPTIONS_BACKEND_MENU);
|
|
}
|
|
|
|
static void TranslateMenuItem(const HMENU hMenu, const int menuID, const std::wstring& accelerator = L"", const char *key = nullptr) {
|
|
auto des = GetI18NCategory(I18NCat::DESKTOPUI);
|
|
|
|
std::wstring translated;
|
|
if (key == nullptr || !strcmp(key, "")) {
|
|
std::string_view initialText = GetMenuItemInitialText(hMenu, menuID);
|
|
if (!initialText.empty()) {
|
|
translated = ConvertUTF8ToWString(des->T(initialText));
|
|
}
|
|
} else {
|
|
translated = ConvertUTF8ToWString(des->T(key));
|
|
}
|
|
translated.append(accelerator);
|
|
|
|
ModifyMenu(hMenu, menuID, MF_STRING | MF_BYCOMMAND, menuID, translated.c_str());
|
|
}
|
|
|
|
void DoTranslateMenus(HWND hWnd, HMENU menu) {
|
|
auto useDefHotkey = [](int virtKey) {
|
|
return !KeyMap::PspButtonHasMappings(virtKey);
|
|
};
|
|
|
|
TranslateMenuItem(menu, ID_FILE_MENU);
|
|
TranslateMenuItem(menu, ID_EMULATION_MENU);
|
|
TranslateMenuItem(menu, ID_DEBUG_MENU);
|
|
TranslateMenuItem(menu, ID_OPTIONS_MENU);
|
|
TranslateMenuItem(menu, ID_HELP_MENU);
|
|
|
|
// File menu
|
|
TranslateMenuItem(menu, ID_FILE_LOAD);
|
|
TranslateMenuItem(menu, ID_FILE_LOAD_DIR);
|
|
TranslateMenuItem(menu, ID_FILE_LOAD_MEMSTICK);
|
|
TranslateMenuItem(menu, ID_FILE_OPEN_NEW_INSTANCE);
|
|
TranslateMenuItem(menu, ID_FILE_MEMSTICK);
|
|
TranslateMenuItem(menu, ID_FILE_SAVESTATE_SLOT_MENU, useDefHotkey(VIRTKEY_NEXT_SLOT) ? L"\tF3" : L"");
|
|
TranslateMenuItem(menu, ID_FILE_QUICKLOADSTATE, useDefHotkey(VIRTKEY_LOAD_STATE) ? L"\tF4" : L"");
|
|
TranslateMenuItem(menu, ID_FILE_QUICKSAVESTATE, useDefHotkey(VIRTKEY_SAVE_STATE) ? L"\tF2" : L"");
|
|
TranslateMenuItem(menu, ID_FILE_LOADSTATEFILE);
|
|
TranslateMenuItem(menu, ID_FILE_SAVESTATEFILE);
|
|
TranslateMenuItem(menu, ID_FILE_RECORD_MENU);
|
|
TranslateMenuItem(menu, ID_FILE_EXIT, L"\tAlt+F4");
|
|
|
|
// Emulation menu
|
|
TranslateMenuItem(menu, ID_EMULATION_PAUSE);
|
|
TranslateMenuItem(menu, ID_EMULATION_STOP, g_Config.bSystemControls ? L"\tCtrl+W" : L"");
|
|
TranslateMenuItem(menu, ID_EMULATION_RESET, g_Config.bSystemControls ? L"\tCtrl+B" : L"");
|
|
TranslateMenuItem(menu, ID_EMULATION_SWITCH_UMD, g_Config.bSystemControls ? L"\tCtrl+U" : L"");
|
|
TranslateMenuItem(menu, ID_EMULATION_ROTATION_MENU);
|
|
TranslateMenuItem(menu, ID_EMULATION_ROTATION_H);
|
|
TranslateMenuItem(menu, ID_EMULATION_ROTATION_V);
|
|
TranslateMenuItem(menu, ID_EMULATION_ROTATION_H_R);
|
|
TranslateMenuItem(menu, ID_EMULATION_ROTATION_V_R);
|
|
|
|
// Debug menu
|
|
TranslateMenuItem(menu, ID_TOGGLE_BREAK, g_Config.bSystemControls ? L"\tF8" : L"", "Break");
|
|
TranslateMenuItem(menu, ID_DEBUG_BREAKONLOAD);
|
|
TranslateMenuItem(menu, ID_DEBUG_IGNOREILLEGALREADS);
|
|
TranslateMenuItem(menu, ID_DEBUG_LOADMAPFILE);
|
|
TranslateMenuItem(menu, ID_DEBUG_SAVEMAPFILE);
|
|
TranslateMenuItem(menu, ID_DEBUG_LOADSYMFILE);
|
|
TranslateMenuItem(menu, ID_DEBUG_SAVESYMFILE);
|
|
TranslateMenuItem(menu, ID_DEBUG_RESETSYMBOLTABLE);
|
|
TranslateMenuItem(menu, ID_DEBUG_TAKESCREENSHOT); // TODO: Automatically show the bound key.
|
|
TranslateMenuItem(menu, ID_DEBUG_SAVEFRAMEDUMP);
|
|
TranslateMenuItem(menu, ID_DEBUG_SHOWDEBUGSTATISTICS);
|
|
TranslateMenuItem(menu, ID_DEBUG_RESTARTGRAPHICS);
|
|
TranslateMenuItem(menu, ID_DEBUG_DISASSEMBLY, g_Config.bSystemControls ? L"\tCtrl+D" : L"");
|
|
TranslateMenuItem(menu, ID_DEBUG_GEDEBUGGER, g_Config.bSystemControls ? L"\tCtrl+G" : L"");
|
|
TranslateMenuItem(menu, ID_DEBUG_EXTRACTFILE);
|
|
TranslateMenuItem(menu, ID_DEBUG_LOG, g_Config.bSystemControls ? L"\tCtrl+L" : L"");
|
|
TranslateMenuItem(menu, ID_DEBUG_MEMORYBASE);
|
|
TranslateMenuItem(menu, ID_DEBUG_MEMORYVIEW, g_Config.bSystemControls ? L"\tCtrl+M" : L"");
|
|
|
|
// Options menu
|
|
TranslateMenuItem(menu, ID_OPTIONS_LANGUAGE);
|
|
TranslateMenuItem(menu, ID_OPTIONS_TOPMOST);
|
|
TranslateMenuItem(menu, ID_OPTIONS_PAUSE_FOCUS);
|
|
TranslateMenuItem(menu, ID_OPTIONS_IGNOREWINKEY);
|
|
TranslateMenuItem(menu, ID_OPTIONS_MORE_SETTINGS);
|
|
TranslateMenuItem(menu, ID_OPTIONS_CONTROLS);
|
|
TranslateMenuItem(menu, ID_OPTIONS_DISPLAY_LAYOUT);
|
|
|
|
// Movie menu
|
|
TranslateMenuItem(menu, ID_FILE_DUMPFRAMES);
|
|
TranslateMenuItem(menu, ID_FILE_DUMP_VIDEO_OUTPUT);
|
|
TranslateMenuItem(menu, ID_FILE_DUMPAUDIO);
|
|
|
|
// Skip display multipliers x1-x10
|
|
TranslateMenuItem(menu, ID_OPTIONS_FULLSCREEN, g_Config.bSystemControls ? L"\tAlt+Return, F11" : L"");
|
|
TranslateMenuItem(menu, ID_OPTIONS_VSYNC);
|
|
TranslateMenuItem(menu, ID_OPTIONS_SCREEN_MENU, g_Config.bSystemControls ? L"\tCtrl+1" : L"");
|
|
TranslateMenuItem(menu, ID_OPTIONS_SCREENAUTO);
|
|
// Skip rendering resolution 2x-5x..
|
|
TranslateMenuItem(menu, ID_OPTIONS_WINDOW_MENU);
|
|
// Skip window size 1x-4x..
|
|
TranslateMenuItem(menu, ID_OPTIONS_BACKEND_MENU);
|
|
TranslateMenuItem(menu, ID_OPTIONS_DIRECT3D11);
|
|
TranslateMenuItem(menu, ID_OPTIONS_OPENGL);
|
|
TranslateMenuItem(menu, ID_OPTIONS_VULKAN);
|
|
|
|
TranslateMenuItem(menu, ID_OPTIONS_RENDERMODE_MENU);
|
|
TranslateMenuItem(menu, ID_OPTIONS_SKIP_BUFFER_EFFECTS);
|
|
TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_MENU, g_Config.bSystemControls ? L"\tF7" : L"");
|
|
TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_AUTO);
|
|
TranslateMenuItem(menu, ID_OPTIONS_FRAMESKIP_0);
|
|
// Skip frameskipping 1-8..
|
|
TranslateMenuItem(menu, ID_OPTIONS_TEXTUREFILTERING_MENU);
|
|
TranslateMenuItem(menu, ID_OPTIONS_TEXTUREFILTERING_AUTO);
|
|
TranslateMenuItem(menu, ID_OPTIONS_NEARESTFILTERING);
|
|
TranslateMenuItem(menu, ID_OPTIONS_LINEARFILTERING);
|
|
TranslateMenuItem(menu, ID_OPTIONS_AUTOMAXQUALITYFILTERING);
|
|
TranslateMenuItem(menu, ID_OPTIONS_SMART2DTEXTUREFILTERING);
|
|
TranslateMenuItem(menu, ID_OPTIONS_SCREENFILTER_MENU);
|
|
TranslateMenuItem(menu, ID_OPTIONS_BUFLINEARFILTER);
|
|
TranslateMenuItem(menu, ID_OPTIONS_BUFNEARESTFILTER);
|
|
TranslateMenuItem(menu, ID_OPTIONS_TEXTURESCALING_MENU);
|
|
TranslateMenuItem(menu, ID_TEXTURESCALING_OFF);
|
|
// Skip texture scaling 2x-5x...
|
|
TranslateMenuItem(menu, ID_TEXTURESCALING_XBRZ);
|
|
TranslateMenuItem(menu, ID_TEXTURESCALING_HYBRID);
|
|
TranslateMenuItem(menu, ID_TEXTURESCALING_BICUBIC);
|
|
TranslateMenuItem(menu, ID_TEXTURESCALING_HYBRID_BICUBIC);
|
|
TranslateMenuItem(menu, ID_TEXTURESCALING_DEPOSTERIZE);
|
|
TranslateMenuItem(menu, ID_EMULATION_SOUND);
|
|
TranslateMenuItem(menu, ID_EMULATION_CHEATS, g_Config.bSystemControls ? L"\tCtrl+T" : L"");
|
|
TranslateMenuItem(menu, ID_EMULATION_CHAT, g_Config.bSystemControls ? L"\tCtrl+C" : L"");
|
|
|
|
// Help menu: it's translated in CreateHelpMenu.
|
|
TranslateMenuItem(menu, ID_HELP_OPENWEBSITE);
|
|
TranslateMenuItem(menu, ID_HELP_OPENFORUM);
|
|
TranslateMenuItem(menu, ID_HELP_BUYGOLD);
|
|
TranslateMenuItem(menu, ID_HELP_GITHUB);
|
|
TranslateMenuItem(menu, ID_HELP_DISCORD);
|
|
TranslateMenuItem(menu, ID_HELP_ABOUT);
|
|
}
|
|
|
|
void TranslateMenus(HWND hWnd, HMENU menu) {
|
|
|
|
const std::string curLanguageID = g_i18nrepo.LanguageID();
|
|
if (curLanguageID != menuLanguageID || KeyMap::HasChanged(menuKeymapGeneration)) {
|
|
DoTranslateMenus(hWnd, menu);
|
|
menuLanguageID = curLanguageID;
|
|
}
|
|
|
|
// Dynamically create the save state slot selector menu.
|
|
// TODO: In the future, maybe change it to separate save and load submenus?
|
|
HMENU fileMenu = GetSubmenuById(menu, ID_FILE_MENU);
|
|
HMENU saveStateSlots = GetSubmenuById(fileMenu, ID_FILE_SAVESTATE_SLOT_MENU);
|
|
while (GetMenuItemCount(saveStateSlots) > 0) {
|
|
RemoveMenu(saveStateSlots, 0, MF_BYPOSITION);
|
|
}
|
|
|
|
auto di = GetI18NCategory(I18NCat::DIALOG);
|
|
// Add new items
|
|
for (int i = 0; i < g_Config.iSaveStateSlotCount; ++i) {
|
|
std::string number = StringFromFormat("%d", i + 1);
|
|
if (i < 10) {
|
|
// Add an accelerator for the first 10 slots.
|
|
number = "&" + number;
|
|
}
|
|
std::string label = ApplySafeSubstitutions(di->T("Slot %1"), number);
|
|
AppendMenu(
|
|
saveStateSlots,
|
|
MF_STRING,
|
|
ID_FILE_SAVESTATE_SLOT_BASE + i,
|
|
ConvertUTF8ToWString(label).c_str()
|
|
);
|
|
}
|
|
|
|
DrawMenuBar(hWnd);
|
|
}
|
|
|
|
void BrowseAndBootDone(std::string_view filename);
|
|
|
|
void BrowseAndBoot(RequesterToken token, std::string defaultPath, bool browseDirectory) {
|
|
bool browsePauseAfter = false;
|
|
if (GetUIState() == UISTATE_INGAME) {
|
|
browsePauseAfter = Core_IsStepping();
|
|
if (!browsePauseAfter)
|
|
Core_Break(BreakReason::BreakOnBoot, 0);
|
|
}
|
|
auto mm = GetI18NCategory(I18NCat::MAINMENU);
|
|
|
|
W32Util::MakeTopMost(GetHWND(), false);
|
|
|
|
if (browseDirectory) {
|
|
System_BrowseForFolder(token, mm->T("Load"), Path(), [](std::string_view value, int) {
|
|
BrowseAndBootDone(value);
|
|
});
|
|
} else {
|
|
System_BrowseForFile(token, mm->T("Load"), BrowseFileType::BOOTABLE, [](std::string_view value, int) {
|
|
BrowseAndBootDone(value);
|
|
});
|
|
}
|
|
}
|
|
|
|
void BrowseAndBootDone(std::string_view filename) {
|
|
if (GetUIState() == UISTATE_INGAME || GetUIState() == UISTATE_EXCEPTION || GetUIState() == UISTATE_PAUSEMENU) {
|
|
Core_Resume();
|
|
}
|
|
std::string fileStr(filename);
|
|
fileStr = ReplaceAll(fileStr, "\\", "/");
|
|
System_PostUIMessage(UIMessage::REQUEST_GAME_BOOT, fileStr);
|
|
W32Util::MakeTopMost(GetHWND(), g_Config.bTopMost);
|
|
}
|
|
|
|
static void UmdSwitchAction(RequesterToken token) {
|
|
auto des = GetI18NCategory(I18NCat::DESKTOPUI);
|
|
System_BrowseForFile(token, des->T("Switch UMD"), BrowseFileType::BOOTABLE, [](std::string_view value, int) {
|
|
// This is safe because the callback runs on the emu thread.
|
|
__UmdReplace(Path(value));
|
|
});
|
|
}
|
|
|
|
static void SaveStateActionFinished(SaveState::Status status, std::string_view message, std::string_view metadata) {
|
|
// Reuse the message from the pause screen.
|
|
ShowMessageAfterSaveStateAction(status, message, metadata);
|
|
// This is just used to restore the mouse cursor from wait mode.
|
|
PostMessage(MainWindow::GetHWND(), WM_USER_SAVESTATE_FINISH, 0, 0);
|
|
}
|
|
|
|
// not static
|
|
void setTexScalingMultiplier(int level) {
|
|
System_RunOnMainThread([level]() {
|
|
g_Config.iTexScalingLevel = level;
|
|
});
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
}
|
|
|
|
static void setTexScalingType(int type) {
|
|
System_RunOnMainThread([type]() {
|
|
g_Config.iTexScalingType = type;
|
|
});
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
}
|
|
|
|
static void setSkipBufferEffects(bool skip) {
|
|
System_RunOnMainThread([skip]() {
|
|
g_Config.bSkipBufferEffects = skip;
|
|
});
|
|
System_PostUIMessage(UIMessage::GPU_RENDER_RESIZED);
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
}
|
|
|
|
static void setFrameSkipping(int framesToSkip = -1) {
|
|
if (framesToSkip >= FRAMESKIP_OFF)
|
|
g_Config.iFrameSkip = framesToSkip;
|
|
else {
|
|
if (++g_Config.iFrameSkip > FRAMESKIP_MAX)
|
|
g_Config.iFrameSkip = FRAMESKIP_OFF;
|
|
}
|
|
|
|
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
|
|
|
std::ostringstream messageStream;
|
|
messageStream << gr->T("Frame Skipping") << ":" << " ";
|
|
|
|
if (g_Config.iFrameSkip == FRAMESKIP_OFF)
|
|
messageStream << gr->T("Off");
|
|
else
|
|
messageStream << g_Config.iFrameSkip;
|
|
|
|
g_OSD.Show(OSDType::MESSAGE_INFO, messageStream.str());
|
|
}
|
|
|
|
static void RestartApp() {
|
|
g_Config.bRestartRequired = true;
|
|
PostMessage(MainWindow::GetHWND(), WM_USER_DESTROY, 0, 0);
|
|
}
|
|
|
|
void MainWindowMenu_Process(HWND hWnd, WPARAM wParam) {
|
|
std::string fn;
|
|
|
|
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
|
|
|
const int wmId = LOWORD(wParam);
|
|
// Parse the menu selections:
|
|
switch (wmId) {
|
|
case ID_FILE_LOAD:
|
|
BrowseAndBoot(NON_EPHEMERAL_TOKEN, "", false);
|
|
break;
|
|
|
|
case ID_FILE_LOAD_DIR:
|
|
BrowseAndBoot(NON_EPHEMERAL_TOKEN, "", true);
|
|
break;
|
|
|
|
case ID_FILE_LOAD_MEMSTICK:
|
|
BrowseAndBoot(NON_EPHEMERAL_TOKEN, GetSysDirectory(DIRECTORY_GAME).ToString());
|
|
break;
|
|
|
|
case ID_FILE_LOAD_VSH:
|
|
System_PostUIMessage(UIMessage::REQUEST_GAME_BOOT, (g_Config.nandRootDirectory / "flash0/vsh/module/vshmain.prx").ToString());
|
|
break;
|
|
|
|
case ID_FILE_OPEN_NEW_INSTANCE:
|
|
W32Util::SpawnNewInstance(false);
|
|
break;
|
|
|
|
case ID_FILE_MEMSTICK:
|
|
System_LaunchUrl(LaunchUrlType::LOCAL_FILE, g_Config.memStickDirectory.ToString());
|
|
break;
|
|
|
|
case ID_TOGGLE_BREAK:
|
|
if (GetUIState() == UISTATE_PAUSEMENU) {
|
|
// Causes hang (outdated comment?)
|
|
// System_PostUIMessage(UIMessage::REQUEST_GAME_RUN, "");
|
|
|
|
if (disasmWindow)
|
|
SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0);
|
|
} else if (Core_IsStepping()) { // It is paused, then continue to run.
|
|
if (disasmWindow)
|
|
SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0);
|
|
else
|
|
Core_Resume();
|
|
} else {
|
|
if (disasmWindow)
|
|
SendMessage(disasmWindow->GetDlgHandle(), WM_COMMAND, IDC_STOPGO, 0);
|
|
else
|
|
Core_Break(BreakReason::DebugBreak, 0);
|
|
}
|
|
noFocusPause = !noFocusPause; // If we pause, override pause on lost focus
|
|
break;
|
|
|
|
case ID_EMULATION_PAUSE:
|
|
System_PostUIMessage(UIMessage::REQUEST_GAME_PAUSE);
|
|
break;
|
|
|
|
case ID_EMULATION_STOP:
|
|
System_PostUIMessage(UIMessage::REQUEST_GAME_STOP);
|
|
break;
|
|
|
|
case ID_EMULATION_RESET:
|
|
if (MainWindow::ConfirmAction(hWnd, true)) {
|
|
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
|
|
}
|
|
break;
|
|
|
|
case ID_EMULATION_SWITCH_UMD:
|
|
UmdSwitchAction(NON_EPHEMERAL_TOKEN);
|
|
break;
|
|
|
|
case ID_EMULATION_ROTATION_H:
|
|
{
|
|
DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
|
displayLayoutConfig.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL;
|
|
break;
|
|
}
|
|
case ID_EMULATION_ROTATION_V:
|
|
{
|
|
DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
|
displayLayoutConfig.iInternalScreenRotation = ROTATION_LOCKED_VERTICAL;
|
|
break;
|
|
}
|
|
case ID_EMULATION_ROTATION_H_R:
|
|
{
|
|
DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
|
displayLayoutConfig.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL180;
|
|
break;
|
|
}
|
|
case ID_EMULATION_ROTATION_V_R:
|
|
{
|
|
DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
|
displayLayoutConfig.iInternalScreenRotation = ROTATION_LOCKED_VERTICAL180;
|
|
break;
|
|
}
|
|
|
|
case ID_EMULATION_CHEATS:
|
|
g_Config.bEnableCheats = !g_Config.bEnableCheats;
|
|
g_OSD.ShowOnOff(gr->T("Cheats"), g_Config.bEnableCheats);
|
|
break;
|
|
|
|
case ID_EMULATION_CHAT:
|
|
if (GetUIState() == UISTATE_INGAME) {
|
|
System_PostUIMessage(UIMessage::SHOW_CHAT_SCREEN);
|
|
}
|
|
break;
|
|
|
|
case ID_FILE_LOADSTATEFILE:
|
|
if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate()) {
|
|
if (W32Util::BrowseForFileName(true, hWnd, L"Load state", nullptr, nullptr, L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) {
|
|
SetCursor(LoadCursor(0, IDC_WAIT));
|
|
SaveState::Load(Path(fn), -1, SaveStateActionFinished);
|
|
}
|
|
}
|
|
break;
|
|
case ID_FILE_SAVESTATEFILE:
|
|
if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) {
|
|
if (W32Util::BrowseForFileName(false, hWnd, L"Save state", nullptr, L"state.ppst", L"Save States (*.ppst)\0*.ppst\0All files\0*.*\0\0", L"ppst", fn)) {
|
|
SetCursor(LoadCursor(0, IDC_WAIT));
|
|
SaveState::Save(Path(fn), -1, SaveStateActionFinished);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ID_FILE_SAVESTATE_NEXT_SLOT:
|
|
{
|
|
if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) {
|
|
SaveState::NextSlot();
|
|
System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ID_FILE_SAVESTATE_NEXT_SLOT_HC:
|
|
{
|
|
if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) {
|
|
// We let F3 (search next) in the imdebugger take priority, if active.
|
|
if (!KeyMap::PspButtonHasMappings(VIRTKEY_NEXT_SLOT) && !g_Config.bShowImDebugger) {
|
|
SaveState::NextSlot();
|
|
System_PostUIMessage(UIMessage::SAVESTATE_DISPLAY_SLOT);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ID_FILE_QUICKLOADSTATE:
|
|
if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate()) {
|
|
SetCursor(LoadCursor(0, IDC_WAIT));
|
|
SaveState::LoadSlot(SaveState::GetGamePrefix(g_paramSFO), g_Config.iCurrentStateSlot, SaveStateActionFinished);
|
|
}
|
|
break;
|
|
|
|
case ID_FILE_QUICKLOADSTATE_HC:
|
|
{
|
|
if (!Achievements::WarnUserIfHardcoreModeActive(false) && !NetworkWarnUserIfOnlineAndCantSavestate()) {
|
|
if (!KeyMap::PspButtonHasMappings(VIRTKEY_LOAD_STATE)) {
|
|
SetCursor(LoadCursor(0, IDC_WAIT));
|
|
SaveState::LoadSlot(SaveState::GetGamePrefix(g_paramSFO), g_Config.iCurrentStateSlot, SaveStateActionFinished);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ID_FILE_QUICKSAVESTATE:
|
|
{
|
|
if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) {
|
|
SetCursor(LoadCursor(0, IDC_WAIT));
|
|
SaveState::SaveSlot(SaveState::GetGamePrefix(g_paramSFO), g_Config.iCurrentStateSlot, SaveStateActionFinished);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ID_FILE_QUICKSAVESTATE_HC:
|
|
{
|
|
if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) {
|
|
if (!KeyMap::PspButtonHasMappings(VIRTKEY_SAVE_STATE)) {
|
|
SetCursor(LoadCursor(0, IDC_WAIT));
|
|
SaveState::SaveSlot(SaveState::GetGamePrefix(g_paramSFO), g_Config.iCurrentStateSlot, SaveStateActionFinished);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case ID_OPTIONS_LANGUAGE:
|
|
System_PostUIMessage(UIMessage::SHOW_LANGUAGE_SCREEN);
|
|
break;
|
|
|
|
case ID_OPTIONS_IGNOREWINKEY:
|
|
g_Config.bIgnoreWindowsKey = !g_Config.bIgnoreWindowsKey;
|
|
break;
|
|
|
|
case ID_OPTIONS_SCREENAUTO: SetInternalResolution(RESOLUTION_AUTO); break;
|
|
case ID_OPTIONS_SCREEN1X: SetInternalResolution(RESOLUTION_NATIVE); break;
|
|
case ID_OPTIONS_SCREEN2X: SetInternalResolution(RESOLUTION_2X); break;
|
|
case ID_OPTIONS_SCREEN3X: SetInternalResolution(RESOLUTION_3X); break;
|
|
case ID_OPTIONS_SCREEN4X: SetInternalResolution(RESOLUTION_4X); break;
|
|
case ID_OPTIONS_SCREEN5X: SetInternalResolution(RESOLUTION_5X); break;
|
|
case ID_OPTIONS_SCREEN6X: SetInternalResolution(RESOLUTION_6X); break;
|
|
case ID_OPTIONS_SCREEN7X: SetInternalResolution(RESOLUTION_7X); break;
|
|
case ID_OPTIONS_SCREEN8X: SetInternalResolution(RESOLUTION_8X); break;
|
|
case ID_OPTIONS_SCREEN9X: SetInternalResolution(RESOLUTION_9X); break;
|
|
case ID_OPTIONS_SCREEN10X: SetInternalResolution(RESOLUTION_MAX); break;
|
|
|
|
case ID_OPTIONS_WINDOW1X: SetWindowSize(1); break;
|
|
case ID_OPTIONS_WINDOW2X: SetWindowSize(2); break;
|
|
case ID_OPTIONS_WINDOW3X: SetWindowSize(3); break;
|
|
case ID_OPTIONS_WINDOW4X: SetWindowSize(4); break;
|
|
case ID_OPTIONS_WINDOW5X: SetWindowSize(5); break;
|
|
case ID_OPTIONS_WINDOW6X: SetWindowSize(6); break;
|
|
case ID_OPTIONS_WINDOW7X: SetWindowSize(7); break;
|
|
case ID_OPTIONS_WINDOW8X: SetWindowSize(8); break;
|
|
case ID_OPTIONS_WINDOW9X: SetWindowSize(9); break;
|
|
case ID_OPTIONS_WINDOW10X: SetWindowSize(10); break;
|
|
|
|
case ID_OPTIONS_RESOLUTIONDUMMY:
|
|
{
|
|
SetInternalResolution();
|
|
break;
|
|
}
|
|
|
|
case ID_OPTIONS_VSYNC:
|
|
g_Config.bVSync = !g_Config.bVSync;
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
break;
|
|
|
|
case ID_OPTIONS_FRAMESKIP_AUTO:
|
|
g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip;
|
|
if (g_Config.bAutoFrameSkip && g_Config.bSkipBufferEffects) {
|
|
setSkipBufferEffects(false);
|
|
}
|
|
break;
|
|
|
|
case ID_TEXTURESCALING_OFF: setTexScalingMultiplier(TEXSCALING_OFF); break;
|
|
case ID_TEXTURESCALING_2X: setTexScalingMultiplier(TEXSCALING_2X); break;
|
|
case ID_TEXTURESCALING_3X: setTexScalingMultiplier(TEXSCALING_3X); break;
|
|
case ID_TEXTURESCALING_4X: setTexScalingMultiplier(TEXSCALING_4X); break;
|
|
case ID_TEXTURESCALING_5X: setTexScalingMultiplier(TEXSCALING_MAX); break;
|
|
|
|
case ID_TEXTURESCALING_XBRZ: setTexScalingType(TextureScalerCommon::XBRZ); break;
|
|
case ID_TEXTURESCALING_HYBRID: setTexScalingType(TextureScalerCommon::HYBRID); break;
|
|
case ID_TEXTURESCALING_BICUBIC: setTexScalingType(TextureScalerCommon::BICUBIC); break;
|
|
case ID_TEXTURESCALING_HYBRID_BICUBIC: setTexScalingType(TextureScalerCommon::HYBRID_BICUBIC); break;
|
|
|
|
case ID_TEXTURESCALING_DEPOSTERIZE:
|
|
g_Config.bTexDeposterize = !g_Config.bTexDeposterize;
|
|
System_PostUIMessage(UIMessage::GPU_CONFIG_CHANGED);
|
|
break;
|
|
|
|
case ID_OPTIONS_DIRECT3D11:
|
|
g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11;
|
|
g_Config.Save("gpu_choice");
|
|
RestartApp();
|
|
break;
|
|
|
|
case ID_OPTIONS_OPENGL:
|
|
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
|
|
g_Config.Save("gpu_choice");
|
|
RestartApp();
|
|
break;
|
|
|
|
case ID_OPTIONS_VULKAN:
|
|
g_Config.iGPUBackend = (int)GPUBackend::VULKAN;
|
|
g_Config.Save("gpu_choice");
|
|
RestartApp();
|
|
break;
|
|
|
|
case ID_OPTIONS_SKIP_BUFFER_EFFECTS:
|
|
setSkipBufferEffects(!g_Config.bSkipBufferEffects);
|
|
g_OSD.ShowOnOff(gr->T("Skip Buffer Effects"), g_Config.bSkipBufferEffects);
|
|
break;
|
|
|
|
case ID_DEBUG_SHOWDEBUGSTATISTICS:
|
|
// This is still useful as a shortcut to tell users to use.
|
|
// So let's fake the enum.
|
|
if ((DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS) {
|
|
g_Config.iDebugOverlay = (int)DebugOverlay::OFF;
|
|
} else {
|
|
g_Config.iDebugOverlay = (int)DebugOverlay::DEBUG_STATS;
|
|
}
|
|
System_PostUIMessage(UIMessage::REQUEST_CLEAR_JIT);
|
|
break;
|
|
|
|
case ID_OPTIONS_DISPLAY_LAYOUT:
|
|
System_PostUIMessage(UIMessage::SHOW_DISPLAY_LAYOUT_EDITOR);
|
|
break;
|
|
|
|
|
|
case ID_OPTIONS_FRAMESKIP_0: setFrameSkipping(FRAMESKIP_OFF); break;
|
|
case ID_OPTIONS_FRAMESKIP_1: setFrameSkipping(FRAMESKIP_1); break;
|
|
case ID_OPTIONS_FRAMESKIP_2: setFrameSkipping(FRAMESKIP_2); break;
|
|
case ID_OPTIONS_FRAMESKIP_3: setFrameSkipping(FRAMESKIP_3); break;
|
|
case ID_OPTIONS_FRAMESKIP_4: setFrameSkipping(FRAMESKIP_4); break;
|
|
case ID_OPTIONS_FRAMESKIP_5: setFrameSkipping(FRAMESKIP_5); break;
|
|
case ID_OPTIONS_FRAMESKIP_6: setFrameSkipping(FRAMESKIP_6); break;
|
|
case ID_OPTIONS_FRAMESKIP_7: setFrameSkipping(FRAMESKIP_7); break;
|
|
case ID_OPTIONS_FRAMESKIP_8: setFrameSkipping(FRAMESKIP_MAX); break;
|
|
|
|
case ID_FILE_EXIT:
|
|
if (MainWindow::ConfirmAction(hWnd, false)) {
|
|
DestroyWindow(hWnd);
|
|
}
|
|
break;
|
|
|
|
case ID_DEBUG_BREAKONLOAD:
|
|
g_Config.bAutoRun = !g_Config.bAutoRun;
|
|
break;
|
|
|
|
case ID_DEBUG_SAVEFRAMEDUMP:
|
|
{
|
|
System_PostUIMessage(UIMessage::SAVE_FRAME_DUMP);
|
|
break;
|
|
}
|
|
|
|
// g_symbolMap access below is routed through Core_RunOnCPUThread() instead of poking at it
|
|
// directly from this GUI thread - see Core_RunOnCPUThread() in Core.h. The file-browse
|
|
// dialogs are modal, so they stay outside the queued callback; NotifyDebuggerMapLoaded()
|
|
// also stays outside, since it locks g_frameMutex internally (CDisasm/CMemoryDlg's
|
|
// NotifyMapLoaded()) and Core_RunOnCPUThread's queue can be drained from inside a
|
|
// g_frameMutex-locked NativeFrame() span, so calling it from within the lambda could
|
|
// deadlock.
|
|
case ID_DEBUG_LOADMAPFILE:
|
|
if (W32Util::BrowseForFileName(true, hWnd, L"Load .ppmap", nullptr, nullptr, L"Maps\0*.ppmap\0All files\0*.*\0\0", L"ppmap", fn)) {
|
|
Core_RunOnCPUThread([&] { g_symbolMap->LoadSymbolMap(Path(fn)); });
|
|
NotifyDebuggerMapLoaded();
|
|
}
|
|
break;
|
|
|
|
case ID_DEBUG_SAVEMAPFILE:
|
|
if (W32Util::BrowseForFileName(false, hWnd, L"Save .ppmap", nullptr, L"map.ppmap", L"Maps\0*.ppmap\0All files\0*.*\0\0", L"ppmap", fn)) {
|
|
Core_RunOnCPUThread([&] { g_symbolMap->SaveSymbolMap(Path(fn)); });
|
|
}
|
|
break;
|
|
|
|
case ID_DEBUG_LOADSYMFILE:
|
|
if (W32Util::BrowseForFileName(true, hWnd, L"Load .sym", nullptr, nullptr, L"Symbols\0*.sym\0All files\0*.*\0\0", L"sym", fn)) {
|
|
Core_RunOnCPUThread([&] { g_symbolMap->LoadNocashSym(Path(fn)); });
|
|
NotifyDebuggerMapLoaded();
|
|
}
|
|
break;
|
|
|
|
case ID_DEBUG_SAVESYMFILE:
|
|
if (W32Util::BrowseForFileName(false, hWnd, L"Save .sym", nullptr, L"symbols.sym", L"Symbols\0*.sym\0All files\0*.*\0\0", L"sym", fn)) {
|
|
Core_RunOnCPUThread([&] { g_symbolMap->SaveNocashSym(Path(fn)); });
|
|
}
|
|
break;
|
|
|
|
case ID_DEBUG_RESETSYMBOLTABLE:
|
|
Core_RunOnCPUThread([&] { g_symbolMap->Clear(); });
|
|
NotifyDebuggerMapLoaded();
|
|
break;
|
|
|
|
case ID_DEBUG_DISASSEMBLY:
|
|
CreateDisasmWindow();
|
|
if (disasmWindow)
|
|
disasmWindow->Show(true);
|
|
break;
|
|
|
|
case ID_DEBUG_GEDEBUGGER:
|
|
#if PPSSPP_API(ANY_GL)
|
|
CreateGeDebuggerWindow();
|
|
if (geDebuggerWindow)
|
|
geDebuggerWindow->Show(true);
|
|
#endif
|
|
break;
|
|
|
|
case ID_DEBUG_MEMORYVIEW:
|
|
CreateMemoryWindow();
|
|
if (memoryWindow)
|
|
memoryWindow->Show(true);
|
|
break;
|
|
|
|
case ID_DEBUG_MEMORYBASE:
|
|
{
|
|
System_CopyStringToClipboard(StringFromFormat("%016llx", (uint64_t)(uintptr_t)Memory::base));
|
|
break;
|
|
}
|
|
|
|
case ID_DEBUG_EXTRACTFILE:
|
|
{
|
|
std::string filename;
|
|
if (!InputBox_GetString(MainWindow::GetHInstance(), hWnd, L"Disc filename", filename, filename)) {
|
|
break;
|
|
}
|
|
const char *lastSlash = strrchr(filename.c_str(), '/');
|
|
if (lastSlash) {
|
|
fn = lastSlash + 1;
|
|
} else {
|
|
fn.clear();
|
|
}
|
|
|
|
PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
|
|
if (!info.exists) {
|
|
MessageBox(hWnd, L"File does not exist.", L"Sorry", 0);
|
|
} else if (info.type == FILETYPE_DIRECTORY) {
|
|
MessageBox(hWnd, L"Cannot extract directories.", L"Sorry", 0);
|
|
} else if (W32Util::BrowseForFileName(false, hWnd, L"Save file as...", nullptr, nullptr, L"All files\0*.*\0\0", L"", fn)) {
|
|
const u32 handle = pspFileSystem.OpenFile(filename, FILEACCESS_READ, "");
|
|
// Note: len may be in blocks.
|
|
size_t len = pspFileSystem.SeekFile(handle, 0, FILEMOVE_END);
|
|
const bool isBlockMode = pspFileSystem.DevType(handle) & PSPDevType::BLOCK;
|
|
|
|
FILE *fp = File::OpenCFile(Path(fn), "wb");
|
|
pspFileSystem.SeekFile(handle, 0, FILEMOVE_BEGIN);
|
|
u8 buffer[4096];
|
|
size_t bufferSize = isBlockMode ? sizeof(buffer) / 2048 : sizeof(buffer);
|
|
while (len > 0) {
|
|
// This is all in blocks, not bytes, if isBlockMode.
|
|
const size_t remain = std::min(len, bufferSize);
|
|
const size_t readSize = pspFileSystem.ReadFile(handle, buffer, remain);
|
|
if (readSize == 0)
|
|
break;
|
|
const size_t bytes = isBlockMode ? readSize * 2048 : readSize;
|
|
fwrite(buffer, 1, bytes, fp);
|
|
len -= readSize;
|
|
}
|
|
pspFileSystem.CloseFile(handle);
|
|
fclose(fp);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ID_DEBUG_LOG:
|
|
g_logManager.GetConsoleListener()->Show(g_logManager.GetConsoleListener()->Hidden());
|
|
break;
|
|
|
|
case ID_DEBUG_IGNOREILLEGALREADS:
|
|
g_Config.bIgnoreBadMemAccess = !g_Config.bIgnoreBadMemAccess;
|
|
break;
|
|
|
|
case ID_OPTIONS_FULLSCREEN:
|
|
if (!g_Config.bShowImDebugger) {
|
|
g_Config.bFullScreen = !g_Config.bFullScreen;
|
|
SendApplyFullscreenState();
|
|
}
|
|
break;
|
|
|
|
case ID_OPTIONS_TEXTUREFILTERING_AUTO: g_Config.iTexFiltering = TEX_FILTER_AUTO; break;
|
|
case ID_OPTIONS_NEARESTFILTERING: g_Config.iTexFiltering = TEX_FILTER_FORCE_NEAREST; break;
|
|
case ID_OPTIONS_LINEARFILTERING: g_Config.iTexFiltering = TEX_FILTER_FORCE_LINEAR; break;
|
|
case ID_OPTIONS_AUTOMAXQUALITYFILTERING: g_Config.iTexFiltering = TEX_FILTER_AUTO_MAX_QUALITY; break;
|
|
|
|
case ID_OPTIONS_SMART2DTEXTUREFILTERING: g_Config.bSmart2DTexFiltering = !g_Config.bSmart2DTexFiltering; break;
|
|
|
|
case ID_OPTIONS_BUFLINEARFILTER:
|
|
{
|
|
DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
|
displayLayoutConfig.iDisplayFilter = SCALE_LINEAR;
|
|
break;
|
|
}
|
|
case ID_OPTIONS_BUFNEARESTFILTER:
|
|
{
|
|
DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
|
displayLayoutConfig.iDisplayFilter = SCALE_NEAREST;
|
|
break;
|
|
}
|
|
|
|
case ID_OPTIONS_TOPMOST:
|
|
g_Config.bTopMost = !g_Config.bTopMost;
|
|
W32Util::MakeTopMost(hWnd, g_Config.bTopMost);
|
|
break;
|
|
|
|
case ID_OPTIONS_PAUSE_FOCUS:
|
|
g_Config.bPauseOnLostFocus = !g_Config.bPauseOnLostFocus;
|
|
break;
|
|
|
|
case ID_OPTIONS_CONTROLS:
|
|
System_PostUIMessage(UIMessage::SHOW_CONTROL_MAPPING);
|
|
break;
|
|
|
|
case ID_OPTIONS_MORE_SETTINGS:
|
|
System_PostUIMessage(UIMessage::SHOW_SETTINGS);
|
|
break;
|
|
|
|
case ID_EMULATION_SOUND:
|
|
g_Config.bEnableSound = !g_Config.bEnableSound;
|
|
break;
|
|
|
|
case ID_HELP_OPENWEBSITE:
|
|
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/");
|
|
break;
|
|
|
|
case ID_HELP_BUYGOLD:
|
|
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/buygold");
|
|
break;
|
|
|
|
case ID_HELP_OPENFORUM:
|
|
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://forums.ppsspp.org/");
|
|
break;
|
|
|
|
case ID_HELP_GITHUB:
|
|
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://github.com/hrydgard/ppsspp/");
|
|
break;
|
|
|
|
case ID_HELP_DISCORD:
|
|
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://discord.gg/5NJB6dD");
|
|
break;
|
|
|
|
case ID_HELP_ABOUT:
|
|
DialogManager::EnableAll(FALSE);
|
|
DialogBox(MainWindow::GetHInstance(), (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)AboutDlgProc);
|
|
DialogManager::EnableAll(TRUE);
|
|
break;
|
|
|
|
case ID_DEBUG_TAKESCREENSHOT:
|
|
TakeUserScreenshot();
|
|
break;
|
|
|
|
case ID_DEBUG_RESTARTGRAPHICS:
|
|
System_PostUIMessage(UIMessage::RESTART_GRAPHICS);
|
|
break;
|
|
|
|
case ID_FILE_DUMPFRAMES:
|
|
g_Config.bDumpFrames = !g_Config.bDumpFrames;
|
|
break;
|
|
|
|
case ID_FILE_DUMP_VIDEO_OUTPUT:
|
|
g_Config.bDumpVideoOutput = !g_Config.bDumpVideoOutput;
|
|
break;
|
|
|
|
case ID_FILE_DUMPAUDIO:
|
|
g_Config.bDumpAudio = !g_Config.bDumpAudio;
|
|
break;
|
|
|
|
default:
|
|
if (wmId >= ID_FILE_SAVESTATE_SLOT_BASE && wmId < ID_FILE_SAVESTATE_SLOT_BASE + g_Config.iSaveStateSlotCount) {
|
|
if (!Achievements::WarnUserIfHardcoreModeActive(true) && !NetworkWarnUserIfOnlineAndCantSavestate()) {
|
|
g_Config.iCurrentStateSlot = wmId - ID_FILE_SAVESTATE_SLOT_BASE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
#ifdef RC_CLIENT_SUPPORTS_RAINTEGRATION
|
|
if (rc_client_raintegration_activate_menu_item(Achievements::GetClient(), LOWORD(wParam))) {
|
|
break;
|
|
}
|
|
MessageBox(hWnd, L"Unhandled menu item. Did you unload RAIntegration?", L"Sorry", 0);
|
|
#else
|
|
MessageBox(hWnd, L"Unhandled menu item. Please report a bug.", L"Sorry", 0);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
void HideDebugWindows() {
|
|
if (disasmWindow)
|
|
disasmWindow->Show(false);
|
|
#if PPSSPP_API(ANY_GL)
|
|
if (geDebuggerWindow)
|
|
geDebuggerWindow->Show(false);
|
|
#endif
|
|
if (memoryWindow)
|
|
memoryWindow->Show(false);
|
|
if (vfpudlg)
|
|
vfpudlg->Show(false);
|
|
}
|
|
|
|
static void UpdateBackendSubMenu(HMENU menu);
|
|
|
|
void UpdateMenus(HMENU menuSelected) {
|
|
HMENU menu = GetMenu(GetHWND());
|
|
|
|
if (menuSelected) {
|
|
// Technically we only need to update the selected menu.
|
|
if (menuSelected == g_hMenuBackend) {
|
|
UpdateBackendSubMenu(menu);
|
|
return;
|
|
}
|
|
bool found = false;
|
|
for (auto topLevelMenu : g_topLevelMenus) {
|
|
if (menuSelected == topLevelMenu) {
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
// Don't do anything
|
|
return;
|
|
}
|
|
}
|
|
|
|
#define CHECKITEM(item,value) CheckMenuItem(menu,item,MF_BYCOMMAND | ((value) ? MF_CHECKED : MF_UNCHECKED));
|
|
CHECKITEM(ID_DEBUG_IGNOREILLEGALREADS, g_Config.bIgnoreBadMemAccess);
|
|
CHECKITEM(ID_DEBUG_SHOWDEBUGSTATISTICS, (DebugOverlay)g_Config.iDebugOverlay == DebugOverlay::DEBUG_STATS);
|
|
CHECKITEM(ID_DEBUG_BREAKONLOAD, !g_Config.bAutoRun);
|
|
CHECKITEM(ID_OPTIONS_FRAMESKIP_AUTO, g_Config.bAutoFrameSkip);
|
|
CHECKITEM(ID_OPTIONS_FRAMESKIP, g_Config.iFrameSkip != FRAMESKIP_OFF);
|
|
CHECKITEM(ID_OPTIONS_VSYNC, g_Config.bVSync);
|
|
CHECKITEM(ID_OPTIONS_TOPMOST, g_Config.bTopMost);
|
|
CHECKITEM(ID_OPTIONS_PAUSE_FOCUS, g_Config.bPauseOnLostFocus);
|
|
CHECKITEM(ID_OPTIONS_SMART2DTEXTUREFILTERING, g_Config.bSmart2DTexFiltering);
|
|
CHECKITEM(ID_EMULATION_SOUND, g_Config.bEnableSound);
|
|
CHECKITEM(ID_TEXTURESCALING_DEPOSTERIZE, g_Config.bTexDeposterize);
|
|
CHECKITEM(ID_EMULATION_CHEATS, g_Config.bEnableCheats);
|
|
CHECKITEM(ID_OPTIONS_IGNOREWINKEY, g_Config.bIgnoreWindowsKey);
|
|
CHECKITEM(ID_FILE_DUMPFRAMES, g_Config.bDumpFrames);
|
|
CHECKITEM(ID_FILE_DUMP_VIDEO_OUTPUT, g_Config.bDumpVideoOutput);
|
|
CHECKITEM(ID_FILE_DUMPAUDIO, g_Config.bDumpAudio);
|
|
CHECKITEM(ID_OPTIONS_SKIP_BUFFER_EFFECTS, g_Config.bSkipBufferEffects);
|
|
|
|
static const int displayrotationitems[] = {
|
|
ID_EMULATION_ROTATION_H,
|
|
ID_EMULATION_ROTATION_V,
|
|
ID_EMULATION_ROTATION_H_R,
|
|
ID_EMULATION_ROTATION_V_R
|
|
};
|
|
|
|
DisplayLayoutConfig &displayLayoutConfig = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
|
|
|
|
if (displayLayoutConfig.iInternalScreenRotation < ROTATION_LOCKED_HORIZONTAL)
|
|
displayLayoutConfig.iInternalScreenRotation = ROTATION_LOCKED_HORIZONTAL;
|
|
|
|
else if (displayLayoutConfig.iInternalScreenRotation > ROTATION_LOCKED_VERTICAL180)
|
|
displayLayoutConfig.iInternalScreenRotation = ROTATION_LOCKED_VERTICAL180;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(displayrotationitems); i++) {
|
|
CheckMenuItem(menu, displayrotationitems[i], MF_BYCOMMAND | ((i + 1) == displayLayoutConfig.iInternalScreenRotation ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
static const int zoomitems[11] = {
|
|
ID_OPTIONS_SCREENAUTO,
|
|
ID_OPTIONS_SCREEN1X,
|
|
ID_OPTIONS_SCREEN2X,
|
|
ID_OPTIONS_SCREEN3X,
|
|
ID_OPTIONS_SCREEN4X,
|
|
ID_OPTIONS_SCREEN5X,
|
|
ID_OPTIONS_SCREEN6X,
|
|
ID_OPTIONS_SCREEN7X,
|
|
ID_OPTIONS_SCREEN8X,
|
|
ID_OPTIONS_SCREEN9X,
|
|
ID_OPTIONS_SCREEN10X,
|
|
};
|
|
if (g_Config.iInternalResolution < RESOLUTION_AUTO)
|
|
g_Config.iInternalResolution = RESOLUTION_AUTO;
|
|
|
|
else if (g_Config.iInternalResolution > RESOLUTION_MAX)
|
|
g_Config.iInternalResolution = RESOLUTION_MAX;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(zoomitems); i++) {
|
|
CheckMenuItem(menu, zoomitems[i], MF_BYCOMMAND | ((i == g_Config.iInternalResolution) ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
static const int windowSizeItems[10] = {
|
|
ID_OPTIONS_WINDOW1X,
|
|
ID_OPTIONS_WINDOW2X,
|
|
ID_OPTIONS_WINDOW3X,
|
|
ID_OPTIONS_WINDOW4X,
|
|
ID_OPTIONS_WINDOW5X,
|
|
ID_OPTIONS_WINDOW6X,
|
|
ID_OPTIONS_WINDOW7X,
|
|
ID_OPTIONS_WINDOW8X,
|
|
ID_OPTIONS_WINDOW9X,
|
|
ID_OPTIONS_WINDOW10X,
|
|
};
|
|
|
|
RECT rc;
|
|
GetClientRect(GetHWND(), &rc);
|
|
|
|
int checkW = displayLayoutConfig.InternalRotationIsPortrait() ? 272 : 480;
|
|
int checkH = displayLayoutConfig.InternalRotationIsPortrait() ? 480 : 272;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(windowSizeItems); i++) {
|
|
bool check = (i + 1) * checkW == rc.right - rc.left || (i + 1) * checkH == rc.bottom - rc.top;
|
|
CheckMenuItem(menu, windowSizeItems[i], MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
static const int texscalingitems[] = {
|
|
ID_TEXTURESCALING_OFF,
|
|
ID_TEXTURESCALING_2X,
|
|
ID_TEXTURESCALING_3X,
|
|
ID_TEXTURESCALING_4X,
|
|
ID_TEXTURESCALING_5X,
|
|
};
|
|
if (g_Config.iTexScalingLevel < TEXSCALING_OFF)
|
|
g_Config.iTexScalingLevel = TEXSCALING_OFF;
|
|
|
|
else if (g_Config.iTexScalingLevel > TEXSCALING_MAX)
|
|
g_Config.iTexScalingLevel = TEXSCALING_MAX;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(texscalingitems); i++) {
|
|
// OFF is 1, skip 0.
|
|
bool selected = i + 1 == g_Config.iTexScalingLevel;
|
|
CheckMenuItem(menu, texscalingitems[i], MF_BYCOMMAND | (selected ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
EnableMenuItem(menu, ID_TEXTURESCALING_3X, MF_ENABLED);
|
|
EnableMenuItem(menu, ID_TEXTURESCALING_5X, MF_ENABLED);
|
|
|
|
static const int texscalingtypeitems[] = {
|
|
ID_TEXTURESCALING_XBRZ,
|
|
ID_TEXTURESCALING_HYBRID,
|
|
ID_TEXTURESCALING_BICUBIC,
|
|
ID_TEXTURESCALING_HYBRID_BICUBIC,
|
|
};
|
|
if (g_Config.iTexScalingType < TextureScalerCommon::XBRZ)
|
|
g_Config.iTexScalingType = TextureScalerCommon::XBRZ;
|
|
|
|
else if (g_Config.iTexScalingType > TextureScalerCommon::HYBRID_BICUBIC)
|
|
g_Config.iTexScalingType = TextureScalerCommon::HYBRID_BICUBIC;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(texscalingtypeitems); i++) {
|
|
CheckMenuItem(menu, texscalingtypeitems[i], MF_BYCOMMAND | ((i == g_Config.iTexScalingType) ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
static const int texfilteringitems[] = {
|
|
ID_OPTIONS_TEXTUREFILTERING_AUTO,
|
|
ID_OPTIONS_NEARESTFILTERING,
|
|
ID_OPTIONS_LINEARFILTERING,
|
|
ID_OPTIONS_AUTOMAXQUALITYFILTERING,
|
|
};
|
|
if (g_Config.iTexFiltering < TEX_FILTER_AUTO)
|
|
g_Config.iTexFiltering = TEX_FILTER_AUTO;
|
|
else if (g_Config.iTexFiltering > TEX_FILTER_AUTO_MAX_QUALITY)
|
|
g_Config.iTexFiltering = TEX_FILTER_AUTO_MAX_QUALITY;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(texfilteringitems); i++) {
|
|
CheckMenuItem(menu, texfilteringitems[i], MF_BYCOMMAND | ((i + 1) == g_Config.iTexFiltering ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
static const int bufferfilteritems[] = {
|
|
ID_OPTIONS_BUFLINEARFILTER,
|
|
ID_OPTIONS_BUFNEARESTFILTER,
|
|
};
|
|
if (displayLayoutConfig.iDisplayFilter < SCALE_LINEAR)
|
|
displayLayoutConfig.iDisplayFilter = SCALE_LINEAR;
|
|
|
|
else if (displayLayoutConfig.iDisplayFilter > SCALE_NEAREST)
|
|
displayLayoutConfig.iDisplayFilter = SCALE_NEAREST;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(bufferfilteritems); i++) {
|
|
CheckMenuItem(menu, bufferfilteritems[i], MF_BYCOMMAND | ((i + 1) == displayLayoutConfig.iDisplayFilter ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
static const int frameskipping[] = {
|
|
ID_OPTIONS_FRAMESKIP_0,
|
|
ID_OPTIONS_FRAMESKIP_1,
|
|
ID_OPTIONS_FRAMESKIP_2,
|
|
ID_OPTIONS_FRAMESKIP_3,
|
|
ID_OPTIONS_FRAMESKIP_4,
|
|
ID_OPTIONS_FRAMESKIP_5,
|
|
ID_OPTIONS_FRAMESKIP_6,
|
|
ID_OPTIONS_FRAMESKIP_7,
|
|
ID_OPTIONS_FRAMESKIP_8,
|
|
};
|
|
|
|
if (g_Config.iFrameSkip < FRAMESKIP_OFF)
|
|
g_Config.iFrameSkip = FRAMESKIP_OFF;
|
|
|
|
else if (g_Config.iFrameSkip > FRAMESKIP_MAX)
|
|
g_Config.iFrameSkip = FRAMESKIP_MAX;
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(frameskipping); i++) {
|
|
CheckMenuItem(menu, frameskipping[i], MF_BYCOMMAND | ((i == g_Config.iFrameSkip) ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
if (g_Config.iCurrentStateSlot < 0)
|
|
g_Config.iCurrentStateSlot = 0;
|
|
|
|
else if (g_Config.iCurrentStateSlot >= g_Config.iSaveStateSlotCount)
|
|
g_Config.iCurrentStateSlot = g_Config.iSaveStateSlotCount - 1;
|
|
|
|
for (int i = 0; i < g_Config.iSaveStateSlotCount; i++) {
|
|
CheckMenuItem(menu, ID_FILE_SAVESTATE_SLOT_BASE + i, MF_BYCOMMAND | ((i == g_Config.iCurrentStateSlot) ? MF_CHECKED : MF_UNCHECKED));
|
|
}
|
|
|
|
#if !PPSSPP_API(ANY_GL)
|
|
EnableMenuItem(menu, ID_DEBUG_GEDEBUGGER, MF_GRAYED);
|
|
#endif
|
|
|
|
UpdateCommands();
|
|
}
|
|
|
|
// This one is pretty expensive so we handle it separately.
|
|
static void UpdateBackendSubMenu(HMENU menu) {
|
|
const bool allowD3D11 = g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11);
|
|
const bool allowOpenGL = g_Config.IsBackendEnabled(GPUBackend::OPENGL);
|
|
const bool allowVulkan = g_Config.IsBackendEnabled(GPUBackend::VULKAN);
|
|
|
|
switch (GetGPUBackend()) {
|
|
case GPUBackend::OPENGL:
|
|
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED);
|
|
EnableMenuItem(menu, ID_OPTIONS_OPENGL, MF_GRAYED);
|
|
EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED);
|
|
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED);
|
|
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_CHECKED);
|
|
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_UNCHECKED);
|
|
break;
|
|
case GPUBackend::VULKAN:
|
|
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, allowD3D11 ? MF_ENABLED : MF_GRAYED);
|
|
EnableMenuItem(menu, ID_OPTIONS_OPENGL, allowOpenGL ? MF_ENABLED : MF_GRAYED);
|
|
EnableMenuItem(menu, ID_OPTIONS_VULKAN, MF_GRAYED);
|
|
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_UNCHECKED);
|
|
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED);
|
|
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_CHECKED);
|
|
break;
|
|
case GPUBackend::DIRECT3D11:
|
|
EnableMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_GRAYED);
|
|
EnableMenuItem(menu, ID_OPTIONS_OPENGL, allowOpenGL ? MF_ENABLED : MF_GRAYED);
|
|
EnableMenuItem(menu, ID_OPTIONS_VULKAN, allowVulkan ? MF_ENABLED : MF_GRAYED);
|
|
CheckMenuItem(menu, ID_OPTIONS_DIRECT3D11, MF_CHECKED);
|
|
CheckMenuItem(menu, ID_OPTIONS_OPENGL, MF_UNCHECKED);
|
|
CheckMenuItem(menu, ID_OPTIONS_VULKAN, MF_UNCHECKED);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void UpdateCommands() {
|
|
static GlobalUIState lastGlobalUIState = UISTATE_PAUSEMENU;
|
|
static CoreState lastCoreState = CORE_POWERDOWN;
|
|
|
|
HMENU menu = GetMenu(GetHWND());
|
|
EnableMenuItem(menu, ID_DEBUG_LOG, g_Config.bEnableLogging ? MF_ENABLED : MF_GRAYED);
|
|
SetIngameMenuItemStates(menu, GetUIState());
|
|
|
|
if (lastGlobalUIState == GetUIState() && lastCoreState == coreState)
|
|
return;
|
|
|
|
lastCoreState = coreState;
|
|
lastGlobalUIState = GetUIState();
|
|
|
|
bool isPaused = Core_IsStepping() && GetUIState() == UISTATE_INGAME;
|
|
TranslateMenuItem(menu, ID_TOGGLE_BREAK, L"\tF8", isPaused ? "Run" : "Break");
|
|
}
|
|
|
|
void UpdateSwitchUMD() {
|
|
HMENU menu = GetMenu(GetHWND());
|
|
GlobalUIState state = GetUIState();
|
|
UINT umdSwitchEnable = state == UISTATE_INGAME && getUMDReplacePermit() ? MF_ENABLED : MF_GRAYED;
|
|
EnableMenuItem(menu, ID_EMULATION_SWITCH_UMD, umdSwitchEnable);
|
|
}
|
|
|
|
// Message handler for about box.
|
|
LRESULT CALLBACK AboutDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
{
|
|
W32Util::CenterWindow(hDlg);
|
|
HWND versionBox = GetDlgItem(hDlg, IDC_VERSION);
|
|
std::string windowText = System_GetPropertyBool(SYSPROP_APP_GOLD) ? "PPSSPP Gold " : "PPSSPP ";
|
|
windowText.append(PPSSPP_GIT_VERSION);
|
|
SetWindowText(versionBox, ConvertUTF8ToWString(windowText).c_str());
|
|
DarkModeInitDialog(hDlg);
|
|
return TRUE;
|
|
}
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return TRUE;
|
|
}
|
|
break;
|
|
return FALSE;
|
|
}
|
|
|
|
default:
|
|
return DarkModeDlgProc(hDlg, message, wParam, lParam);
|
|
}
|
|
return FALSE;
|
|
}
|
|
}
|