mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 07:35:38 +00:00
Removed all horizontal text scrolling code from ComponentList (TextComponent is now used instead for this)
Also some general code cleanup and refactoring
This commit is contained in:
parent
8ea2ead679
commit
c30d035e3f
|
@ -172,8 +172,8 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
row.addElement(ed, false, true);
|
||||
|
||||
// Pass input to the actual RatingComponent instead of the spacer.
|
||||
row.input_handler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
row.inputHandler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
break;
|
||||
}
|
||||
case MD_DATE: {
|
||||
|
@ -187,8 +187,8 @@ GuiMetaDataEd::GuiMetaDataEd(MetaDataList* md,
|
|||
row.addElement(ed, false);
|
||||
|
||||
// Pass input to the actual DateTimeEditComponent instead of the spacer.
|
||||
row.input_handler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
row.inputHandler = std::bind(&GuiComponent::input, ed.get(), std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
break;
|
||||
}
|
||||
case MD_CONTROLLER: {
|
||||
|
|
|
@ -350,7 +350,6 @@ void GuiScraperSearch::search(ScraperSearchParams& params)
|
|||
mAutomaticModeGameEntry = 0;
|
||||
|
||||
mResultList->clear();
|
||||
mResultList->setLoopRows(false);
|
||||
mScraperResults.clear();
|
||||
mMDRetrieveURLsHandle.reset();
|
||||
mThumbnailReqMap.clear();
|
||||
|
@ -409,9 +408,7 @@ void GuiScraperSearch::stop()
|
|||
void GuiScraperSearch::onSearchDone(std::vector<ScraperSearchResult>& results)
|
||||
{
|
||||
mResultList->clear();
|
||||
|
||||
mScraperResults = results;
|
||||
mResultList->setLoopRows(true);
|
||||
|
||||
auto font = Font::get(FONT_SIZE_MEDIUM);
|
||||
unsigned int color {mMenuColorPrimary};
|
||||
|
@ -512,9 +509,10 @@ void GuiScraperSearch::onSearchDone(std::vector<ScraperSearchResult>& results)
|
|||
gameName.append(" [").append(otherPlatforms).append("]");
|
||||
|
||||
row.elements.clear();
|
||||
row.addElement(
|
||||
std::make_shared<TextComponent>(Utils::String::toUpper(gameName), font, color),
|
||||
false);
|
||||
auto gameEntry =
|
||||
std::make_shared<TextComponent>(Utils::String::toUpper(gameName), font, color);
|
||||
gameEntry->setHorizontalScrolling(true);
|
||||
row.addElement(gameEntry, true);
|
||||
row.makeAcceptInputHandler([this, i] { returnResult(mScraperResults.at(i)); });
|
||||
mResultList->addRow(row);
|
||||
}
|
||||
|
@ -602,7 +600,7 @@ void GuiScraperSearch::updateInfoPane()
|
|||
|
||||
mResultName->setText(Utils::String::toUpper(res.mdl.get("name")));
|
||||
mResultDesc->setText(Utils::String::toUpper(res.mdl.get("desc")));
|
||||
mDescContainer->reset();
|
||||
mDescContainer->resetComponent();
|
||||
|
||||
mResultThumbnail->setImage("");
|
||||
const std::string& thumb {res.screenshotUrl.empty() ? res.coverUrl : res.screenshotUrl};
|
||||
|
@ -670,7 +668,7 @@ bool GuiScraperSearch::input(InputConfig* config, Input input)
|
|||
if (config->isMappedTo("a", input) && input.value != 0) {
|
||||
if (mBlockAccept || mScraperResults.empty())
|
||||
return true;
|
||||
mResultList->setLoopRows(false);
|
||||
mResultList->setHorizontalScrolling(false);
|
||||
}
|
||||
|
||||
// Check whether we should allow a refine of the game name.
|
||||
|
@ -691,7 +689,7 @@ bool GuiScraperSearch::input(InputConfig* config, Input input)
|
|||
allowRefine = true;
|
||||
|
||||
if (allowRefine) {
|
||||
mResultList->stopLooping();
|
||||
mResultList->resetSelectedRow();
|
||||
openInputScreen(mLastSearch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,10 +79,10 @@ void GamelistView::onFileChanged(FileData* file, bool reloadGamelist)
|
|||
void GamelistView::onShow()
|
||||
{
|
||||
for (auto& animation : mLottieAnimComponents)
|
||||
animation->resetFileAnimation();
|
||||
animation->resetComponent();
|
||||
|
||||
for (auto& animation : mGIFAnimComponents)
|
||||
animation->resetFileAnimation();
|
||||
animation->resetComponent();
|
||||
|
||||
for (auto& video : mStaticVideoComponents)
|
||||
video->stopVideoPlayer();
|
||||
|
@ -795,10 +795,11 @@ void GamelistView::updateView(const CursorState& state)
|
|||
}
|
||||
|
||||
for (auto& container : mContainerComponents)
|
||||
container->reset();
|
||||
container->resetComponent();
|
||||
|
||||
for (auto& scrollableText : mTextComponents)
|
||||
scrollableText->resetLooping();
|
||||
// Reset horizontally scrolling text.
|
||||
for (auto& text : mTextComponents)
|
||||
text->resetComponent();
|
||||
|
||||
for (auto& rating : mRatingComponents)
|
||||
rating->setValue(file->metadata.get("rating"));
|
||||
|
|
|
@ -69,17 +69,18 @@ void SystemView::goToSystem(SystemData* system, bool animate)
|
|||
selector->setNeedsRefresh();
|
||||
}
|
||||
|
||||
// Reset horizontally scrolling text.
|
||||
for (auto& text : mSystemElements[mPrimary->getCursor()].textComponents)
|
||||
text->resetLooping();
|
||||
text->resetComponent();
|
||||
|
||||
for (auto& video : mSystemElements[mPrimary->getCursor()].videoComponents)
|
||||
video->setStaticVideo();
|
||||
|
||||
for (auto& anim : mSystemElements[mPrimary->getCursor()].lottieAnimComponents)
|
||||
anim->resetFileAnimation();
|
||||
anim->resetComponent();
|
||||
|
||||
for (auto& anim : mSystemElements[mPrimary->getCursor()].GIFAnimComponents)
|
||||
anim->resetFileAnimation();
|
||||
anim->resetComponent();
|
||||
|
||||
updateGameSelectors();
|
||||
updateGameCount();
|
||||
|
@ -223,8 +224,9 @@ std::vector<HelpPrompt> SystemView::getHelpPrompts()
|
|||
|
||||
void SystemView::onCursorChanged(const CursorState& state)
|
||||
{
|
||||
// Reset horizontally scrolling text.
|
||||
for (auto& text : mSystemElements[mPrimary->getCursor()].textComponents)
|
||||
text->resetLooping();
|
||||
text->resetComponent();
|
||||
|
||||
const int cursor {mPrimary->getCursor()};
|
||||
const int scrollVelocity {mPrimary->getScrollingVelocity()};
|
||||
|
@ -279,7 +281,7 @@ void SystemView::onCursorChanged(const CursorState& state)
|
|||
}
|
||||
|
||||
for (auto& container : mSystemElements[mPrimary->getCursor()].containerComponents)
|
||||
container->reset();
|
||||
container->resetComponent();
|
||||
|
||||
// This is needed to avoid erratic camera movements during extreme navigation input when using
|
||||
// slide transitions. This should very rarely occur during normal application usage.
|
||||
|
@ -312,10 +314,10 @@ void SystemView::onCursorChanged(const CursorState& state)
|
|||
video->setStaticVideo();
|
||||
|
||||
for (auto& anim : mSystemElements[mPrimary->getCursor()].lottieAnimComponents)
|
||||
anim->resetFileAnimation();
|
||||
anim->resetComponent();
|
||||
|
||||
for (auto& anim : mSystemElements[mPrimary->getCursor()].GIFAnimComponents)
|
||||
anim->resetFileAnimation();
|
||||
anim->resetComponent();
|
||||
|
||||
updateGameSelectors();
|
||||
startViewVideos();
|
||||
|
|
|
@ -310,8 +310,10 @@ public:
|
|||
virtual void pauseViewVideos() {}
|
||||
virtual void muteViewVideos() {}
|
||||
|
||||
// For Lottie animations.
|
||||
virtual void resetFileAnimation() {};
|
||||
// Used to reset various components like text scrolling, animations etc.
|
||||
virtual void resetComponent() {}
|
||||
// Used by TextComponent.
|
||||
virtual void setHorizontalScrolling(bool state) {}
|
||||
|
||||
// Default implementation just handles <pos> and <size> tags as normalized float pairs.
|
||||
// You probably want to keep this behavior for any derived classes as well as add your own.
|
||||
|
|
|
@ -22,11 +22,6 @@ ComponentList::ComponentList()
|
|||
, mRowHeight {std::round(Font::get(FONT_SIZE_MEDIUM)->getHeight())}
|
||||
, mSelectorBarOffset {0.0f}
|
||||
, mCameraOffset {0.0f}
|
||||
, mLoopRows {false}
|
||||
, mLoopScroll {false}
|
||||
, mLoopOffset {0}
|
||||
, mLoopOffset2 {0}
|
||||
, mLoopTime {0}
|
||||
, mScrollIndicatorStatus {SCROLL_NONE}
|
||||
{
|
||||
// Adjust the padding relative to the aspect ratio and screen resolution to make it look
|
||||
|
@ -85,8 +80,8 @@ bool ComponentList::input(InputConfig* config, Input input)
|
|||
}
|
||||
|
||||
// Give it to the current row's input handler.
|
||||
if (mEntries.at(mCursor).data.input_handler) {
|
||||
if (mEntries.at(mCursor).data.input_handler(config, input))
|
||||
if (mEntries.at(mCursor).data.inputHandler) {
|
||||
if (mEntries.at(mCursor).data.inputHandler(config, input))
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
@ -132,12 +127,6 @@ bool ComponentList::input(InputConfig* config, Input input)
|
|||
|
||||
void ComponentList::update(int deltaTime)
|
||||
{
|
||||
if (!mFocused && mLoopRows) {
|
||||
mLoopOffset = 0;
|
||||
mLoopOffset2 = 0;
|
||||
mLoopTime = 0;
|
||||
}
|
||||
|
||||
// Scroll indicator logic, used by ScrollIndicatorComponent.
|
||||
bool scrollIndicatorChanged {false};
|
||||
|
||||
|
@ -167,39 +156,11 @@ void ComponentList::update(int deltaTime)
|
|||
|
||||
listUpdate(deltaTime);
|
||||
|
||||
if (size()) {
|
||||
float rowWidth {0.0f};
|
||||
|
||||
if (mFocused && size()) {
|
||||
// Update our currently selected row.
|
||||
for (auto it = mEntries.at(mCursor).data.elements.cbegin();
|
||||
it != mEntries.at(mCursor).data.elements.cend(); ++it) {
|
||||
it->component->update(deltaTime);
|
||||
rowWidth += it->component->getSize().x;
|
||||
}
|
||||
|
||||
if (mLoopRows && rowWidth + mHorizontalPadding / 2.0f > mSize.x) {
|
||||
// Loop the text.
|
||||
const float speed {
|
||||
Font::get(FONT_SIZE_MEDIUM)->sizeText("ABCDEFGHIJKLMNOPQRSTUVWXYZ").x * 0.247f};
|
||||
const float delay {1500.0f};
|
||||
const float scrollLength {rowWidth};
|
||||
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;
|
||||
|
||||
mLoopOffset = static_cast<int>(Utils::Math::loop(delay, scrollTime + returnTime,
|
||||
static_cast<float>(mLoopTime),
|
||||
scrollLength + returnLength));
|
||||
|
||||
if (mLoopOffset > (scrollLength - (mSize.x - returnLength)))
|
||||
mLoopOffset2 = static_cast<int>(mLoopOffset - (scrollLength + returnLength));
|
||||
else if (mLoopOffset2 < 0)
|
||||
mLoopOffset2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,12 +169,6 @@ void ComponentList::onCursorChanged(const CursorState& state)
|
|||
{
|
||||
mSetupCompleted = true;
|
||||
|
||||
if (mLoopRows) {
|
||||
mLoopOffset = 0;
|
||||
mLoopOffset2 = 0;
|
||||
mLoopTime = 0;
|
||||
}
|
||||
|
||||
// Update the selector bar position.
|
||||
// In the future this might be animated.
|
||||
mSelectorBarOffset = 0;
|
||||
|
@ -299,10 +254,9 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
mRenderer->pushClipRect(glm::ivec2 {clipRectPosX, clipRectPosY},
|
||||
glm::ivec2 {clipRectSizeX, clipRectSizeY});
|
||||
|
||||
// Scroll the camera.
|
||||
// Move camera the scroll distance.
|
||||
trans = glm::translate(trans, glm::vec3 {0.0f, -mCameraOffset, 0.0f});
|
||||
|
||||
glm::mat4 loopTrans {trans};
|
||||
const bool darkColorScheme {Settings::getInstance()->getString("MenuColorScheme") != "light"};
|
||||
|
||||
// Draw selector bar if we're using the dark color scheme.
|
||||
|
@ -316,30 +270,10 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
std::vector<GuiComponent*> drawAfterCursor;
|
||||
bool drawAll {false};
|
||||
for (size_t i {0}; i < mEntries.size(); ++i) {
|
||||
|
||||
if (mLoopRows && mFocused && mLoopOffset > 0) {
|
||||
loopTrans =
|
||||
glm::translate(trans, glm::vec3 {static_cast<float>(-mLoopOffset), 0.0f, 0.0f});
|
||||
}
|
||||
|
||||
auto& entry = mEntries.at(i);
|
||||
drawAll = !mFocused || i != static_cast<unsigned int>(mCursor);
|
||||
for (auto it = entry.data.elements.cbegin(); it != entry.data.elements.cend(); ++it) {
|
||||
if (drawAll || it->invert_when_selected) {
|
||||
auto renderLoopFunc = [&]() {
|
||||
// Needed to avoid flickering when returning to the start position.
|
||||
if (mLoopOffset == 0 && mLoopOffset2 == 0)
|
||||
mLoopScroll = false;
|
||||
it->component->render(loopTrans);
|
||||
// Render row again if text is moved far enough for it to repeat.
|
||||
if (mLoopOffset2 < 0 || mLoopScroll) {
|
||||
mLoopScroll = true;
|
||||
loopTrans = glm::translate(
|
||||
trans, glm::vec3 {static_cast<float>(-mLoopOffset2), 0.0f, 0.0f});
|
||||
it->component->render(loopTrans);
|
||||
}
|
||||
};
|
||||
|
||||
if (drawAll || it->invertWhenSelected) {
|
||||
// For the row where the cursor is at, we want to remove any hue from the
|
||||
// font or image before inverting, as it would otherwise lead to an ugly
|
||||
// inverted color (e.g. red inverting to a green hue).
|
||||
|
@ -358,14 +292,14 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
unsigned char byteBlue {static_cast<unsigned char>(origColor >> 8 & 0xFF)};
|
||||
// If it's neutral, just proceed with normal rendering.
|
||||
if (byteRed == byteGreen && byteGreen == byteBlue) {
|
||||
renderLoopFunc();
|
||||
it->component->render(trans);
|
||||
}
|
||||
else {
|
||||
if (isTextComponent)
|
||||
it->component->setColor(mMenuColorPrimary);
|
||||
else
|
||||
it->component->setColorShift(mMenuColorPrimary);
|
||||
renderLoopFunc();
|
||||
it->component->render(trans);
|
||||
// Revert to the original color after rendering.
|
||||
if (isTextComponent)
|
||||
it->component->setColor(origColor);
|
||||
|
@ -383,7 +317,6 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
}
|
||||
}
|
||||
|
||||
// Custom rendering.
|
||||
mRenderer->setMatrix(trans);
|
||||
|
||||
// Draw selector bar if we're using the light color scheme.
|
||||
|
@ -408,14 +341,14 @@ void ComponentList::render(const glm::mat4& parentTrans)
|
|||
}
|
||||
|
||||
// Draw separators.
|
||||
float y {0.0f};
|
||||
float offsetY {0.0f};
|
||||
for (unsigned int i {0}; i < mEntries.size(); ++i) {
|
||||
mRenderer->drawRect(0.0f, y, mSize.x, 1.0f * mRenderer->getScreenResolutionModifier(),
|
||||
mRenderer->drawRect(0.0f, offsetY, mSize.x, 1.0f * mRenderer->getScreenResolutionModifier(),
|
||||
mMenuColorSeparators, mMenuColorSeparators, false, mOpacity, mDimming);
|
||||
y += mRowHeight;
|
||||
offsetY += mRowHeight;
|
||||
}
|
||||
|
||||
mRenderer->drawRect(0.0f, y, mSize.x, 1.0f * mRenderer->getScreenResolutionModifier(),
|
||||
mRenderer->drawRect(0.0f, offsetY, mSize.x, 1.0f * mRenderer->getScreenResolutionModifier(),
|
||||
mMenuColorSeparators, mMenuColorSeparators, false, mOpacity, mDimming);
|
||||
mRenderer->popClipRect();
|
||||
}
|
||||
|
@ -427,14 +360,14 @@ void ComponentList::updateElementPosition(const ComponentListRow& row)
|
|||
yOffset += mRowHeight;
|
||||
|
||||
// Assumes updateElementSize has already been called.
|
||||
float x {mHorizontalPadding / 2.0f};
|
||||
float offsetX {mHorizontalPadding / 2.0f};
|
||||
|
||||
for (unsigned int i {0}; i < row.elements.size(); ++i) {
|
||||
const auto comp = row.elements.at(i).component;
|
||||
|
||||
// Center vertically.
|
||||
comp->setPosition(x, (mRowHeight - std::floor(comp->getSize().y)) / 2.0f + yOffset);
|
||||
x += comp->getSize().x;
|
||||
comp->setPosition(offsetX, (mRowHeight - std::floor(comp->getSize().y)) / 2.0f + yOffset);
|
||||
offsetX += comp->getSize().x;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -444,13 +377,13 @@ void ComponentList::updateElementSize(const ComponentListRow& row)
|
|||
std::vector<std::shared_ptr<GuiComponent>> resizeVec;
|
||||
|
||||
for (auto it = row.elements.cbegin(); it != row.elements.cend(); ++it) {
|
||||
if (it->resize_width)
|
||||
if (it->resizeWidth)
|
||||
resizeVec.push_back(it->component);
|
||||
else
|
||||
width -= it->component->getSize().x;
|
||||
}
|
||||
|
||||
// Redistribute the "unused" width equally among the components with resize_width set to true.
|
||||
// Redistribute the "unused" width equally among the components if resizeWidth is set to true.
|
||||
width = width / resizeVec.size();
|
||||
for (auto it = resizeVec.cbegin(); it != resizeVec.cend(); ++it)
|
||||
(*it)->setSize(width, (*it)->getSize().y);
|
||||
|
@ -487,9 +420,9 @@ std::vector<HelpPrompt> ComponentList::getHelpPrompts()
|
|||
return prompts;
|
||||
}
|
||||
|
||||
bool ComponentList::moveCursor(int amt)
|
||||
bool ComponentList::moveCursor(int amount)
|
||||
{
|
||||
bool ret {listInput(amt)};
|
||||
const bool returnValue {listInput(amount)};
|
||||
listInput(0);
|
||||
return ret;
|
||||
return returnValue;
|
||||
}
|
||||
|
|
|
@ -12,41 +12,41 @@
|
|||
#include "IList.h"
|
||||
|
||||
struct ComponentListElement {
|
||||
ComponentListElement(const std::shared_ptr<GuiComponent>& cmp = nullptr,
|
||||
bool resize_w = true,
|
||||
bool inv = true)
|
||||
: component(cmp)
|
||||
, resize_width(resize_w)
|
||||
, invert_when_selected(inv)
|
||||
ComponentListElement(const std::shared_ptr<GuiComponent>& componentArg = nullptr,
|
||||
bool resizeWidthArg = true,
|
||||
bool invertWhenSelectedArg = true)
|
||||
: component {componentArg}
|
||||
, resizeWidth {resizeWidthArg}
|
||||
, invertWhenSelected {invertWhenSelectedArg}
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<GuiComponent> component;
|
||||
bool resize_width;
|
||||
bool invert_when_selected;
|
||||
bool resizeWidth;
|
||||
bool invertWhenSelected;
|
||||
};
|
||||
|
||||
struct ComponentListRow {
|
||||
std::vector<ComponentListElement> elements;
|
||||
|
||||
// The input handler is called when the user enters any input while this row is
|
||||
// highlighted (including up/down).
|
||||
// highlighted (including up/down navigation).
|
||||
// Return false to let the list try to use it or true if the input has been consumed.
|
||||
// If no input handler is supplied (input_handler == nullptr), the default behavior is
|
||||
// to forward the input to the rightmost element in the currently selected row.
|
||||
std::function<bool(InputConfig*, Input)> input_handler;
|
||||
// If no input handler is supplied (inputHandler == nullptr), then the default behavior
|
||||
// is to forward the input to the rightmost element in the currently selected row.
|
||||
std::function<bool(InputConfig*, Input)> inputHandler;
|
||||
|
||||
void addElement(const std::shared_ptr<GuiComponent>& component,
|
||||
bool resize_width,
|
||||
bool invert_when_selected = true)
|
||||
bool resizeWidth,
|
||||
bool invertWhenSelected = true)
|
||||
{
|
||||
elements.push_back(ComponentListElement(component, resize_width, invert_when_selected));
|
||||
elements.push_back(ComponentListElement(component, resizeWidth, invertWhenSelected));
|
||||
}
|
||||
|
||||
// Utility function for making an input handler for "when the users presses A on this, do func".
|
||||
// Utility function for making an input handler for an input event.
|
||||
void makeAcceptInputHandler(const std::function<void()>& func)
|
||||
{
|
||||
input_handler = [func](InputConfig* config, Input input) -> bool {
|
||||
inputHandler = [func](InputConfig* config, Input input) -> bool {
|
||||
if (config->isMappedTo("a", input) && input.value != 0) {
|
||||
func();
|
||||
return true;
|
||||
|
@ -78,26 +78,33 @@ public:
|
|||
|
||||
void onSizeChanged() override;
|
||||
void onFocusGained() override { mFocused = true; }
|
||||
void onFocusLost() override { mFocused = false; }
|
||||
void onFocusLost() override
|
||||
{
|
||||
mFocused = false;
|
||||
resetSelectedRow();
|
||||
}
|
||||
|
||||
bool moveCursor(int amt);
|
||||
bool moveCursor(int amount);
|
||||
int getCursorId() const { return mCursor; }
|
||||
|
||||
const float getRowHeight() const { return mRowHeight; }
|
||||
void setRowHeight(float height) { mRowHeight = height; }
|
||||
const float getTotalRowHeight() const { return mRowHeight * mEntries.size(); }
|
||||
|
||||
// Horizontal looping for row content that doesn't fit on-screen.
|
||||
void setLoopRows(bool state)
|
||||
void resetSelectedRow()
|
||||
{
|
||||
stopLooping();
|
||||
mLoopRows = state;
|
||||
if (mEntries.size() > static_cast<size_t>(mCursor)) {
|
||||
for (auto& comp : mEntries.at(mCursor).data.elements)
|
||||
comp.component->resetComponent();
|
||||
}
|
||||
}
|
||||
void stopLooping()
|
||||
|
||||
void setHorizontalScrolling(bool state)
|
||||
{
|
||||
mLoopOffset = 0;
|
||||
mLoopOffset2 = 0;
|
||||
mLoopTime = 0;
|
||||
for (auto& entry : mEntries) {
|
||||
for (auto& element : entry.data.elements)
|
||||
element.component->setHorizontalScrolling(state);
|
||||
}
|
||||
}
|
||||
|
||||
void resetScrollIndicatorStatus()
|
||||
|
@ -140,12 +147,6 @@ private:
|
|||
float mSelectorBarOffset;
|
||||
float mCameraOffset;
|
||||
|
||||
bool mLoopRows;
|
||||
bool mLoopScroll;
|
||||
int mLoopOffset;
|
||||
int mLoopOffset2;
|
||||
int mLoopTime;
|
||||
|
||||
std::function<void(CursorState state)> mCursorChangedCallback;
|
||||
std::function<void(ScrollIndicator state, bool singleRowScroll)>
|
||||
mScrollIndicatorChangedCallback;
|
||||
|
|
|
@ -263,7 +263,7 @@ void GIFAnimComponent::setAnimation(const std::string& path)
|
|||
mAnimationStartTime = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
void GIFAnimComponent::resetFileAnimation()
|
||||
void GIFAnimComponent::resetComponent()
|
||||
{
|
||||
mExternalPause = false;
|
||||
mPlayCount = 0;
|
||||
|
|
|
@ -27,7 +27,7 @@ public:
|
|||
void setAnimation(const std::string& path);
|
||||
void setPauseAnimation(bool state) { mExternalPause = state; }
|
||||
|
||||
void resetFileAnimation() override;
|
||||
void resetComponent() override;
|
||||
void onSizeChanged() override;
|
||||
|
||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
|
|
|
@ -229,7 +229,7 @@ void LottieAnimComponent::setAnimation(const std::string& path)
|
|||
mAnimationStartTime = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
void LottieAnimComponent::resetFileAnimation()
|
||||
void LottieAnimComponent::resetComponent()
|
||||
{
|
||||
mExternalPause = false;
|
||||
mPlayCount = 0;
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
}
|
||||
void setPauseAnimation(bool state) { mExternalPause = state; }
|
||||
|
||||
void resetFileAnimation() override;
|
||||
void resetComponent() override;
|
||||
void onSizeChanged() override;
|
||||
|
||||
virtual void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
|
|
|
@ -41,7 +41,7 @@ void ScrollableContainer::setAutoScroll(bool autoScroll)
|
|||
if (autoScroll) {
|
||||
mScrollDir = glm::vec2 {0.0f, 1.0f};
|
||||
mAutoScrollDelay = static_cast<int>(mAutoScrollDelayConstant);
|
||||
reset();
|
||||
resetComponent();
|
||||
}
|
||||
else {
|
||||
mScrollDir = glm::vec2 {};
|
||||
|
@ -60,7 +60,7 @@ void ScrollableContainer::setScrollParameters(float autoScrollDelayConstant,
|
|||
mAutoScrollSpeedConstant = AUTO_SCROLL_SPEED / glm::clamp(autoScrollSpeedConstant, 0.1f, 10.0f);
|
||||
}
|
||||
|
||||
void ScrollableContainer::reset()
|
||||
void ScrollableContainer::resetComponent()
|
||||
{
|
||||
mScrollPos = glm::vec2 {0.0f, 0.0f};
|
||||
mAutoScrollResetAccumulator = 0;
|
||||
|
@ -161,7 +161,7 @@ void ScrollableContainer::update(int deltaTime)
|
|||
if (mWindow->isMediaViewerActive() || mWindow->isScreensaverActive() ||
|
||||
!mWindow->getAllowTextScrolling()) {
|
||||
if (mScrollPos != glm::vec2 {0.0f, 0.0f} && !mWindow->isLaunchScreenDisplayed())
|
||||
reset();
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
void setScrollParameters(float autoScrollDelayConstant,
|
||||
float autoScrollResetDelayConstant,
|
||||
float autoScrollSpeedConstant) override;
|
||||
void reset();
|
||||
void resetComponent() override;
|
||||
|
||||
void applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||
const std::string& view,
|
||||
|
|
|
@ -33,14 +33,13 @@ TextComponent::TextComponent()
|
|||
, mNoTopMargin {false}
|
||||
, mSelectable {false}
|
||||
, mVerticalAutoSizing {false}
|
||||
, mLoopHorizontal {false}
|
||||
, mLoopScroll {false}
|
||||
, mLoopSpeed {0.0f}
|
||||
, mLoopSpeedMultiplier {1.0f}
|
||||
, mLoopDelay {1500.0f}
|
||||
, mLoopOffset1 {0}
|
||||
, mLoopOffset2 {0}
|
||||
, mLoopTime {0}
|
||||
, mHorizontalScrolling {false}
|
||||
, mScrollSpeed {0.0f}
|
||||
, mScrollSpeedMultiplier {1.0f}
|
||||
, mScrollDelay {1500.0f}
|
||||
, mScrollOffset1 {0.0f}
|
||||
, mScrollOffset2 {0.0f}
|
||||
, mScrollTime {0.0f}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -71,14 +70,13 @@ TextComponent::TextComponent(const std::string& text,
|
|||
, mNoTopMargin {false}
|
||||
, mSelectable {false}
|
||||
, mVerticalAutoSizing {false}
|
||||
, mLoopHorizontal {false}
|
||||
, mLoopScroll {false}
|
||||
, mLoopSpeed {0.0f}
|
||||
, mLoopSpeedMultiplier {1.0f}
|
||||
, mLoopDelay {1500.0f}
|
||||
, mLoopOffset1 {0}
|
||||
, mLoopOffset2 {0}
|
||||
, mLoopTime {0}
|
||||
, mHorizontalScrolling {false}
|
||||
, mScrollSpeed {0.0f}
|
||||
, mScrollSpeedMultiplier {1.0f}
|
||||
, mScrollDelay {1500.0f}
|
||||
, mScrollOffset1 {0.0f}
|
||||
, mScrollOffset2 {0.0f}
|
||||
, mScrollTime {0.0f}
|
||||
{
|
||||
setFont(font);
|
||||
setColor(color);
|
||||
|
@ -200,7 +198,7 @@ void TextComponent::render(const glm::mat4& parentTrans)
|
|||
mRenderer->drawRect(0.0f, 0.0f, mSize.x, mSize.y, 0x0000FF33, 0x0000FF33);
|
||||
}
|
||||
|
||||
if (mLoopHorizontal && mTextCache != nullptr) {
|
||||
if (mHorizontalScrolling && mTextCache != nullptr) {
|
||||
// Clip everything to be inside our bounds.
|
||||
glm::vec3 dim {mSize.x, mSize.y, 0.0f};
|
||||
dim.x = (trans[0].x * dim.x + trans[3].x) - trans[3].x;
|
||||
|
@ -218,13 +216,12 @@ void TextComponent::render(const glm::mat4& parentTrans)
|
|||
|
||||
if (mTextCache->metrics.size.x < mSize.x) {
|
||||
if (mHorizontalAlignment == Alignment::ALIGN_CENTER)
|
||||
offsetX = static_cast<float>((mSize.x - mTextCache->metrics.size.x) / 2.0f);
|
||||
offsetX = (mSize.x - mTextCache->metrics.size.x) / 2.0f;
|
||||
else if (mHorizontalAlignment == Alignment::ALIGN_RIGHT)
|
||||
offsetX = mSize.x - mTextCache->metrics.size.x;
|
||||
}
|
||||
|
||||
trans = glm::translate(trans,
|
||||
glm::vec3 {offsetX - static_cast<float>(mLoopOffset1), 0.0f, 0.0f});
|
||||
trans = glm::translate(trans, glm::vec3 {offsetX - mScrollOffset1, 0.0f, 0.0f});
|
||||
}
|
||||
|
||||
auto renderFunc = [this](glm::mat4 trans) {
|
||||
|
@ -271,17 +268,18 @@ void TextComponent::render(const glm::mat4& parentTrans)
|
|||
break;
|
||||
}
|
||||
case ALIGN_CENTER: {
|
||||
mRenderer->drawRect(
|
||||
mLoopHorizontal ? 0.0f : (mSize.x - mTextCache->metrics.size.x) / 2.0f,
|
||||
0.0f, mTextCache->metrics.size.x, mTextCache->metrics.size.y,
|
||||
0x00000033, 0x00000033);
|
||||
mRenderer->drawRect(mHorizontalScrolling ?
|
||||
0.0f :
|
||||
(mSize.x - mTextCache->metrics.size.x) / 2.0f,
|
||||
0.0f, mTextCache->metrics.size.x,
|
||||
mTextCache->metrics.size.y, 0x00000033, 0x00000033);
|
||||
break;
|
||||
}
|
||||
case ALIGN_RIGHT: {
|
||||
mRenderer->drawRect(mLoopHorizontal ? 0.0f :
|
||||
mSize.x - mTextCache->metrics.size.x,
|
||||
0.0f, mTextCache->metrics.size.x,
|
||||
mTextCache->metrics.size.y, 0x00000033, 0x00000033);
|
||||
mRenderer->drawRect(
|
||||
mHorizontalScrolling ? 0.0f : mSize.x - mTextCache->metrics.size.x,
|
||||
0.0f, mTextCache->metrics.size.x, mTextCache->metrics.size.y,
|
||||
0x00000033, 0x00000033);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
@ -295,21 +293,15 @@ void TextComponent::render(const glm::mat4& parentTrans)
|
|||
|
||||
renderFunc(trans);
|
||||
|
||||
if (mLoopHorizontal && mTextCache != nullptr && mTextCache->metrics.size.x > mSize.x) {
|
||||
// Needed to avoid flickering when returning to the start position.
|
||||
if (mLoopOffset1 == 0 && mLoopOffset2 == 0)
|
||||
mLoopScroll = false;
|
||||
// Render again if text has moved far enough for it to repeat.
|
||||
if (mLoopOffset2 < 0 || (mLoopDelay != 0.0f && mLoopScroll)) {
|
||||
mLoopScroll = true;
|
||||
if (mHorizontalScrolling && mTextCache != nullptr && mTextCache->metrics.size.x > mSize.x) {
|
||||
if (mScrollOffset2 < 0.0f) {
|
||||
trans = glm::translate(parentTrans * getTransform(),
|
||||
glm::vec3 {static_cast<float>(-mLoopOffset2), 0.0f, 0.0f});
|
||||
mRenderer->setMatrix(trans);
|
||||
glm::vec3 {-mScrollOffset2, 0.0f, 0.0f});
|
||||
renderFunc(trans);
|
||||
}
|
||||
}
|
||||
|
||||
if (mLoopHorizontal && mTextCache != nullptr)
|
||||
if (mHorizontalScrolling && mTextCache != nullptr)
|
||||
mRenderer->popClipRect();
|
||||
}
|
||||
|
||||
|
@ -320,7 +312,7 @@ void TextComponent::setValue(const std::string& value)
|
|||
mThemeMetadata == "genre" || mThemeMetadata == "players")) {
|
||||
setText(mDefaultValue);
|
||||
}
|
||||
else if (mLoopHorizontal) {
|
||||
else if (mHorizontalScrolling) {
|
||||
setText(Utils::String::replace(value, "\n", " "));
|
||||
}
|
||||
else {
|
||||
|
@ -328,53 +320,52 @@ void TextComponent::setValue(const std::string& value)
|
|||
}
|
||||
}
|
||||
|
||||
void TextComponent::setHorizontalLooping(bool state)
|
||||
void TextComponent::setHorizontalScrolling(bool state)
|
||||
{
|
||||
resetLooping();
|
||||
mLoopHorizontal = state;
|
||||
resetComponent();
|
||||
mHorizontalScrolling = state;
|
||||
|
||||
if (mLoopHorizontal)
|
||||
mLoopSpeed =
|
||||
mFont->sizeText("ABCDEFGHIJKLMNOPQRSTUVWXYZ").x * 0.247f * mLoopSpeedMultiplier;
|
||||
if (mHorizontalScrolling)
|
||||
mScrollSpeed =
|
||||
mFont->sizeText("ABCDEFGHIJKLMNOPQRSTUVWXYZ").x * 0.247f * mScrollSpeedMultiplier;
|
||||
}
|
||||
|
||||
void TextComponent::update(int deltaTime)
|
||||
{
|
||||
if (mLoopHorizontal && mTextCache != nullptr) {
|
||||
if (mHorizontalScrolling && mTextCache != nullptr) {
|
||||
// Don't scroll if the media viewer or screensaver is active or if text scrolling
|
||||
// is disabled;
|
||||
if (mWindow->isMediaViewerActive() || mWindow->isScreensaverActive() ||
|
||||
!mWindow->getAllowTextScrolling()) {
|
||||
if (mLoopTime != 0 && !mWindow->isLaunchScreenDisplayed())
|
||||
resetLooping();
|
||||
if (mScrollTime != 0 && !mWindow->isLaunchScreenDisplayed())
|
||||
resetComponent();
|
||||
return;
|
||||
}
|
||||
|
||||
assert(mLoopSpeed != 0.0f);
|
||||
assert(mScrollSpeed != 0.0f);
|
||||
|
||||
mLoopOffset1 = 0;
|
||||
mLoopOffset2 = 0;
|
||||
mScrollOffset1 = 0.0f;
|
||||
mScrollOffset2 = 0.0f;
|
||||
|
||||
if (mTextCache->metrics.size.x > mSize.x) {
|
||||
// Loop the text.
|
||||
const float scrollLength {mTextCache->metrics.size.x};
|
||||
const float returnLength {mLoopSpeed * 1.5f / mLoopSpeedMultiplier};
|
||||
const float scrollTime {(scrollLength * 1000.0f) / mLoopSpeed};
|
||||
const float returnTime {(returnLength * 1000.0f) / mLoopSpeed};
|
||||
const int maxTime {static_cast<int>(mLoopDelay + scrollTime + returnTime)};
|
||||
const float returnLength {mScrollSpeed * 1.5f / mScrollSpeedMultiplier};
|
||||
const float scrollTime {(scrollLength * 1000.0f) / mScrollSpeed};
|
||||
const float returnTime {(returnLength * 1000.0f) / mScrollSpeed};
|
||||
const float maxTime {mScrollDelay + scrollTime + returnTime};
|
||||
|
||||
mLoopTime += deltaTime;
|
||||
while (mLoopTime > maxTime)
|
||||
mLoopTime -= maxTime;
|
||||
mScrollTime += deltaTime;
|
||||
|
||||
mLoopOffset1 = static_cast<int>(Utils::Math::loop(mLoopDelay, scrollTime + returnTime,
|
||||
static_cast<float>(mLoopTime),
|
||||
scrollLength + returnLength));
|
||||
while (mScrollTime > maxTime)
|
||||
mScrollTime -= maxTime;
|
||||
|
||||
if (mLoopOffset1 > (scrollLength - (mSize.x - returnLength)))
|
||||
mLoopOffset2 = static_cast<int>(mLoopOffset1 - (scrollLength + returnLength));
|
||||
else if (mLoopOffset2 < 0)
|
||||
mLoopOffset2 = 0;
|
||||
mScrollOffset1 = Utils::Math::loop(mScrollDelay, scrollTime + returnTime, mScrollTime,
|
||||
scrollLength + returnLength);
|
||||
|
||||
if (mScrollOffset1 > (scrollLength - (mSize.x - returnLength)))
|
||||
mScrollOffset2 = mScrollOffset1 - (scrollLength + returnLength);
|
||||
else if (mScrollOffset2 < 0)
|
||||
mScrollOffset2 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -418,7 +409,7 @@ void TextComponent::onTextChanged()
|
|||
|
||||
const bool isMultiline {mAutoCalcExtent.y == 1 || mSize.y > lineHeight};
|
||||
|
||||
if (mLoopHorizontal) {
|
||||
if (mHorizontalScrolling) {
|
||||
mTextCache = std::shared_ptr<TextCache>(font->buildTextCache(text, 0.0f, 0.0f, mColor));
|
||||
}
|
||||
else if (isMultiline && !isScrollable) {
|
||||
|
@ -564,14 +555,14 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
const std::string& containerType {elem->get<std::string>("containerType")};
|
||||
if (containerType == "horizontal") {
|
||||
if (elem->has("containerScrollSpeed")) {
|
||||
mLoopSpeedMultiplier =
|
||||
mScrollSpeedMultiplier =
|
||||
glm::clamp(elem->get<float>("containerScrollSpeed"), 0.1f, 10.0f);
|
||||
}
|
||||
if (elem->has("containerStartDelay")) {
|
||||
mLoopDelay =
|
||||
mScrollDelay =
|
||||
glm::clamp(elem->get<float>("containerStartDelay"), 0.0f, 10.0f) * 1000.0f;
|
||||
}
|
||||
mLoopHorizontal = true;
|
||||
mHorizontalScrolling = true;
|
||||
}
|
||||
else if (containerType != "vertical") {
|
||||
LOG(LogError) << "TextComponent: Invalid theme configuration, property "
|
||||
|
@ -692,7 +683,7 @@ void TextComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
|
||||
setFont(Font::getFromTheme(elem, properties, mFont, maxHeight, false));
|
||||
|
||||
// We need to do this after setting the font as the loop speed is calculated from its size.
|
||||
if (mLoopHorizontal)
|
||||
setHorizontalLooping(true);
|
||||
// We need to do this after setting the font as the scroll speed is calculated from its size.
|
||||
if (mHorizontalScrolling)
|
||||
setHorizontalScrolling(true);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ public:
|
|||
void setRenderBackground(bool render) { mRenderBackground = render; }
|
||||
|
||||
void render(const glm::mat4& parentTrans) override;
|
||||
void onFocusLost() override { resetComponent(); }
|
||||
|
||||
std::string getValue() const override { return mText; }
|
||||
void setValue(const std::string& value) override;
|
||||
|
@ -86,14 +87,16 @@ public:
|
|||
return (mTextCache == nullptr ? 0 : mTextCache->metrics.maxGlyphHeight);
|
||||
}
|
||||
|
||||
// Horizontal looping for single-line content that is too long to fit.
|
||||
void setHorizontalLooping(bool state);
|
||||
// Horizontal scrolling for single-line content that is too long to fit.
|
||||
void setHorizontalScrolling(bool state) override;
|
||||
void setHorizontalScrollingSpeedMultiplier(float speed) { mScrollSpeedMultiplier = speed; }
|
||||
void setHorizontalScrollingDelay(float delay) { mScrollDelay = delay; }
|
||||
|
||||
void resetLooping()
|
||||
void resetComponent()
|
||||
{
|
||||
mLoopOffset1 = 0;
|
||||
mLoopOffset2 = 0;
|
||||
mLoopTime = 0;
|
||||
mScrollOffset1 = 0;
|
||||
mScrollOffset2 = 0;
|
||||
mScrollTime = 0;
|
||||
}
|
||||
|
||||
void update(int deltaTime) override;
|
||||
|
@ -144,14 +147,13 @@ private:
|
|||
bool mSelectable;
|
||||
bool mVerticalAutoSizing;
|
||||
|
||||
bool mLoopHorizontal;
|
||||
bool mLoopScroll;
|
||||
float mLoopSpeed;
|
||||
float mLoopSpeedMultiplier;
|
||||
float mLoopDelay;
|
||||
int mLoopOffset1;
|
||||
int mLoopOffset2;
|
||||
int mLoopTime;
|
||||
bool mHorizontalScrolling;
|
||||
float mScrollSpeed;
|
||||
float mScrollSpeedMultiplier;
|
||||
float mScrollDelay;
|
||||
float mScrollOffset1;
|
||||
float mScrollOffset2;
|
||||
float mScrollTime;
|
||||
};
|
||||
|
||||
#endif // ES_CORE_COMPONENTS_TEXT_COMPONENT_H
|
||||
|
|
|
@ -107,7 +107,7 @@ GuiInputConfig::GuiInputConfig(InputConfig* target,
|
|||
row.addElement(mapping, true);
|
||||
mMappings.push_back(mapping);
|
||||
|
||||
row.input_handler = [this, i, mapping](InputConfig* config, Input input) -> bool {
|
||||
row.inputHandler = [this, i, mapping](InputConfig* config, Input input) -> bool {
|
||||
// Ignore input not from our target device.
|
||||
if (config != mTargetConfig)
|
||||
return false;
|
||||
|
|
Loading…
Reference in a new issue