Added new textHorizontalScrolling, textHorizontalScrollSpeed and textHorizontalScrollDelay textlist properties

Also removed the horizontal text scrolling code and did some general refactoring
This commit is contained in:
Leon Styhre 2023-08-08 19:35:20 +02:00
parent c30d035e3f
commit 7999f89c5b
2 changed files with 66 additions and 118 deletions

View file

@ -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},

View file

@ -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)