2020-09-15 19:12:32 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-06-21 12:25:28 +00:00
|
|
|
//
|
2020-09-15 19:12:32 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2020-06-21 12:25:28 +00:00
|
|
|
// Window.cpp
|
|
|
|
//
|
2020-11-11 23:46:59 +00:00
|
|
|
// Window management, screensaver management, and help prompts.
|
2020-09-15 19:12:32 +00:00
|
|
|
// The input stack starts here as well, as this is the first instance called by InputManager.
|
2020-06-21 12:25:28 +00:00
|
|
|
//
|
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
#include "Window.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
|
2014-01-25 23:34:29 +00:00
|
|
|
#include "components/HelpComponent.h"
|
2014-03-04 22:48:33 +00:00
|
|
|
#include "components/ImageComponent.h"
|
2021-06-22 22:24:15 +00:00
|
|
|
#if defined(BUILD_VLC_PLAYER)
|
2021-03-22 17:12:25 +00:00
|
|
|
#include "components/VideoVlcComponent.h"
|
2021-06-22 22:24:15 +00:00
|
|
|
#endif
|
2021-05-12 21:03:29 +00:00
|
|
|
#include "AudioManager.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "InputManager.h"
|
|
|
|
#include "Log.h"
|
2021-05-12 21:03:29 +00:00
|
|
|
#include "Sound.h"
|
2021-07-07 18:31:46 +00:00
|
|
|
#include "resources/Font.h"
|
2020-07-14 17:16:21 +00:00
|
|
|
|
2018-01-29 22:50:10 +00:00
|
|
|
#include <algorithm>
|
2017-11-01 22:21:10 +00:00
|
|
|
#include <iomanip>
|
2013-04-08 14:41:25 +00:00
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
#define CLOCK_BACKGROUND_CREATION false
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
Window::Window()
|
2021-07-07 18:31:46 +00:00
|
|
|
: mScreensaver(nullptr)
|
|
|
|
, mMediaViewer(nullptr)
|
|
|
|
, mLaunchScreen(nullptr)
|
|
|
|
, mInfoPopup(nullptr)
|
2021-09-18 07:53:26 +00:00
|
|
|
, mListScrollOpacity(0)
|
2021-07-07 18:31:46 +00:00
|
|
|
, mFrameTimeElapsed(0)
|
|
|
|
, mFrameCountElapsed(0)
|
|
|
|
, mAverageDeltaTime(10)
|
2021-09-18 07:53:26 +00:00
|
|
|
, mTimeSinceLastInput(0)
|
|
|
|
, mNormalizeNextUpdate(false)
|
2021-07-07 18:31:46 +00:00
|
|
|
, mAllowSleep(true)
|
|
|
|
, mSleeping(false)
|
|
|
|
, mRenderScreensaver(false)
|
|
|
|
, mRenderMediaViewer(false)
|
|
|
|
, mRenderLaunchScreen(false)
|
|
|
|
, mGameLaunchedState(false)
|
|
|
|
, mAllowTextScrolling(true)
|
|
|
|
, mCachedBackground(false)
|
|
|
|
, mInvalidatedCachedBackground(false)
|
|
|
|
, mVideoPlayerCount(0)
|
|
|
|
, mTopScale(0.5)
|
|
|
|
, mChangedThemeSet(false)
|
2013-04-08 14:41:25 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
mHelp = new HelpComponent(this);
|
|
|
|
mBackgroundOverlay = new ImageComponent(this);
|
2021-09-19 12:37:10 +00:00
|
|
|
mBackgroundOverlayOpacity = 0;
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Window::~Window()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
delete mBackgroundOverlay;
|
2013-12-12 19:48:29 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Delete all our GUIs.
|
|
|
|
while (peekGui())
|
|
|
|
delete peekGui();
|
2017-03-25 17:02:28 +00:00
|
|
|
|
2020-10-11 07:59:49 +00:00
|
|
|
if (mInfoPopup)
|
|
|
|
delete mInfoPopup;
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
delete mHelp;
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
void Window::pushGui(GuiComponent* gui)
|
2013-04-08 14:41:25 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mGuiStack.size() > 0) {
|
|
|
|
auto& top = mGuiStack.back();
|
|
|
|
top->topWindow(false);
|
|
|
|
}
|
|
|
|
mGuiStack.push_back(gui);
|
|
|
|
gui->updateHelpPrompts();
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
void Window::removeGui(GuiComponent* gui)
|
2013-04-08 14:41:25 +00:00
|
|
|
{
|
2020-07-18 11:21:44 +00:00
|
|
|
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++) {
|
|
|
|
if (*it == gui) {
|
|
|
|
it = mGuiStack.erase(it);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// We just popped the stack and the stack is not empty.
|
2020-07-18 11:21:44 +00:00
|
|
|
if (it == mGuiStack.cend() && mGuiStack.size()) {
|
2020-06-21 12:25:28 +00:00
|
|
|
mGuiStack.back()->updateHelpPrompts();
|
|
|
|
mGuiStack.back()->topWindow(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
GuiComponent* Window::peekGui()
|
2013-04-08 14:41:25 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mGuiStack.size() == 0)
|
|
|
|
return nullptr;
|
2013-04-08 14:41:25 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return mGuiStack.back();
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
|
|
|
|
2017-12-01 17:42:27 +00:00
|
|
|
bool Window::init()
|
2013-04-08 17:40:15 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!Renderer::init()) {
|
2020-08-30 20:25:38 +00:00
|
|
|
LOG(LogError) << "Renderer failed to initialize.";
|
2020-06-21 12:25:28 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-07-09 10:37:37 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
InputManager::getInstance()->init();
|
2013-07-09 10:37:37 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
ResourceManager::getInstance()->reloadAll();
|
2013-04-10 17:29:07 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Keep a reference to the default fonts, so they don't keep getting destroyed/recreated.
|
|
|
|
if (mDefaultFonts.empty()) {
|
|
|
|
mDefaultFonts.push_back(Font::get(FONT_SIZE_SMALL));
|
|
|
|
mDefaultFonts.push_back(Font::get(FONT_SIZE_MEDIUM));
|
|
|
|
mDefaultFonts.push_back(Font::get(FONT_SIZE_LARGE));
|
|
|
|
}
|
2013-07-09 10:37:37 +00:00
|
|
|
|
2021-01-12 22:10:06 +00:00
|
|
|
mBackgroundOverlay->setImage(":/graphics/screen_gradient.png");
|
2020-09-17 20:00:07 +00:00
|
|
|
mBackgroundOverlay->setResize(static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:31:46 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()));
|
2014-03-04 22:48:33 +00:00
|
|
|
|
2021-01-12 21:41:28 +00:00
|
|
|
mListScrollFont = Font::get(FONT_SIZE_LARGE);
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Update our help because font sizes probably changed.
|
|
|
|
if (peekGui())
|
|
|
|
peekGui()->updateHelpPrompts();
|
2014-01-25 23:34:29 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return true;
|
2013-04-08 17:40:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Window::deinit()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Hide all GUI elements on uninitialisation - this disable.
|
2020-07-18 11:21:44 +00:00
|
|
|
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++)
|
|
|
|
(*it)->onHide();
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
InputManager::getInstance()->deinit();
|
|
|
|
ResourceManager::getInstance()->unloadAll();
|
2021-07-07 18:31:46 +00:00
|
|
|
#if defined(BUILD_VLC_PLAYER)
|
2021-03-22 17:12:25 +00:00
|
|
|
VideoVlcComponent::deinit();
|
2021-07-07 18:31:46 +00:00
|
|
|
#endif
|
2020-06-21 12:25:28 +00:00
|
|
|
Renderer::deinit();
|
2013-04-08 17:40:15 +00:00
|
|
|
}
|
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
void Window::input(InputConfig* config, Input input)
|
|
|
|
{
|
2020-09-18 16:40:22 +00:00
|
|
|
mTimeSinceLastInput = 0;
|
|
|
|
|
2021-06-22 15:42:35 +00:00
|
|
|
// The DebugSkipInputLogging option has to be set manually in es_settings.xml as
|
|
|
|
// it does not have any settings menu entry.
|
|
|
|
if (Settings::getInstance()->getBool("Debug") &&
|
2021-07-07 18:31:46 +00:00
|
|
|
!Settings::getInstance()->getBool("DebugSkipInputLogging")) {
|
2020-09-15 19:12:32 +00:00
|
|
|
logInput(config, input);
|
2021-07-07 18:31:46 +00:00
|
|
|
}
|
2020-09-15 19:12:32 +00:00
|
|
|
|
2021-05-16 11:12:31 +00:00
|
|
|
if (mMediaViewer && mRenderMediaViewer) {
|
|
|
|
if (config->isMappedLike("right", input) && input.value != 0)
|
|
|
|
mMediaViewer->showNext();
|
|
|
|
else if (config->isMappedLike("left", input) && input.value != 0)
|
|
|
|
mMediaViewer->showPrevious();
|
|
|
|
else if (input.value != 0)
|
|
|
|
// Any other input than left or right stops the media viewer.
|
|
|
|
stopMediaViewer();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-14 17:15:22 +00:00
|
|
|
if (mGameLaunchedState && mLaunchScreen && mRenderLaunchScreen) {
|
|
|
|
if (input.value != 0) {
|
|
|
|
mLaunchScreen->closeLaunchScreen();
|
|
|
|
mRenderLaunchScreen = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-10 21:33:57 +00:00
|
|
|
if (mScreensaver) {
|
|
|
|
if (mScreensaver->isScreensaverActive() &&
|
2021-07-07 18:31:46 +00:00
|
|
|
Settings::getInstance()->getBool("ScreensaverControls") &&
|
|
|
|
((Settings::getInstance()->getString("ScreensaverType") == "video") ||
|
|
|
|
(Settings::getInstance()->getString("ScreensaverType") == "slideshow"))) {
|
2020-11-10 21:18:20 +00:00
|
|
|
bool customImageSlideshow = false;
|
|
|
|
if (Settings::getInstance()->getString("ScreensaverType") == "slideshow" &&
|
2021-07-07 18:31:46 +00:00
|
|
|
Settings::getInstance()->getBool("ScreensaverSlideshowCustomImages"))
|
2020-11-10 21:18:20 +00:00
|
|
|
customImageSlideshow = true;
|
|
|
|
|
2020-11-10 21:42:25 +00:00
|
|
|
if ((customImageSlideshow || mScreensaver->getCurrentGame() != nullptr) &&
|
2021-07-07 18:31:46 +00:00
|
|
|
(config->isMappedTo("a", input) || config->isMappedTo("y", input) ||
|
|
|
|
config->isMappedLike("left", input) || config->isMappedLike("right", input))) {
|
2020-07-27 14:53:54 +00:00
|
|
|
// Left or right browses to the next video or image.
|
|
|
|
if (config->isMappedLike("left", input) || config->isMappedLike("right", input)) {
|
2020-06-21 12:25:28 +00:00
|
|
|
if (input.value != 0) {
|
|
|
|
// Handle screensaver control.
|
2020-11-10 21:33:57 +00:00
|
|
|
mScreensaver->nextGame();
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2020-07-27 14:53:54 +00:00
|
|
|
else if (config->isMappedTo("a", input) && input.value != 0) {
|
2020-07-14 17:16:21 +00:00
|
|
|
// Launch game.
|
2020-11-12 16:13:24 +00:00
|
|
|
stopScreensaver();
|
2020-11-10 21:33:57 +00:00
|
|
|
mScreensaver->launchGame();
|
2020-06-21 12:25:28 +00:00
|
|
|
// To force handling the wake up process.
|
|
|
|
mSleeping = true;
|
|
|
|
}
|
2020-11-12 16:13:24 +00:00
|
|
|
else if (config->isMappedTo("y", input) && input.value != 0) {
|
|
|
|
// Jump to the game in its gamelist, but do not launch it.
|
|
|
|
stopScreensaver();
|
|
|
|
NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND);
|
|
|
|
mScreensaver->goToGame();
|
|
|
|
// To force handling the wake up process.
|
|
|
|
mSleeping = true;
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mSleeping) {
|
|
|
|
// Wake up.
|
2020-11-12 16:13:24 +00:00
|
|
|
stopScreensaver();
|
2020-06-21 12:25:28 +00:00
|
|
|
mSleeping = false;
|
|
|
|
onWake();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-18 16:40:22 +00:00
|
|
|
// Any keypress cancels the screensaver.
|
2020-11-10 21:18:20 +00:00
|
|
|
if (input.value != 0 && isScreensaverActive()) {
|
2020-11-12 16:13:24 +00:00
|
|
|
stopScreensaver();
|
2020-09-18 16:40:22 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2021-08-19 20:28:31 +00:00
|
|
|
if (config->isMappedTo("a", input) && input.value != 0 &&
|
|
|
|
Settings::getInstance()->getString("MenuOpeningEffect") == "scale-up" && mTopScale < 1.0f &&
|
|
|
|
mGuiStack.size() == 2) {
|
|
|
|
// The user has entered a submenu when the initial menu screen has not finished scaling
|
|
|
|
// up. So scale it to full size so it won't be stuck at a smaller size when returning
|
|
|
|
// from the submenu.
|
|
|
|
mTopScale = 1.0f;
|
|
|
|
GuiComponent* menu = mGuiStack.back();
|
|
|
|
glm::vec2 menuCenter{menu->getCenter()};
|
|
|
|
menu->setOrigin(0.5f, 0.5f);
|
|
|
|
menu->setPosition(menuCenter.x, menuCenter.y, 0.0f);
|
|
|
|
menu->setScale(1.0f);
|
|
|
|
}
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_g &&
|
2021-07-07 18:31:46 +00:00
|
|
|
SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug")) {
|
2020-06-21 12:25:28 +00:00
|
|
|
// Toggle debug grid with Ctrl-G.
|
|
|
|
Settings::getInstance()->setBool("DebugGrid",
|
2021-07-07 18:31:46 +00:00
|
|
|
!Settings::getInstance()->getBool("DebugGrid"));
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
else if (config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_t &&
|
2021-07-07 18:31:46 +00:00
|
|
|
SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug")) {
|
2020-06-21 12:25:28 +00:00
|
|
|
// Toggle TextComponent debug view with Ctrl-T.
|
|
|
|
Settings::getInstance()->setBool("DebugText",
|
2021-07-07 18:31:46 +00:00
|
|
|
!Settings::getInstance()->getBool("DebugText"));
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
else if (config->getDeviceId() == DEVICE_KEYBOARD && input.value && input.id == SDLK_i &&
|
2021-07-07 18:31:46 +00:00
|
|
|
SDL_GetModState() & KMOD_LCTRL && Settings::getInstance()->getBool("Debug")) {
|
2020-11-16 16:46:36 +00:00
|
|
|
// Toggle ImageComponent debug view with Ctrl-I.
|
2020-06-21 12:25:28 +00:00
|
|
|
Settings::getInstance()->setBool("DebugImage",
|
2021-07-07 18:31:46 +00:00
|
|
|
!Settings::getInstance()->getBool("DebugImage"));
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (peekGui())
|
|
|
|
// This is where the majority of inputs will be consumed: the GuiComponent Stack.
|
|
|
|
this->peekGui()->input(config, input);
|
|
|
|
}
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
|
|
|
|
2021-06-11 15:02:06 +00:00
|
|
|
void Window::textInput(const std::string& text)
|
|
|
|
{
|
|
|
|
if (peekGui())
|
|
|
|
peekGui()->textInput(text);
|
|
|
|
}
|
|
|
|
|
2020-09-15 19:12:32 +00:00
|
|
|
void Window::logInput(InputConfig* config, Input input)
|
|
|
|
{
|
|
|
|
std::string mapname = "";
|
|
|
|
std::vector<std::string> maps = config->getMappedTo(input);
|
|
|
|
|
|
|
|
for (auto mn : maps) {
|
|
|
|
mapname += mn;
|
|
|
|
mapname += ", ";
|
|
|
|
}
|
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
LOG(LogDebug) << "Window::logInput(" << config->getDeviceName() << "): " << input.string()
|
|
|
|
<< ", isMappedTo=" << mapname << "value=" << input.value;
|
2020-09-15 19:12:32 +00:00
|
|
|
}
|
|
|
|
|
2013-04-08 14:41:25 +00:00
|
|
|
void Window::update(int deltaTime)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mNormalizeNextUpdate) {
|
|
|
|
mNormalizeNextUpdate = false;
|
2020-09-17 20:00:07 +00:00
|
|
|
mTimeSinceLastInput = 0;
|
2020-06-21 12:25:28 +00:00
|
|
|
if (deltaTime > mAverageDeltaTime)
|
|
|
|
deltaTime = mAverageDeltaTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
mFrameTimeElapsed += deltaTime;
|
|
|
|
mFrameCountElapsed++;
|
|
|
|
if (mFrameTimeElapsed > 500) {
|
|
|
|
mAverageDeltaTime = mFrameTimeElapsed / mFrameCountElapsed;
|
|
|
|
|
2020-08-15 07:33:08 +00:00
|
|
|
if (Settings::getInstance()->getBool("DisplayGPUStatistics")) {
|
2020-06-21 12:25:28 +00:00
|
|
|
std::stringstream ss;
|
|
|
|
|
|
|
|
// FPS.
|
2021-07-07 18:31:46 +00:00
|
|
|
ss << std::fixed << std::setprecision(1)
|
|
|
|
<< (1000.0f * static_cast<float>(mFrameCountElapsed) /
|
|
|
|
static_cast<float>(mFrameTimeElapsed))
|
|
|
|
<< " FPS (";
|
|
|
|
ss << std::fixed << std::setprecision(2)
|
|
|
|
<< (static_cast<float>(mFrameTimeElapsed) / static_cast<float>(mFrameCountElapsed))
|
|
|
|
<< " ms)";
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-08-15 07:33:08 +00:00
|
|
|
// The following calculations are not accurate, and the font calculation is completely
|
|
|
|
// broken. For now, still report the figures as it's somehow useful to locate memory
|
|
|
|
// leaks and similar. But this needs to be completely overhauled later on.
|
2020-06-21 12:25:28 +00:00
|
|
|
// VRAM.
|
2020-08-08 20:33:27 +00:00
|
|
|
float textureVramUsageMiB = TextureResource::getTotalMemUsage() / 1024.0f / 1024.0f;
|
|
|
|
float textureTotalUsageMiB = TextureResource::getTotalTextureSize() / 1024.0f / 1024.0f;
|
|
|
|
float fontVramUsageMiB = Font::getTotalMemUsage() / 1024.0f / 1024.0f;
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
ss << "\nFont VRAM: " << fontVramUsageMiB
|
|
|
|
<< " MiB\nTexture VRAM: " << textureVramUsageMiB
|
|
|
|
<< " MiB\nMax Texture VRAM: " << textureTotalUsageMiB << " MiB";
|
|
|
|
mFrameDataText = std::unique_ptr<TextCache>(mDefaultFonts.at(0)->buildTextCache(
|
|
|
|
ss.str(), Renderer::getScreenWidth() * 0.02f, Renderer::getScreenHeight() * 0.02f,
|
|
|
|
0xFF00FFFF, 1.3f));
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mFrameTimeElapsed = 0;
|
|
|
|
mFrameCountElapsed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
mTimeSinceLastInput += deltaTime;
|
|
|
|
|
|
|
|
if (peekGui())
|
|
|
|
peekGui()->update(deltaTime);
|
|
|
|
|
2021-04-05 08:05:08 +00:00
|
|
|
// If the theme set changed, we need to update the background once so that the camera
|
|
|
|
// will be moved. This is required as theme set changes always makes a transition to
|
2021-06-14 17:15:22 +00:00
|
|
|
// the system view. If we wouldn't make this update, the camera movement would take
|
|
|
|
// place once the menu has been closed.
|
2021-04-05 08:05:08 +00:00
|
|
|
if (mChangedThemeSet && mGuiStack.size() > 1) {
|
|
|
|
mGuiStack.front()->update(deltaTime);
|
|
|
|
mChangedThemeSet = false;
|
|
|
|
}
|
|
|
|
|
2021-05-16 11:12:31 +00:00
|
|
|
if (mMediaViewer && mRenderMediaViewer)
|
|
|
|
mMediaViewer->update(deltaTime);
|
|
|
|
|
2021-06-14 17:15:22 +00:00
|
|
|
if (mLaunchScreen && mRenderLaunchScreen)
|
|
|
|
mLaunchScreen->update(deltaTime);
|
|
|
|
|
2021-05-16 11:12:31 +00:00
|
|
|
if (mScreensaver && mRenderScreensaver)
|
2020-11-10 21:33:57 +00:00
|
|
|
mScreensaver->update(deltaTime);
|
2013-04-08 14:41:25 +00:00
|
|
|
}
|
|
|
|
|
2021-08-22 14:43:15 +00:00
|
|
|
bool Window::isBackgroundDimmed()
|
|
|
|
{
|
|
|
|
return !mGuiStack.empty() && (mGuiStack.front() != mGuiStack.back() || mRenderLaunchScreen);
|
|
|
|
}
|
|
|
|
|
2013-07-17 06:47:02 +00:00
|
|
|
void Window::render()
|
|
|
|
{
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::mat4 trans{Renderer::getIdentity()};
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
mRenderedHelpPrompts = false;
|
|
|
|
|
|
|
|
// Draw only bottom and top of GuiStack (if they are different).
|
2021-08-22 14:43:15 +00:00
|
|
|
if (!mGuiStack.empty()) {
|
2020-06-21 12:25:28 +00:00
|
|
|
auto& bottom = mGuiStack.front();
|
|
|
|
auto& top = mGuiStack.back();
|
|
|
|
|
2021-05-16 11:12:31 +00:00
|
|
|
if (mRenderMediaViewer || mRenderScreensaver) {
|
2020-09-17 20:00:07 +00:00
|
|
|
bottom->cancelAllAnimations();
|
|
|
|
bottom->stopAllAnimations();
|
|
|
|
}
|
|
|
|
|
2021-05-16 15:43:18 +00:00
|
|
|
// Don't render the system view or gamelist view if the media viewer is active or if the
|
|
|
|
// video or slideshow screensaver is running. The exception is if the fallback screensaver
|
|
|
|
// is active due to a lack of videos or images.
|
|
|
|
bool renderBottom = true;
|
|
|
|
if (mRenderMediaViewer)
|
|
|
|
renderBottom = false;
|
|
|
|
else if (mRenderScreensaver && mScreensaver->isFallbackScreensaver())
|
|
|
|
renderBottom = true;
|
|
|
|
else if (mRenderScreensaver &&
|
2021-07-07 18:31:46 +00:00
|
|
|
Settings::getInstance()->getString("ScreensaverType") == "video")
|
2021-05-16 15:43:18 +00:00
|
|
|
renderBottom = false;
|
|
|
|
else if (mRenderScreensaver &&
|
2021-07-07 18:31:46 +00:00
|
|
|
Settings::getInstance()->getString("ScreensaverType") == "slideshow")
|
2021-05-16 15:43:18 +00:00
|
|
|
renderBottom = false;
|
|
|
|
|
|
|
|
if (renderBottom)
|
2021-08-15 17:30:31 +00:00
|
|
|
bottom->render(trans);
|
2020-11-18 22:52:29 +00:00
|
|
|
|
2021-06-14 17:15:22 +00:00
|
|
|
if (bottom != top || mRenderLaunchScreen) {
|
2021-07-07 18:31:46 +00:00
|
|
|
#if defined(USE_OPENGL_21)
|
2020-09-13 11:21:38 +00:00
|
|
|
if (!mCachedBackground) {
|
|
|
|
// Generate a cache texture of the shaded background when opening the menu, which
|
|
|
|
// will remain valid until the menu is closed. This is way faster than having to
|
|
|
|
// render the shaders for every frame.
|
2021-07-07 18:31:46 +00:00
|
|
|
#if (CLOCK_BACKGROUND_CREATION)
|
|
|
|
const auto backgroundStartTime = std::chrono::system_clock::now();
|
|
|
|
#endif
|
2021-03-17 19:29:43 +00:00
|
|
|
|
2020-09-13 11:21:38 +00:00
|
|
|
std::shared_ptr<TextureResource> mPostprocessedBackground;
|
|
|
|
mPostprocessedBackground = TextureResource::get("");
|
2021-07-07 18:31:46 +00:00
|
|
|
unsigned char* processedTexture =
|
|
|
|
new unsigned char[Renderer::getScreenWidth() * Renderer::getScreenHeight() * 4];
|
2020-09-13 11:21:38 +00:00
|
|
|
|
2021-08-22 14:43:15 +00:00
|
|
|
// De-focus the background using multiple passes of gaussian blur, with the number
|
2021-03-17 19:29:43 +00:00
|
|
|
// of iterations relative to the screen resolution.
|
|
|
|
Renderer::shaderParameters backgroundParameters;
|
2021-03-18 18:46:45 +00:00
|
|
|
|
|
|
|
if (Settings::getInstance()->getBool("MenuBlurBackground")) {
|
|
|
|
float heightModifier = Renderer::getScreenHeightModifier();
|
2021-07-07 18:31:46 +00:00
|
|
|
// clang-format off
|
2021-03-18 18:46:45 +00:00
|
|
|
if (heightModifier < 1)
|
|
|
|
backgroundParameters.blurPasses = 2; // Below 1080
|
|
|
|
else if (heightModifier >= 4)
|
|
|
|
backgroundParameters.blurPasses = 12; // 8K
|
|
|
|
else if (heightModifier >= 2.9)
|
|
|
|
backgroundParameters.blurPasses = 10; // 6K
|
|
|
|
else if (heightModifier >= 2.6)
|
|
|
|
backgroundParameters.blurPasses = 8; // 5K
|
|
|
|
else if (heightModifier >= 2)
|
|
|
|
backgroundParameters.blurPasses = 5; // 4K
|
|
|
|
else if (heightModifier >= 1.3)
|
|
|
|
backgroundParameters.blurPasses = 3; // 1440
|
|
|
|
else if (heightModifier >= 1)
|
|
|
|
backgroundParameters.blurPasses = 2; // 1080
|
2021-07-07 18:31:46 +00:00
|
|
|
// clang-format on
|
2021-03-18 18:46:45 +00:00
|
|
|
|
|
|
|
// Also dim the background slightly.
|
|
|
|
backgroundParameters.fragmentDimValue = 0.60f;
|
|
|
|
|
|
|
|
Renderer::shaderPostprocessing(Renderer::SHADER_BLUR_HORIZONTAL |
|
2021-07-07 18:31:46 +00:00
|
|
|
Renderer::SHADER_BLUR_VERTICAL |
|
|
|
|
Renderer::SHADER_DIM,
|
|
|
|
backgroundParameters, processedTexture);
|
2021-03-18 18:46:45 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Dim the background slightly.
|
|
|
|
backgroundParameters.fragmentDimValue = 0.60f;
|
2021-07-07 18:31:46 +00:00
|
|
|
Renderer::shaderPostprocessing(Renderer::SHADER_DIM, backgroundParameters,
|
|
|
|
processedTexture);
|
2021-03-18 18:46:45 +00:00
|
|
|
}
|
2020-11-11 23:46:59 +00:00
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
mPostprocessedBackground->initFromPixels(
|
|
|
|
processedTexture, Renderer::getScreenWidth(), Renderer::getScreenHeight());
|
2020-11-11 23:46:59 +00:00
|
|
|
|
|
|
|
mBackgroundOverlay->setImage(mPostprocessedBackground);
|
|
|
|
|
|
|
|
// The following is done to avoid fading in if the cached image was
|
|
|
|
// invalidated (rather than the menu being opened).
|
|
|
|
if (mInvalidatedCachedBackground) {
|
|
|
|
mBackgroundOverlayOpacity = 255;
|
|
|
|
mInvalidatedCachedBackground = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mBackgroundOverlayOpacity = 25;
|
|
|
|
}
|
2020-09-13 11:21:38 +00:00
|
|
|
|
|
|
|
delete[] processedTexture;
|
|
|
|
mCachedBackground = true;
|
2021-03-17 19:29:43 +00:00
|
|
|
|
2021-07-07 18:31:46 +00:00
|
|
|
#if (CLOCK_BACKGROUND_CREATION)
|
|
|
|
const auto backgroundEndTime = std::chrono::system_clock::now();
|
|
|
|
LOG(LogDebug) << "Window::render(): Time to create cached background: "
|
|
|
|
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
|
|
backgroundEndTime - backgroundStartTime)
|
|
|
|
.count()
|
|
|
|
<< " ms";
|
|
|
|
#endif
|
2021-03-17 19:29:43 +00:00
|
|
|
}
|
2021-06-22 15:52:57 +00:00
|
|
|
// Fade in the cached background if the menu opening effect has been set to scale-up.
|
|
|
|
if (Settings::getInstance()->getString("MenuOpeningEffect") == "scale-up") {
|
2021-03-17 19:29:43 +00:00
|
|
|
mBackgroundOverlay->setOpacity(mBackgroundOverlayOpacity);
|
|
|
|
if (mBackgroundOverlayOpacity < 255)
|
2021-08-17 18:55:29 +00:00
|
|
|
mBackgroundOverlayOpacity = glm::clamp(mBackgroundOverlayOpacity + 30, 0, 255);
|
2020-09-13 11:21:38 +00:00
|
|
|
}
|
2021-07-07 18:31:46 +00:00
|
|
|
#endif // USE_OPENGL_21
|
2020-11-11 23:46:59 +00:00
|
|
|
|
2021-08-15 17:30:31 +00:00
|
|
|
mBackgroundOverlay->render(trans);
|
2020-09-13 11:21:38 +00:00
|
|
|
|
2021-06-22 15:52:57 +00:00
|
|
|
// Scale-up menu opening effect.
|
2020-09-13 11:46:34 +00:00
|
|
|
if (Settings::getInstance()->getString("MenuOpeningEffect") == "scale-up") {
|
2021-06-14 17:15:22 +00:00
|
|
|
if (mTopScale < 1.0f) {
|
2021-08-17 18:55:29 +00:00
|
|
|
mTopScale = glm::clamp(mTopScale + 0.07f, 0.0f, 1.0f);
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::vec2 topCenter{top->getCenter()};
|
2021-08-19 20:28:31 +00:00
|
|
|
top->setOrigin(0.5f, 0.5f);
|
|
|
|
top->setPosition(topCenter.x, topCenter.y, 0.0f);
|
2021-06-14 17:15:22 +00:00
|
|
|
top->setScale(mTopScale);
|
|
|
|
}
|
2020-09-13 11:21:38 +00:00
|
|
|
}
|
|
|
|
|
2021-06-14 17:15:22 +00:00
|
|
|
if (!mRenderLaunchScreen)
|
2021-08-15 17:30:31 +00:00
|
|
|
top->render(trans);
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2020-09-13 11:21:38 +00:00
|
|
|
else {
|
|
|
|
mCachedBackground = false;
|
2021-07-07 18:31:46 +00:00
|
|
|
mTopScale = 0.5f;
|
2020-09-13 11:21:38 +00:00
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
2021-01-13 22:46:51 +00:00
|
|
|
// Render the quick list scrolling overlay, which is triggered in IList.
|
2021-01-12 21:41:28 +00:00
|
|
|
if (mListScrollOpacity != 0) {
|
2021-08-15 17:30:31 +00:00
|
|
|
Renderer::setMatrix(Renderer::getIdentity());
|
2021-01-12 21:41:28 +00:00
|
|
|
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:31:46 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()),
|
|
|
|
0x00000000 | mListScrollOpacity, 0x00000000 | mListScrollOpacity);
|
2021-01-12 21:41:28 +00:00
|
|
|
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::vec2 offset{mListScrollFont->sizeText(mListScrollText)};
|
2021-08-16 16:25:01 +00:00
|
|
|
offset.x = (Renderer::getScreenWidth() - offset.x) * 0.5f;
|
|
|
|
offset.y = (Renderer::getScreenHeight() - offset.y) * 0.5f;
|
2021-01-12 21:41:28 +00:00
|
|
|
|
2021-08-16 16:25:01 +00:00
|
|
|
TextCache* cache = mListScrollFont->buildTextCache(mListScrollText, offset.x, offset.y,
|
2021-07-07 18:31:46 +00:00
|
|
|
0xFFFFFF00 | mListScrollOpacity);
|
2021-01-12 21:41:28 +00:00
|
|
|
mListScrollFont->renderTextCache(cache);
|
|
|
|
delete cache;
|
|
|
|
}
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!mRenderedHelpPrompts)
|
2021-08-15 17:30:31 +00:00
|
|
|
mHelp->render(trans);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
unsigned int screensaverTimer =
|
2021-07-07 18:31:46 +00:00
|
|
|
static_cast<unsigned int>(Settings::getInstance()->getInt("ScreensaverTimer"));
|
2020-11-05 17:18:11 +00:00
|
|
|
if (mTimeSinceLastInput >= screensaverTimer && screensaverTimer != 0) {
|
2021-05-16 11:12:31 +00:00
|
|
|
// If the media viewer is running or if a menu is open, reset the screensaver timer so
|
|
|
|
// that the screensaver won't start.
|
|
|
|
if (mRenderMediaViewer || mGuiStack.front() != mGuiStack.back())
|
2020-07-18 11:21:44 +00:00
|
|
|
mTimeSinceLastInput = 0;
|
2020-11-10 21:18:20 +00:00
|
|
|
// If a game has been launched, reset the screensaver timer as we don't want to start
|
|
|
|
// the screensaver in the background when running a game.
|
|
|
|
else if (mGameLaunchedState)
|
|
|
|
mTimeSinceLastInput = 0;
|
2020-11-10 21:33:57 +00:00
|
|
|
else if (!isProcessing() && !mScreensaver->isScreensaverActive())
|
2020-11-10 21:18:20 +00:00
|
|
|
startScreensaver();
|
2020-07-18 11:21:44 +00:00
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Always call the screensaver render function regardless of whether the screensaver is active
|
|
|
|
// or not because it may perform a fade on transition.
|
2020-11-10 21:18:20 +00:00
|
|
|
renderScreensaver();
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-11-10 21:33:57 +00:00
|
|
|
if (!mRenderScreensaver && mInfoPopup)
|
2021-08-15 17:30:31 +00:00
|
|
|
mInfoPopup->render(trans);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-11-05 17:18:11 +00:00
|
|
|
if (mTimeSinceLastInput >= screensaverTimer && screensaverTimer != 0) {
|
2020-11-10 21:33:57 +00:00
|
|
|
if (!isProcessing() && mAllowSleep && (!mScreensaver)) {
|
2020-06-21 12:25:28 +00:00
|
|
|
// Go to sleep.
|
|
|
|
if (mSleeping == false) {
|
|
|
|
mSleeping = true;
|
|
|
|
onSleep();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-13 11:21:38 +00:00
|
|
|
|
2021-05-16 11:12:31 +00:00
|
|
|
if (mRenderMediaViewer)
|
2021-09-18 09:49:39 +00:00
|
|
|
mMediaViewer->render(trans);
|
2021-05-16 11:12:31 +00:00
|
|
|
|
2021-06-14 17:15:22 +00:00
|
|
|
if (mRenderLaunchScreen)
|
2021-09-18 09:49:39 +00:00
|
|
|
mLaunchScreen->render(trans);
|
2021-06-14 17:15:22 +00:00
|
|
|
|
2020-09-13 11:21:38 +00:00
|
|
|
if (Settings::getInstance()->getBool("DisplayGPUStatistics") && mFrameDataText) {
|
2021-08-15 17:30:31 +00:00
|
|
|
Renderer::setMatrix(Renderer::getIdentity());
|
2020-09-13 11:21:38 +00:00
|
|
|
mDefaultFonts.at(1)->renderTextCache(mFrameDataText.get());
|
|
|
|
}
|
2013-07-17 06:47:02 +00:00
|
|
|
}
|
|
|
|
|
2019-01-31 20:19:34 +00:00
|
|
|
void Window::renderLoadingScreen(std::string text)
|
2013-12-12 19:48:29 +00:00
|
|
|
{
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::mat4 trans{Renderer::getIdentity()};
|
2020-06-21 12:25:28 +00:00
|
|
|
Renderer::setMatrix(trans);
|
2020-12-29 10:06:01 +00:00
|
|
|
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:31:46 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()), 0x000000FF, 0x000000FF);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
ImageComponent splash(this, true);
|
|
|
|
splash.setResize(Renderer::getScreenWidth() * 0.6f, 0.0f);
|
2020-06-21 17:35:43 +00:00
|
|
|
splash.setImage(":/graphics/splash.svg");
|
2021-08-16 16:25:01 +00:00
|
|
|
splash.setPosition((Renderer::getScreenWidth() - splash.getSize().x) / 2.0f,
|
|
|
|
(Renderer::getScreenHeight() - splash.getSize().y) / 2.0f * 0.6f);
|
2020-06-21 12:25:28 +00:00
|
|
|
splash.render(trans);
|
|
|
|
|
|
|
|
auto& font = mDefaultFonts.at(1);
|
2021-07-07 18:31:46 +00:00
|
|
|
TextCache* cache = font->buildTextCache(text, 0.0f, 0.0f, 0x656565FF);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2021-08-16 16:25:01 +00:00
|
|
|
float x = std::round((Renderer::getScreenWidth() - cache->metrics.size.x) / 2.0f);
|
2020-12-28 10:29:32 +00:00
|
|
|
float y = std::round(Renderer::getScreenHeight() * 0.835f);
|
2021-08-17 16:41:45 +00:00
|
|
|
trans = glm::translate(trans, glm::vec3{x, y, 0.0f});
|
2020-06-21 12:25:28 +00:00
|
|
|
Renderer::setMatrix(trans);
|
|
|
|
font->renderTextCache(cache);
|
|
|
|
delete cache;
|
|
|
|
|
|
|
|
Renderer::swapBuffers();
|
2013-12-12 19:48:29 +00:00
|
|
|
}
|
2014-01-25 23:34:29 +00:00
|
|
|
|
2021-01-12 21:41:28 +00:00
|
|
|
void Window::renderListScrollOverlay(unsigned char opacity, const std::string& text)
|
|
|
|
{
|
|
|
|
mListScrollOpacity = static_cast<unsigned char>(opacity * 0.6f);
|
|
|
|
mListScrollText = text;
|
|
|
|
}
|
|
|
|
|
2014-05-15 01:58:16 +00:00
|
|
|
void Window::renderHelpPromptsEarly()
|
|
|
|
{
|
2021-08-15 17:30:31 +00:00
|
|
|
mHelp->render(Renderer::getIdentity());
|
2020-06-21 12:25:28 +00:00
|
|
|
mRenderedHelpPrompts = true;
|
2014-05-15 01:58:16 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 20:41:47 +00:00
|
|
|
void Window::setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpStyle& style)
|
2014-01-25 23:34:29 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
mHelp->clearPrompts();
|
|
|
|
mHelp->setStyle(style);
|
|
|
|
|
|
|
|
std::vector<HelpPrompt> addPrompts;
|
|
|
|
|
|
|
|
std::map<std::string, bool> inputSeenMap;
|
|
|
|
std::map<std::string, int> mappedToSeenMap;
|
|
|
|
for (auto it = prompts.cbegin(); it != prompts.cend(); it++) {
|
|
|
|
// Only add it if the same icon hasn't already been added.
|
|
|
|
if (inputSeenMap.emplace(it->first, true).second) {
|
|
|
|
// This symbol hasn't been seen yet, what about the action name?
|
|
|
|
auto mappedTo = mappedToSeenMap.find(it->second);
|
|
|
|
if (mappedTo != mappedToSeenMap.cend()) {
|
|
|
|
// Yes, it has!
|
|
|
|
|
|
|
|
// Can we combine? (dpad only).
|
|
|
|
if ((it->first == "up/down" &&
|
2021-07-07 18:31:46 +00:00
|
|
|
addPrompts.at(mappedTo->second).first != "left/right") ||
|
|
|
|
(it->first == "left/right" &&
|
|
|
|
addPrompts.at(mappedTo->second).first != "up/down")) {
|
|
|
|
// Yes.
|
2020-06-21 12:25:28 +00:00
|
|
|
addPrompts.at(mappedTo->second).first = "up/down/left/right";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
addPrompts.push_back(*it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-09-17 20:00:07 +00:00
|
|
|
mappedToSeenMap.emplace(it->second, static_cast<int>(addPrompts.size()));
|
2020-06-21 12:25:28 +00:00
|
|
|
addPrompts.push_back(*it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-23 18:31:15 +00:00
|
|
|
// Sort prompts so it goes [dpad_all] [dpad_u/d] [dpad_l/r] [a/b/x/y/l/r] [start/back].
|
2020-06-21 12:25:28 +00:00
|
|
|
std::sort(addPrompts.begin(), addPrompts.end(),
|
2021-07-07 18:31:46 +00:00
|
|
|
[](const HelpPrompt& a, const HelpPrompt& b) -> bool {
|
2021-08-17 16:41:45 +00:00
|
|
|
static const std::vector<std::string> map = {"up/down/left/right",
|
|
|
|
"up/down",
|
|
|
|
"left/right",
|
|
|
|
"a",
|
|
|
|
"b",
|
|
|
|
"x",
|
|
|
|
"y",
|
|
|
|
"r",
|
2021-09-17 19:14:43 +00:00
|
|
|
"l",
|
|
|
|
"rt",
|
|
|
|
"lt",
|
2021-08-17 16:41:45 +00:00
|
|
|
"start",
|
|
|
|
"back"};
|
2021-09-19 12:57:54 +00:00
|
|
|
int i = 0;
|
2021-07-07 18:31:46 +00:00
|
|
|
int aVal = 0;
|
|
|
|
int bVal = 0;
|
2021-09-19 12:57:54 +00:00
|
|
|
while (i < static_cast<int>(map.size())) {
|
2021-07-07 18:31:46 +00:00
|
|
|
if (a.first == map[i])
|
|
|
|
aVal = i;
|
|
|
|
if (b.first == map[i])
|
|
|
|
bVal = i;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return aVal > bVal;
|
|
|
|
});
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
mHelp->setPrompts(addPrompts);
|
2014-01-25 23:34:29 +00:00
|
|
|
}
|
2014-06-02 00:14:22 +00:00
|
|
|
|
2021-05-23 17:12:31 +00:00
|
|
|
void Window::reloadHelpPrompts()
|
|
|
|
{
|
|
|
|
if (mHelp) {
|
|
|
|
delete mHelp;
|
|
|
|
mHelp = new HelpComponent(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-21 15:10:09 +00:00
|
|
|
void Window::setInfoPopup(InfoPopup* infoPopup)
|
|
|
|
{
|
|
|
|
delete mInfoPopup;
|
|
|
|
mInfoPopup = infoPopup;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::stopInfoPopup()
|
|
|
|
{
|
|
|
|
if (mInfoPopup)
|
|
|
|
mInfoPopup->stop();
|
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void Window::startScreensaver()
|
2019-04-07 12:52:36 +00:00
|
|
|
{
|
2020-11-10 21:33:57 +00:00
|
|
|
if (mScreensaver && !mRenderScreensaver) {
|
2020-06-21 12:25:28 +00:00
|
|
|
// Tell the GUI components the screensaver is starting.
|
2020-07-18 11:21:44 +00:00
|
|
|
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++)
|
2020-11-10 21:33:57 +00:00
|
|
|
(*it)->onScreensaverActivate();
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-09-17 20:00:07 +00:00
|
|
|
stopInfoPopup();
|
2021-10-06 15:24:25 +00:00
|
|
|
setAllowTextScrolling(false);
|
2020-11-10 21:33:57 +00:00
|
|
|
mScreensaver->startScreensaver(true);
|
|
|
|
mRenderScreensaver = true;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2019-04-07 12:52:36 +00:00
|
|
|
}
|
|
|
|
|
2020-11-12 16:13:24 +00:00
|
|
|
bool Window::stopScreensaver()
|
2019-04-07 12:52:36 +00:00
|
|
|
{
|
2020-11-10 21:33:57 +00:00
|
|
|
if (mScreensaver && mRenderScreensaver) {
|
|
|
|
mScreensaver->stopScreensaver();
|
|
|
|
mRenderScreensaver = false;
|
2021-10-06 15:24:25 +00:00
|
|
|
setAllowTextScrolling(true);
|
2019-04-07 12:52:36 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Tell the GUI components the screensaver has stopped.
|
2020-09-27 11:14:50 +00:00
|
|
|
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++) {
|
2020-11-10 21:33:57 +00:00
|
|
|
(*it)->onScreensaverDeactivate();
|
2020-09-27 11:14:50 +00:00
|
|
|
// If the menu is open, pause the video so it won't start playing beneath the menu.
|
|
|
|
if (mGuiStack.front() != mGuiStack.back())
|
|
|
|
(*it)->onPauseVideo();
|
|
|
|
}
|
2019-04-07 12:54:06 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return true;
|
|
|
|
}
|
2019-04-07 12:54:06 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return false;
|
2019-04-07 12:52:36 +00:00
|
|
|
}
|
|
|
|
|
2020-11-10 21:18:20 +00:00
|
|
|
void Window::renderScreensaver()
|
2019-04-07 12:52:36 +00:00
|
|
|
{
|
2020-11-10 21:33:57 +00:00
|
|
|
if (mScreensaver)
|
|
|
|
mScreensaver->renderScreensaver();
|
2019-04-07 12:52:36 +00:00
|
|
|
}
|
2021-05-16 11:12:31 +00:00
|
|
|
|
|
|
|
void Window::startMediaViewer(FileData* game)
|
|
|
|
{
|
|
|
|
if (mMediaViewer) {
|
2021-10-06 15:24:25 +00:00
|
|
|
if (mMediaViewer->startMediaViewer(game)) {
|
|
|
|
setAllowTextScrolling(false);
|
2021-05-16 11:12:31 +00:00
|
|
|
mRenderMediaViewer = true;
|
2021-10-06 15:24:25 +00:00
|
|
|
}
|
2021-05-16 11:12:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::stopMediaViewer()
|
|
|
|
{
|
2021-10-06 15:24:25 +00:00
|
|
|
if (mMediaViewer) {
|
2021-05-16 11:12:31 +00:00
|
|
|
mMediaViewer->stopMediaViewer();
|
2021-10-06 15:24:25 +00:00
|
|
|
setAllowTextScrolling(true);
|
|
|
|
}
|
2021-05-16 11:12:31 +00:00
|
|
|
|
|
|
|
mRenderMediaViewer = false;
|
|
|
|
}
|
2021-05-29 08:58:51 +00:00
|
|
|
|
2021-06-14 17:15:22 +00:00
|
|
|
void Window::displayLaunchScreen(FileData* game)
|
|
|
|
{
|
|
|
|
if (mLaunchScreen) {
|
|
|
|
mLaunchScreen->displayLaunchScreen(game);
|
|
|
|
mRenderLaunchScreen = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::closeLaunchScreen()
|
|
|
|
{
|
|
|
|
if (mLaunchScreen)
|
|
|
|
mLaunchScreen->closeLaunchScreen();
|
|
|
|
|
|
|
|
mRenderLaunchScreen = false;
|
|
|
|
}
|
|
|
|
|
2021-05-29 08:58:51 +00:00
|
|
|
void Window::increaseVideoPlayerCount()
|
|
|
|
{
|
|
|
|
mVideoCountMutex.lock();
|
|
|
|
mVideoPlayerCount++;
|
|
|
|
mVideoCountMutex.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::decreaseVideoPlayerCount()
|
|
|
|
{
|
|
|
|
mVideoCountMutex.lock();
|
|
|
|
mVideoPlayerCount--;
|
|
|
|
mVideoCountMutex.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Window::getVideoPlayerCount()
|
|
|
|
{
|
|
|
|
int videoPlayerCount;
|
|
|
|
mVideoCountMutex.lock();
|
|
|
|
videoPlayerCount = mVideoPlayerCount;
|
|
|
|
mVideoCountMutex.unlock();
|
|
|
|
return videoPlayerCount;
|
2021-09-18 07:53:26 +00:00
|
|
|
}
|
2021-06-11 15:02:06 +00:00
|
|
|
|
|
|
|
void Window::setLaunchedGame()
|
|
|
|
{
|
|
|
|
// Tell the GUI components that a game has been launched.
|
|
|
|
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++)
|
|
|
|
(*it)->onGameLaunchedActivate();
|
|
|
|
|
|
|
|
mGameLaunchedState = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::unsetLaunchedGame()
|
|
|
|
{
|
|
|
|
// Tell the GUI components that the user is back in ES-DE again.
|
|
|
|
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++)
|
|
|
|
(*it)->onGameLaunchedDeactivate();
|
|
|
|
|
|
|
|
mGameLaunchedState = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Window::invalidateCachedBackground()
|
|
|
|
{
|
|
|
|
mCachedBackground = false;
|
|
|
|
mInvalidatedCachedBackground = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Window::isProcessing()
|
|
|
|
{
|
2021-07-07 18:31:46 +00:00
|
|
|
return count_if(mGuiStack.cbegin(), mGuiStack.cend(),
|
|
|
|
[](GuiComponent* c) { return c->isProcessing(); }) > 0;
|
2021-06-11 15:02:06 +00:00
|
|
|
}
|