From 7999f89c5bcf05e56b11ff08ad8b6285314aafbc Mon Sep 17 00:00:00 2001 From: Leon Styhre <leon@leonstyhre.com> Date: Tue, 8 Aug 2023 19:35:20 +0200 Subject: [PATCH] Added new textHorizontalScrolling, textHorizontalScrollSpeed and textHorizontalScrollDelay textlist properties Also removed the horizontal text scrolling code and did some general refactoring --- es-core/src/ThemeData.cpp | 3 + .../components/primary/TextListComponent.h | 181 ++++++------------ 2 files changed, 66 insertions(+), 118 deletions(-) diff --git a/es-core/src/ThemeData.cpp b/es-core/src/ThemeData.cpp index a204b601e..7025c2639 100644 --- a/es-core/src/ThemeData.cpp +++ b/es-core/src/ThemeData.cpp @@ -232,6 +232,9 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>> {"selectedSecondaryColor", COLOR}, {"selectedBackgroundColor", COLOR}, {"selectedSecondaryBackgroundColor", COLOR}, + {"textHorizontalScrolling", BOOLEAN}, + {"textHorizontalScrollSpeed", FLOAT}, + {"textHorizontalScrollDelay", FLOAT}, {"fontPath", PATH}, {"fontSize", FLOAT}, {"horizontalAlignment", STRING}, diff --git a/es-core/src/components/primary/TextListComponent.h b/es-core/src/components/primary/TextListComponent.h index 34ae3ace3..f2a5193cb 100644 --- a/es-core/src/components/primary/TextListComponent.h +++ b/es-core/src/components/primary/TextListComponent.h @@ -12,8 +12,8 @@ #include "Log.h" #include "Sound.h" #include "components/IList.h" +#include "components/TextComponent.h" #include "components/primary/PrimaryComponent.h" -#include "resources/Font.h" enum class TextListEntryType { PRIMARY, @@ -22,7 +22,7 @@ enum class TextListEntryType { struct TextListData { TextListEntryType entryType; - std::shared_ptr<TextCache> textCache; + std::shared_ptr<TextComponent> entryName; }; template <typename T> @@ -33,6 +33,7 @@ class TextListComponent : public PrimaryComponent<T>, private IList<TextListData protected: using List::mCursor; using List::mEntries; + using List::mLastCursor; using List::mScrollVelocity; using List::mSize; using List::mWindow; @@ -66,13 +67,6 @@ public: mCursorChangedCallback = func; } - void setFont(const std::shared_ptr<Font>& font) - { - mFont = font; - for (auto it = mEntries.begin(); it != mEntries.end(); ++it) - it->data.textCache.reset(); - } - const std::string& getIndicators() const { return mIndicators; } const std::string& getCollectionIndicators() const { return mCollectionIndicators; } const LetterCase getLetterCase() const override { return mLetterCase; } @@ -91,7 +85,7 @@ public: } private: - void onShow() override { mLoopTime = 0; } + void onShow() override { mEntries.at(mCursor).data.entryName->resetComponent(); } void onScroll() override { if (mGamelistView && @@ -126,10 +120,6 @@ private: std::function<void(CursorState state)> mCursorChangedCallback; float mCamOffset; int mPreviousScrollVelocity; - int mLoopOffset1; - int mLoopOffset2; - int mLoopTime; - bool mLoopScroll; bool mGamelistView; std::shared_ptr<Font> mFont; @@ -146,6 +136,9 @@ private: unsigned int mSelectedSecondaryColor; unsigned int mSelectedBackgroundColor; unsigned int mSelectedSecondaryBackgroundColor; + bool mHorizontalScrolling; + float mHorizontalScrollSpeed; + float mHorizontalScrollDelay; PrimaryAlignment mAlignment; float mHorizontalMargin; LetterCase mLetterCase; @@ -166,10 +159,6 @@ TextListComponent<T>::TextListComponent() , mRenderer {Renderer::getInstance()} , mCamOffset {0.0f} , mPreviousScrollVelocity {0} - , mLoopOffset1 {0} - , mLoopOffset2 {0} - , mLoopTime {0} - , mLoopScroll {false} , mGamelistView {std::is_same_v<T, FileData*> ? true : false} , mFont {Font::get(FONT_SIZE_MEDIUM_FIXED)} , mSelectorHeight {mFont->getSize() * 1.5f} @@ -184,6 +173,9 @@ TextListComponent<T>::TextListComponent() , mSelectedSecondaryColor {0x00FF00FF} , mSelectedBackgroundColor {0x00000000} , mSelectedSecondaryBackgroundColor {0x00000000} + , mHorizontalScrolling {true} + , mHorizontalScrollSpeed {1.0f} + , mHorizontalScrollDelay {3000.0f} , mAlignment {PrimaryAlignment::ALIGN_CENTER} , mHorizontalMargin {0.0f} , mLetterCase {LetterCase::NONE} @@ -201,6 +193,23 @@ TextListComponent<T>::TextListComponent() template <typename T> void TextListComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeData>& theme) { + entry.data.entryName = std::make_shared<TextComponent>( + mHorizontalScrolling ? entry.name : + mFont->wrapText(entry.name, mSize.x - mHorizontalMargin * 2.0f), + mFont, 0x000000FF); + + if (mHorizontalScrolling) { + glm::vec2 textSize {entry.data.entryName->getSize()}; + if (textSize.x > mSize.x - (mHorizontalMargin * 2.0f)) { + // Set the text width to the width of the textlist to trigger horizontal scrolling. + entry.data.entryName->setHorizontalScrollingSpeedMultiplier(mHorizontalScrollSpeed); + entry.data.entryName->setHorizontalScrollingDelay(mHorizontalScrollDelay); + entry.data.entryName->setHorizontalScrolling(true); + textSize.x = mSize.x - (mHorizontalMargin * 2.0f); + entry.data.entryName->setSize(textSize); + } + } + List::add(entry); } @@ -270,72 +279,25 @@ template <typename T> bool TextListComponent<T>::input(InputConfig* config, Inpu template <typename T> void TextListComponent<T>::update(int deltaTime) { List::listUpdate(deltaTime); - - if ((mWindow->isMediaViewerActive() || mWindow->isScreensaverActive() || - !mWindow->getAllowTextScrolling())) { - mLoopTime = 0; - } - else { - // Always reset the loop offsets. - mLoopOffset1 = 0; - mLoopOffset2 = 0; - - // If we're not scrolling and this object's text exceeds our size, then loop it. - const float limit {mSize.x - mHorizontalMargin * 2.0f}; - float length {0.0f}; - - if (mEntries.at(static_cast<unsigned int>(mCursor)).data.textCache != nullptr) - length = mEntries.at(static_cast<unsigned int>(mCursor)).data.textCache->getSize().x; - - if (length != 0.0f && length > limit) { - // Loop the text. - const float speed {mFont->sizeText("ABCDEFGHIJKLMNOPQRSTUVWXYZ").x * 0.247f}; - const float delay {3000.0f}; - const float scrollLength {length}; - const float returnLength {speed * 1.5f}; - const float scrollTime {(scrollLength * 1000.0f) / speed}; - const float returnTime {(returnLength * 1000.0f) / speed}; - const int maxTime {static_cast<int>(delay + scrollTime + returnTime)}; - - mLoopTime += deltaTime; - while (mLoopTime > maxTime) - mLoopTime -= maxTime; - - mLoopOffset1 = static_cast<int>(Utils::Math::loop(delay, scrollTime + returnTime, - static_cast<float>(mLoopTime), - scrollLength + returnLength)); - - if (mLoopOffset1 > (scrollLength - (limit - returnLength))) - mLoopOffset2 = static_cast<int>(mLoopOffset1 - (scrollLength + returnLength)); - } - } - + mEntries.at(static_cast<unsigned int>(mCursor)).data.entryName->update(deltaTime); GuiComponent::update(deltaTime); } template <typename T> void TextListComponent<T>::render(const glm::mat4& parentTrans) { - if ((mWindow->isMediaViewerActive() || mWindow->isScreensaverActive() || - !mWindow->getAllowTextScrolling())) { - mLoopOffset1 = 0; - mLoopOffset2 = 0; - } - if (size() == 0) return; glm::mat4 trans {parentTrans * List::getTransform()}; - std::shared_ptr<Font>& font {mFont}; int startEntry {0}; int screenCount {0}; - float y {0.0f}; - + float offsetY {0.0f}; float entrySize {0.0f}; float lineSpacingHeight {0.0f}; - entrySize = font->getSize() * mLineSpacing; - lineSpacingHeight = font->getSize() * mLineSpacing - font->getSize() * 1.0f; + entrySize = mFont->getSize() * mLineSpacing; + lineSpacingHeight = (mFont->getSize() * mLineSpacing) - mFont->getSize(); // Number of entries that can fit on the screen simultaneously. screenCount = static_cast<int>(std::floor((mSize.y + lineSpacingHeight / 2.0f) / entrySize)); @@ -387,7 +349,7 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT glm::ivec2 {static_cast<int>(std::round(dim.x - mHorizontalMargin * 2.0f)), static_cast<int>(std::round(dim.y))}); - for (int i = startEntry; i < listCutoff; ++i) { + for (int i {startEntry}; i < listCutoff; ++i) { Entry& entry {mEntries.at(i)}; unsigned int color {0x00000000}; unsigned int backgroundColor {0x00000000}; @@ -401,39 +363,33 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT backgroundColor = (mCursor == i ? mSelectedSecondaryBackgroundColor : 0x00000000); } - if (!entry.data.textCache) { - entry.data.textCache = - std::unique_ptr<TextCache>(font->buildTextCache(entry.name, 0, 0, 0x000000FF)); - } - if constexpr (std::is_same_v<T, FileData*>) { // 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); + entry.data.entryName->setColor(color & 0xFFFFFF44); else if (!entry.object->getCountAsGame()) - entry.data.textCache->setColor(color & 0xFFFFFF77); + entry.data.entryName->setColor(color & 0xFFFFFF77); else - entry.data.textCache->setColor(color); + entry.data.entryName->setColor(color); } else { - entry.data.textCache->setColor(color); + entry.data.entryName->setColor(color); } - glm::vec3 offset {0.0f, y, 0.0f}; + glm::vec3 offset {0.0f, offsetY, 0.0f}; switch (mAlignment) { case PrimaryAlignment::ALIGN_LEFT: offset.x = mHorizontalMargin; break; case PrimaryAlignment::ALIGN_CENTER: - offset.x = - static_cast<float>((mSize.x - entry.data.textCache->metrics.size.x) / 2.0f); + offset.x = static_cast<float>((mSize.x - entry.data.entryName->getSize().x) / 2.0f); if (offset.x < mHorizontalMargin) offset.x = mHorizontalMargin; break; case PrimaryAlignment::ALIGN_RIGHT: - offset.x = (mSize.x - entry.data.textCache->metrics.size.x); + offset.x = (mSize.x - entry.data.entryName->getSize().x); offset.x -= mHorizontalMargin; if (offset.x < mHorizontalMargin) offset.x = mHorizontalMargin; @@ -443,44 +399,18 @@ template <typename T> void TextListComponent<T>::render(const glm::mat4& parentT // Render text. glm::mat4 drawTrans {trans}; - // Currently selected item text might be looping. - if (mCursor == i && mLoopOffset1 > 0) { - drawTrans = glm::translate( - drawTrans, offset - glm::vec3 {static_cast<float>(mLoopOffset1), 0.0f, 0.0f}); - } - else { - drawTrans = glm::translate(drawTrans, offset); - } - - // Needed to avoid flickering when returning to the start position. - if (mLoopOffset1 == 0 && mLoopOffset2 == 0) - mLoopScroll = false; - + drawTrans = glm::translate(drawTrans, offset); mRenderer->setMatrix(drawTrans); if (i == mCursor && backgroundColor != 0x00000000) { mRenderer->drawRect(mSelectorHorizontalOffset, mSelectorVerticalOffset, - entry.data.textCache->metrics.size.x, mSelectorHeight, - backgroundColor, backgroundColor); + entry.data.entryName->getSize().x, mSelectorHeight, backgroundColor, + backgroundColor); } - font->renderTextCache(entry.data.textCache.get()); + entry.data.entryName->render(drawTrans); - // Render currently selected row again if text is moved far enough for it to repeat. - if ((mCursor == i && mLoopOffset2 < 0) || (mCursor == i && mLoopScroll)) { - mLoopScroll = true; - drawTrans = trans; - drawTrans = glm::translate( - drawTrans, offset - glm::vec3 {static_cast<float>(mLoopOffset2), 0.0f, 0.0f}); - mRenderer->setMatrix(drawTrans); - if (i == mCursor && backgroundColor != 0x00000000) { - mRenderer->drawRect(mSelectorHorizontalOffset, mSelectorVerticalOffset, - entry.data.textCache->metrics.size.x, mSelectorHeight, - backgroundColor, backgroundColor); - } - font->renderTextCache(entry.data.textCache.get()); - } - y += entrySize; + offsetY += entrySize; } mRenderer->popClipRect(); if constexpr (std::is_same_v<T, FileData*>) @@ -551,7 +481,21 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, mSelectedSecondaryBackgroundColor = mSelectedBackgroundColor; } - setFont(Font::getFromTheme(elem, properties, mFont, 0.0f, false)); + if (elem->has("textHorizontalScrolling")) + mHorizontalScrolling = elem->get<bool>("textHorizontalScrolling"); + + if (elem->has("textHorizontalScrollSpeed")) { + mHorizontalScrollSpeed = + glm::clamp(elem->get<float>("textHorizontalScrollSpeed"), 0.1f, 10.0f); + } + + if (elem->has("textHorizontalScrollDelay")) { + mHorizontalScrollDelay = + glm::clamp(elem->get<float>("textHorizontalScrollDelay"), 0.0f, 10.0f) * 1000.0f; + } + + mFont = Font::getFromTheme(elem, properties, mFont, 0.0f, false); + const float selectorHeight {mFont->getHeight(mLineSpacing)}; mSelectorHeight = selectorHeight; @@ -742,7 +686,8 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, template <typename T> void TextListComponent<T>::onCursorChanged(const CursorState& state) { - mLoopTime = 0; + if (mEntries.size() > static_cast<size_t>(mLastCursor)) + mEntries.at(mLastCursor).data.entryName->resetComponent(); if constexpr (std::is_same_v<T, SystemData*>) { float startPos {mCamOffset}; @@ -752,8 +697,8 @@ template <typename T> void TextListComponent<T>::onCursorChanged(const CursorSta float animTime {400.0f}; float timeDiff {1.0f}; - // If startPos is inbetween two positions then reduce the time slightly as the distance will - // be shorter meaning the animation would play for too long if not compensated for. + // If startPos is inbetween two positions then reduce the time slightly as the distance + // will be shorter meaning the animation would play for too long if not compensated for. if (mScrollVelocity == 1) timeDiff = endPos - startPos; else if (mScrollVelocity == -1)