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