1 // Super basic screen manager. Let's you, well, switch between screens. Can also be used
2 // to pop one screen in front for a bit while keeping another one running, it's basically
3 // a native "activity stack". Well actually that part is still a TODO.
4 //
5 // Semantics
6 //
7 // switchScreen: When you call this, on a newed screen, the ScreenManager takes ownership.
8 // On the next update, it switches to the new screen and deletes the previous screen.
9 //
10 // TODO: A way to do smooth transitions between screens. Will probably involve screenshotting
11 // the previous screen and then animating it on top of the current screen with transparency
12 // and/or other similar effects.
13 
14 #pragma once
15 
16 #include <cstdint>
17 #include <mutex>
18 #include <string>
19 #include <unordered_map>
20 #include <vector>
21 
22 #include "Common/Common.h"
23 #include "Common/Input/InputState.h"
24 
25 namespace UI {
26 	class View;
27 }
28 
29 enum DialogResult {
30 	DR_OK,
31 	DR_CANCEL,
32 	DR_YES,
33 	DR_NO,
34 	DR_BACK,
35 };
36 
37 class ScreenManager;
38 class UIContext;
39 
40 namespace Draw {
41 	class DrawContext;
42 }
43 
44 class Screen {
45 public:
Screen()46 	Screen() : screenManager_(nullptr) { }
~Screen()47 	virtual ~Screen() {
48 		screenManager_ = nullptr;
49 	}
50 
onFinish(DialogResult reason)51 	virtual void onFinish(DialogResult reason) {}
update()52 	virtual void update() {}
preRender()53 	virtual void preRender() {}
render()54 	virtual void render() {}
postRender()55 	virtual void postRender() {}
resized()56 	virtual void resized() {}
dialogFinished(const Screen * dialog,DialogResult result)57 	virtual void dialogFinished(const Screen *dialog, DialogResult result) {}
touch(const TouchInput & touch)58 	virtual bool touch(const TouchInput &touch) { return false;  }
key(const KeyInput & key)59 	virtual bool key(const KeyInput &key) { return false; }
axis(const AxisInput & touch)60 	virtual bool axis(const AxisInput &touch) { return false; }
sendMessage(const char * msg,const char * value)61 	virtual void sendMessage(const char *msg, const char *value) {}
deviceLost()62 	virtual void deviceLost() {}
deviceRestored()63 	virtual void deviceRestored() {}
64 
RecreateViews()65 	virtual void RecreateViews() {}
66 
screenManager()67 	ScreenManager *screenManager() { return screenManager_; }
setScreenManager(ScreenManager * sm)68 	void setScreenManager(ScreenManager *sm) { screenManager_ = sm; }
69 
70 	// This one is icky to use because you can't know what's in it until you know
71 	// what screen it is.
dialogData()72 	virtual void *dialogData() { return 0; }
73 
tag()74 	virtual std::string tag() const { return std::string(""); }
75 
isTransparent()76 	virtual bool isTransparent() const { return false; }
isTopLevel()77 	virtual bool isTopLevel() const { return false; }
78 
transformTouch(const TouchInput & touch)79 	virtual TouchInput transformTouch(const TouchInput &touch) { return touch; }
80 
81 private:
82 	ScreenManager *screenManager_;
83 	DISALLOW_COPY_AND_ASSIGN(Screen);
84 };
85 
86 class Transition {
87 public:
Transition()88 	Transition() {}
89 };
90 
91 enum {
92 	LAYER_SIDEMENU = 1,
93 	LAYER_TRANSPARENT = 2,
94 };
95 
96 typedef void(*PostRenderCallback)(UIContext *ui, void *userdata);
97 
98 class ScreenManager {
99 public:
100 	ScreenManager();
101 	virtual ~ScreenManager();
102 
103 	void switchScreen(Screen *screen);
104 	void update();
105 
setUIContext(UIContext * context)106 	void setUIContext(UIContext *context) { uiContext_ = context; }
getUIContext()107 	UIContext *getUIContext() { return uiContext_; }
108 
setDrawContext(Draw::DrawContext * context)109 	void setDrawContext(Draw::DrawContext *context) { thin3DContext_ = context; }
getDrawContext()110 	Draw::DrawContext *getDrawContext() { return thin3DContext_; }
111 
setPostRenderCallback(PostRenderCallback cb,void * userdata)112 	void setPostRenderCallback(PostRenderCallback cb, void *userdata) {
113 		postRenderCb_ = cb;
114 		postRenderUserdata_ = userdata;
115 	}
116 
117 	void render();
118 	void resized();
119 	void shutdown();
120 
121 	void deviceLost();
122 	void deviceRestored();
123 
124 	// Push a dialog box in front. Currently 1-level only.
125 	void push(Screen *screen, int layerFlags = 0);
126 
127 	// Recreate all views
128 	void RecreateAllViews();
129 
130 	// Pops the dialog away.
131 	void finishDialog(Screen *dialog, DialogResult result = DR_OK);
132 	Screen *dialogParent(const Screen *dialog) const;
133 
134 	// Instant touch, separate from the update() mechanism.
135 	bool touch(const TouchInput &touch);
136 	bool key(const KeyInput &key);
137 	bool axis(const AxisInput &touch);
138 
139 	// Generic facility for gross hacks :P
140 	void sendMessage(const char *msg, const char *value);
141 
142 	Screen *topScreen() const;
143 
144 	void getFocusPosition(float &x, float &y, float &z);
145 
146 	std::recursive_mutex inputLock_;
147 
148 private:
149 	void pop();
150 	void switchToNext();
151 	void processFinishDialog();
152 
153 	UIContext *uiContext_;
154 	Draw::DrawContext *thin3DContext_;
155 
156 	PostRenderCallback postRenderCb_ = nullptr;
157 	void *postRenderUserdata_ = nullptr;
158 
159 	const Screen *dialogFinished_;
160 	DialogResult dialogResult_;
161 
162 	struct Layer {
163 		Screen *screen;
164 		int flags;  // From LAYER_ enum above
165 		UI::View *focusedView;  // TODO: save focus here. Going for quick solution now to reset focus.
166 	};
167 
168 	// Dialog stack. These are shown "on top" of base screens and the Android back button works as expected.
169 	// Used for options, in-game menus and other things you expect to be able to back out from onto something.
170 	std::vector<Layer> stack_;
171 	std::vector<Layer> nextStack_;
172 
173 	std::unordered_map<int64_t, int> lastAxis_;
174 };
175