Fixed the quick list scroll overlay and made it configurable using a menu option.

This commit is contained in:
Leon Styhre 2021-01-12 22:41:28 +01:00
parent b987abed8b
commit c5b0042dff
7 changed files with 120 additions and 39 deletions

View file

@ -778,6 +778,10 @@ Whether to sort your favorite games above your other games in the gamelists.
With this setting enabled, there is a star symbol added at the beginning of the game name in the gamelist views. It's strongly recommended to keep this setting enabled if the option to sort favorite games above non-favorites has been enabled. If not, favorite games would be sorted on top of the gamelist with no visual indication that they are favorites, which would be very confusing.
**Enable quick list scrolling overlay**
With this option enabled, there will be an overlay displayed when scrolling the gamelists quickly, i.e. when holding down the _Up_, _Down_, _Left shoulder_ or _Right shoulder_ buttons for some time. The overlay will darken the background slightly and display the first two characters of the game name. If the game is a favorite and the setting to sort favorites above non-favorites has been enabled, a star will be shown instead.
**Enable shortcut to toggle favorites**
This setting enables the _Y_ button for quickly toggling a game as favorite. Although this may be convenient at times, it's also quite easy to accidentally remove a favorite tagging of a game when using the application more casually. As such it could sometimes make sense to disable this functionality. It's of course still possible to mark a game as favorite using the metadata editor when this setting is disabled. For additional restrictions, the application can be set to Kid or Kiosk mode as is explained [elsewhere](USERGUIDE.md#ui-modes) in this guide. Note that this setting does not affect the functionality to use the _Y_ button to add games to custom collections.

View file

@ -374,6 +374,18 @@ void GuiMenu::openUISettings()
}
});
// Enable quick list scrolling overlay.
auto list_scroll_overlay = std::make_shared<SwitchComponent>(mWindow);
list_scroll_overlay->setState(Settings::getInstance()->getBool("ListScrollOverlay"));
s->addWithLabel("ENABLE QUICK LIST SCROLLING OVERLAY", list_scroll_overlay);
s->addSaveFunc([list_scroll_overlay, s] {
if (list_scroll_overlay->getState() !=
Settings::getInstance()->getBool("ListScrollOverlay")) {
Settings::getInstance()->setBool("ListScrollOverlay", list_scroll_overlay->getState());
s->setNeedsSaving();
}
});
// Enable the 'Y' button for tagging games as favorites.
auto favorites_add_button = std::make_shared<SwitchComponent>(mWindow);
favorites_add_button->setState(Settings::getInstance()->getBool("FavoritesAddButton"));

View file

@ -121,6 +121,7 @@ void Settings::setDefaults()
mBoolMap["FoldersOnTop"] = { true, true };
mBoolMap["FavoritesFirst"] = { true, true };
mBoolMap["FavoritesStar"] = { true, true };
mBoolMap["ListScrollOverlay"] = { false, false };
mBoolMap["FavoritesAddButton"] = { true, true };
mBoolMap["GamelistFilters"] = { true, true };
mBoolMap["QuickSystemSelect"] = { true, true };

View file

