Implement resetting from a popup menu on the pause menu.

This commit is contained in:
Henrik Rydgård 2025-03-28 14:31:01 +01:00
parent 7314a65cc5
commit 116f8cf3af
10 changed files with 81 additions and 37 deletions

View file

@ -273,8 +273,10 @@ void ScreenManager::sendMessage(UIMessage message, const char *value) {
backgroundScreen_->sendMessage(message, value);
}
if (!stack_.empty()) {
stack_.back().screen->sendMessage(message, value);
// NOTE: Changed this to send the message to all screens, instead of just the top one,
// to allow EmuScreen to receive messages from popup menus. Hope this didn't break anything..
for (auto &iter : stack_) {
iter.screen->sendMessage(message, value);
}
}

View file

@ -165,7 +165,6 @@ public:
bool key(const KeyInput &key);
void axis(const AxisInput *axes, size_t count);
// Generic facility for gross hacks :P
void sendMessage(UIMessage message, const char *value);
const Screen *topScreen() const {

View file

@ -164,7 +164,7 @@ void ViewGroup::Draw(UIContext &dc) {
if (hasDropShadow_) {
// Darken things behind.
dc.FillRect(UI::Drawable(0x60000000), dc.GetBounds().Expand(dropShadowExpand_));
float dropsize = 30.0f;
const float dropsize = 30.0f;
dc.Draw()->DrawImage4Grid(dc.theme->dropShadow4Grid,
bounds_.x - dropsize, bounds_.y,
bounds_.x2() + dropsize, bounds_.y2()+dropsize*1.5f, 0xDF000000, 3.0f);

View file

@ -570,6 +570,8 @@ static void NotifyUserIfSlow() {
}
void __DisplayFlip(int cyclesLate) {
_dbg_assert_(gpu);
__DisplaySetFramerate();
flippedThisFrame = true;
@ -585,21 +587,19 @@ void __DisplayFlip(int cyclesLate) {
bool fastForwardSkipFlip = g_Config.iFastForwardMode != (int)FastForwardMode::CONTINUOUS;
if (gpu) {
Draw::DrawContext *draw = gpu->GetDrawContext();
if (draw) {
g_frameTiming.presentMode = ComputePresentMode(draw, &g_frameTiming.presentInterval);
if (!draw->GetDeviceCaps().presentInstantModeChange && g_frameTiming.presentMode == Draw::PresentMode::FIFO) {
// Some backends can't just flip into MAILBOX/IMMEDIATE mode instantly.
// Vulkan doesn't support the interval setting, so we force skipping the flip.
// TODO: We'll clean this up in a more backend-independent way later.
fastForwardSkipFlip = true;
}
} else {
g_frameTiming.presentMode = Draw::PresentMode::FIFO;
g_frameTiming.presentInterval = 1;
Draw::DrawContext *draw = gpu->GetDrawContext();
if (draw) {
g_frameTiming.presentMode = ComputePresentMode(draw, &g_frameTiming.presentInterval);
if (!draw->GetDeviceCaps().presentInstantModeChange && g_frameTiming.presentMode == Draw::PresentMode::FIFO) {
// Some backends can't just flip into MAILBOX/IMMEDIATE mode instantly.
// Vulkan doesn't support the interval setting, so we force skipping the flip.
// TODO: We'll clean this up in a more backend-independent way later.
fastForwardSkipFlip = true;
}
} else {
// Surely can never get here?
g_frameTiming.presentMode = Draw::PresentMode::FIFO;
g_frameTiming.presentInterval = 1;
}
if (!g_Config.bSkipBufferEffects) {

View file

@ -325,7 +325,7 @@ void DisplayLayoutScreen::CreateViews() {
settingsVisible_.resize(g_Config.vPostShaderNames.size());
}
static ContextMenuItem postShaderContextMenu[] = {
static const ContextMenuItem postShaderContextMenu[] = {
{ "Move Up", "I_ARROW_UP" },
{ "Move Down", "I_ARROW_DOWN" },
{ "Remove", "I_TRASHCAN" },

View file

@ -1365,12 +1365,6 @@ void EmuScreen::update() {
}
}
if (bootPending_) {
// Keep trying the boot until bootPending_ is lifted.
// It may be delayed due to RetroAchievements or any other cause.
bootGame(gamePath_);
}
// Simply forcibly update to the current screen size every frame. Doesn't cost much.
// If bounds is set to be smaller than the actual pixel resolution of the display, respect that.
// TODO: Should be able to use g_dpi_scale here instead. Might want to store the dpi scale in the UI context too.
@ -1472,7 +1466,7 @@ ScreenRenderRole EmuScreen::renderRole(bool isTop) const {
return false;
}
if (!PSP_IsInited()) {
if (!PSP_IsInited() && !bootPending_) {
return false;
}
@ -1498,6 +1492,14 @@ void EmuScreen::darken() {
}
ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
// Moved from update, because we want it to be possible for booting to happen even when the screen
// is in the background, like when choosing Reset from the pause menu.
if (bootPending_) {
// Keep trying the boot until bootPending_ is lifted.
// It may be delayed due to RetroAchievements or any other cause.
bootGame(gamePath_);
}
ScreenRenderFlags flags = ScreenRenderFlags::NONE;
Draw::Viewport viewport{ 0.0f, 0.0f, (float)g_display.pixel_xres, (float)g_display.pixel_yres, 0.0f, 1.0f };
using namespace Draw;
@ -1556,7 +1558,7 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
gpu->CopyDisplayToOutput(true);
PSP_EndHostFrame();
}
if (gpu->PresentedThisFrame()) {
if (gpu && gpu->PresentedThisFrame()) {
framebufferBound = true;
}
if (!framebufferBound) {

View file

@ -540,6 +540,40 @@ void GamePauseScreen::CreateViews() {
return UI::EVENT_DONE;
});
Button *menuButton = middleColumn->Add(new Button("", ImageID("I_THREE_DOTS"), new LinearLayoutParams(64, 64)));
menuButton->OnClick.Add([this, menuButton](UI::EventParams &e) {
static const ContextMenuItem ingameContextMenu[] = {
{ "Reset" },
};
PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(ingameContextMenu, ARRAY_SIZE(ingameContextMenu), I18NCat::DIALOG, menuButton);
screenManager()->push(contextMenu);
contextMenu->OnChoice.Add([=](EventParams &e) -> UI::EventReturn {
switch (e.a) {
case 0: // Reset
{
std::string confirmMessage = GetConfirmExitMessage();
if (!confirmMessage.empty()) {
auto di = GetI18NCategory(I18NCat::DIALOG);
screenManager()->push(new PromptScreen(gamePath_, confirmMessage, di->T("Reset"), di->T("Cancel"), [=](bool result) {
if (result) {
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
}
}));
} else {
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
break;
}
}
default:
break;
}
return UI::EVENT_DONE;
});
return UI::EVENT_DONE;
});
// What's this for?
rightColumnHolder->Add(new Spacer(10.0f));
}
@ -561,9 +595,10 @@ void GamePauseScreen::dialogFinished(const Screen *dialog, DialogResult dr) {
} else {
if (tag == "Game") {
g_BackgroundAudio.SetGame(Path());
} else if (tag != "ContextMenuPopup") {
// There may have been changes to our savestates, so let's recreate.
RecreateViews();
}
// There may have been changes to our savestates, so let's recreate.
RecreateViews();
}
}
@ -609,7 +644,6 @@ std::string GetConfirmExitMessage() {
// No need to ask for this type of confirmation for dumps.
return confirmMessage;
}
auto di = GetI18NCategory(I18NCat::DIALOG);
confirmMessage = ApplySafeSubstitutions(di->T("You haven't saved your progress for %1."), NiceTimeFormat((int)unsavedSeconds));
confirmMessage += '\n';

View file

@ -825,7 +825,7 @@ namespace MainWindow
};
}
bool ConfirmExit(HWND hWnd) {
bool ConfirmAction(HWND hWnd, bool actionIsReset) {
const GlobalUIState state = GetUIState();
if (state == UISTATE_MENU || state == UISTATE_EXIT) {
return true;
@ -837,8 +837,12 @@ namespace MainWindow
}
auto di = GetI18NCategory(I18NCat::DIALOG);
auto mm = GetI18NCategory(I18NCat::MAINMENU);
confirmExitMessage += '\n';
confirmExitMessage += di->T("Are you sure you want to exit?");
if (!actionIsReset) {
confirmExitMessage += '\n';
confirmExitMessage += di->T("Are you sure you want to exit?");
} else {
// Reset is bit rarer, let's just omit the extra message for now.
}
return IDYES == MessageBox(hWnd, ConvertUTF8ToWString(confirmExitMessage).c_str(), ConvertUTF8ToWString(mm->T("Exit")).c_str(), MB_YESNO | MB_ICONQUESTION);
}
@ -1121,7 +1125,7 @@ namespace MainWindow
case WM_CLOSE:
{
if (ConfirmExit(hWnd)) {
if (ConfirmAction(hWnd, false)) {
DestroyWindow(hWnd);
}
return 0;

View file

@ -83,7 +83,8 @@ namespace MainWindow
void SetWindowSize(int zoom);
void RunCallbackInWndProc(void (*callback)(void *window, void *userdata), void *userdata);
void SetKeepScreenBright(bool keepBright);
bool ConfirmExit(HWND hWnd);
bool ConfirmAction(HWND hWnd, bool actionIsReset);
}
#endif

View file

@ -513,7 +513,9 @@ namespace MainWindow {
break;
case ID_EMULATION_RESET:
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
if (MainWindow::ConfirmAction(hWnd, true)) {
System_PostUIMessage(UIMessage::REQUEST_GAME_RESET);
}
break;
case ID_EMULATION_SWITCH_UMD:
@ -756,7 +758,7 @@ namespace MainWindow {
case ID_OPTIONS_FRAMESKIPTYPE_PRCNT: setFrameSkippingType(FRAMESKIPTYPE_PRCNT); break;
case ID_FILE_EXIT:
if (MainWindow::ConfirmExit(hWnd)) {
if (MainWindow::ConfirmAction(hWnd, false)) {
DestroyWindow(hWnd);
}
break;