Refactored duplicate functionality in GridGameList and BasicGameList into

ISimpleGameList.
BasicGameList and DetailedGameList now automatically switch as metadata
changes.
This commit is contained in:
Aloshi 2013-12-22 16:16:01 -06:00
parent 9249d67048
commit 12ee215873
21 changed files with 404 additions and 385 deletions

View file

@ -193,10 +193,11 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugiconfig.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/pugiXML/pugixml.hpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/BasicGameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/DetailedGameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/GameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/GridGameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/BasicGameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/DetailedGameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/IGameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/ISimpleGameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/GridGameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/SystemListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/SystemView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/ViewController.h
@ -271,10 +272,11 @@ set(ES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/resources/ResourceManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/resources/TextureResource.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/BasicGameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/DetailedGameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/GameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/GridGameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/BasicGameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/DetailedGameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/IGameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/ISimpleGameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/GridGameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/SystemListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/SystemView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/ViewController.cpp

View file

@ -5,7 +5,7 @@
static const std::string LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
GuiFastSelect::GuiFastSelect(Window* window, GameListView* gamelist) : GuiComponent(window),
GuiFastSelect::GuiFastSelect(Window* window, IGameListView* gamelist) : GuiComponent(window),
mBackground(window), mSortText(window), mLetterText(window), mGameList(gamelist)
{
setPosition(Renderer::getScreenWidth() * 0.2f, Renderer::getScreenHeight() * 0.2f);

View file

@ -1,7 +1,7 @@
#pragma once
#include "../GuiComponent.h"
#include "../views/GameListView.h"
#include "../views/gamelist/IGameListView.h"
#include "NinePatchComponent.h"
#include "TextComponent.h"
@ -9,7 +9,7 @@
class GuiFastSelect : public GuiComponent
{
public:
GuiFastSelect(Window* window, GameListView* gamelist);
GuiFastSelect(Window* window, IGameListView* gamelist);
bool input(InputConfig* config, Input input);
void update(int deltaTime);
@ -31,5 +31,5 @@ private:
TextComponent mSortText;
TextComponent mLetterText;
GameListView* mGameList;
IGameListView* mGameList;
};

View file

@ -24,6 +24,7 @@ public:
void clear();
void setCursor(const T& select);
void setCursor(typename const std::vector<Entry>::const_iterator& it);
inline const T& getSelected() const { return mEntries.at(mCursor).object; }
inline const std::vector<Entry>& getList() const { return mEntries; }
@ -171,6 +172,14 @@ void ImageGridComponent<T>::setCursor(const T& obj)
LOG(LogError) << "Tried to set cursor to object we couldn't find";
}
template<typename T>
void ImageGridComponent<T>::setCursor(typename const std::vector<Entry>::const_iterator& it)
{
assert(it != mEntries.end());
mCursor = it - mEntries.begin();
onCursorChanged(CURSOR_STOPPED);
}
template<typename T>
void ImageGridComponent<T>::stopScrolling()
{

View file

@ -49,6 +49,7 @@ public:
inline const std::vector<ListRow>& getList() const { return mRowVector; }
void setCursor(const T& select);
void setCursor(typename const std::vector<ListRow>::const_iterator& it);
void stopScrolling();
inline bool isScrolling() const { return mScrollDir != 0; }
@ -375,6 +376,15 @@ void TextListComponent<T>::setCursor(const T& obj)
LOG(LogError) << "Tried to set cursor to object we couldn't find";
}
template <typename T>
void TextListComponent<T>::setCursor(typename const std::vector<ListRow>::const_iterator& it)
{
assert(it != mRowVector.end());
mCursor = it - mRowVector.begin();
onCursorChanged(CURSOR_STOPPED);
}
template <typename T>
void TextListComponent<T>::onCursorChanged(CursorState state)
{

View file

@ -1,183 +0,0 @@
#include "BasicGameListView.h"
#include "ViewController.h"
#include "../Renderer.h"
#include "../Window.h"
#include "../ThemeData.h"
BasicGameListView::BasicGameListView(Window* window, FileData* root)
: GameListView(window, root),
mHeaderText(window), mHeaderImage(window), mBackground(window), mList(window)
{
mHeaderText.setText("Header");
mHeaderText.setSize(mSize.x(), 0);
mHeaderText.setPosition(0, 0);
mHeaderText.setCentered(true);
mHeaderImage.setResize(0, mSize.y() * 0.185f, false);
mHeaderImage.setOrigin(0.5f, 0.0f);
mHeaderImage.setPosition(mSize.x() / 2, 0);
mBackground.setResize(mSize.x(), mSize.y(), true);
mList.setSize(mSize.x(), mSize.y() * 0.8f);
mList.setPosition(0, mSize.y() * 0.2f);
populateList(root);
addChild(&mBackground);
addChild(&mList);
addChild(&mHeaderText);
}
void BasicGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
{
const ImageDef& bg = theme->getImage("backgroundImage");
mBackground.setTiling(bg.tile);
mBackground.setImage(bg.getTexture());
const ImageDef& hdr = theme->getImage("headerImage");
mHeaderImage.setTiling(hdr.tile);
mHeaderImage.setImage(hdr.getTexture());
if(mHeaderImage.hasImage())
{
removeChild(&mHeaderText);
addChild(&mHeaderImage);
}else{
addChild(&mHeaderText);
removeChild(&mHeaderImage);
}
mList.setTheme(theme);
}
void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
{
// we don't care about metadata changes (since we don't display metadata),
// so we just ignore the FILE_METADATA_CHANGED case
// if it's immediately inside our current folder
if(file->getParent() == getCurrentFolder())
{
if(change == FILE_REMOVED)
{
mList.remove(file); // will automatically make sure cursor ends up in a "safe" place
}else if(change == FILE_ADDED)
{
FileData* cursor = getCursor();
populateList(cursor->getParent());
mList.setCursor(cursor);
}
}
// the root file was sorted (so children were sorted too)
if(file == mRoot && change == FILE_SORTED)
{
FileData* cursor = getCursor();
populateList(cursor->getParent());
mList.setCursor(cursor);
}
}
void buildHeader(FileData* from, std::stringstream& ss)
{
if(from->getParent())
{
buildHeader(from->getParent(), ss);
ss << " -> ";
}
ss << from->getName();
}
void BasicGameListView::populateList(FileData* root)
{
mList.clear();
std::stringstream ss;
buildHeader(root, ss);
mHeaderText.setText(ss.str());
for(auto it = root->getChildren().begin(); it != root->getChildren().end(); it++)
{
mList.add((*it)->getName(), *it, ((*it)->getType() == FOLDER));
}
}
void BasicGameListView::setCursor(FileData* cursor)
{
if(cursor->getParent() != getCursor()->getParent())
{
// Rebuild the folder stack
std::stack<FileData*> path;
FileData* cur = cursor;
while((cur = cur->getParent()) != mRoot)
path.push(cur);
while(!mCursorStack.empty())
mCursorStack.pop();
while(!path.empty()) // put back in reverse order (flip)
{
mCursorStack.push(path.top());
path.pop();
}
populateList(cursor->getParent());
}
mList.setCursor(cursor);
}
bool BasicGameListView::input(InputConfig* config, Input input)
{
if(input.value != 0)
{
if(config->isMappedTo("a", input))
{
if(mList.getList().size() > 0)
{
FileData* cursor = getCursor();
if(cursor->getType() == GAME)
{
mWindow->getViewController()->launch(cursor);
}else{
// it's a folder
if(cursor->getChildren().size() > 0)
{
mCursorStack.push(cursor);
populateList(cursor);
}
}
return true;
}
}else if(config->isMappedTo("b", input))
{
if(mCursorStack.size())
{
populateList(mCursorStack.top()->getParent());
mList.setCursor(mCursorStack.top());
mCursorStack.pop();
mTheme->playSound("backSound");
}else{
mList.stopScrolling();
mWindow->getViewController()->goToSystemSelect();
}
return true;
}else if(config->isMappedTo("right", input))
{
mList.stopScrolling();
mWindow->getViewController()->goToNextGameList();
return true;
}else if(config->isMappedTo("left", input))
{
mList.stopScrolling();
mWindow->getViewController()->goToPrevGameList();
return true;
}
}
return GameListView::input(config, input);
}

View file

@ -1,34 +0,0 @@
#pragma once
#include "GameListView.h"
#include "../components/TextListComponent.h"
#include "../components/TextComponent.h"
#include "../components/ImageComponent.h"
class BasicGameListView : public GameListView
{
public:
BasicGameListView(Window* window, FileData* root);
// Called when a FileData* is added, has its metadata changed, or is removed
virtual void onFileChanged(FileData* file, FileChangeType change);
virtual bool input(InputConfig* config, Input input) override;
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
inline FileData* getCursor() { return mList.getSelected(); }
virtual void setCursor(FileData* file) override;
protected:
void populateList(FileData* root);
TextComponent mHeaderText;
ImageComponent mHeaderImage;
ImageComponent mBackground;
TextListComponent<FileData*> mList;
inline FileData* getCurrentFolder() { return getCursor()->getParent(); }
std::stack<FileData*> mCursorStack;
};

View file

@ -1,93 +0,0 @@
#include "GridGameListView.h"
#include "../ThemeData.h"
#include "../Window.h"
#include "ViewController.h"
GridGameListView::GridGameListView(Window* window, FileData* root) : GameListView(window, root),
mGrid(window), mBackground(window)
{
mBackground.setResize(mSize.x(), mSize.y(), true);
addChild(&mBackground);
mGrid.setPosition(0, mSize.y() * 0.2f);
mGrid.setSize(mSize.x(), mSize.y() * 0.8f);
addChild(&mGrid);
populateList(root);
}
void GridGameListView::onFileChanged(FileData* file, FileChangeType change)
{
// fuck it, just completely repopulate always all the time
FileData* cursor = getCursor();
populateList(cursor->getParent());
mGrid.setCursor(cursor);
}
void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
{
mBackground.setImage(theme->getImage("backgroundImage").getTexture());
mBackground.setTiling(theme->getImage("backgroundImage").tile);
}
FileData* GridGameListView::getCursor()
{
return mGrid.getSelected();
}
void GridGameListView::setCursor(FileData* file)
{
assert(file->getParent() == getCursor()->getParent()); // too lazy to implement right now
mGrid.setCursor(file);
}
bool GridGameListView::input(InputConfig* config, Input input)
{
if(input.value != 0)
{
if(config->isMappedTo("a", input))
{
if(mGrid.getList().size() > 0)
{
FileData* cursor = getCursor();
if(cursor->getType() == GAME)
{
mWindow->getViewController()->launch(cursor);
}else{
// it's a folder
if(cursor->getChildren().size() > 0)
{
mCursorStack.push(cursor);
populateList(cursor);
}
}
return true;
}
}else if(config->isMappedTo("b", input))
{
if(mCursorStack.size())
{
populateList(mCursorStack.top()->getParent());
mGrid.setCursor(mCursorStack.top());
mCursorStack.pop();
mTheme->playSound("backSound");
}else{
mGrid.stopScrolling();
mWindow->getViewController()->goToSystemSelect();
}
return true;
}
}
return GameListView::input(config, input);
}
void GridGameListView::populateList(FileData* root)
{
mGrid.clear();
for(auto it = root->getChildren().begin(); it != root->getChildren().end(); it++)
{
mGrid.add((*it)->getThumbnailPath(), *it);
}
}

View file

@ -1,28 +0,0 @@
#pragma once
#include "GameListView.h"
#include "../components/ImageGridComponent.h"
#include "../components/ImageComponent.h"
#include <stack>
class GridGameListView : public GameListView
{
public:
GridGameListView(Window* window, FileData* root);
virtual void onFileChanged(FileData* file, FileChangeType change) override;
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
FileData* getCursor() override;
void setCursor(FileData*) override;
virtual bool input(InputConfig* config, Input input) override;
private:
void populateList(FileData* root);
ImageGridComponent<FileData*> mGrid;
ImageComponent mBackground;
std::stack<FileData*> mCursorStack;
};

View file

@ -2,9 +2,9 @@
#include "../Log.h"
#include "../SystemData.h"
#include "BasicGameListView.h"
#include "DetailedGameListView.h"
#include "GridGameListView.h"
#include "gamelist/BasicGameListView.h"
#include "gamelist/DetailedGameListView.h"
#include "gamelist/GridGameListView.h"
#include "../components/GuiMenu.h"
#include "../animations/LaunchAnimation.h"
#include "../animations/MoveCameraAnimation.h"
@ -116,7 +116,7 @@ void ViewController::launch(FileData* game, Eigen::Vector3f center)
});
}
std::shared_ptr<GameListView> ViewController::getGameListView(SystemData* system)
std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* system)
{
//if we already made one, return that one
auto exists = mGameListViews.find(system);
@ -124,7 +124,7 @@ std::shared_ptr<GameListView> ViewController::getGameListView(SystemData* system
return exists->second;
//if we didn't, make it, remember it, and return it
std::shared_ptr<GameListView> view;
std::shared_ptr<IGameListView> view;
if(system != NULL)
{
@ -141,11 +141,11 @@ std::shared_ptr<GameListView> ViewController::getGameListView(SystemData* system
}
if(detailed)
view = std::shared_ptr<GameListView>(new DetailedGameListView(mWindow, system->getRootFolder()));
view = std::shared_ptr<IGameListView>(new DetailedGameListView(mWindow, system->getRootFolder()));
else
view = std::shared_ptr<GameListView>(new BasicGameListView(mWindow, system->getRootFolder()));
view = std::shared_ptr<IGameListView>(new BasicGameListView(mWindow, system->getRootFolder()));
//view = std::shared_ptr<GameListView>(new GridGameListView(mWindow, system->getRootFolder()));
view = std::shared_ptr<IGameListView>(new GridGameListView(mWindow, system->getRootFolder()));
view->setTheme(system->getTheme());
}else{
@ -240,3 +240,21 @@ void ViewController::preload()
getGameListView(*it);
}
}
void ViewController::reloadGameListView(IGameListView* view)
{
for(auto it = mGameListViews.begin(); it != mGameListViews.end(); it++)
{
if(it->second.get() == view)
{
SystemData* system = it->first;
FileData* cursor = view->getCursor();
mGameListViews.erase(it);
std::shared_ptr<IGameListView> newView = getGameListView(system);
newView->setCursor(cursor);
mCurrentView = newView;
break;
}
}
}

View file

@ -1,6 +1,6 @@
#pragma once
#include "GameListView.h"
#include "gamelist/IGameListView.h"
#include "SystemListView.h"
class SystemData;
@ -14,6 +14,10 @@ public:
// Caches things so there's no pauses during transitions.
void preload();
// If a basic view detected a metadata change, it can request to recreate
// the current gamelist view (as it may change to be detailed).
void reloadGameListView(IGameListView* gamelist);
// Navigation.
void goToNextGameList();
void goToPrevGameList();
@ -55,11 +59,11 @@ public:
private:
void playViewTransition();
std::shared_ptr<GameListView> getGameListView(SystemData* system);
std::shared_ptr<IGameListView> getGameListView(SystemData* system);
std::shared_ptr<SystemListView> getSystemListView();
std::shared_ptr<GuiComponent> mCurrentView;
std::map< SystemData*, std::shared_ptr<GameListView> > mGameListViews;
std::map< SystemData*, std::shared_ptr<IGameListView> > mGameListViews;
std::shared_ptr<SystemListView> mSystemListView;
Eigen::Affine3f mCamera;

View file

@ -0,0 +1,71 @@
#include "BasicGameListView.h"
#include "../ViewController.h"
#include "../../Renderer.h"
#include "../../Window.h"
#include "../../ThemeData.h"
#include "../../SystemData.h"
BasicGameListView::BasicGameListView(Window* window, FileData* root)
: ISimpleGameListView(window, root), mList(window)
{
mList.setSize(mSize.x(), mSize.y() * 0.8f);
mList.setPosition(0, mSize.y() * 0.2f);
addChild(&mList);
populateList(root->getChildren());
}
void BasicGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
{
ISimpleGameListView::onThemeChanged(theme);
mList.setTheme(theme);
}
void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
{
if(change == FILE_METADATA_CHANGED)
{
// might switch to a detailed view
mWindow->getViewController()->reloadGameListView(this);
return;
}
ISimpleGameListView::onFileChanged(file, change);
}
void BasicGameListView::populateList(const std::vector<FileData*>& files)
{
mList.clear();
mHeaderText.setText(files.at(0)->getSystem()->getFullName());
for(auto it = files.begin(); it != files.end(); it++)
{
mList.add((*it)->getName(), *it, ((*it)->getType() == FOLDER));
}
}
FileData* BasicGameListView::getCursor()
{
return mList.getSelected();
}
void BasicGameListView::setCursor(FileData* cursor)
{
typedef TextListComponent<FileData*>::ListRow Row;
const std::vector<Row>& list = mList.getList();
auto found = std::find_if(list.begin(), list.end(), [&](const Row& row) { return (row.object == cursor); });
if(found != list.end())
{
mList.setCursor(found);
}else{
populateList(cursor->getParent()->getChildren());
mList.setCursor(cursor);
}
}
void BasicGameListView::launch(FileData* game)
{
mWindow->getViewController()->launch(game);
}

View file

@ -0,0 +1,24 @@
#pragma once
#include "ISimpleGameListView.h"
#include "../../components/TextListComponent.h"
class BasicGameListView : public ISimpleGameListView
{
public:
BasicGameListView(Window* window, FileData* root);
// Called when a FileData* is added, has its metadata changed, or is removed
virtual void onFileChanged(FileData* file, FileChangeType change);
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme);
virtual FileData* getCursor() override;
virtual void setCursor(FileData* file) override;
protected:
virtual void populateList(const std::vector<FileData*>& files) override;
virtual void launch(FileData* game) override;
TextListComponent<FileData*> mList;
};

