Text scrolling now stops when launching a game and when the screensaver starts.

Also did some additional code cleanup.
This commit is contained in:
Leon Styhre 2020-09-17 22:00:07 +02:00
parent 254029fed6
commit d4f5b2d20d
13 changed files with 147 additions and 83 deletions

View file

@ -56,7 +56,7 @@ Many bugs have been fixed, and numerous features that were only partially implem
* Refactoring, cleanup and documentation of the source code, removal of deprecated files etc.
* All required fonts bundled with the application, no dependencies on the OS to provide them any longer
* Made pugixml an external dependency instead of bundling it
* Decreased CPU usage dramatically by only rendering the currently visible view (previously every view were always rendered)
* Decreased CPU usage dramatically by only rendering the currently visible view (previously all views were always rendered)
* Updated the CMake/CPack install and package build script to work as expected (it can now generate .deb, .rpm, .dmg and NSIS installation packages)
* Added support for Clang/LLVM, made the application build with no errors or warnings using this compiler (Unix and macOS only)
* License files included for all the libraries and resources that are bundled with the application

View file

@ -1,4 +1,6 @@
// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// FileData.cpp
//
// Provides game file data structures and functions to access and sort this information.
@ -39,7 +41,7 @@ FileData::FileData(
mParent(nullptr),
mOnlyFolders(false),
mDeletionFlag(false),
// Metadata is REALLY set in the constructor!
// Metadata is set in the constructor.
metadata(type == GAME ? GAME_METADATA : FOLDER_METADATA)
{
// Metadata needs at least a name field (since that's what getName() will return).
@ -382,12 +384,10 @@ std::string FileData::getKey() {
const bool FileData::isArcadeAsset()
{
const std::string stem = Utils::FileSystem::getStem(mPath);
return (
(mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) ||
return ((mSystem && (mSystem->hasPlatformId(PlatformIds::ARCADE) ||
mSystem->hasPlatformId(PlatformIds::NEOGEO))) &&
(MameNames::getInstance()->isBios(stem) ||
MameNames::getInstance()->isDevice(stem))
);
MameNames::getInstance()->isDevice(stem)));
}
FileData* FileData::getSourceFileData()
@ -756,6 +756,9 @@ void FileData::launchGame(Window* window)
Scripting::fireEvent("game-end", rom, getSourceFileData()->metadata.get("name"));
// Re-enable the text scrolling that was disabled in ViewController on game launch.
window->setAllowTextScrolling(true);
// Update number of times the game has been launched.
FileData* gameToUpdate = getSourceFileData();

View file

@ -1,4 +1,6 @@
// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// FileData.h
//
// Provides game file data structures and functions to access and sort this information.
@ -6,12 +8,12 @@
// (launching initiated in ViewController).
//
#pragma once
#ifndef ES_APP_FILE_DATA_H
#define ES_APP_FILE_DATA_H
#include "utils/FileSystemUtil.h"
#include "MetaData.h"
#include <unordered_map>
class SystemData;
@ -111,7 +113,8 @@ public:
bool ascending;
std::string description;
SortType(ComparisonFunction* sortFunction,
SortType(
ComparisonFunction* sortFunction,
bool sortAscending,
const std::string& sortDescription)
: comparisonFunction(sortFunction),
@ -145,7 +148,6 @@ private:
bool mOnlyFolders;
// Used for flagging a game for deletion from its gamelist.xml file.
bool mDeletionFlag;
const std::string FAVORITE_CHAR = "\uF005";
};
@ -158,6 +160,7 @@ public:
void refreshMetadata();
FileData* getSourceFileData();
std::string getKey();
private:
// Needs to be updated when metadata changes.
std::string mCollectionFileName;

View file

@ -53,7 +53,6 @@ private:
STATE_SCREENSAVER_ACTIVE
};
private:
bool mVideosCounted;
unsigned long mVideoCount;
VideoComponent* mVideoScreensaver;

View file

@ -306,6 +306,9 @@ void ViewController::launch(FileData* game, Vector3f center)
if (mCurrentView)
mCurrentView->onPauseVideo();
// Disable text scrolling. It will be enabled again in FileData upon returning from the game.
mWindow->setAllowTextScrolling(false);
stopAnimation(1); // Make sure the fade in isn't still playing.
mWindow->stopInfoPopup(); // Make sure we disable any existing info popup.
mLockInput = true;

View file

@ -86,7 +86,10 @@ public:
ViewMode viewing;
inline SystemData* getSystem() const
{ assert(viewing == GAME_LIST || viewing == SYSTEM_SELECT); return system; }
{
assert(viewing == GAME_LIST || viewing == SYSTEM_SELECT);
return system;
}
private:
friend ViewController;

View file

@ -20,17 +20,18 @@
#include <iomanip>
Window::Window()
: mNormalizeNextUpdate(false),
: mScreenSaver(nullptr),
mInfoPopup(nullptr),
mNormalizeNextUpdate(false),
mFrameTimeElapsed(0),
mFrameCountElapsed(0),
mAverageDeltaTime(10),
mAllowSleep(true),
mSleeping(false),
mTimeSinceLastInput(0),
mScreenSaver(nullptr),
mRenderScreenSaver(false),
mGameLaunchedState(false),
mInfoPopup(nullptr),
mAllowTextScrolling(true),
mCachedBackground(false),
mSaturationAmount(1.0),
mTopOpacity(0),
@ -106,8 +107,8 @@ bool Window::init()
}
mBackgroundOverlay->setImage(":/graphics/scroll_gradient.png");
mBackgroundOverlay->setResize((float)Renderer::getScreenWidth(),
(float)Renderer::getScreenHeight());
mBackgroundOverlay->setResize(static_cast<float>(Renderer::getScreenWidth()),
static_cast<float>(Renderer::getScreenHeight()));
// Update our help because font sizes probably changed.
if (peekGui())
@ -222,6 +223,7 @@ void Window::update(int deltaTime)
{
if (mNormalizeNextUpdate) {
mNormalizeNextUpdate = false;
mTimeSinceLastInput = 0;
if (deltaTime > mAverageDeltaTime)
deltaTime = mAverageDeltaTime;
}
@ -236,9 +238,11 @@ void Window::update(int deltaTime)
// FPS.
ss << std::fixed << std::setprecision(1) <<
(1000.0f * (float)mFrameCountElapsed / (float)mFrameTimeElapsed) << " FPS (";
(1000.0f * static_cast<float>(mFrameCountElapsed) /
static_cast<float>(mFrameTimeElapsed)) << " FPS (";
ss << std::fixed << std::setprecision(2) <<
((float)mFrameTimeElapsed / (float)mFrameCountElapsed) << " ms)";
(static_cast<float>(mFrameTimeElapsed) /
static_cast<float>(mFrameCountElapsed)) << " ms)";
// 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
@ -280,6 +284,11 @@ void Window::render()
auto& bottom = mGuiStack.front();
auto& top = mGuiStack.back();
if (mRenderScreenSaver) {
bottom->cancelAllAnimations();
bottom->stopAllAnimations();
}
bottom->render(transform);
if (bottom != top) {
#if defined(USE_OPENGL_21)
@ -343,7 +352,8 @@ void Window::render()
if (!mRenderedHelpPrompts)
mHelp->render(transform);
unsigned int screensaverTime = (unsigned int)Settings::getInstance()->getInt("ScreenSaverTime");
unsigned int screensaverTime =
static_cast<unsigned int>(Settings::getInstance()->getInt("ScreenSaverTime"));
// If a game has been launched, reset the screensaver timer when it's been reached as we
// don't want to start the screensaver in the background when running a game.
if (mTimeSinceLastInput >= screensaverTime && screensaverTime != 0) {
@ -501,7 +511,7 @@ void Window::setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpSt
}
else {
// No, it hasn't!
mappedToSeenMap.emplace(it->second, (int)addPrompts.size());
mappedToSeenMap.emplace(it->second, static_cast<int>(addPrompts.size()));
addPrompts.push_back(*it);
}
}
@ -578,6 +588,7 @@ void Window::startScreenSaver()
for (auto it = mGuiStack.cbegin(); it != mGuiStack.cend(); it++)
(*it)->onScreenSaverActivate();
stopInfoPopup();
mScreenSaver->startScreenSaver();
mRenderScreenSaver = true;
}

