Files
ppsspp/Common/UI/ScreenManager.h
T
Henrik RydgårdandClaude Opus 5.5 08649f0f15 UI: Make switchScreen replace the whole screen stack
It only replaced the top screen, but most callers switch from a dialog:
Play on the game screen, the store, the installers, the framedump
launcher. The screens under it stayed alive, so launching a game from the
game screen and exiting it left [MainScreen, MainScreen], one more each
time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 16:21:10 +02:00

131 lines
3.3 KiB
C++

#pragma once
#include <atomic>
#include <cstdint>
#include <mutex>
#include <string>
#include <deque>
#include <unordered_map>
#include <vector>
#include "Common/Common.h"
#include "Common/Input/InputState.h"
#include "Common/System/System.h"
#include "Common/UI/Screen.h"
class Screen;
class UIContext;
/*
class Transition {
public:
Transition() = default;
};
*/
enum {
LAYER_TRANSPARENT = 2,
};
typedef void (*PostRenderCallback)(UIContext *ui, void *userdata);
class ScreenManager {
public:
virtual ~ScreenManager();
// Replaces the whole stack with the screen, at the start of the next frame.
void switchScreen(Screen *screen);
void ProcessScreenSwitches();
void ProcessInputEvent(const QueuedEvent &event);
void Update();
void setUIContext(UIContext *context) { uiContext_ = context; }
UIContext *getUIContext() { return uiContext_; }
Draw::DrawContext *getDrawContext() { return draw_; }
void setPostRenderCallback(PostRenderCallback cb, void *userdata) {
postRenderCb_ = cb;
postRenderUserdata_ = userdata;
}
ScreenRenderFlags Render(std::function<void()> afterPreRender);
void resized();
void shutdown();
void deviceLost();
void deviceRestored(Draw::DrawContext *draw);
// Push a dialog box in front. Currently 1-level only.
void push(Screen *screen, int layerFlags = 0);
// Recreate all views
void RecreateAllViews();
// Pops the dialog away.
void finishDialog(Screen *dialog, DialogResult result = DR_OK);
Screen *dialogParent(const Screen *dialog) const;
// True if the screen is in the stack, with something (like a popup) on top of it.
bool HasScreenAbove(const Screen *screen) const;
void sendMessage(UIMessage message, const char *value);
const Screen *topScreen() const {
return stack_.empty() ? nullptr : stack_.back().screen;
}
Screen *topScreen() {
return stack_.empty() ? nullptr : stack_.back().screen;
}
void cancelScreensAbove(Screen *screen);
void getFocusPosition(float &x, float &y, float &z);
// Will delete any existing overlay screen.
void SetBackgroundOverlayScreens(Screen *backgroundScreen, Screen *overlayScreen);
InputMode PassInputToMapper() const {
return passInputToMapper_;
}
// Safe to call from any thread. Updated once per frame.
bool IsTopScreenTopLevel() const {
return topIsTopLevel_;
}
private:
void pop();
void switchToNext();
void processFinishDialog();
UIContext *uiContext_ = nullptr;
Draw::DrawContext *draw_ = nullptr;
PostRenderCallback postRenderCb_ = nullptr;
void *postRenderUserdata_ = nullptr;
const Screen *dialogFinished_ = nullptr;
DialogResult dialogResult_{};
Screen *backgroundScreen_ = nullptr;
Screen *overlayScreen_ = nullptr;
Screen *cancelScreensAbove_ = nullptr;
struct Layer {
Screen *screen;
int flags; // From LAYER_ enum above
UI::View *focusedView; // TODO: save focus here. Going for quick solution now to reset focus.
};
// Dialog stack. These are shown "on top" of base screens and the Android back button works as expected.
// Used for options, in-game menus and other things you expect to be able to back out from onto something.
std::vector<Layer> stack_;
std::vector<Layer> nextStack_;
std::unordered_map<int64_t, int> lastAxis_;
std::atomic<InputMode> passInputToMapper_{InputMode::None};
std::atomic<bool> topIsTopLevel_{false};
};