Files
ppsspp/Common/UI/Screen.h
T
Henrik RydgårdandClaude Opus 5.5 27899cc875 UI: Give views in lazily created tabs the views requester token
GetRequesterToken() only returns the views token inside CreateViews(),
but tabbed screens create every tab other than the first on demand, and
the persist restore after CreateViews() can create one too. So text
inputs and file choosers there (Networking tab nickname, search filter,
RemoteISO and achievement settings) registered their [this] callbacks
under the screen token, which a recreate doesn't forget. Open the native
input box, rotate, press OK, and the callback wrote through the deleted
view.

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

157 lines
4.2 KiB
C++

// Super basic screen manager. Let's you, well, switch between screens. Can also be used
// to pop one screen in front for a bit while keeping another one running, it's basically
// a native "activity stack". Well actually that part is still a TODO.
//
// Semantics
//
// switchScreen: When you call this, on a newed screen, the ScreenManager takes ownership.
// On the next update, it switches to the new screen and deletes the previous screen.
//
// TODO: A way to do smooth transitions between screens. Will probably involve screenshotting
// the previous screen and then animating it on top of the current screen with transparency
// and/or other similar effects.
#pragma once
#include <cstdint>
#include <string>
#include "Common/Common.h"
#include "Common/Input/InputState.h"
#include "Common/System/System.h"
namespace UI {
class View;
}
namespace Draw {
class DrawContext;
}
enum DialogResult {
DR_NONE,
DR_OK,
DR_CANCEL,
DR_YES,
DR_NO,
DR_BACK,
};
const char *DialogResultToString(DialogResult result);
class ScreenManager;
class UIContext;
enum class ScreenFocusChange {
FOCUS_LOST_TOP, // Another screen was pushed on top
FOCUS_BECAME_TOP, // Became the top screen again
};
enum class ScreenRenderMode {
DEFAULT = 0,
FIRST = 1,
BEHIND = 4,
TOP = 8,
};
ENUM_CLASS_BITOPS(ScreenRenderMode);
enum class ScreenRenderRole {
NONE = 0,
CAN_BE_BACKGROUND = 1,
MUST_BE_FIRST = 2,
};
ENUM_CLASS_BITOPS(ScreenRenderRole);
enum class ViewLayoutMode {
ApplyInsets = 0, // For gameplay, option #1
IgnoreInsets, // For gameplay, option #2
IgnoreBottomInset,
};
enum class QueuedEventType : u8 {
KEY,
AXIS,
TOUCH,
};
struct QueuedEvent {
QueuedEventType type;
union {
TouchInput touch;
KeyInput key;
AxisInput axis;
};
};
enum class ScreenRenderFlags {
NONE = 0,
HANDLED_THROTTLING = 1,
};
ENUM_CLASS_BITOPS(ScreenRenderFlags);
enum class InputMode {
None = 0,
Keyboard = 1,
Mouse = 2,
Other = 4,
ImDebuggerToggle = 8, // ugly hack. debugger and pause goes through.
};
ENUM_CLASS_BITOPS(InputMode);
class Screen {
public:
Screen() = default;
virtual ~Screen();
virtual void onFinish(DialogResult reason) {}
virtual void update() {}
virtual ScreenRenderFlags PreRender(ScreenRenderMode mode) { return ScreenRenderFlags::NONE; }
virtual ScreenRenderFlags render(ScreenRenderMode mode) = 0;
virtual void resized() {}
virtual void dialogFinished(const Screen *dialog, DialogResult result) {}
virtual void sendMessage(UIMessage message, const char *value) {}
virtual void deviceLost() {}
virtual void deviceRestored(Draw::DrawContext *draw) {}
virtual ScreenRenderRole renderRole(bool isTop) const { return ScreenRenderRole::NONE; }
virtual bool wantBrightBackground() const { return false; } // special hack for DisplayLayoutScreen.
virtual void focusChanged(ScreenFocusChange focusChange);
virtual bool touch(const TouchInput &touch) = 0;
virtual bool key(const KeyInput &key) = 0;
virtual void axis(const AxisInput &axis) = 0;
virtual void RecreateViews() {}
// NOTE: This is polled every frame, not called on every input event.
virtual InputMode PassInputToMapper() const { return InputMode::None; }
ScreenManager *screenManager() { return screenManager_; }
const ScreenManager *screenManager() const { return screenManager_; }
void setScreenManager(ScreenManager *sm) { screenManager_ = sm; }
virtual const char *tag() const = 0;
virtual bool isTransparent() const { return false; }
virtual bool isTopLevel() const { return false; }
virtual TouchInput transformTouch(const TouchInput &touch) { return touch; }
virtual bool WantsTextInput() const { return false; }
protected:
// Requests made while creating views (by the views themselves, or with callbacks that capture them) get a separate
// token, so they can be forgotten when the views are deleted, while the screen's own requests stay alive.
int GetRequesterToken();
void SetCreatingViews(bool creating) { creatingViews_ = creating; }
bool IsCreatingViews() const { return creatingViews_; }
// Drops the callbacks of pending requests made by the views, which are about to be deleted.
void ForgetViewRequests();
private:
ScreenManager *screenManager_ = nullptr;
int token_ = -1;
int viewsToken_ = -1;
bool creatingViews_ = false;
DISALLOW_COPY_AND_ASSIGN(Screen);
};