View file

@ -60,7 +60,7 @@ public:
void pushGui(GuiComponent* gui);
void removeGui(GuiComponent* gui);
GuiComponent* peekGui();
inline int getGuiStackSize() { return (int)mGuiStack.size(); }
inline int getGuiStackSize() { return static_cast<int>(mGuiStack.size()); }
void textInput(const char* text);
void input(InputConfig* config, Input input);
@ -94,6 +94,8 @@ public:
void setLaunchedGame();
void unsetLaunchedGame();
bool getGameLaunchedState() { return mGameLaunchedState; };
void setAllowTextScrolling(bool setting) { mAllowTextScrolling = setting; };
bool getAllowTextScrolling() { return mAllowTextScrolling; };
void invalidateCachedBackground() { mCachedBackground = false; };
@ -108,30 +110,27 @@ private:
ImageComponent* mBackgroundOverlay;
ScreenSaver* mScreenSaver;
InfoPopup* mInfoPopup;
bool mRenderScreenSaver;
bool mGameLaunchedState;
std::vector<GuiComponent*> mGuiStack;
std::vector<std::shared_ptr<Font>> mDefaultFonts;
int mFrameTimeElapsed;
int mFrameCountElapsed;
int mAverageDeltaTime;
std::unique_ptr<TextCache> mFrameDataText;
bool mNormalizeNextUpdate;
int mFrameTimeElapsed;
int mFrameCountElapsed;
int mAverageDeltaTime;
bool mAllowSleep;
bool mSleeping;
unsigned int mTimeSinceLastInput;
bool mRenderScreenSaver;
bool mGameLaunchedState;
bool mAllowTextScrolling;
bool mCachedBackground;
float mSaturationAmount;
unsigned char mTopOpacity;
float mTopScale;
float mDimValue;
bool mCachedBackground;
bool mAllowSleep;
bool mSleeping;
unsigned int mTimeSinceLastInput;
bool mRenderedHelpPrompts;
};

