From da93533aedd0fb95a41567c36bf9c8020b5b0ce6 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 4 Dec 2022 15:56:59 +0100 Subject: [PATCH] Fixed multiple navigation issues. --- es-app/src/views/SystemView.cpp | 39 +++++++- .../src/components/primary/GridComponent.h | 90 +++++++++---------- .../components/primary/TextListComponent.h | 29 +++--- 3 files changed, 95 insertions(+), 63 deletions(-) diff --git a/es-app/src/views/SystemView.cpp b/es-app/src/views/SystemView.cpp index e89b863ee..8f86e9266 100644 --- a/es-app/src/views/SystemView.cpp +++ b/es-app/src/views/SystemView.cpp @@ -205,6 +205,9 @@ std::vector SystemView::getHelpPrompts() else prompts.push_back(HelpPrompt("left/right", "choose")); } + else if (mGrid != nullptr) { + prompts.push_back(HelpPrompt("up/down/left/right", "choose")); + } else if (mTextList != nullptr) { prompts.push_back(HelpPrompt("up/down", "choose")); } @@ -223,9 +226,43 @@ std::vector SystemView::getHelpPrompts() void SystemView::onCursorChanged(const CursorState& state) { const int cursor {mPrimary->getCursor()}; + const int scrollVelocity {mPrimary->getScrollingVelocity()}; const std::string& transitionStyle {Settings::getInstance()->getString("TransitionStyle")}; mFadeTransitions = transitionStyle == "fade"; + // Some logic needed to avoid various navigation glitches with GridComponent and + // TextListComponent. + if (state == CursorState::CURSOR_STOPPED && mCarousel == nullptr) { + const int numEntries {static_cast(mPrimary->getNumEntries())}; + bool doStop {false}; + + if (cursor == 0 && mLastCursor == numEntries - 1 && std::abs(scrollVelocity) == 1) + doStop = false; + else if (cursor == 0) + doStop = true; + else if (cursor == numEntries - 1 && mLastCursor == 0 && std::abs(scrollVelocity) == 1) + doStop = false; + else if (cursor == numEntries - 1) + doStop = true; + + if (!doStop && mGrid != nullptr && std::abs(scrollVelocity) == mGrid->getColumnCount()) { + const int columns {mGrid->getColumnCount()}; + const int columnModulus {numEntries % columns}; + + if (cursor < columns) + doStop = true; + else if (cursor >= numEntries - (columnModulus == 0 ? columns : columnModulus)) + doStop = true; + } + + if (doStop) { + if (mGrid != nullptr) + mGrid->setScrollVelocity(0); + mPrimary->stopScrolling(); + mNavigated = false; + } + } + // Avoid double updates. if (cursor != mLastCursor) { for (auto& selector : mSystemElements[cursor].gameSelectors) { @@ -239,8 +276,6 @@ void SystemView::onCursorChanged(const CursorState& state) video->stopVideoPlayer(); } - const int scrollVelocity {mPrimary->getScrollingVelocity()}; - // 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. if (transitionStyle == "slide") { diff --git a/es-core/src/components/primary/GridComponent.h b/es-core/src/components/primary/GridComponent.h index 4adf92ec7..c9fe5317e 100644 --- a/es-core/src/components/primary/GridComponent.h +++ b/es-core/src/components/primary/GridComponent.h @@ -41,6 +41,9 @@ public: void updateEntry(Entry& entry, const std::shared_ptr& theme); void onDemandTextureLoad() override; void calculateLayout(); + const int getColumnCount() const { return mColumns; } + const int getRowCount() const { return mRows; } + void setScrollVelocity(int velocity) { mScrollVelocity = velocity; } void setCancelTransitionsCallback(const std::function& func) override { @@ -93,7 +96,11 @@ private: const T& getPrevious() const override { return List::getPrevious(); } const T& getFirst() const override { return List::getFirst(); } const T& getLast() const override { return List::getLast(); } - bool setCursor(const T& obj) override { return List::setCursor(obj); } + bool setCursor(const T& obj) override + { + mLastCursor = mCursor; + return List::setCursor(obj); + } bool remove(const T& obj) override { return List::remove(obj); } int size() const override { return List::size(); } @@ -129,7 +136,6 @@ private: bool mGamelistView; bool mFractionalRows; bool mLayoutValid; - bool mRowJump; bool mWasScrolling; bool mJustCalculatedLayout; }; @@ -164,7 +170,6 @@ GridComponent::GridComponent() , mGamelistView {std::is_same_v ? true : false} , mFractionalRows {false} , mLayoutValid {false} - , mRowJump {false} , mWasScrolling {false} , mJustCalculatedLayout {false} { @@ -377,36 +382,33 @@ template bool GridComponent::input(InputConfig* config, Input in { if (size() > 0) { if (input.value != 0) { - mRowJump = false; - if (config->isMappedLike("left", input)) { if (mCancelTransitionsCallback) mCancelTransitionsCallback(); - if (mCursor % mColumns == 0) - mRowJump = true; List::listInput(-1); return true; } if (config->isMappedLike("right", input)) { if (mCancelTransitionsCallback) mCancelTransitionsCallback(); - if (mCursor % mColumns == mColumns - 1) - mRowJump = true; List::listInput(1); return true; } if (config->isMappedLike("up", input)) { - if (mCancelTransitionsCallback) - mCancelTransitionsCallback(); - mRowJump = true; - List::listInput(-mColumns); + if (mCursor >= mColumns) { + if (mCancelTransitionsCallback) + mCancelTransitionsCallback(); + List::listInput(-mColumns); + } return true; } if (config->isMappedLike("down", input)) { - if (mCancelTransitionsCallback) - mCancelTransitionsCallback(); - mRowJump = true; - List::listInput(mColumns); + const int columnModulus {size() % mColumns}; + if (mCursor < size() - (columnModulus == 0 ? mColumns : columnModulus)) { + if (mCancelTransitionsCallback) + mCancelTransitionsCallback(); + List::listInput(mColumns); + } return true; } if (config->isMappedLike("lefttrigger", input)) { @@ -732,39 +734,37 @@ template void GridComponent::onCursorChanged(const CursorState& else endRow -= visibleRows; - if (startPos != endPos) { - Animation* anim {new LambdaAnimation( - [this, startPos, endPos, posMax, startRow, endRow](float t) { - // Non-linear interpolation. - t = 1.0f - (1.0f - t) * (1.0f - t); + Animation* anim {new LambdaAnimation( + [this, startPos, endPos, posMax, startRow, endRow](float t) { + // Non-linear interpolation. + t = 1.0f - (1.0f - t) * (1.0f - t); - float f {(endPos * t) + (startPos * (1.0f - t))}; - if (f < 0) - f += posMax; - if (f >= posMax) - f -= posMax; + float f {(endPos * t) + (startPos * (1.0f - t))}; + if (f < 0) + f += posMax; + if (f >= posMax) + f -= posMax; - mEntryOffset = f; + mEntryOffset = f; - if (mInstantRowTransitions) - mScrollPos = endRow; - else - mScrollPos = {(endRow * t) + (startRow * (1.0f - t))}; + if (mInstantRowTransitions) + mScrollPos = endRow; + else + mScrollPos = {(endRow * t) + (startRow * (1.0f - t))}; - if (mInstantItemTransitions) { - mTransitionFactor = 1.0f; - } - else { - // Linear interpolation. - mTransitionFactor = t; - // Non-linear interpolation doesn't seem to be a good match for this component. - // mTransitionFactor = {(1.0f * t) + (0.0f * (1.0f - t))}; - } - }, - static_cast(animTime))}; + if (mInstantItemTransitions) { + mTransitionFactor = 1.0f; + } + else { + // Linear interpolation. + mTransitionFactor = t; + // Non-linear interpolation doesn't seem to be a good match for this component. + // mTransitionFactor = {(1.0f * t) + (0.0f * (1.0f - t))}; + } + }, + static_cast(animTime))}; - GuiComponent::setAnimation(anim, 0, nullptr, false, 0); - } + GuiComponent::setAnimation(anim, 0, nullptr, false, 0); if (mCursorChangedCallback) mCursorChangedCallback(state); diff --git a/es-core/src/components/primary/TextListComponent.h b/es-core/src/components/primary/TextListComponent.h index bf986a299..4484e89a8 100644 --- a/es-core/src/components/primary/TextListComponent.h +++ b/es-core/src/components/primary/TextListComponent.h @@ -201,15 +201,19 @@ template bool TextListComponent::input(InputConfig* config, Inpu return true; } if (config->isMappedLike("leftshoulder", input)) { - if (mCancelTransitionsCallback) - mCancelTransitionsCallback(); - List::listInput(-10); + if (mCursor != 0) { + if (mCancelTransitionsCallback) + mCancelTransitionsCallback(); + List::listInput(-10); + } return true; } if (config->isMappedLike("rightshoulder", input)) { - if (mCancelTransitionsCallback) - mCancelTransitionsCallback(); - List::listInput(10); + if (mCursor != size() - 1) { + if (mCancelTransitionsCallback) + mCancelTransitionsCallback(); + List::listInput(10); + } return true; } if (config->isMappedLike("lefttrigger", input)) { @@ -233,16 +237,9 @@ template bool TextListComponent::input(InputConfig* config, Inpu config->isMappedLike("rightshoulder", input) || config->isMappedLike("lefttrigger", input) || config->isMappedLike("righttrigger", input)) { - if constexpr (std::is_same_v) { - if (isScrolling()) - onCursorChanged(CursorState::CURSOR_STOPPED); - List::listInput(0); - } - else { - if (isScrolling()) - onCursorChanged(CursorState::CURSOR_STOPPED); - List::listInput(0); - } + if (isScrolling()) + onCursorChanged(CursorState::CURSOR_STOPPED); + List::listInput(0); } } }