diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt index fc7f95c67e..7c146831c6 100644 --- a/Common/CMakeLists.txt +++ b/Common/CMakeLists.txt @@ -281,6 +281,8 @@ add_library(Common STATIC UI/Root.h UI/Screen.cpp UI/Screen.h + UI/ScreenManager.cpp + UI/ScreenManager.h UI/UI.cpp UI/UI.h UI/Context.cpp diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index d11d158f10..042a8472ac 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -562,6 +562,7 @@ + @@ -1022,6 +1023,7 @@ + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index cd892a2ea1..e9d3d4dca2 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -798,6 +798,9 @@ GPU\OpenGL + + UI + @@ -1472,6 +1475,9 @@ GPU\OpenGL + + UI + diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index 2195085816..de5f2503f6 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -7,6 +7,7 @@ #include "Common/UI/Context.h" #include "Common/UI/Root.h" #include "Common/UI/Notice.h" +#include "Common/UI/ScreenManager.h" #include "Common/StringUtils.h" #include "Common/Data/Text/I18n.h" #include "Common/System/System.h" diff --git a/Common/UI/Screen.cpp b/Common/UI/Screen.cpp index c447483e4b..e886ce5ab1 100644 --- a/Common/UI/Screen.cpp +++ b/Common/UI/Screen.cpp @@ -1,16 +1,7 @@ -#include "Common/System/Display.h" #include "Common/System/Request.h" -#include "Common/Input/InputState.h" -#include "Common/UI/Root.h" #include "Common/UI/Screen.h" -#include "Common/UI/ScrollView.h" #include "Common/UI/UI.h" -#include "Common/UI/View.h" -#include "Common/UI/ViewGroup.h" -#include "Common/Data/Collections/TinySet.h" - #include "Common/Log.h" -#include "Common/TimeUtil.h" void Screen::focusChanged(ScreenFocusChange focusChange) { const char *eventName = ""; @@ -50,489 +41,6 @@ Screen::~Screen() { } } -ScreenManager::~ScreenManager() { - shutdown(); -} - -void ScreenManager::switchScreen(Screen *screen) { - if (!screen) { - ERROR_LOG(Log::UI, "Can't switch to empty screen"); - return; - } - - INFO_LOG(Log::UI, "ScreenManager::switchScreen('%s')", screen->tag()); - - if (!nextStack_.empty() && screen == nextStack_.front().screen) { - ERROR_LOG(Log::UI, "Already switching to this screen"); - return; - } - - // Note that if a dialog is found, this will be a silent background switch that - // will only become apparent if the dialog is closed. The previous screen will stick around - // until that switch. - // TODO: is this still true? - if (!nextStack_.empty()) { - for (int i = 0; i < nextStack_.size(); i++) { - INFO_LOG(Log::UI, "NextStack contents[%d].screen->tag(): '%s'", i, nextStack_[i].screen->tag()); - } - - ERROR_LOG(Log::UI, "Already had a nextStack_! Asynchronous open while doing something? Deleting the new screen."); - delete screen; - return; - } - if (screen == nullptr) { - WARN_LOG(Log::UI, "Switching to a zero screen, this can't be good"); - } - if (stack_.empty() || screen != stack_.back().screen) { - if (screen) { - screen->setScreenManager(this); - } - nextStack_.push_back({ screen, 0 }); - } -} - -void ScreenManager::cancelScreensAbove(Screen *screen) { - bool found = false; - for (int i = 0; i < stack_.size(); i++) { - if (stack_[i].screen == screen) { - found = true; - } - } - - if (found) { - cancelScreensAbove_ = screen; - } -} - -void ScreenManager::update() { - if (cancelScreensAbove_) { - bool found = false; - for (int i = (int)stack_.size() - 1; i >= 0; i--) { - if (stack_[i].screen == cancelScreensAbove_) { - break; - } - Layer temp = stack_.back(); - stack_.pop_back(); - delete temp.screen; - } - cancelScreensAbove_ = nullptr; - } - - if (!nextStack_.empty()) { - switchToNext(); - } - - if (overlayScreen_) { - // NOTE: This is not a full UIScreen update, to avoid double global event processing. - overlayScreen_->update(); - } - - // Process queued events. - std::deque events; - { - std::lock_guard eventGuard(eventQueueLock_); - events = std::move(eventQueue_); - eventQueue_.clear(); - } - - for (const QueuedEvent &ev : events) { - switch (ev.type) { - case QueuedEventType::TOUCH: - { - const TouchInput &touch = ev.touch; - // Send release all events to every screen layer. - if (touch.flags & TouchInputFlags::RELEASE_ALL) { - for (auto &layer : stack_) { - Screen *screen = layer.screen; - layer.screen->touch(screen->transformTouch(touch)); - } - } else if (!stack_.empty()) { - // Let the overlay know about touch-downs, to be able to dismiss popups. - bool skip = false; - if (overlayScreen_ && (touch.flags & TouchInputFlags::DOWN)) { - skip = overlayScreen_->touch(overlayScreen_->transformTouch(touch)); - } - if (!skip) { - Screen *screen = stack_.back().screen; - stack_.back().screen->touch(screen->transformTouch(touch)); - } - } - break; - } - case QueuedEventType::KEY: - { - const KeyInput &key = ev.key; - // Send key up to every screen layer, to avoid stuck keys. - if (key.flags & KeyInputFlags::UP) { - for (auto &layer : stack_) { - layer.screen->key(key); - } - } else if (!stack_.empty()) { - stack_.back().screen->key(key); - } - break; - } - case QueuedEventType::AXIS: - { - const AxisInput &axis = ev.axis; - if (!stack_.empty()) { - stack_.back().screen->axis(axis); - } - break; - } - default: - ERROR_LOG(Log::UI, "Unknown queued event type: %d", (int)ev.type); - break; - } - } - - // Only the front screen gets update(). - if (!stack_.empty()) { - Screen *backScreen = stack_.back().screen; - backScreen->update(); - passInputToMapper_ = backScreen->PassInputToMapper(); - } -} - -void ScreenManager::switchToNext() { - if (nextStack_.empty()) { - ERROR_LOG(Log::System, "switchToNext: No nextStack_!"); - } - - Layer temp = {nullptr, 0}; - if (!stack_.empty()) { - temp = stack_.back(); - temp.screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); - stack_.pop_back(); - } - stack_.push_back(nextStack_.front()); - nextStack_.front().screen->focusChanged(ScreenFocusChange::FOCUS_BECAME_TOP); - delete temp.screen; - UI::SetFocusedView(nullptr, UI::FocusFlags::CAUSE_SCREEN_CHANGE); - - // When will this ever happen? Should handle focus here too? - for (size_t i = 1; i < nextStack_.size(); ++i) { - stack_.push_back(nextStack_[i]); - } - nextStack_.clear(); -} - -void ScreenManager::touch(const TouchInput &touch) { - QueuedEvent ev{}; - ev.type = QueuedEventType::TOUCH; - ev.touch = touch; - std::lock_guard guard(eventQueueLock_); - eventQueue_.push_back(ev); -} - -void ScreenManager::key(const KeyInput &key) { - QueuedEvent ev{}; - ev.type = QueuedEventType::KEY; - ev.key = key; - std::lock_guard guard(eventQueueLock_); - eventQueue_.push_back(ev); -} - -void ScreenManager::axis(const AxisInput *axes, size_t count) { - QueuedEvent ev{}; - ev.type = QueuedEventType::AXIS; - std::lock_guard guard(eventQueueLock_); - for (size_t i = 0; i < count; i++) { - ev.axis = axes[i]; - eventQueue_.push_back(ev); - } -} - -void ScreenManager::deviceLost() { - for (auto &iter : stack_) - iter.screen->deviceLost(); -} - -void ScreenManager::deviceRestored(Draw::DrawContext *draw) { - draw_ = draw; - for (auto &iter : stack_) - iter.screen->deviceRestored(draw); -} - -void ScreenManager::resized() { - INFO_LOG(Log::UI, "ScreenManager::resized(g_display.dp_xres/dp_yres: %dx%d)", g_display.dp_xres, g_display.dp_yres); - // Have to notify the whole stack, otherwise there will be problems when going back - // to non-top screens. - for (auto &layer : stack_) { - layer.screen->resized(); - } -} - -ScreenRenderFlags ScreenManager::render() { - using namespace Draw; - - ScreenRenderFlags flags = ScreenRenderFlags::NONE; - - // First, go through the whole stack and have every screen render any non-backbuffer render passes. - // In EmuScreen, this might result in running emulation. - for (size_t i = 0; i < stack_.size(); i++) { - const auto &layer = stack_[i]; - ScreenRenderMode mode = ScreenRenderMode::DEFAULT; - if (i == stack_.size() - 1) { - mode |= ScreenRenderMode::TOP; - } - flags |= layer.screen->PreRender(mode); - } - - // Now, start the final render pass. This is now the ONLY place where binding the null fb is allowed. - draw_->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR}, "BackBuffer"); - getUIContext()->BeginFrame(); - - const Draw::Viewport viewport{0.0f, 0.0f, (float)g_display.pixel_xres, (float)g_display.pixel_yres, 0.0f, 1.0f}; - draw_->SetViewport(viewport); - draw_->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres); - draw_->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres); - - if (!stack_.empty()) { - // Collect the screens to render - TinySet layers; - - // Start at the end, collect screens to form the transparency stack. - // Then we'll iterate them in reverse order. - // Note that we skip the overlay screen, we handle it separately. - // Additionally, we pick up a "background" screen. Normally it will be either - // the EmuScreen or the actual global background screen. - auto iter = stack_.end(); - Screen *coveringScreen = nullptr; - Screen *foundBackgroundScreen = nullptr; - bool first = true; - - do { - --iter; - ScreenRenderRole role = iter->screen->renderRole(first); - if (!foundBackgroundScreen && (role & ScreenRenderRole::CAN_BE_BACKGROUND)) { - // There still might be a screen that wants to be background - generally the EmuScreen if present. - layers.push_back(iter->screen); - foundBackgroundScreen = iter->screen; - } else if (!coveringScreen) { - layers.push_back(iter->screen); - } - if (iter->flags != LAYER_TRANSPARENT) { - coveringScreen = iter->screen; - } - first = false; - if (role & ScreenRenderRole::MUST_BE_FIRST) { - break; - } - } while (iter != stack_.begin()); - - if (backgroundScreen_ && !foundBackgroundScreen) { - layers.push_back(backgroundScreen_); - foundBackgroundScreen = backgroundScreen_; - } - - // OK, now we iterate backwards over our little pile of collected screens. - for (int i = (int)layers.size() - 1; i >= 0; i--) { - ScreenRenderMode mode = ScreenRenderMode::DEFAULT; - if (i == (int)layers.size() - 1) { - // Bottom. - mode = ScreenRenderMode::FIRST; - if (i == 0) { - mode |= ScreenRenderMode::TOP; - } - } else if (i == 0) { - mode = ScreenRenderMode::TOP; - } else { - mode = ScreenRenderMode::BEHIND; - } - flags |= layers[i]->render(mode); - } - - if (overlayScreen_) { - // It doesn't care about mode. - flags |= overlayScreen_->render(ScreenRenderMode::TOP); - } - - getUIContext()->Flush(); - - if (postRenderCb_) { - // Really can't render anything after this! Will crash the screenshot mechanism if we do. - postRenderCb_(getUIContext(), postRenderUserdata_); - } - } else { - ERROR_LOG(Log::UI, "No current screen!"); - } - - processFinishDialog(); - return flags; -} - -void ScreenManager::getFocusPosition(float &x, float &y, float &z) { - UI::ScrollView::GetLastScrollPosition(x, y); - - UI::View *v = UI::GetFocusedView(); - x += v ? v->GetBounds().x : 0; - y += v ? v->GetBounds().y : 0; - z = stack_.size(); -} - -void ScreenManager::sendMessage(UIMessage message, const char *value) { - if (message == UIMessage::RECREATE_VIEWS) { - RecreateAllViews(); - } else if (message == UIMessage::LOST_FOCUS) { - TouchInput input{}; - input.x = -50000.0f; - input.y = -50000.0f; - input.flags = TouchInputFlags::RELEASE_ALL; - input.timestamp = time_now_d(); - input.id = 0; - touch(input); - } - - if (backgroundScreen_) { - backgroundScreen_->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.. - // NOTE: We do not use the iterator solution here, because the screen array may change by sendMessage! - // Although if it does, that's very bad. - // We also pick out the stack size before, so we don't get infinite growth if a screen is pushed from the handler. - // We probably should delay pushes, though... - const size_t stack_size = stack_.size(); - for (int i = 0; i < stack_size; i++) { - if (stack_[i].screen) { - stack_[i].screen->sendMessage(message, value); - } - } -} - -void ScreenManager::shutdown() { - for (const auto &layer : stack_) - delete layer.screen; - stack_.clear(); - for (const auto &layer : nextStack_) - delete layer.screen; - nextStack_.clear(); - delete overlayScreen_; - overlayScreen_ = nullptr; - delete backgroundScreen_; - backgroundScreen_ = nullptr; -} - -void ScreenManager::push(Screen *screen, int layerFlags) { - screen->setScreenManager(this); - if (screen->isTransparent()) { - layerFlags |= LAYER_TRANSPARENT; - } - - // Release touches and unfocus. - UI::SetFocusedView(nullptr, UI::FocusFlags::CAUSE_SCREEN_CHANGE); - TouchInput input{}; - input.x = -50000.0f; - input.y = -50000.0f; - input.flags = TouchInputFlags::RELEASE_ALL; - input.timestamp = time_now_d(); - input.id = 0; - touch(input); - - Layer layer = {screen, layerFlags}; - - if (!stack_.empty()) { - stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); - } - - if (nextStack_.empty()) { - layer.screen->focusChanged(ScreenFocusChange::FOCUS_BECAME_TOP); - stack_.push_back(layer); - } else { - nextStack_.push_back(layer); - } -} - -void ScreenManager::pop() { - if (!stack_.empty()) { - stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); - - delete stack_.back().screen; - stack_.pop_back(); - - if (!stack_.empty()) { - stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); - } - } else { - ERROR_LOG(Log::UI, "Can't pop when stack empty"); - } -} - -void ScreenManager::RecreateAllViews() { - for (auto &layer : stack_) { - layer.screen->RecreateViews(); - } -} - -void ScreenManager::finishDialog(Screen *dialog, DialogResult result) { - if (stack_.empty()) { - ERROR_LOG(Log::UI, "Must be in a dialog to finishDialog"); - return; - } - if (dialog != stack_.back().screen) { - ERROR_LOG(Log::UI, "Wrong dialog being finished!"); - return; - } - dialog->onFinish(result); - dialogFinished_ = dialog; - dialogResult_ = result; -} - -Screen *ScreenManager::dialogParent(const Screen *dialog) const { - for (size_t i = 1; i < stack_.size(); ++i) { - if (stack_[i].screen == dialog) { - // The previous screen was the caller (not necessarily the topmost.) - return stack_[i - 1].screen; - } - } - - return nullptr; -} - -void ScreenManager::processFinishDialog() { - if (dialogFinished_) { - { - // Another dialog may have been pushed before the render, so search for it. - Screen *caller = dialogParent(dialogFinished_); - bool erased = false; - for (size_t i = 0; i < stack_.size(); ++i) { - if (stack_[i].screen == dialogFinished_) { - stack_[i].screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); - stack_.erase(stack_.begin() + i); - erased = true; - } - } - - if (erased && !stack_.empty()) { - stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_BECAME_TOP); - } - - if (!caller) { - ERROR_LOG(Log::UI, "ERROR: no top screen when finishing dialog"); - } else if (caller != topScreen()) { - // The caller may get confused if we call dialogFinished() now. - WARN_LOG(Log::UI, "Skipping non-top dialog when finishing dialog."); - } else { - caller->dialogFinished(dialogFinished_, dialogResult_); - } - } - delete dialogFinished_; - dialogFinished_ = nullptr; - } -} - -void ScreenManager::SetBackgroundOverlayScreens(Screen *backgroundScreen, Screen *overlayScreen) { - delete backgroundScreen_; - backgroundScreen_ = backgroundScreen; - backgroundScreen_->setScreenManager(this); - - delete overlayScreen_; - overlayScreen_ = overlayScreen; - overlayScreen_->setScreenManager(this); -} - const char *DialogResultToString(DialogResult result) { switch (result) { case DR_NONE: return "DR_NONE"; diff --git a/Common/UI/Screen.h b/Common/UI/Screen.h index 347f8ae456..03f4284021 100644 --- a/Common/UI/Screen.h +++ b/Common/UI/Screen.h @@ -14,11 +14,7 @@ #pragma once #include -#include #include -#include -#include -#include #include "Common/Common.h" #include "Common/Input/InputState.h" @@ -28,6 +24,10 @@ namespace UI { class View; } +namespace Draw { +class DrawContext; +} + enum DialogResult { DR_NONE, DR_OK, @@ -41,10 +41,6 @@ const char *DialogResultToString(DialogResult result); class ScreenManager; class UIContext; -namespace Draw { - class DrawContext; -} - enum class ScreenFocusChange { FOCUS_LOST_TOP, // Another screen was pushed on top FOCUS_BECAME_TOP, // Became the top screen again @@ -58,12 +54,6 @@ enum class ScreenRenderMode { }; ENUM_CLASS_BITOPS(ScreenRenderMode); -enum class ScreenRenderFlags { - NONE = 0, - HANDLED_THROTTLING = 1, -}; -ENUM_CLASS_BITOPS(ScreenRenderFlags); - enum class ScreenRenderRole { NONE = 0, CAN_BE_BACKGROUND = 1, @@ -77,15 +67,6 @@ enum class ViewLayoutMode { IgnoreBottomInset, }; -enum class InputMode { - None = 0, - Keyboard = 1, - Mouse = 2, - Other = 4, - ImDebuggerToggle = 8, // ugly hack. debugger and pause goes through. -}; -ENUM_CLASS_BITOPS(InputMode); - enum class QueuedEventType : u8 { KEY, AXIS, @@ -101,6 +82,21 @@ struct QueuedEvent { }; }; +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; @@ -126,8 +122,7 @@ public: virtual void RecreateViews() {} - // NOTE: This is polled every frame, not called on every input event. This is - // a step towards eventually removing the ScreenManager input mutex. + // NOTE: This is polled every frame, not called on every input event. virtual InputMode PassInputToMapper() const { return InputMode::None; } ScreenManager *screenManager() { return screenManager_; } @@ -154,110 +149,3 @@ private: DISALLOW_COPY_AND_ASSIGN(Screen); }; - -class Transition { -public: - Transition() = default; -}; - -enum { - LAYER_TRANSPARENT = 2, -}; - -typedef void (*PostRenderCallback)(UIContext *ui, void *userdata); - -class ScreenManager { -public: - virtual ~ScreenManager(); - - void switchScreen(Screen *screen); - 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(); - 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; - - // Instant touch, separate from the update() mechanism. - void touch(const TouchInput &touch); - void key(const KeyInput &key); - void axis(const AxisInput *axes, size_t count); - - 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_; - } - -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 stack_; - std::vector nextStack_; - - std::unordered_map lastAxis_; - - std::mutex eventQueueLock_; - std::deque eventQueue_; - - InputMode passInputToMapper_ = InputMode::None; -}; diff --git a/Common/UI/ScreenManager.cpp b/Common/UI/ScreenManager.cpp new file mode 100644 index 0000000000..d7bbbd3b80 --- /dev/null +++ b/Common/UI/ScreenManager.cpp @@ -0,0 +1,491 @@ +#include "Common/System/Display.h" +#include "Common/Data/Collections/TinySet.h" +#include "Common/UI/ScreenManager.h" +#include "Common/UI/Root.h" +#include "Common/UI/View.h" +#include "Common/UI/ScrollView.h" +#include "Common/GPU/thin3d.h" +#include "Common/TimeUtil.h" + +ScreenManager::~ScreenManager() { + shutdown(); +} + +void ScreenManager::switchScreen(Screen *screen) { + if (!screen) { + ERROR_LOG(Log::UI, "Can't switch to empty screen"); + return; + } + + INFO_LOG(Log::UI, "ScreenManager::switchScreen('%s')", screen->tag()); + + if (!nextStack_.empty() && screen == nextStack_.front().screen) { + ERROR_LOG(Log::UI, "Already switching to this screen"); + return; + } + + // Note that if a dialog is found, this will be a silent background switch that + // will only become apparent if the dialog is closed. The previous screen will stick around + // until that switch. + // TODO: is this still true? + if (!nextStack_.empty()) { + for (int i = 0; i < nextStack_.size(); i++) { + INFO_LOG(Log::UI, "NextStack contents[%d].screen->tag(): '%s'", i, nextStack_[i].screen->tag()); + } + + ERROR_LOG(Log::UI, "Already had a nextStack_! Asynchronous open while doing something? Deleting the new screen."); + delete screen; + return; + } + if (screen == nullptr) { + WARN_LOG(Log::UI, "Switching to a zero screen, this can't be good"); + } + if (stack_.empty() || screen != stack_.back().screen) { + if (screen) { + screen->setScreenManager(this); + } + nextStack_.push_back({screen, 0}); + } +} + +void ScreenManager::cancelScreensAbove(Screen *screen) { + bool found = false; + for (int i = 0; i < stack_.size(); i++) { + if (stack_[i].screen == screen) { + found = true; + } + } + + if (found) { + cancelScreensAbove_ = screen; + } +} + +void ScreenManager::update() { + if (cancelScreensAbove_) { + bool found = false; + for (int i = (int)stack_.size() - 1; i >= 0; i--) { + if (stack_[i].screen == cancelScreensAbove_) { + break; + } + Layer temp = stack_.back(); + stack_.pop_back(); + delete temp.screen; + } + cancelScreensAbove_ = nullptr; + } + + if (!nextStack_.empty()) { + switchToNext(); + } + + if (overlayScreen_) { + // NOTE: This is not a full UIScreen update, to avoid double global event processing. + overlayScreen_->update(); + } + + // Process queued events. + std::deque events; + { + std::lock_guard eventGuard(eventQueueLock_); + events = std::move(eventQueue_); + eventQueue_.clear(); + } + + for (const QueuedEvent &ev : events) { + switch (ev.type) { + case QueuedEventType::TOUCH: + { + const TouchInput &touch = ev.touch; + // Send release all events to every screen layer. + if (touch.flags & TouchInputFlags::RELEASE_ALL) { + for (auto &layer : stack_) { + Screen *screen = layer.screen; + layer.screen->touch(screen->transformTouch(touch)); + } + } else if (!stack_.empty()) { + // Let the overlay know about touch-downs, to be able to dismiss popups. + bool skip = false; + if (overlayScreen_ && (touch.flags & TouchInputFlags::DOWN)) { + skip = overlayScreen_->touch(overlayScreen_->transformTouch(touch)); + } + if (!skip) { + Screen *screen = stack_.back().screen; + stack_.back().screen->touch(screen->transformTouch(touch)); + } + } + break; + } + case QueuedEventType::KEY: + { + const KeyInput &key = ev.key; + // Send key up to every screen layer, to avoid stuck keys. + if (key.flags & KeyInputFlags::UP) { + for (auto &layer : stack_) { + layer.screen->key(key); + } + } else if (!stack_.empty()) { + stack_.back().screen->key(key); + } + break; + } + case QueuedEventType::AXIS: + { + const AxisInput &axis = ev.axis; + if (!stack_.empty()) { + stack_.back().screen->axis(axis); + } + break; + } + default: + ERROR_LOG(Log::UI, "Unknown queued event type: %d", (int)ev.type); + break; + } + } + + // Only the front screen gets update(). + if (!stack_.empty()) { + Screen *backScreen = stack_.back().screen; + backScreen->update(); + passInputToMapper_ = backScreen->PassInputToMapper(); + } +} + +void ScreenManager::switchToNext() { + if (nextStack_.empty()) { + ERROR_LOG(Log::System, "switchToNext: No nextStack_!"); + } + + Layer temp = {nullptr, 0}; + if (!stack_.empty()) { + temp = stack_.back(); + temp.screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); + stack_.pop_back(); + } + stack_.push_back(nextStack_.front()); + nextStack_.front().screen->focusChanged(ScreenFocusChange::FOCUS_BECAME_TOP); + delete temp.screen; + UI::SetFocusedView(nullptr, UI::FocusFlags::CAUSE_SCREEN_CHANGE); + + // When will this ever happen? Should handle focus here too? + for (size_t i = 1; i < nextStack_.size(); ++i) { + stack_.push_back(nextStack_[i]); + } + nextStack_.clear(); +} + +void ScreenManager::touch(const TouchInput &touch) { + QueuedEvent ev{}; + ev.type = QueuedEventType::TOUCH; + ev.touch = touch; + std::lock_guard guard(eventQueueLock_); + eventQueue_.push_back(ev); +} + +void ScreenManager::key(const KeyInput &key) { + QueuedEvent ev{}; + ev.type = QueuedEventType::KEY; + ev.key = key; + std::lock_guard guard(eventQueueLock_); + eventQueue_.push_back(ev); +} + +void ScreenManager::axis(const AxisInput *axes, size_t count) { + QueuedEvent ev{}; + ev.type = QueuedEventType::AXIS; + std::lock_guard guard(eventQueueLock_); + for (size_t i = 0; i < count; i++) { + ev.axis = axes[i]; + eventQueue_.push_back(ev); + } +} + +void ScreenManager::deviceLost() { + for (auto &iter : stack_) + iter.screen->deviceLost(); +} + +void ScreenManager::deviceRestored(Draw::DrawContext *draw) { + draw_ = draw; + for (auto &iter : stack_) + iter.screen->deviceRestored(draw); +} + +void ScreenManager::resized() { + INFO_LOG(Log::UI, "ScreenManager::resized(g_display.dp_xres/dp_yres: %dx%d)", g_display.dp_xres, g_display.dp_yres); + // Have to notify the whole stack, otherwise there will be problems when going back + // to non-top screens. + for (auto &layer : stack_) { + layer.screen->resized(); + } +} + +ScreenRenderFlags ScreenManager::render() { + using namespace Draw; + + ScreenRenderFlags flags = ScreenRenderFlags::NONE; + + // First, go through the whole stack and have every screen render any non-backbuffer render passes. + // In EmuScreen, this might result in running emulation. + for (size_t i = 0; i < stack_.size(); i++) { + const auto &layer = stack_[i]; + ScreenRenderMode mode = ScreenRenderMode::DEFAULT; + if (i == stack_.size() - 1) { + mode |= ScreenRenderMode::TOP; + } + flags |= layer.screen->PreRender(mode); + } + + // Now, start the final render pass. This is now the ONLY place where binding the null fb is allowed. + draw_->BindFramebufferAsRenderTarget(nullptr, {RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR}, "BackBuffer"); + getUIContext()->BeginFrame(); + + const Draw::Viewport viewport{0.0f, 0.0f, (float)g_display.pixel_xres, (float)g_display.pixel_yres, 0.0f, 1.0f}; + draw_->SetViewport(viewport); + draw_->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres); + draw_->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres); + + if (!stack_.empty()) { + // Collect the screens to render + TinySet layers; + + // Start at the end, collect screens to form the transparency stack. + // Then we'll iterate them in reverse order. + // Note that we skip the overlay screen, we handle it separately. + // Additionally, we pick up a "background" screen. Normally it will be either + // the EmuScreen or the actual global background screen. + auto iter = stack_.end(); + Screen *coveringScreen = nullptr; + Screen *foundBackgroundScreen = nullptr; + bool first = true; + + do { + --iter; + ScreenRenderRole role = iter->screen->renderRole(first); + if (!foundBackgroundScreen && (role & ScreenRenderRole::CAN_BE_BACKGROUND)) { + // There still might be a screen that wants to be background - generally the EmuScreen if present. + layers.push_back(iter->screen); + foundBackgroundScreen = iter->screen; + } else if (!coveringScreen) { + layers.push_back(iter->screen); + } + if (iter->flags != LAYER_TRANSPARENT) { + coveringScreen = iter->screen; + } + first = false; + if (role & ScreenRenderRole::MUST_BE_FIRST) { + break; + } + } while (iter != stack_.begin()); + + if (backgroundScreen_ && !foundBackgroundScreen) { + layers.push_back(backgroundScreen_); + foundBackgroundScreen = backgroundScreen_; + } + + // OK, now we iterate backwards over our little pile of collected screens. + for (int i = (int)layers.size() - 1; i >= 0; i--) { + ScreenRenderMode mode = ScreenRenderMode::DEFAULT; + if (i == (int)layers.size() - 1) { + // Bottom. + mode = ScreenRenderMode::FIRST; + if (i == 0) { + mode |= ScreenRenderMode::TOP; + } + } else if (i == 0) { + mode = ScreenRenderMode::TOP; + } else { + mode = ScreenRenderMode::BEHIND; + } + flags |= layers[i]->render(mode); + } + + if (overlayScreen_) { + // It doesn't care about mode. + flags |= overlayScreen_->render(ScreenRenderMode::TOP); + } + + getUIContext()->Flush(); + + if (postRenderCb_) { + // Really can't render anything after this! Will crash the screenshot mechanism if we do. + postRenderCb_(getUIContext(), postRenderUserdata_); + } + } else { + ERROR_LOG(Log::UI, "No current screen!"); + } + + processFinishDialog(); + return flags; +} + +void ScreenManager::getFocusPosition(float &x, float &y, float &z) { + UI::ScrollView::GetLastScrollPosition(x, y); + + UI::View *v = UI::GetFocusedView(); + x += v ? v->GetBounds().x : 0; + y += v ? v->GetBounds().y : 0; + z = stack_.size(); +} + +void ScreenManager::sendMessage(UIMessage message, const char *value) { + if (message == UIMessage::RECREATE_VIEWS) { + RecreateAllViews(); + } else if (message == UIMessage::LOST_FOCUS) { + TouchInput input{}; + input.x = -50000.0f; + input.y = -50000.0f; + input.flags = TouchInputFlags::RELEASE_ALL; + input.timestamp = time_now_d(); + input.id = 0; + touch(input); + } + + if (backgroundScreen_) { + backgroundScreen_->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.. + // NOTE: We do not use the iterator solution here, because the screen array may change by sendMessage! + // Although if it does, that's very bad. + // We also pick out the stack size before, so we don't get infinite growth if a screen is pushed from the handler. + // We probably should delay pushes, though... + const size_t stack_size = stack_.size(); + for (int i = 0; i < stack_size; i++) { + if (stack_[i].screen) { + stack_[i].screen->sendMessage(message, value); + } + } +} + +void ScreenManager::shutdown() { + for (const auto &layer : stack_) + delete layer.screen; + stack_.clear(); + for (const auto &layer : nextStack_) + delete layer.screen; + nextStack_.clear(); + delete overlayScreen_; + overlayScreen_ = nullptr; + delete backgroundScreen_; + backgroundScreen_ = nullptr; +} + +void ScreenManager::push(Screen *screen, int layerFlags) { + screen->setScreenManager(this); + if (screen->isTransparent()) { + layerFlags |= LAYER_TRANSPARENT; + } + + // Release touches and unfocus. + UI::SetFocusedView(nullptr, UI::FocusFlags::CAUSE_SCREEN_CHANGE); + TouchInput input{}; + input.x = -50000.0f; + input.y = -50000.0f; + input.flags = TouchInputFlags::RELEASE_ALL; + input.timestamp = time_now_d(); + input.id = 0; + touch(input); + + Layer layer = {screen, layerFlags}; + + if (!stack_.empty()) { + stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); + } + + if (nextStack_.empty()) { + layer.screen->focusChanged(ScreenFocusChange::FOCUS_BECAME_TOP); + stack_.push_back(layer); + } else { + nextStack_.push_back(layer); + } +} + +void ScreenManager::pop() { + if (!stack_.empty()) { + stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); + + delete stack_.back().screen; + stack_.pop_back(); + + if (!stack_.empty()) { + stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); + } + } else { + ERROR_LOG(Log::UI, "Can't pop when stack empty"); + } +} + +void ScreenManager::RecreateAllViews() { + for (auto &layer : stack_) { + layer.screen->RecreateViews(); + } +} + +void ScreenManager::finishDialog(Screen *dialog, DialogResult result) { + if (stack_.empty()) { + ERROR_LOG(Log::UI, "Must be in a dialog to finishDialog"); + return; + } + if (dialog != stack_.back().screen) { + ERROR_LOG(Log::UI, "Wrong dialog being finished!"); + return; + } + dialog->onFinish(result); + dialogFinished_ = dialog; + dialogResult_ = result; +} + +Screen *ScreenManager::dialogParent(const Screen *dialog) const { + for (size_t i = 1; i < stack_.size(); ++i) { + if (stack_[i].screen == dialog) { + // The previous screen was the caller (not necessarily the topmost.) + return stack_[i - 1].screen; + } + } + + return nullptr; +} + +void ScreenManager::processFinishDialog() { + if (dialogFinished_) { + { + // Another dialog may have been pushed before the render, so search for it. + Screen *caller = dialogParent(dialogFinished_); + bool erased = false; + for (size_t i = 0; i < stack_.size(); ++i) { + if (stack_[i].screen == dialogFinished_) { + stack_[i].screen->focusChanged(ScreenFocusChange::FOCUS_LOST_TOP); + stack_.erase(stack_.begin() + i); + erased = true; + } + } + + if (erased && !stack_.empty()) { + stack_.back().screen->focusChanged(ScreenFocusChange::FOCUS_BECAME_TOP); + } + + if (!caller) { + ERROR_LOG(Log::UI, "ERROR: no top screen when finishing dialog"); + } else if (caller != topScreen()) { + // The caller may get confused if we call dialogFinished() now. + WARN_LOG(Log::UI, "Skipping non-top dialog when finishing dialog."); + } else { + caller->dialogFinished(dialogFinished_, dialogResult_); + } + } + delete dialogFinished_; + dialogFinished_ = nullptr; + } +} + +void ScreenManager::SetBackgroundOverlayScreens(Screen *backgroundScreen, Screen *overlayScreen) { + delete backgroundScreen_; + backgroundScreen_ = backgroundScreen; + backgroundScreen_->setScreenManager(this); + + delete overlayScreen_; + overlayScreen_ = overlayScreen; + overlayScreen_->setScreenManager(this); +} diff --git a/Common/UI/ScreenManager.h b/Common/UI/ScreenManager.h new file mode 100644 index 0000000000..c88c6f775d --- /dev/null +++ b/Common/UI/ScreenManager.h @@ -0,0 +1,126 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#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(); + + void switchScreen(Screen *screen); + 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(); + 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; + + // Instant touch, separate from the update() mechanism. + void touch(const TouchInput &touch); + void key(const KeyInput &key); + void axis(const AxisInput *axes, size_t count); + + 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_; + } + +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 stack_; + std::vector nextStack_; + + std::unordered_map lastAxis_; + + std::mutex eventQueueLock_; + std::deque eventQueue_; + + InputMode passInputToMapper_ = InputMode::None; +}; diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index 97d3b26d7c..4817514066 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -8,7 +8,7 @@ #include "Common/Input/KeyCodes.h" #include "Common/UI/UIScreen.h" #include "Common/UI/Context.h" -#include "Common/UI/Screen.h" +#include "Common/UI/ScreenManager.h" #include "Common/UI/Root.h" #include "Common/Render/DrawBuffer.h" diff --git a/UI/AdhocServerScreen.cpp b/UI/AdhocServerScreen.cpp index 9324423131..dbbf3761f7 100644 --- a/UI/AdhocServerScreen.cpp +++ b/UI/AdhocServerScreen.cpp @@ -18,6 +18,7 @@ #include "Common/Net/Resolve.h" #include "Common/UI/Root.h" #include "Common/UI/PopupScreens.h" +#include "Common/UI/ScreenManager.h" #include "Common/Data/Text/Parsers.h" #include "Common/StringUtils.h" #include "Common/Net/HTTPClient.h" diff --git a/UI/ChatScreen.cpp b/UI/ChatScreen.cpp index ba7ccc0be2..cbcaaef106 100644 --- a/UI/ChatScreen.cpp +++ b/UI/ChatScreen.cpp @@ -6,6 +6,7 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" #include "Common/UI/ScrollView.h" +#include "Common/UI/ScreenManager.h" #include "Common/UI/UI.h" #include "Common/Data/Text/I18n.h" diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index d4993ee9b4..0c491b8905 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -26,6 +26,7 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" #include "Common/UI/Notice.h" +#include "Common/UI/ScreenManager.h" #include "Common/VR/PPSSPPVR.h" #include "Common/Log.h" #include "Common/Data/Color/RGBAUtil.h" diff --git a/UI/CustomButtonMappingScreen.cpp b/UI/CustomButtonMappingScreen.cpp index 0cfc94d570..0fc971c36b 100644 --- a/UI/CustomButtonMappingScreen.cpp +++ b/UI/CustomButtonMappingScreen.cpp @@ -23,6 +23,7 @@ #include "Common/UI/ViewGroup.h" #include "Common/UI/ScrollView.h" #include "Common/UI/PopupScreens.h" +#include "Common/UI/ScreenManager.h" #include "Common/Data/Text/I18n.h" #include "Common/Data/Color/RGBAUtil.h" diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 3bf8234b41..497d8a001a 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -27,6 +27,7 @@ #include "Common/StringUtils.h" #include "Common/System/System.h" #include "Common/System/Request.h" +#include "Common/UI/ScreenManager.h" #include "Core/System.h" #include "Core/Config.h" #include "Core/CwCheat.h" diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index b6cbef6abe..13fd7b1f8d 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -43,6 +43,7 @@ #include "Common/UI/ViewGroup.h" #include "Common/UI/UI.h" #include "Common/UI/IconCache.h" +#include "Common/UI/ScreenManager.h" #include "Common/Render/Text/draw_text.h" #include "Common/Profiler/Profiler.h" diff --git a/UI/DeveloperToolsScreen.cpp b/UI/DeveloperToolsScreen.cpp index 0f3a728191..63321d4d9c 100644 --- a/UI/DeveloperToolsScreen.cpp +++ b/UI/DeveloperToolsScreen.cpp @@ -27,6 +27,7 @@ #include "Common/File/FileUtil.h" #include "Common/Render/Text/draw_text.h" #include "Common/StringUtils.h" +#include "Common/UI/ScreenManager.h" #include "GPU/Common/TextureReplacer.h" #include "GPU/Common/PostShader.h" #include "Core/MIPS/MIPSTracer.h" diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 7c1aee5720..836c83ad30 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -25,6 +25,7 @@ #include "Common/UI/View.h" #include "Common/UI/UIScreen.h" #include "Common/UI/TabHolder.h" +#include "Common/UI/ScreenManager.h" #include "Common/Math/math_util.h" #include "Common/System/NativeApp.h" #include "Common/VR/PPSSPPVR.h" diff --git a/UI/DriverManagerScreen.cpp b/UI/DriverManagerScreen.cpp index 11355b4676..3ad5fa8219 100644 --- a/UI/DriverManagerScreen.cpp +++ b/UI/DriverManagerScreen.cpp @@ -7,6 +7,7 @@ #include "Common/StringUtils.h" #include "Common/UI/PopupScreens.h" #include "Common/UI/Notice.h" +#include "Common/UI/ScreenManager.h" #include "Core/Config.h" #include "Core/System.h" diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 004a858d3d..93cc0c9350 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -33,6 +33,7 @@ using namespace std::placeholders; #include "Common/UI/Tween.h" #include "Common/UI/View.h" #include "Common/UI/AsyncImageFileView.h" +#include "Common/UI/ScreenManager.h" #include "Common/VR/PPSSPPVR.h" #include "Common/Data/Text/I18n.h" diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index e1c854d0f8..8113f73507 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -2,6 +2,7 @@ #include "Common/Data/Text/I18n.h" #include "Common/UI/UI.h" #include "Common/UI/View.h" +#include "Common/UI/ScreenManager.h" #include "Common/GPU/Shader.h" #include "Common/GPU/ShaderWriter.h" diff --git a/UI/GameBrowser.cpp b/UI/GameBrowser.cpp index a74bfc5033..68c9fbd6a3 100644 --- a/UI/GameBrowser.cpp +++ b/UI/GameBrowser.cpp @@ -25,6 +25,7 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" #include "Common/UI/Root.h" +#include "Common/UI/ScreenManager.h" #include "Common/Math/curves.h" #include "Common/Net/URL.h" diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index a7c4584e2a..8f46736091 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -34,6 +34,7 @@ #include "Common/System/OSD.h" #include "Common/System/Request.h" #include "Common/System/NativeApp.h" +#include "Common/UI/ScreenManager.h" #include "Core/Config.h" #include "Core/Reporting.h" #include "Core/System.h" diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index e0b978f4c2..a41d7382b0 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -30,6 +30,7 @@ #include "Common/UI/ViewGroup.h" #include "Common/UI/Context.h" #include "Common/UI/Notice.h" +#include "Common/UI/ScreenManager.h" #include "Common/Render/ManagedTexture.h" #include "Common/VR/PPSSPPVR.h" #include "Common/BitSet.h" diff --git a/UI/InstallZipScreen.cpp b/UI/InstallZipScreen.cpp index cf7bbf22f9..140b4040ed 100644 --- a/UI/InstallZipScreen.cpp +++ b/UI/InstallZipScreen.cpp @@ -19,6 +19,7 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" #include "Common/UI/Notice.h" +#include "Common/UI/ScreenManager.h" #include "Common/StringUtils.h" #include "Common/File/FileUtil.h" #include "Common/Data/Text/I18n.h" diff --git a/UI/JitCompareScreen.cpp b/UI/JitCompareScreen.cpp index d223a1f760..c64c451816 100644 --- a/UI/JitCompareScreen.cpp +++ b/UI/JitCompareScreen.cpp @@ -3,6 +3,7 @@ #include "UI/JitCompareScreen.h" #include "Common/Data/Text/I18n.h" #include "Common/UI/ViewGroup.h" +#include "Common/UI/ScreenManager.h" #include "Common/Render/DrawBuffer.h" #include "Core/MemMap.h" #include "Core/MIPS/MIPSTables.h" diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 3cadee899b..a034919bd8 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -28,6 +28,7 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" +#include "Common/UI/ScreenManager.h" #include "Common/File/FileUtil.h" #include "Common/StringUtils.h" #include "Core/System.h" diff --git a/UI/MemStickScreen.cpp b/UI/MemStickScreen.cpp index f794fe4cc6..40d291f903 100644 --- a/UI/MemStickScreen.cpp +++ b/UI/MemStickScreen.cpp @@ -24,6 +24,7 @@ #include "Common/UI/View.h" #include "Common/UI/ViewGroup.h" #include "Common/UI/PopupScreens.h" +#include "Common/UI/ScreenManager.h" #include "Common/StringUtils.h" #include "Common/System/System.h" diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index d46075f2ec..28ec75c0ec 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -37,6 +37,7 @@ #include "Common/Data/Color/RGBAUtil.h" #include "Common/Data/Encoding/Utf8.h" #include "Common/Data/Text/I18n.h" +#include "Common/UI/ScreenManager.h" #include "Common/TimeUtil.h" #include "Common/File/FileUtil.h" #include "Common/Render/ManagedTexture.h" diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 5f9cfb7610..62c07447da 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -56,6 +56,7 @@ #include "Common/GPU/thin3d.h" #include "Common/UI/UI.h" #include "Common/UI/Screen.h" +#include "Common/UI/ScreenManager.h" #include "Common/UI/Context.h" #include "Common/UI/View.h" #include "Common/UI/IconCache.h" diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index 32b2502e8a..e6c827374d 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -25,6 +25,7 @@ #include "Common/UI/UIScreen.h" #include "Common/UI/PopupScreens.h" #include "Common/UI/Notice.h" +#include "Common/UI/ScreenManager.h" #include "Common/GPU/thin3d.h" #include "Common/Data/Text/I18n.h" diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index f616904ab8..cfd0775941 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -38,6 +38,7 @@ #include "Common/File/PathBrowser.h" #include "Common/UI/PopupScreens.h" #include "Common/UI/Notice.h" +#include "Common/UI/ScreenManager.h" #include "Common/Data/Format/JSONReader.h" #include "Common/Data/Text/I18n.h" #include "Common/Common.h" diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index 02080aaf3b..413d831fe3 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -23,6 +23,7 @@ #include "Common/UI/AsyncImageFileView.h" #include "Common/UI/Context.h" #include "Common/UI/ScrollView.h" +#include "Common/UI/ScreenManager.h" #include "Common/Data/Text/I18n.h" #include "Common/File/FileUtil.h" #include "Common/Log.h" diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index b2452df513..bb0a50a65e 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -14,6 +14,7 @@ #include "Core/Config.h" #include "Core/RetroAchievements.h" +#include "Common/UI/ScreenManager.h" #include "UI/RetroAchievementScreens.h" #include "UI/BackgroundAudio.h" #include "UI/OnScreenDisplay.h" diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index a59cfddfbf..29aa0be2b9 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -31,6 +31,7 @@ #include "Common/UI/PopupScreens.h" #include "Common/UI/ViewGroup.h" #include "Common/UI/AsyncImageFileView.h" +#include "Common/UI/ScreenManager.h" #include "UI/SavedataScreen.h" #include "UI/MainScreen.h" #include "UI/GameInfoCache.h" diff --git a/UI/SimpleDialogScreen.cpp b/UI/SimpleDialogScreen.cpp index e0c0cc201c..1453a92b29 100644 --- a/UI/SimpleDialogScreen.cpp +++ b/UI/SimpleDialogScreen.cpp @@ -2,6 +2,7 @@ #include "Common/Data/Text/I18n.h" #include "UI/SimpleDialogScreen.h" #include "Common/UI/PopupScreens.h" +#include "Common/UI/ScreenManager.h" #include "UI/MiscViews.h" ViewLayoutMode UISimpleBaseDialogScreen::LayoutMode() const { diff --git a/UI/Store.cpp b/UI/Store.cpp index 7185ef345c..c467a0f5b4 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -22,6 +22,7 @@ #include "Common/UI/ViewGroup.h" #include "Common/UI/IconCache.h" #include "Common/UI/ScrollView.h" +#include "Common/UI/ScreenManager.h" #include "Common/Render/DrawBuffer.h" #include "Common/Log.h" diff --git a/UI/SystemInfoScreen.cpp b/UI/SystemInfoScreen.cpp index ca7e5ce2cd..cd0264322c 100644 --- a/UI/SystemInfoScreen.cpp +++ b/UI/SystemInfoScreen.cpp @@ -19,6 +19,7 @@ #include "Common/System/Request.h" #include "Common/UI/Context.h" #include "Common/UI/Notice.h" +#include "Common/UI/ScreenManager.h" #include "Core/System.h" #include "Core/Config.h" #include "GPU/GPUState.h" // ugh diff --git a/UI/TabbedDialogScreen.cpp b/UI/TabbedDialogScreen.cpp index ca9a3f842a..2542c20fc9 100644 --- a/UI/TabbedDialogScreen.cpp +++ b/UI/TabbedDialogScreen.cpp @@ -9,6 +9,7 @@ #include "Common/UI/ViewGroup.h" #include "Common/UI/ScrollView.h" #include "Common/UI/PopupScreens.h" +#include "Common/UI/ScreenManager.h" #include "UI/MiscViews.h" #include "Common/UI/Context.h" #include "UI/TabbedDialogScreen.h" diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index cfadb621f9..edf7481d05 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -25,6 +25,7 @@ #include "Common/System/Display.h" #include "Common/UI/Context.h" #include "Common/UI/PopupScreens.h" +#include "Common/UI/ScreenManager.h" #include "Common/CommonTypes.h" #include "Common/Log.h" diff --git a/UI/TouchControlVisibilityScreen.cpp b/UI/TouchControlVisibilityScreen.cpp index cf052ed4dc..fd9a5c4d0c 100644 --- a/UI/TouchControlVisibilityScreen.cpp +++ b/UI/TouchControlVisibilityScreen.cpp @@ -21,6 +21,7 @@ #include "Common/StringUtils.h" #include "Common/UI/TabHolder.h" #include "Common/UI/PopupScreens.h" +#include "Common/UI/ScreenManager.h" #include "Core/Config.h" diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index fbed1c53ed..c06762e56d 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -221,6 +221,7 @@ + @@ -406,6 +407,7 @@ + @@ -503,4 +505,4 @@ - + \ No newline at end of file diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index ca0c481ca5..91ab265c90 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -591,6 +591,9 @@ ext\pugixml + + UI + @@ -1145,6 +1148,9 @@ ext\pugixml + + UI + @@ -1187,4 +1193,4 @@ ext\at3_standalone - + \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index cba82ed6a4..0a058f5f2c 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -386,6 +386,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Common/UI/AsyncImageFileView.cpp \ $(SRC)/Common/UI/Root.cpp \ $(SRC)/Common/UI/Screen.cpp \ + $(SRC)/Common/UI/ScreenManager.cpp \ $(SRC)/Common/UI/UI.cpp \ $(SRC)/Common/UI/Context.cpp \ $(SRC)/Common/UI/UIScreen.cpp \