View file

@ -1,4 +1,6 @@
// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// IList.h
//
// Gamelist base class.
@ -10,6 +12,7 @@
#include "components/ImageComponent.h"
#include "resources/Font.h"
#include "PowerSaver.h"
#include "Window.h"
enum CursorState {
CURSOR_STOPPED,
@ -63,10 +66,8 @@ public:
protected:
int mCursor;
int mScrollTier;
int mScrollVelocity;
int mScrollTierAccumulator;
int mScrollCursorAccumulator;
@ -79,6 +80,7 @@ protected:
const ListLoopType mLoopType;
std::vector<Entry> mEntries;
Window* mWindow;
public:
IList(
@ -88,7 +90,8 @@ public:
: GuiComponent(window),
mGradient(window),
mTierList(tierList),
mLoopType(loopType)
mLoopType(loopType),
mWindow(window)
{
mCursor = 0;
mScrollTier = 0;
@ -98,7 +101,8 @@ public:
mTitleOverlayOpacity = 0x00;
mTitleOverlayColor = 0xFFFFFF00;
mGradient.setResize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
mGradient.setResize(static_cast<float>(Renderer::getScreenWidth()),
static_cast<float>(Renderer::getScreenHeight()));
mGradient.setImage(":/graphics/scroll_gradient.png");
mTitleOverlayFont = Font::get(FONT_SIZE_LARGE);
}
@ -164,7 +168,7 @@ public:
{
for (auto it = mEntries.cbegin(); it != mEntries.cend(); it++) {
if ((*it).object == obj) {
mCursor = (int)(it - mEntries.cbegin());
mCursor = static_cast<int>(it - mEntries.cbegin());
onCursorChanged(CURSOR_STOPPED);
return true;
}
@ -191,7 +195,7 @@ public:
return false;
}
inline int size() const { return (int)mEntries.size(); }
inline int size() const { return static_cast<int>(mEntries.size()); }
protected:
void remove(typename std::vector<Entry>::const_iterator& it)
@ -247,7 +251,7 @@ protected:
else if (op <= 0)
mTitleOverlayOpacity = 0;
else
mTitleOverlayOpacity = (unsigned char)op;
mTitleOverlayOpacity = static_cast<unsigned char>(op);
if (mScrollVelocity == 0 || size() < 2)
return;

View file

@ -1,4 +1,6 @@
// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// ScrollableContainer.cpp
//
// Area containing scrollable information, for example the game description
@ -9,6 +11,7 @@
#include "math/Vector2i.h"
#include "renderers/Renderer.h"
#include "Window.h"
#define AUTO_SCROLL_RESET_DELAY 3000 // ms to reset to top after we reach the bottom.
#define AUTO_SCROLL_DELAY 2000 // ms to wait before we start to scroll.
@ -33,11 +36,12 @@ void ScrollableContainer::render(const Transform4x4f& parentTrans)
Transform4x4f trans = parentTrans * getTransform();
Vector2i clipPos((int)trans.translation().x(), (int)trans.translation().y());
Vector2i clipPos(static_cast<int>(trans.translation().x()),
static_cast<int>(trans.translation().y()));
Vector3f dimScaled = trans * Vector3f(mSize.x(), mSize.y(), 0);
Vector2i clipDim((int)(dimScaled.x() - trans.translation().x()),
(int)(dimScaled.y() - trans.translation().y()));
Vector2i clipDim(static_cast<int>((dimScaled.x()) - trans.translation().x()),
static_cast<int>((dimScaled.y()) - trans.translation().y()));
Renderer::pushClipRect(clipPos, clipDim);
@ -76,6 +80,13 @@ void ScrollableContainer::setScrollPos(const Vector2f& pos)
void ScrollableContainer::update(int deltaTime)
{
// Don't scroll if the screensaver is active or text scrolling is disabled;
if (mWindow->isScreenSaverActive() || !mWindow->getAllowTextScrolling()) {
if (mScrollPos != 0)
reset();
return;
}
if (mAutoScrollSpeed != 0) {
mAutoScrollAccumulator += deltaTime;

View file

@ -1,11 +1,12 @@
// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// ScrollableContainer.h
//
// Area containing scrollable information, for example the game description
// text container in the detailed, video and grid views.
//
#pragma once
#ifndef ES_CORE_COMPONENTS_SCROLLABLE_CONTAINER_H
#define ES_CORE_COMPONENTS_SCROLLABLE_CONTAINER_H

View file

@ -1,4 +1,6 @@
// SPDX-License-Identifier: MIT
//
// EmulationStation Desktop Edition
// TextListComponent.h
//
// Used for displaying and navigating the gamelists.
@ -12,6 +14,7 @@
#include "utils/StringUtil.h"
#include "Log.h"
#include "Sound.h"
#include <memory>
class TextCache;
@ -33,6 +36,7 @@ protected:
using IList<TextListData, T>::getTransform;
using IList<TextListData, T>::mSize;
using IList<TextListData, T>::mCursor;
using IList<TextListData, T>::mWindow;
// The following change is required for compilation with Clang.
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2070
// using IList<TextListData, T>::Entry;
@ -152,12 +156,13 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
if (size() == 0)
return;
const float entrySize = Math::max(font->getHeight(1.0), (float)font->getSize()) * mLineSpacing;
const float entrySize = Math::max(font->getHeight(1.0),
static_cast<float>(font->getSize())) * mLineSpacing;
int startEntry = 0;
// Number of entries that can fit on the screen simultaneously.
int screenCount = (int)(mSize.y() / entrySize + 0.5f);
int screenCount = static_cast<int>(mSize.y() / entrySize + 0.5f);
if (size() >= screenCount) {
startEntry = mCursor - screenCount/2;
@ -197,12 +202,12 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
// Clip to inside margins.
Vector3f dim(mSize.x(), mSize.y(), 0);
dim = trans * dim - trans.translation();
Renderer::pushClipRect(Vector2i((int)(trans.translation().x() + mHorizontalMargin),
(int)trans.translation().y()), Vector2i((int)(dim.x() - mHorizontalMargin*2),
(int)dim.y()));
Renderer::pushClipRect(Vector2i(static_cast<int>(trans.translation().x() +
mHorizontalMargin), static_cast<int>(trans.translation().y())),
Vector2i(static_cast<int>(dim.x() - mHorizontalMargin*2), static_cast<int>(dim.y())));
for (int i = startEntry; i < listCutoff; i++) {
typename IList<TextListData, T>::Entry& entry = mEntries.at((unsigned int)i);
typename IList<TextListData, T>::Entry& entry = mEntries.at(static_cast<unsigned int>(i));
unsigned int color;
if (mCursor == i && mSelectedColor)
@ -211,12 +216,12 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
color = mColors[entry.data.colorId];
if (!entry.data.textCache)
entry.data.textCache = std::unique_ptr<TextCache>
(font->buildTextCache(mUppercase ?
entry.data.textCache = std::unique_ptr<TextCache>(
font->buildTextCache(mUppercase ?
Utils::String::toUpper(entry.name) : entry.name, 0, 0, 0x000000FF));
// If a game is marked as hidden, lower the text opacity quite a lot.
// For games marked not to be counted, lower the opacity moderately.
// If a game is marked as hidden, lower the text opacity a lot.
// If a game is marked to not be counted, lower the opacity a moderate amount.
if (entry.object->getHidden())
entry.data.textCache->setColor(color & 0xFFFFFF44);
else if (!entry.object->getCountAsGame())
@ -231,7 +236,7 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
offset[0] = mHorizontalMargin;
break;
case ALIGN_CENTER:
offset[0] = (int)((mSize.x() - entry.data.textCache->metrics.size.x()) / 2);
offset[0] = static_cast<int>((mSize.x() - entry.data.textCache->metrics.size.x()) / 2);
if (offset[0] < mHorizontalMargin)
offset[0] = mHorizontalMargin;
break;
@ -248,7 +253,7 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
// Currently selected item text might be scrolling.
if ((mCursor == i) && (mMarqueeOffset > 0))
drawTrans.translate(offset - Vector3f((float)mMarqueeOffset, 0, 0));
drawTrans.translate(offset - Vector3f(static_cast<float>(mMarqueeOffset), 0, 0));
else
drawTrans.translate(offset);
@ -259,11 +264,10 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
// scrolled far enough for it to repeat.
if ((mCursor == i) && (mMarqueeOffset2 < 0)) {
drawTrans = trans;
drawTrans.translate(offset - Vector3f((float)mMarqueeOffset2, 0, 0));
drawTrans.translate(offset - Vector3f(static_cast<float>(mMarqueeOffset2), 0, 0));
Renderer::setMatrix(drawTrans);
font->renderTextCache(entry.data.textCache.get());
}
y += entrySize;
}
@ -323,13 +327,17 @@ void TextListComponent<T>::update(int deltaTime)
{
listUpdate(deltaTime);
if (mWindow->isScreenSaverActive() || !mWindow->getAllowTextScrolling())
stopScrolling();
if (!isScrolling() && size() > 0) {
// Always reset the marquee offsets.
mMarqueeOffset = 0;
mMarqueeOffset2 = 0;
// If we're not scrolling and this object's text goes outside our size, marquee it!
const float textLength = mFont->sizeText(mEntries.at((unsigned int)mCursor).name).x();
const float textLength = mFont->sizeText(
mEntries.at(static_cast<unsigned int>(mCursor)).name).x();
const float limit = mSize.x() - mHorizontalMargin * 2;
if (textLength > limit) {
@ -341,17 +349,17 @@ void TextListComponent<T>::update(int deltaTime)
const float returnLength = speed * 1.5f;
const float scrollTime = (scrollLength * 1000) / speed;
const float returnTime = (returnLength * 1000) / speed;
const int maxTime = (int)(delay + scrollTime + returnTime);
const int maxTime = static_cast<int>(delay + scrollTime + returnTime);
mMarqueeTime += deltaTime;
while (mMarqueeTime > maxTime)
mMarqueeTime -= maxTime;
mMarqueeOffset = (int)(Math::Scroll::loop(delay, scrollTime + returnTime,
(float)mMarqueeTime, scrollLength + returnLength));
mMarqueeOffset = static_cast<int>(Math::Scroll::loop(delay, scrollTime + returnTime,
static_cast<float>(mMarqueeTime), scrollLength + returnLength));
if (mMarqueeOffset > (scrollLength - (limit - returnLength)))
mMarqueeOffset2 = (int)(mMarqueeOffset - (scrollLength + returnLength));
mMarqueeOffset2 = static_cast<int>(mMarqueeOffset - (scrollLength + returnLength));
}
}
@ -413,7 +421,7 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
setFont(Font::getFromTheme(elem, properties, mFont));
const float selectorHeight = Math::max(mFont->getHeight(1.0),
(float)mFont->getSize()) * mLineSpacing;
static_cast<float>(mFont->getSize())) * mLineSpacing;
setSelectorHeight(selectorHeight);
if (properties & ALIGNMENT) {
@ -431,7 +439,7 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
if (elem->has("horizontalMargin")) {
mHorizontalMargin = elem->get<float>("horizontalMargin") *
(this->mParent ? this->mParent->getSize().x() :
(float)Renderer::getScreenWidth());
static_cast<float>(Renderer::getScreenWidth()));
}
}
@ -444,7 +452,8 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme,
if (elem->has("selectorHeight"))
setSelectorHeight(elem->get<float>("selectorHeight") * Renderer::getScreenHeight());
if (elem->has("selectorOffsetY")) {
float scale = this->mParent ? this->mParent->getSize().y() : (float)Renderer::getScreenHeight();
float scale = this->mParent ? this->mParent->getSize().y() :
static_cast<float>(Renderer::getScreenHeight());
setSelectorOffsetY(elem->get<float>("selectorOffsetY") * scale);
}
else {

View file

@ -373,13 +373,20 @@ void VideoComponent::onPauseVideo()
void VideoComponent::onScreenSaverActivate()
{
mScreensaverActive = true;
mBlockPlayer = true;
mPause = true;
if (Settings::getInstance()->getString("ScreenSaverBehavior") == "dim")
stopVideo();
manageState();
}
void VideoComponent::onScreenSaverDeactivate()
{
mScreensaverActive = false;
mBlockPlayer = false;
// mPause = false;
// Stop video when deactivating the screensaver to force a reload of the
// static image (if the theme is configured as such).
stopVideo();
manageState();
}
@ -398,6 +405,17 @@ void VideoComponent::onGameLaunchedDeactivate()
void VideoComponent::topWindow(bool isTop)
{
mDisable = !isTop;
if (isTop) {
mBlockPlayer = false;
mPause = false;
// Stop video when closing the menu to force a reload of the
// static image (if the theme is configured as such).
stopVideo();
}
else {
mBlockPlayer = true;
mPause = true;
}
manageState();
}