View file

@ -1,4 +1,6 @@
#include "DetailedGameListView.h"
#include "../../Window.h"
#include "../ViewController.h"
DetailedGameListView::DetailedGameListView(Window* window, FileData* root) :
BasicGameListView(window, root),
@ -75,10 +77,11 @@ void DetailedGameListView::updateInfoPanel()
}
}
void DetailedGameListView::onFileChanged(FileData* file, FileChangeType type)
void DetailedGameListView::launch(FileData* game)
{
BasicGameListView::onFileChanged(file, type);
Eigen::Vector3f target(Renderer::getScreenWidth() / 2.0f, Renderer::getScreenHeight() / 2.0f, 0);
if(mImage.hasImage())
target = mImage.getPosition();
if(type == FILE_METADATA_CHANGED && file == getCursor())
updateInfoPanel();
mWindow->getViewController()->launch(game, target);
}

View file

@ -1,9 +1,7 @@
#pragma once
#include "BasicGameListView.h"
#include "../components/ImageComponent.h"
#include "../components/TextComponent.h"
#include "../components/ScrollableContainer.h"
#include "../../components/ScrollableContainer.h"
class DetailedGameListView : public BasicGameListView
{
@ -12,7 +10,8 @@ public:
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
virtual void onFileChanged(FileData* file, FileChangeType change);
protected:
virtual void launch(FileData* game) override;
private:
void updateInfoPanel();
@ -24,4 +23,3 @@ private:
ScrollableContainer mDescContainer;
TextComponent mDescription;
};

View file

@ -0,0 +1,56 @@
#include "GridGameListView.h"
#include "../../ThemeData.h"
#include "../../Window.h"
#include "../ViewController.h"
GridGameListView::GridGameListView(Window* window, FileData* root) : ISimpleGameListView(window, root),
mGrid(window)
{
mGrid.setPosition(0, mSize.y() * 0.2f);
mGrid.setSize(mSize.x(), mSize.y() * 0.8f);
addChild(&mGrid);
populateList(root->getChildren());
}
FileData* GridGameListView::getCursor()
{
return mGrid.getSelected();
}
void GridGameListView::setCursor(FileData* file)
{
typedef ImageGridComponent<FileData*>::Entry Entry;
auto& list = mGrid.getList();
auto found = std::find_if(list.begin(), list.end(), [&] (const Entry& e) { return (e.object == file); });
if(found != list.end())
{
mGrid.setCursor(found);
}else{
populateList(file->getParent()->getChildren());
mGrid.setCursor(file);
}
}
bool GridGameListView::input(InputConfig* config, Input input)
{
if(config->isMappedTo("left", input) || config->isMappedTo("right", input))
return GuiComponent::input(config, input);
return ISimpleGameListView::input(config, input);
}
void GridGameListView::populateList(const std::vector<FileData*>& files)
{
mGrid.clear();
for(auto it = files.begin(); it != files.end(); it++)
{
mGrid.add((*it)->getThumbnailPath(), *it);
}
}
void GridGameListView::launch(FileData* game)
{
mWindow->getViewController()->launch(game);
}

View file

@ -0,0 +1,25 @@
#pragma once
#include "ISimpleGameListView.h"
#include "../../components/ImageGridComponent.h"
#include "../../components/ImageComponent.h"
#include <stack>
class GridGameListView : public ISimpleGameListView
{
public:
GridGameListView(Window* window, FileData* root);
//virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
virtual FileData* getCursor() override;
virtual void setCursor(FileData*) override;
virtual bool input(InputConfig* config, Input input) override;
protected:
virtual void populateList(const std::vector<FileData*>& files) override;
virtual void launch(FileData* game) override;
ImageGridComponent<FileData*> mGrid;
};

View file

@ -1,11 +1,11 @@
#include "GameListView.h"
#include "../Window.h"
#include "../components/GuiMetaDataEd.h"
#include "../components/GuiMenu.h"
#include "../components/GuiFastSelect.h"
#include "ViewController.h"
#include "IGameListView.h"
#include "../../Window.h"
#include "../../components/GuiMetaDataEd.h"
#include "../../components/GuiMenu.h"
#include "../../components/GuiFastSelect.h"
#include "../ViewController.h"
bool GameListView::input(InputConfig* config, Input input)
bool IGameListView::input(InputConfig* config, Input input)
{
if(config->getDeviceId() == DEVICE_KEYBOARD && input.id == SDLK_F3 && input.value != 0)
{
@ -15,7 +15,7 @@ bool GameListView::input(InputConfig* config, Input input)
p.game = file;
p.system = file->getSystem();
mWindow->pushGui(new GuiMetaDataEd(mWindow, &file->metadata, file->metadata.getMDD(), p, file->getPath().filename().string(),
std::bind(&GameListView::onFileChanged, this, file, FILE_METADATA_CHANGED), [file, this] {
std::bind(&IGameListView::onFileChanged, this, file, FILE_METADATA_CHANGED), [file, this] {
boost::filesystem::remove(file->getPath()); //actually delete the file on the filesystem
file->getParent()->removeChild(file); //unlink it so list repopulations triggered from onFileChanged won't see it
onFileChanged(file, FILE_REMOVED); //tell the view
@ -33,7 +33,7 @@ bool GameListView::input(InputConfig* config, Input input)
return GuiComponent::input(config, input);
}
void GameListView::setTheme(const std::shared_ptr<ThemeData>& theme)
void IGameListView::setTheme(const std::shared_ptr<ThemeData>& theme)
{
mTheme = theme;
onThemeChanged(theme);

View file

@ -1,24 +1,24 @@
#pragma once
#include "../FileData.h"
#include "../Renderer.h"
#include "../../FileData.h"
#include "../../Renderer.h"
class Window;
class GuiComponent;
class FileData;
class ThemeData;
//GameListView needs to know:
//IGameListView needs to know:
// What theme data to use
// The root FileData for the tree it should explore
class GameListView : public GuiComponent
class IGameListView : public GuiComponent
{
public:
GameListView(Window* window, FileData* root) : GuiComponent(window), mRoot(root)
IGameListView(Window* window, FileData* root) : GuiComponent(window), mRoot(root)
{ setSize((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight()); }
virtual ~GameListView() {}
virtual ~IGameListView() {}
// Called when a new file is added, a file is removed, a file's metadata changes, or a file's children are sorted.
// NOTE: FILE_SORTED is only reported for the topmost FileData, where the sort started.

View file

@ -0,0 +1,101 @@
#include "ISimpleGameListView.h"
#include "../../ThemeData.h"
#include "../../Window.h"
#include "../ViewController.h"
ISimpleGameListView::ISimpleGameListView(Window* window, FileData* root) : IGameListView(window, root),
mHeaderText(window), mHeaderImage(window), mBackground(window)
{
mHeaderText.setText("Header");
mHeaderText.setSize(mSize.x(), 0);
mHeaderText.setPosition(0, 0);
mHeaderText.setCentered(true);
mHeaderImage.setResize(0, mSize.y() * 0.185f, false);
mHeaderImage.setOrigin(0.5f, 0.0f);
mHeaderImage.setPosition(mSize.x() / 2, 0);
mBackground.setResize(mSize.x(), mSize.y(), true);
addChild(&mHeaderText);
addChild(&mBackground);
}
void ISimpleGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
{
const ImageDef& bg = theme->getImage("backgroundImage");
mBackground.setTiling(bg.tile);
mBackground.setImage(bg.getTexture());
const ImageDef& hdr = theme->getImage("headerImage");
mHeaderImage.setTiling(hdr.tile);
mHeaderImage.setImage(hdr.getTexture());
if(mHeaderImage.hasImage())
{
removeChild(&mHeaderText);
addChild(&mHeaderImage);
}else{
addChild(&mHeaderText);
removeChild(&mHeaderImage);
}
}
void ISimpleGameListView::onFileChanged(FileData* file, FileChangeType change)
{
// we could be tricky here to be efficient;
// but this shouldn't happen very often so we'll just always repopulate
FileData* cursor = getCursor();
populateList(cursor->getParent()->getChildren());
setCursor(cursor);
}
bool ISimpleGameListView::input(InputConfig* config, Input input)
{
if(input.value != 0)
{
if(config->isMappedTo("a", input))
{
FileData* cursor = getCursor();
if(cursor->getType() == GAME)
{
launch(cursor);
}else{
// it's a folder
if(cursor->getChildren().size() > 0)
{
mCursorStack.push(cursor);
populateList(cursor->getChildren());
}
}
return true;
}else if(config->isMappedTo("b", input))
{
if(mCursorStack.size())
{
populateList(mCursorStack.top()->getParent()->getChildren());
setCursor(mCursorStack.top());
mCursorStack.pop();
getTheme()->playSound("backSound");
}else{
onFocusLost();
mWindow->getViewController()->goToSystemSelect();
}
return true;
}else if(config->isMappedTo("right", input))
{
onFocusLost();
mWindow->getViewController()->goToNextGameList();
return true;
}else if(config->isMappedTo("left", input))
{
onFocusLost();
mWindow->getViewController()->goToPrevGameList();
return true;
}
}
return IGameListView::input(config, input);
}

View file

@ -0,0 +1,36 @@
#pragma once
#include "IGameListView.h"
#include "../../components/TextComponent.h"
#include "../../components/ImageComponent.h"
class ISimpleGameListView : public IGameListView
{
public:
ISimpleGameListView(Window* window, FileData* root);
virtual ~ISimpleGameListView() {}
// Called when a new file is added, a file is removed, a file's metadata changes, or a file's children are sorted.
// NOTE: FILE_SORTED is only reported for the topmost FileData, where the sort started.
// Since sorts are recursive, that FileData's children probably changed too.
virtual void onFileChanged(FileData* file, FileChangeType change);
// Called whenever the theme changes.
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme);
virtual FileData* getCursor() = 0;
virtual void setCursor(FileData*) = 0;
virtual bool input(InputConfig* config, Input input) override;
protected:
virtual void populateList(const std::vector<FileData*>& files) = 0;
virtual void launch(FileData* game) = 0;
TextComponent mHeaderText;
ImageComponent mHeaderImage;
ImageComponent mBackground;
std::stack<FileData*> mCursorStack;
};