mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-29 19:55:37 +00:00
First form of the new system select carousel.
This commit is contained in:
parent
2886e8e8d8
commit
fcb8623b3d
|
@ -308,12 +308,8 @@ Reference
|
|||
---
|
||||
|
||||
#### system
|
||||
* `text name="headerText"` - ALL
|
||||
- A header text, which displays the name of the system. Displayed at the top center of the screen. Centered by default.
|
||||
* `image name="header"` - ALL
|
||||
- A header image. If a non-empty `path` is specified, `text name="headerText"` will be hidden and this image will be, by default, displayed roughly in its place.
|
||||
* image name="system" - ALL
|
||||
- A large image representing the system (usually a picture of the system itself).
|
||||
* `image name="header"` - PATH
|
||||
- A header (logo) image, to be displayed in the system carousel.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -4,58 +4,57 @@
|
|||
#include "../Log.h"
|
||||
#include "../Window.h"
|
||||
#include "ViewController.h"
|
||||
#include "../animations/LambdaAnimation.h"
|
||||
#include "../SystemData.h"
|
||||
|
||||
SystemView::SystemView(Window* window, SystemData* system) : GuiComponent(window),
|
||||
mSystem(system),
|
||||
#define SELECTED_SCALE 1.2f
|
||||
#define LOGO_PADDING (logoSize().x() * (SELECTED_SCALE - 1)/2)
|
||||
|
||||
mHeaderImage(window),
|
||||
mHeaderText(window),
|
||||
mImage(window),
|
||||
mExtras(window)
|
||||
SystemView::SystemView(Window* window) : IList<SystemViewData, SystemData*>(window)
|
||||
{
|
||||
mCamOffset = 0;
|
||||
|
||||
setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||
|
||||
mHeaderImage.setOrigin(0.5f, 0.0f);
|
||||
mHeaderImage.setPosition(mSize.x() / 2, 0);
|
||||
mHeaderImage.setResize(0, mSize.y() * 0.2f);
|
||||
|
||||
mHeaderText.setPosition(0, 6);
|
||||
mHeaderText.setSize(mSize.x(), 0);
|
||||
mHeaderText.setCentered(true);
|
||||
|
||||
mImage.setOrigin(0.5f, 0.5f);
|
||||
mImage.setPosition(mSize.x() / 2, mSize.y() * 0.6f);
|
||||
mImage.setResize(0, mSize.y() * 0.8f);
|
||||
|
||||
addChild(&mExtras);
|
||||
addChild(&mImage);
|
||||
addChild(&mHeaderText);
|
||||
addChild(&mHeaderImage);
|
||||
|
||||
updateData();
|
||||
populate();
|
||||
}
|
||||
|
||||
void SystemView::updateData()
|
||||
void SystemView::populate()
|
||||
{
|
||||
using namespace ThemeFlags;
|
||||
mEntries.clear();
|
||||
|
||||
mExtras.setExtras(ThemeData::makeExtras(mSystem->getTheme(), "system", mWindow));
|
||||
|
||||
mHeaderImage.setImage("");
|
||||
mHeaderImage.applyTheme(mSystem->getTheme(), "system", "header", ALL);
|
||||
|
||||
// header
|
||||
if(mHeaderImage.hasImage())
|
||||
for(auto it = SystemData::sSystemVector.begin(); it != SystemData::sSystemVector.end(); it++)
|
||||
{
|
||||
// use image
|
||||
mHeaderText.setText("");
|
||||
}else{
|
||||
// use text
|
||||
mHeaderImage.setImage("");
|
||||
mHeaderText.setText(mSystem->getFullName());
|
||||
}
|
||||
Entry e;
|
||||
e.name = (*it)->getName();
|
||||
e.object = *it;
|
||||
|
||||
mImage.applyTheme(mSystem->getTheme(), "system", "system", ALL);
|
||||
if((*it)->getTheme()->getElement("system", "header", "image"))
|
||||
{
|
||||
ImageComponent* logo = new ImageComponent(mWindow);
|
||||
logo->setMaxSize(logoSize());
|
||||
logo->applyTheme((*it)->getTheme(), "system", "header", ThemeFlags::PATH);
|
||||
logo->setPosition((logoSize().x() - logo->getSize().x()) / 2, 0);
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(logo);
|
||||
}else{
|
||||
// no logo in theme; use text
|
||||
TextComponent* text = new TextComponent(mWindow);
|
||||
text->setFont(Font::get(FONT_SIZE_LARGE));
|
||||
text->setText((*it)->getName());
|
||||
text->setSize(logoSize());
|
||||
text->setCentered(true);
|
||||
e.data.logo = std::shared_ptr<GuiComponent>(text);
|
||||
}
|
||||
|
||||
e.data.title = nullptr;
|
||||
|
||||
this->add(e);
|
||||
}
|
||||
}
|
||||
|
||||
void SystemView::goToSystem(SystemData* system)
|
||||
{
|
||||
setCursor(system);
|
||||
}
|
||||
|
||||
bool SystemView::input(InputConfig* config, Input input)
|
||||
|
@ -64,27 +63,129 @@ bool SystemView::input(InputConfig* config, Input input)
|
|||
{
|
||||
if(config->isMappedTo("left", input))
|
||||
{
|
||||
mWindow->getViewController()->goToSystemView(mSystem->getPrev());
|
||||
listInput(-1);
|
||||
return true;
|
||||
}
|
||||
if(config->isMappedTo("right", input))
|
||||
{
|
||||
mWindow->getViewController()->goToSystemView(mSystem->getNext());
|
||||
listInput(1);
|
||||
return true;
|
||||
}
|
||||
if(config->isMappedTo("a", input))
|
||||
{
|
||||
mWindow->getViewController()->goToGameList(mSystem);
|
||||
stopScrolling();
|
||||
mWindow->getViewController()->goToGameList(getSelected());
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
if(config->isMappedTo("left", input) || config->isMappedTo("right", input))
|
||||
listInput(0);
|
||||
}
|
||||
|
||||
return GuiComponent::input(config, input);
|
||||
}
|
||||
|
||||
void SystemView::update(int deltaTime)
|
||||
{
|
||||
listUpdate(deltaTime);
|
||||
GuiComponent::update(deltaTime);
|
||||
}
|
||||
|
||||
void SystemView::onCursorChanged(const CursorState& state)
|
||||
{
|
||||
float startPos = mCamOffset;
|
||||
|
||||
const float logoSizeX = logoSize().x() + LOGO_PADDING;
|
||||
|
||||
float posMax = logoSizeX * mEntries.size();
|
||||
float target = mCursor * logoSizeX;
|
||||
|
||||
// what's the shortest way to get to our target?
|
||||
// it's one of these...
|
||||
|
||||
float endPos = target; // directly
|
||||
float dist = abs(endPos - startPos);
|
||||
|
||||
if(abs(target + posMax - startPos) < dist)
|
||||
endPos = target + posMax; // loop around the end (0 -> max)
|
||||
if(abs(target - posMax - startPos) < dist)
|
||||
endPos = target - posMax; // loop around the start (max - 1 -> -1)
|
||||
|
||||
Animation* anim = new LambdaAnimation(
|
||||
[startPos, endPos, posMax, this] (float t)
|
||||
{
|
||||
t -= 1;
|
||||
float f = lerp<float>(startPos, endPos, t*t*t + 1);
|
||||
if(f < 0)
|
||||
f += posMax;
|
||||
if(f >= posMax)
|
||||
f -= posMax;
|
||||
this->mCamOffset = f;
|
||||
}, 400);
|
||||
|
||||
setAnimation(anim);
|
||||
}
|
||||
|
||||
void SystemView::render(const Eigen::Affine3f& parentTrans)
|
||||
{
|
||||
if(size() == 0)
|
||||
return;
|
||||
|
||||
const float logoSizeX = logoSize().x() + LOGO_PADDING;
|
||||
|
||||
Eigen::Affine3f trans = getTransform() * parentTrans;
|
||||
|
||||
// draw background image
|
||||
|
||||
// draw system's stats
|
||||
|
||||
// now for the list elements (logos)
|
||||
Eigen::Affine3f logoTrans = trans;
|
||||
|
||||
int logoCount = (int)(mSize.x() / logoSizeX) + 2; // how many logos we need to draw
|
||||
int center = (int)(mCamOffset / logoSizeX + 0.5f);
|
||||
|
||||
float xOff = (mSize.x() - logoSize().x())/2 - mCamOffset;
|
||||
float yOff = (mSize.y() - logoSize().y())/2;
|
||||
|
||||
// this fixes the case where i != mCursor when wrapping around the end back to zero
|
||||
while(center >= (int)mEntries.size())
|
||||
{
|
||||
center -= mEntries.size();
|
||||
xOff += logoSizeX * mEntries.size();
|
||||
}
|
||||
|
||||
for(int i = center - logoCount/2; i < center + logoCount/2 + logoCount%2; i++)
|
||||
{
|
||||
int index = i;
|
||||
while(index < 0)
|
||||
index += mEntries.size();
|
||||
while(index >= (int)mEntries.size())
|
||||
index -= mEntries.size();
|
||||
|
||||
logoTrans.translation() = trans.translation() + Eigen::Vector3f(i * logoSizeX + xOff, yOff, 0);
|
||||
|
||||
std::shared_ptr<GuiComponent> comp = mEntries.at(index).data.logo;
|
||||
if(comp)
|
||||
{
|
||||
if(i == mCursor) //scale our selection up
|
||||
{
|
||||
// fix the centering because we go by left corner and not center (bleh)
|
||||
logoTrans.translation() -= Eigen::Vector3f((comp->getSize().x() / 2) * (SELECTED_SCALE - 1), (comp->getSize().y() / 2) * (SELECTED_SCALE - 1), 0);
|
||||
logoTrans.scale(Eigen::Vector3f(SELECTED_SCALE, SELECTED_SCALE, 1.0f));
|
||||
mEntries.at(index).data.logo->render(logoTrans);
|
||||
logoTrans.scale(Eigen::Vector3f(1/SELECTED_SCALE, 1/SELECTED_SCALE, 1.0f));
|
||||
}else{
|
||||
mEntries.at(index).data.logo->render(logoTrans);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<HelpPrompt> SystemView::getHelpPrompts()
|
||||
{
|
||||
std::vector<HelpPrompt> prompts;
|
||||
prompts.push_back(HelpPrompt("left/right", "choose"));
|
||||
prompts.push_back(HelpPrompt("a", "select"));
|
||||
return prompts;
|
||||
}
|
||||
|
|
|
@ -4,25 +4,37 @@
|
|||
#include "../components/ImageComponent.h"
|
||||
#include "../components/TextComponent.h"
|
||||
#include "../components/ScrollableContainer.h"
|
||||
#include "../components/IList.h"
|
||||
#include "../resources/TextureResource.h"
|
||||
|
||||
class SystemData;
|
||||
|
||||
class SystemView : public GuiComponent
|
||||
struct SystemViewData
|
||||
{
|
||||
std::shared_ptr<TextCache> title;
|
||||
std::shared_ptr<GuiComponent> logo;
|
||||
};
|
||||
|
||||
class SystemView : public IList<SystemViewData, SystemData*>
|
||||
{
|
||||
public:
|
||||
SystemView(Window* window, SystemData* system);
|
||||
SystemView(Window* window);
|
||||
|
||||
void updateData();
|
||||
void goToSystem(SystemData* system);
|
||||
|
||||
bool input(InputConfig* config, Input input) override;
|
||||
void update(int deltaTime) override;
|
||||
void render(const Eigen::Affine3f& parentTrans) override;
|
||||
|
||||
std::vector<HelpPrompt> getHelpPrompts() override;
|
||||
|
||||
protected:
|
||||
void onCursorChanged(const CursorState& state) override;
|
||||
|
||||
private:
|
||||
SystemData* mSystem;
|
||||
inline Eigen::Vector2f logoSize() const { return Eigen::Vector2f(mSize.x() * 0.3f, mSize.y() * 0.25f); }
|
||||
|
||||
TextComponent mHeaderText;
|
||||
ImageComponent mHeaderImage;
|
||||
ImageComponent mImage;
|
||||
ThemeExtras mExtras;
|
||||
void populate();
|
||||
|
||||
float mCamOffset;
|
||||
};
|
||||
|
|
|
@ -30,7 +30,10 @@ void ViewController::goToStart()
|
|||
void ViewController::goToSystemView(SystemData* system)
|
||||
{
|
||||
mState.viewing = SYSTEM_SELECT;
|
||||
mCurrentView = getSystemView(system);
|
||||
mState.system = system;
|
||||
|
||||
getSystemListView()->goToSystem(system);
|
||||
mCurrentView = getSystemListView();
|
||||
updateHelpPrompts();
|
||||
playViewTransition();
|
||||
}
|
||||
|
@ -54,7 +57,7 @@ void ViewController::goToPrevGameList()
|
|||
void ViewController::goToGameList(SystemData* system)
|
||||
{
|
||||
mState.viewing = GAME_LIST;
|
||||
mState.data.system = system;
|
||||
mState.system = system;
|
||||
|
||||
mCurrentView = getGameListView(system);
|
||||
updateHelpPrompts();
|
||||
|
@ -140,18 +143,15 @@ std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* syste
|
|||
return view;
|
||||
}
|
||||
|
||||
std::shared_ptr<SystemView> ViewController::getSystemView(SystemData* system)
|
||||
std::shared_ptr<SystemView> ViewController::getSystemListView()
|
||||
{
|
||||
//if we already made one, return that one
|
||||
auto exists = mSystemViews.find(system);
|
||||
if(exists != mSystemViews.end())
|
||||
return exists->second;
|
||||
if(mSystemListView)
|
||||
return mSystemListView;
|
||||
|
||||
//if we didn't, make it, remember it, and return it
|
||||
std::shared_ptr<SystemView> view = std::shared_ptr<SystemView>(new SystemView(mWindow, system));
|
||||
view->setPosition((system->getIterator() - SystemData::sSystemVector.begin()) * (float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight());
|
||||
mSystemViews[system] = view;
|
||||
return view;
|
||||
mSystemListView = std::shared_ptr<SystemView>(new SystemView(mWindow));
|
||||
mSystemListView->setPosition(0, (float)Renderer::getScreenHeight());
|
||||
return mSystemListView;
|
||||
}
|
||||
|
||||
|
||||
|
@ -192,13 +192,9 @@ void ViewController::render(const Eigen::Affine3f& parentTrans)
|
|||
Eigen::Vector3f viewStart = trans.inverse().translation();
|
||||
Eigen::Vector3f viewEnd = trans.inverse() * Eigen::Vector3f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight(), 0);
|
||||
|
||||
// draw systemviews
|
||||
for(auto it = mSystemViews.begin(); it != mSystemViews.end(); it++)
|
||||
{
|
||||
// should do clipping
|
||||
it->second->render(trans);
|
||||
}
|
||||
|
||||
// draw systemview
|
||||
getSystemListView()->render(trans);
|
||||
|
||||
// draw gamelists
|
||||
for(auto it = mGameListViews.begin(); it != mGameListViews.end(); it++)
|
||||
{
|
||||
|
@ -223,7 +219,6 @@ void ViewController::preload()
|
|||
{
|
||||
for(auto it = SystemData::sSystemVector.begin(); it != SystemData::sSystemVector.end(); it++)
|
||||
{
|
||||
getSystemView(*it);
|
||||
getGameListView(*it);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,14 +48,11 @@ public:
|
|||
{
|
||||
ViewMode viewing;
|
||||
|
||||
inline SystemData* getSystem() const { assert(viewing == GAME_LIST); return data.system; }
|
||||
inline SystemData* getSystem() const { assert(viewing == GAME_LIST || viewing == SYSTEM_SELECT); return system; }
|
||||
|
||||
private:
|
||||
friend ViewController;
|
||||
union
|
||||
{
|
||||
SystemData* system;
|
||||
} data;
|
||||
SystemData* system;
|
||||
};
|
||||
|
||||
inline const State& getState() const { return mState; }
|
||||
|
@ -65,11 +62,11 @@ public:
|
|||
private:
|
||||
void playViewTransition();
|
||||
std::shared_ptr<IGameListView> getGameListView(SystemData* system);
|
||||
std::shared_ptr<SystemView> getSystemView(SystemData* system);
|
||||
std::shared_ptr<SystemView> getSystemListView();
|
||||
|
||||
std::shared_ptr<GuiComponent> mCurrentView;
|
||||
std::map< SystemData*, std::shared_ptr<IGameListView> > mGameListViews;
|
||||
std::map< SystemData*, std::shared_ptr<SystemView> > mSystemViews;
|
||||
std::shared_ptr<SystemView> mSystemListView;
|
||||
|
||||
Eigen::Affine3f mCamera;
|
||||
float mFadeOpacity;
|
||||
|
|
Loading…
Reference in a new issue