Skip to content

Commit

Permalink
Merge pull request #1 from RetroPie/master
Browse files Browse the repository at this point in the history
Merge pull request RetroPie#797 from cmitu/sdl-vendored-input
  • Loading branch information
fengjixuchui authored Apr 13, 2023
2 parents 0c4b42d + 08d74d3 commit 93690e9
Show file tree
Hide file tree
Showing 16 changed files with 226 additions and 150 deletions.
7 changes: 3 additions & 4 deletions es-app/src/animations/MoveCameraAnimation.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,21 @@
class MoveCameraAnimation : public Animation
{
public:
MoveCameraAnimation(Transform4x4f& camera, const Vector3f& target) : mCameraStart(camera), mTarget(target), cameraOut(camera) {}
MoveCameraAnimation(Transform4x4f& camera, const Vector3f& target) : mCameraStart(camera), mTarget(target), mCameraOut(camera) { }

int getDuration() const override { return 400; }

void apply(float t) override
{
// cubic ease out
t -= 1;
cameraOut.translation() = -Vector3f().lerp(-mCameraStart.translation(), mTarget, t*t*t + 1);
mCameraOut.translation() = -Vector3f().lerp(-mCameraStart.translation(), mTarget, t*t*t + 1 /*cubic ease out*/);
}

private:
Transform4x4f mCameraStart;
Vector3f mTarget;

Transform4x4f& cameraOut;
Transform4x4f& mCameraOut;
};

#endif // ES_APP_ANIMATIONS_MOVE_CAMERA_ANIMATION_H
150 changes: 62 additions & 88 deletions es-app/src/components/TextListComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class TextListComponent : public IList<TextListData, T>
using IList<TextListData, T>::getTransform;
using IList<TextListData, T>::mSize;
using IList<TextListData, T>::mCursor;
using IList<TextListData, T>::mViewportTop;
using IList<TextListData, T>::Entry;

public:
Expand Down Expand Up @@ -92,7 +93,7 @@ class TextListComponent : public IList<TextListData, T>
Alignment mAlignment;
float mHorizontalMargin;

int getFirstVisibleEntry();
int viewportTop();
std::function<void(CursorState state)> mCursorChangedCallback;

std::shared_ptr<Font> mFont;
Expand All @@ -107,10 +108,8 @@ class TextListComponent : public IList<TextListData, T>
std::string mScrollSound;
static const unsigned int COLOR_ID_COUNT = 2;
unsigned int mColors[COLOR_ID_COUNT];
unsigned int mScreenCount;
int mStartEntry = 0;
unsigned int mCursorPrev = -1;
bool mOneEntryUpDn = true;
int mViewportHeight;
int mCursorPrev = -1;

ImageComponent mSelectorImage;
};
Expand Down Expand Up @@ -151,32 +150,33 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)

const float entrySize = Math::max(font->getHeight(1.0), (float)font->getSize()) * mLineSpacing;

// number of entries that can fit on the screen simultaniously
mScreenCount = (int)(mSize.y() / entrySize);
// number of listentries that can fit on the screen
mViewportHeight = (int)(mSize.y() / entrySize);

if(mViewportTop == -1)
{
// returning from screen saver activated game launch
mViewportTop = mCursor - mViewportHeight/2;
}
if(mCursor != mCursorPrev)
{
mStartEntry = (size() > mScreenCount) ? getFirstVisibleEntry() : 0;
mViewportTop = (size() > mViewportHeight) ? viewportTop() : 0;
mCursorPrev = mCursor;
}

unsigned int listCutoff = mStartEntry + mScreenCount;
unsigned int listCutoff = mViewportTop + mViewportHeight;
if(listCutoff > size())
listCutoff = size();

float y = (mSize.y() - (mScreenCount * entrySize)) * 0.5f;
float y = (mSize.y() - (mViewportHeight * entrySize)) * 0.5f;

// draw selector bar
if(mStartEntry < listCutoff)
{
if (mSelectorImage.hasImage()) {
mSelectorImage.setPosition(0.f, y + (mCursor - mStartEntry)*entrySize + mSelectorOffsetY, 0.f);
mSelectorImage.render(trans);
} else {
Renderer::setMatrix(trans);
Renderer::drawRect(0.0f, y + (mCursor - mStartEntry)*entrySize + mSelectorOffsetY, mSize.x(),
mSelectorHeight, mSelectorColor, mSelectorColorEnd, mSelectorColorGradientHorizontal);
}
if (mSelectorImage.hasImage()) {
mSelectorImage.setPosition(0.f, y + (mCursor - mViewportTop)*entrySize + mSelectorOffsetY, 0.f);
mSelectorImage.render(trans);
} else {
Renderer::setMatrix(trans);
Renderer::drawRect(0.0f, y + (mCursor - mViewportTop)*entrySize + mSelectorOffsetY, mSize.x(),
mSelectorHeight, mSelectorColor, mSelectorColorEnd, mSelectorColorGradientHorizontal);
}

// clip to inside margins
Expand All @@ -185,7 +185,7 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
Renderer::pushClipRect(Vector2i((int)(trans.translation().x() + mHorizontalMargin), (int)trans.translation().y()),
Vector2i((int)(dim.x() - mHorizontalMargin*2), (int)dim.y()));

for(int i = mStartEntry; i < listCutoff; i++)
for(int i = mViewportTop; i < listCutoff; i++)
{
typename IList<TextListData, T>::Entry& entry = mEntries.at((unsigned int)i);

Expand Down Expand Up @@ -254,91 +254,65 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)


template <typename T>
int TextListComponent<T>::getFirstVisibleEntry()
int TextListComponent<T>::viewportTop()
{
int viewportTopMax = size() - mViewportHeight;
int topNew = mViewportTop;

if (mCursorPrev == -1)
{
// init or returned from emulator
mCursorPrev = mCursor;
int quot = div(mCursor, mScreenCount).quot;
mStartEntry = quot * mScreenCount;
}
int screenRelCursor = mCursorPrev - mStartEntry;
bool cursorCentered = screenRelCursor == mScreenCount/2;
int visibleEntryMax = size() - mScreenCount;
int firstVisibleEntry = 0;

if(Settings::getInstance()->getBool("UseFullscreenPaging") && !cursorCentered)
int delta = mCursor - mCursorPrev;

if(Settings::getInstance()->getBool("UseFullscreenPaging"))
{
// keep visible cursor constant but move visible list (default)
firstVisibleEntry = mCursor - screenRelCursor;
if(mOneEntryUpDn)
// delta may be greater/less than +/-mViewportHeight on re-sorting of list
if (delta <= -mViewportHeight || delta >= mViewportHeight
// keep cursor sticky at position unless the user navigates
// to the middle of the viewport
|| delta < 0 && mCursor - mViewportTop < mViewportHeight/2
|| delta > 0 && mCursor - mViewportTop > mViewportHeight/2)
{
int delta = mCursor - mCursorPrev;
// detect rollover (== delta is more than one item)
if(delta < -3)
firstVisibleEntry = 0;
else if(delta > 3)
firstVisibleEntry = visibleEntryMax;
else if(screenRelCursor < mScreenCount/2 && delta > 0 /*down pressed*/
|| screenRelCursor > mScreenCount/2 && delta < 0 /*up pressed*/)
// cases for list begin / list end
// move visible cursor and keep visible list section constant
firstVisibleEntry = firstVisibleEntry - delta;
topNew += delta;
}
} else {
// cursor always in middle of visible list
firstVisibleEntry = mCursor - mScreenCount/2;
// no match above will place the cursor more towards the middle
}
// bounds check
if(firstVisibleEntry < 0)
firstVisibleEntry = 0;
else if(firstVisibleEntry > visibleEntryMax)
firstVisibleEntry = visibleEntryMax;
return firstVisibleEntry;
else
// put cursor in middle of visible list
topNew = mCursor - mViewportHeight/2;

if (mCursor <= mViewportHeight/2)
topNew = 0;
else if (mCursor >= viewportTopMax + mViewportHeight/2)
topNew = viewportTopMax;

return topNew;
}

template <typename T>
bool TextListComponent<T>::input(InputConfig* config, Input input)
{
if(size() > 0)
bool isSingleStep = config->isMappedLike("down", input) || config->isMappedLike("up", input);
bool isPageStep = config->isMappedLike("rightshoulder", input) || config->isMappedLike("leftshoulder", input);

if(size() > 0 && (isSingleStep || isPageStep))
{
if(input.value != 0)
{
if(config->isMappedLike("down", input))
{
listInput(1);
mOneEntryUpDn = true;
return true;
}

if(config->isMappedLike("up", input))
{
listInput(-1);
mOneEntryUpDn = true;
return true;
}
if(config->isMappedLike("rightshoulder", input))
{
int delta = Settings::getInstance()->getBool("UseFullscreenPaging") ? mScreenCount : 10;
listInput(delta);
mOneEntryUpDn = false;
return true;
}

if(config->isMappedLike("leftshoulder", input))
int delta;
mCursorPrev = mCursor;
if(isSingleStep)
delta = config->isMappedLike("down", input) ? 1 : -1;
else
{
int delta = Settings::getInstance()->getBool("UseFullscreenPaging") ? mScreenCount : 10;
listInput(-delta);
mOneEntryUpDn = false;
return true;
delta = Settings::getInstance()->getBool("UseFullscreenPaging") ? mViewportHeight : 10;
if (config->isMappedLike("leftshoulder", input))
delta = -delta;
}
listInput(delta);
return true;
}else{
if(config->isMappedLike("down", input) || config->isMappedLike("up", input) ||
config->isMappedLike("rightshoulder", input) || config->isMappedLike("leftshoulder", input))
{
stopScrolling();
}
stopScrolling();
}
}

Expand Down
69 changes: 62 additions & 7 deletions es-app/src/views/ViewController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ void ViewController::goToStart()
if ((*it)->getName() == requestedSystem)
{
goToGameList(*it);
Scripting::fireEvent("system-select", requestedSystem, "requestedsystem");
Scripting::fireEvent("system-select", requestedSystem, "requestedsystem");
FileData* cursor = getGameListView(*it)->getCursor();
if (cursor != NULL)
{
Expand Down Expand Up @@ -193,11 +193,50 @@ void ViewController::playViewTransition()
}else{
advanceAnimation(0, (int)(mFadeOpacity * FADE_DURATION));
}
} else if (transition_style == "slide"){
}
else if (transition_style == "slide")
{
// slide or simple slide
setAnimation(new MoveCameraAnimation(mCamera, target));
bool inGamelistNav = -mCamera.translation().y() == target.y() // not in/out gamelist nav
&& -mCamera.translation().x() - target.x(); // left/right movement
cancelAnimation(0);
Vector3f tgt = Vector3f(target);
Vector3f positionOrig;
if (inGamelistNav) {
const float screenWidth = (float)Renderer::getScreenWidth();
if (-mCamera.translation().x() - tgt.x() >= 2 * screenWidth)
{
// right rollover
mLockInput = true;
tgt.x() = screenWidth * mGameListViews.size();
}
else if (-mCamera.translation().x() - tgt.x() <= 2 * -screenWidth)
{
// left rollover
mLockInput = true;
tgt.x() = -screenWidth;
}
// deny any further input on rollover as mCurrentView would be
// different on subsequent animations, resulting in restoring
// a unrelated mCurrentView/mCamera with the original position
if (mLockInput)
{
positionOrig = Vector3f(mCurrentView->getPosition());
mCurrentView->setPosition(tgt.x(), tgt.y());
}
}

setAnimation(new MoveCameraAnimation(mCamera, tgt), 0, [this, positionOrig] {
if (mLockInput) {
mCurrentView->setPosition(positionOrig);
mCamera.translation() = -positionOrig;
}
mLockInput = false;
});
updateHelpPrompts(); // update help prompts immediately
} else {
}
else
{
// instant
setAnimation(new LambdaAnimation(
[this, target](float /*t*/)
Expand Down Expand Up @@ -247,8 +286,10 @@ void ViewController::launch(FileData* game, Vector3f center)
game->launchGame(mWindow);
setAnimation(new LambdaAnimation(fadeFunc, 800), 0, [this] { mLockInput = false; }, true);
this->onFileChanged(game, FILE_METADATA_CHANGED);
if (mCurrentView)
if (mCurrentView) {
this->getGameListView(game->getSystem())->setViewportTop(-1);
mCurrentView->onShow();
}
});
} else if (transition_style == "slide"){
// move camera to zoom in on center + fade out, launch game, come back in
Expand All @@ -258,8 +299,10 @@ void ViewController::launch(FileData* game, Vector3f center)
mCamera = origCamera;
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 600), 0, [this] { mLockInput = false; }, true);
this->onFileChanged(game, FILE_METADATA_CHANGED);
if (mCurrentView)
if (mCurrentView) {
this->getGameListView(game->getSystem())->setViewportTop(-1);
mCurrentView->onShow();
}
});
} else { // instant
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 10), 0, [this, origCamera, center, game]
Expand All @@ -268,8 +311,10 @@ void ViewController::launch(FileData* game, Vector3f center)
mCamera = origCamera;
setAnimation(new LaunchAnimation(mCamera, mFadeOpacity, center, 10), 0, [this] { mLockInput = false; }, true);
this->onFileChanged(game, FILE_METADATA_CHANGED);
if (mCurrentView)
if (mCurrentView) {
this->getGameListView(game->getSystem())->setViewportTop(-1);
mCurrentView->onShow();
}
});
}
}
Expand Down Expand Up @@ -477,6 +522,7 @@ void ViewController::reloadGameListView(IGameListView* view, bool reloadTheme)
bool isCurrent = (mCurrentView == it->second);
SystemData* system = it->first;
FileData* cursor = view->getCursor();
int viewportTop = view->getViewportTop();
mGameListViews.erase(it);

if(reloadTheme)
Expand All @@ -487,6 +533,7 @@ void ViewController::reloadGameListView(IGameListView* view, bool reloadTheme)
// to counter having come from a placeholder
if (!cursor->isPlaceHolder()) {
newView->setCursor(cursor);
newView->setViewportTop(viewportTop);
}
if(isCurrent)
mCurrentView = newView;
Expand All @@ -504,9 +551,11 @@ void ViewController::reloadAll()
{
// clear all gamelistviews
std::map<SystemData*, FileData*> cursorMap;
std::map<SystemData*, int> viewportTopMap;
for(auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++)
{
cursorMap[it->first] = it->second->getCursor();
viewportTopMap[it->first] = it->second->getViewportTop();
}
mGameListViews.clear();

Expand All @@ -519,6 +568,12 @@ void ViewController::reloadAll()
getGameListView(it->first)->setCursor(it->second);
}

// restore index of first list item on display
for(auto it = viewportTopMap.cbegin(); it != viewportTopMap.cend(); it++)
{
getGameListView(it->first)->setViewportTop(it->second);
}

// Rebuild SystemListView
mSystemListView.reset();
getSystemListView();
Expand Down
Loading

0 comments on commit 93690e9

Please sign in to comment.