@ -36,7 +36,8 @@ Window::Window()
mCachedBackground(false),
mInvalidatedCachedBackground(false),
mTopOpacity(0),
mTopScale(0.5)
mTopScale(0.5),
mListScrollOpacity(0)
{
mHelp = new HelpComponent(this);
mBackgroundOverlay = new ImageComponent(this);
@ -113,6 +114,8 @@ bool Window::init()
mBackgroundOverlay->setResize(static_cast<float>(Renderer::getScreenWidth()),
static_cast<float>(Renderer::getScreenHeight()));
mListScrollFont = Font::get(FONT_SIZE_LARGE);
// Update our help because font sizes probably changed.
if (peekGui())
peekGui()->updateHelpPrompts();
@ -399,6 +402,22 @@ void Window::render()
}
}
if (mListScrollOpacity != 0) {
Renderer::setMatrix(Transform4x4f::Identity());
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
static_cast<float>(Renderer::getScreenHeight()),
0x00000000 | mListScrollOpacity, 0x00000000 | mListScrollOpacity);
Vector2f offset = mListScrollFont->sizeText(mListScrollText);
offset[0] = (Renderer::getScreenWidth() - offset.x()) * 0.5f;
offset[1] = (Renderer::getScreenHeight() - offset.y()) * 0.5f;
TextCache* cache = mListScrollFont->buildTextCache(mListScrollText,
offset.x(), offset.y(), 0xFFFFFF00 | mListScrollOpacity);
mListScrollFont->renderTextCache(cache);
delete cache;
}
if (!mRenderedHelpPrompts)
mHelp->render(transform);
@ -481,6 +500,12 @@ void Window::renderLoadingScreen(std::string text)
Renderer::swapBuffers();
}
void Window::renderListScrollOverlay(unsigned char opacity, const std::string& text)
{
mListScrollOpacity = static_cast<unsigned char>(opacity * 0.6f);
mListScrollText = text;
}
void Window::renderHelpPromptsEarly()
{
mHelp->render(Transform4x4f::Identity());

View file

@ -81,13 +81,23 @@ public:
void setAllowSleep(bool sleep);
void renderLoadingScreen(std::string text);
// The list scroll overlay is triggered from IList when the highest scrolling tier is reached.
void renderListScrollOverlay(unsigned char opacity, const std::string& text);
void renderHelpPromptsEarly(); // Used to render HelpPrompts before a fade.
void setHelpPrompts(const std::vector<HelpPrompt>& prompts, const HelpStyle& style);
void setScreensaver(Screensaver* screensaver) { mScreensaver = screensaver; }
void setInfoPopup(InfoPopup* infoPopup) { delete mInfoPopup; mInfoPopup = infoPopup; }
inline void stopInfoPopup() { if (mInfoPopup) mInfoPopup->stop(); };
void setInfoPopup(InfoPopup* infoPopup)
{
delete mInfoPopup;
mInfoPopup = infoPopup;
}
void stopInfoPopup()
{
if (mInfoPopup)
mInfoPopup->stop();
};
bool isScreensaverActive() { return mRenderScreensaver; };
void startScreensaver();
@ -97,12 +107,16 @@ public:
void setLaunchedGame();
void unsetLaunchedGame();
bool getGameLaunchedState() { return mGameLaunchedState; };
void setAllowTextScrolling(bool setting) { mAllowTextScrolling = setting; };
bool getAllowTextScrolling() { return mAllowTextScrolling; };
void invalidateCachedBackground()
{ mCachedBackground = false; mInvalidatedCachedBackground = true;};
{
mCachedBackground = false;
mInvalidatedCachedBackground = true;
};
private:
void onSleep();
@ -120,6 +134,10 @@ private:
std::vector<std::shared_ptr<Font>> mDefaultFonts;
std::unique_ptr<TextCache> mFrameDataText;
std::string mListScrollText;
std::shared_ptr<Font> mListScrollFont;
unsigned char mListScrollOpacity;
bool mNormalizeNextUpdate;
int mFrameTimeElapsed;
int mFrameCountElapsed;

View file

@ -3,14 +3,14 @@
// EmulationStation Desktop Edition
// IList.h
//
// Gamelist base class.
// List base class, used by both the gamelist views and the menus.
//
#ifndef ES_CORE_COMPONENTS_ILIST_H
#define ES_CORE_COMPONENTS_ILIST_H
#include "components/ImageComponent.h"
#include "resources/Font.h"
#include "utils/StringUtil.h"
#include "Window.h"
enum CursorState {
@ -38,11 +38,10 @@ struct ScrollTierList {
const ScrollTier QUICK_SCROLL_TIERS[] = {
{500, 500},
{2000, 114},
{4000, 32},
{0, 16}
};
const ScrollTierList LIST_SCROLL_STYLE_QUICK = {
4,
3,
QUICK_SCROLL_TIERS
};
@ -51,7 +50,10 @@ const ScrollTier SLOW_SCROLL_TIERS[] = {
{0, 200}
};
const ScrollTierList LIST_SCROLL_STYLE_SLOW = { 2, SLOW_SCROLL_TIERS };
const ScrollTierList LIST_SCROLL_STYLE_SLOW = {
2,
SLOW_SCROLL_TIERS
};
template <typename EntryData, typename UserData>
class IList : public GuiComponent
@ -72,8 +74,6 @@ protected:
unsigned char mTitleOverlayOpacity;
unsigned int mTitleOverlayColor;
ImageComponent mGradient;
std::shared_ptr<Font> mTitleOverlayFont;
const ScrollTierList& mTierList;
const ListLoopType mLoopType;
@ -87,7 +87,6 @@ public:
const ScrollTierList& tierList = LIST_SCROLL_STYLE_QUICK,
const ListLoopType& loopType = LIST_PAUSE_AT_END)
: GuiComponent(window),
mGradient(window),
mTierList(tierList),
mLoopType(loopType),
mWindow(window)
@ -100,10 +99,6 @@ public:
mTitleOverlayOpacity = 0x00;
mTitleOverlayColor = 0xFFFFFF00;
mGradient.setResize(static_cast<float>(Renderer::getScreenWidth()),
static_cast<float>(Renderer::getScreenHeight()));
mGradient.setImage(":/graphics/scroll_gradient.png");
mTitleOverlayFont = Font::get(FONT_SIZE_LARGE);
}
bool isScrolling() const
@ -118,6 +113,10 @@ public:
void stopScrolling()
{
// if (mScrollTier >= 2)
// NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND);
mTitleOverlayOpacity = 0;
listInput(0);
if (mScrollVelocity == 0)
onCursorChanged(CURSOR_STOPPED);
@ -212,7 +211,10 @@ public:
return false;
}
inline int size() const { return static_cast<int>(mEntries.size()); }
inline int size() const
{
return static_cast<int>(mEntries.size());
}
protected:
void remove(typename std::vector<Entry>::const_iterator& it)
@ -259,8 +261,8 @@ protected:
// Update the title overlay opacity.
// Fade in if scroll tier is >= 1, otherwise fade out.
const int dir = (mScrollTier >= mTierList.count - 1) ? 1 : -1;
// We just do a 1-to-1 time -> opacity, no scaling.
int op = mTitleOverlayOpacity + deltaTime*dir;
// We simply translate the time directly to opacity, i.e. no scaling is performed.
int op = mTitleOverlayOpacity + deltaTime * dir;
if (op >= 255)
mTitleOverlayOpacity = 255;
else if (op <= 0)
@ -283,7 +285,7 @@ protected:
scrollCount++;
}
// Are we ready to go even FASTER?
// Should we go to the next scrolling tier?
while (mScrollTier < mTierList.count - 1 && mScrollTierAccumulator >=
mTierList.tiers[mScrollTier].length) {
mScrollTierAccumulator -= mTierList.tiers[mScrollTier].length;
@ -297,28 +299,43 @@ protected:
void listRenderTitleOverlay(const Transform4x4f& /*trans*/)
{
if (size() == 0 || !mTitleOverlayFont || mTitleOverlayOpacity == 0)
if (!Settings::getInstance()->getBool("ListScrollOverlay"))
return;
// We don't bother caching this because it's only two letters and will change pretty
// much every frame if we're scrolling.
const std::string text = getSelectedName().size() >= 2 ?
getSelectedName().substr(0, 2) : "??";
if (size() == 0 || mTitleOverlayOpacity == 0) {
mWindow->renderListScrollOverlay(0, "");
return;
}
Vector2f off = mTitleOverlayFont->sizeText(text);
off[0] = (Renderer::getScreenWidth() - off.x()) * 0.5f;
off[1] = (Renderer::getScreenHeight() - off.y()) * 0.5f;
std::string titleIndex;
bool favoritesSorting;
Transform4x4f identTrans = Transform4x4f::Identity();
if (getSelected()->getSystem()->isCustomCollection())
favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom");
else
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
mGradient.setOpacity(mTitleOverlayOpacity);
mGradient.render(identTrans);
if (favoritesSorting && getSelected()->getFavorite()) {
#if defined(_MSC_VER) // MSVC compiler.
titleIndex = Utils::String::wideStringToString(L"\uF005");
#else
titleIndex = "\uF005";
#endif
}
else {
titleIndex = getSelected()->getName();
if (titleIndex.size()) {
titleIndex[0] = toupper(titleIndex[0]);
if (titleIndex.size() > 1) {
titleIndex = titleIndex.substr(0, 2);
titleIndex[1] = tolower(titleIndex[1]);
}
}
}
TextCache* cache = mTitleOverlayFont->buildTextCache(text, off.x(), off.y(),
0xFFFFFF00 | mTitleOverlayOpacity);
// Relies on mGradient's render for Renderer::setMatrix()
mTitleOverlayFont->renderTextCache(cache);
delete cache;
// The actual rendering takes place in Window to make sure that the overlay is placed on
// top of all GUI elements but below the info popups and GPU statistics overlay.
mWindow->renderListScrollOverlay(mTitleOverlayOpacity, titleIndex);
}
void scroll(int amt)

View file

@ -3,7 +3,7 @@
// EmulationStation Desktop Edition
// TextListComponent.h
//
// Used for displaying and navigating the gamelists.
// Text list used for displaying and navigating the gamelist views.
//
#ifndef ES_APP_COMPONENTS_TEXT_LIST_COMPONENT_H
@ -11,6 +11,7 @@
#include "components/IList.h"
#include "math/Misc.h"
#include "resources/Font.h"
#include "utils/StringUtil.h"
#include "Log.h"
#include "Sound.h"
@ -93,8 +94,11 @@ public:
inline void setLineSpacing(float lineSpacing) { mLineSpacing = lineSpacing; }
protected:
virtual void onScroll() override {
NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND); }
virtual void onScroll() override
{
if (!NavigationSounds::getInstance()->isPlayingThemeNavigationSound(SCROLLSOUND))
NavigationSounds::getInstance()->playThemeNavigationSound(SCROLLSOUND);
}
virtual void onCursorChanged(const CursorState& state) override;
private: