Mostly reimplemented the fast select GUI.

Still not sure how I want to store sort state. I'd kind of like to move
sorting out of the FileData tree altogether and into the display classes.
This commit is contained in:
Aloshi 2013-11-25 14:49:02 -06:00
parent 94ca712759
commit 0cfa38fcf9
14 changed files with 253 additions and 12 deletions

View file

@ -174,6 +174,7 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextEditComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextListComponent.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiDetectDevice.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiFastSelect.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMetaDataEd.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMsgBoxOk.h
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMsgBoxYesNo.h
@ -239,6 +240,7 @@ set(ES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/TextEditComponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiDetectDevice.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiFastSelect.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMetaDataEd.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMsgBoxOk.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/components/GuiMsgBoxYesNo.cpp

View file

@ -65,6 +65,7 @@ Fonts are defined like so:
`<listFont>` - Default size: 0.045.
`<descriptionFont>` - Default size: 0.035.
`<fastSelectLetterFont>` - Default size: 0.15.
Colors
======
@ -81,6 +82,8 @@ or
`<listSelectorColor>` - Default: 000000FF.
`<listSelectedColor>` - Default: 00000000.
`<descriptionColor>` - Default: 48474DFF.
`<fastSelectLetterColor>` - Default: FFFFFFFF.
`<fastSelectTextColor>` - Default: DDDDDDFF.
Images
======
@ -98,6 +101,7 @@ Pretty much any image format is supported.
`<backgroundImage>` - No default.
`<headerImage>` - No default.
`<infoBackgroundImage>` - No default.
`<verticalDividerImage>` - No default.
Sounds
======

View file

@ -17,7 +17,8 @@ enum FileChangeType
{
FILE_ADDED,
FILE_METADATA_CHANGED,
FILE_REMOVED
FILE_REMOVED,
FILE_SORTED
};
// Used for loading/saving gamelist.xml.

View file

@ -11,14 +11,17 @@
// Defaults
std::map<std::string, FontDef > ThemeData::sDefaultFonts = boost::assign::map_list_of
("listFont", FontDef(0.045f, ""))
("descriptionFont", FontDef(0.035f, ""));
("descriptionFont", FontDef(0.035f, ""))
("fastSelectLetterFont", FontDef(0.15f, ""));
std::map<std::string, unsigned int> ThemeData::sDefaultColors = boost::assign::map_list_of
("listPrimaryColor", 0x0000FFFF)
("listSecondaryColor", 0x00FF00FF)
("listSelectorColor", 0x000000FF)
("listSelectedColor", 0x00000000)
("descriptionColor", 0x48474DFF);
("descriptionColor", 0x48474DFF)
("fastSelectLetterColor", 0xFFFFFFFF)
("fastSelectTextColor", 0xDDDDDDFF);
std::map<std::string, ImageDef> ThemeData::sDefaultImages = boost::assign::map_list_of
("backgroundImage", ImageDef("", true))

View file

@ -0,0 +1,159 @@
#include "GuiFastSelect.h"
#include "../ThemeData.h"
#include "../FileSorts.h"
#include "../SystemData.h"
static const std::string LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
GuiFastSelect::GuiFastSelect(Window* window, GameListView* gamelist) : GuiComponent(window),
mBackground(window, ":/button.png"), mSortText(window), mLetterText(window), mGameList(gamelist)
{
setPosition(Renderer::getScreenWidth() * 0.2f, Renderer::getScreenHeight() * 0.2f);
setSize(Renderer::getScreenWidth() * 0.6f, Renderer::getScreenHeight() * 0.6f);
const std::shared_ptr<ThemeData>& theme = mGameList->getTheme();
mBackground.fitTo(mSize);
addChild(&mBackground);
mLetterText.setSize(mSize.x(), mSize.y() * 0.75f);
mLetterText.setCentered(true);
mLetterText.setFromTheme(theme, "fastSelectLetterFont", "fastSelectLetterColor");
addChild(&mLetterText);
mSortText.setPosition(0, mSize.y() * 0.75f);
mSortText.setSize(mSize.x(), mSize.y() * 0.25f);
mSortText.setCentered(true);
mSortText.setFromTheme(theme, "descriptionFont", "fastSelectTextColor");
addChild(&mSortText);
mSortId = 0; // TODO
updateSortText();
mLetterId = LETTERS.find(mGameList->getCursor()->getName()[0]);
if(mLetterId == std::string::npos)
mLetterId = 0;
mScrollDir = 0;
mScrollAccumulator = 0;
scroll(); // initialize the letter value
}
bool GuiFastSelect::input(InputConfig* config, Input input)
{
if(input.value == 0 && config->isMappedTo("select", input))
{
// the user let go of select; make our changes to the gamelist and close this gui
updateGameListSort();
updateGameListCursor();
delete this;
return true;
}
if(config->isMappedTo("up", input))
{
if(input.value != 0)
setScrollDir(-1);
else
setScrollDir(0);
return true;
}else if(config->isMappedTo("down", input))
{
if(input.value != 0)
setScrollDir(1);
else
setScrollDir(0);
return true;
}else if(config->isMappedTo("left", input) && input.value != 0)
{
mSortId = (mSortId + 1) % FileSorts::SortTypes.size();
updateSortText();
return true;
}else if(config->isMappedTo("right", input) && input.value != 0)
{
mSortId--;
if(mSortId < 0)
mSortId += FileSorts::SortTypes.size();
updateSortText();
return true;
}
return GuiComponent::input(config, input);
}
void GuiFastSelect::setScrollDir(int dir)
{
mScrollDir = dir;
scroll();
mScrollAccumulator = -500;
}
void GuiFastSelect::update(int deltaTime)
{
if(mScrollDir != 0)
{
mScrollAccumulator += deltaTime;
while(mScrollAccumulator >= 150)
{
scroll();
mScrollAccumulator -= 150;
}
}
GuiComponent::update(deltaTime);
}
void GuiFastSelect::scroll()
{
mLetterId += mScrollDir;
if(mLetterId < 0)
mLetterId += LETTERS.length();
else if(mLetterId >= (int)LETTERS.length())
mLetterId -= LETTERS.length();
mLetterText.setText(LETTERS.substr(mLetterId, 1));
}
void GuiFastSelect::updateSortText()
{
std::stringstream ss;
ss << "<- " << FileSorts::SortTypes.at(mSortId).description << " ->";
mSortText.setText(ss.str());
}
void GuiFastSelect::updateGameListSort()
{
const FileData::SortType& sort = FileSorts::SortTypes.at(mSortId);
FileData* root = mGameList->getCursor()->getSystem()->getRootFolder();
root->sort(sort); // will also recursively sort children
// notify that the root folder was sorted
mGameList->onFileChanged(root, FILE_SORTED);
}
void GuiFastSelect::updateGameListCursor()
{
const std::vector<FileData*>& list = mGameList->getCursor()->getParent()->getChildren();
// only skip by letter when the sort mode is alphabetical
const FileData::SortType& sort = FileSorts::SortTypes.at(mSortId);
if(sort.comparisonFunction != &FileSorts::compareFileName)
return;
// find the first entry in the list that either exactly matches our target letter or is beyond our target letter
for(auto it = list.cbegin(); it != list.cend(); it++)
{
char check = (*it)->getName().empty() ? 'A' : (*it)->getName()[0];
// if there's an exact match or we've passed it, set the cursor to this one
if(check == LETTERS[mLetterId] || (sort.ascending && check > LETTERS[mLetterId]) || (!sort.ascending && check < LETTERS[mLetterId]))
{
mGameList->setCursor(*it);
break;
}
}
}

View file

@ -0,0 +1,35 @@
#pragma once
#include "../GuiComponent.h"
#include "../views/GameListView.h"
#include "NinePatchComponent.h"
#include "TextComponent.h"
class GuiFastSelect : public GuiComponent
{
public:
GuiFastSelect(Window* window, GameListView* gamelist);
bool input(InputConfig* config, Input input);
void update(int deltaTime);
private:
void setScrollDir(int dir);
void scroll();
void updateGameListCursor();
void updateGameListSort();
void updateSortText();
int mSortId;
int mLetterId;
int mScrollDir;
int mScrollAccumulator;
NinePatchComponent mBackground;
TextComponent mSortText;
TextComponent mLetterText;
GameListView* mGameList;
};

View file

@ -2,6 +2,7 @@
#include "../Renderer.h"
#include "../Log.h"
#include "../Window.h"
#include "../ThemeData.h"
TextComponent::TextComponent(Window* window) : GuiComponent(window),
mFont(NULL), mColor(0x000000FF), mAutoCalcExtent(true, true), mCentered(false)
@ -137,3 +138,9 @@ std::string TextComponent::getValue() const
{
return mText;
}
void TextComponent::setFromTheme(const std::shared_ptr<ThemeData>& theme, const std::string& fontIdentifier, const std::string& colorIdentifier)
{
setFont(theme->getFont(fontIdentifier));
setColor(theme->getColor(colorIdentifier));
}

View file

@ -4,6 +4,8 @@
#include "../GuiComponent.h"
#include "../resources/Font.h"
class ThemeData;
class TextComponent : public GuiComponent
{
public:
@ -26,6 +28,8 @@ public:
std::shared_ptr<Font> getFont() const;
void setFromTheme(const std::shared_ptr<ThemeData>& theme, const std::string& fontIdentifier, const std::string& colorIdentifier);
private:
void calculateExtent();

View file

@ -29,7 +29,7 @@ BasicGameListView::BasicGameListView(Window* window, FileData* root)
addChild(&mHeaderText);
}
void BasicGameListView::setTheme(const std::shared_ptr<ThemeData>& theme)
void BasicGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
{
const ImageDef& bg = theme->getImage("backgroundImage");
mBackground.setTiling(bg.tile);
@ -69,6 +69,14 @@ void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
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)

View file

@ -15,7 +15,7 @@ public:
virtual bool input(InputConfig* config, Input input) override;
virtual void setTheme(const std::shared_ptr<ThemeData>& theme) override;
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
inline FileData* getCursor() { return mList.getSelected(); }
virtual void setCursor(FileData* file) override;

View file

@ -39,10 +39,10 @@ DetailedGameListView::DetailedGameListView(Window* window, FileData* root) :
updateInfoPanel();
}
void DetailedGameListView::setTheme(const std::shared_ptr<ThemeData>& theme)
void DetailedGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
{
mHeaderImage.setResize(mSize.x() * 0.5f, 0, true);
BasicGameListView::setTheme(theme);
BasicGameListView::onThemeChanged(theme);
if(mHeaderImage.getPosition().y() + mHeaderImage.getSize().y() > mImage.getPosition().y())
mHeaderImage.setResize(0, mSize.y() * 0.185f, true);

View file

@ -10,7 +10,7 @@ class DetailedGameListView : public BasicGameListView
public:
DetailedGameListView(Window* window, FileData* root);
virtual void setTheme(const std::shared_ptr<ThemeData>& theme) override;
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
virtual void onFileChanged(FileData* file, FileChangeType change);

View file

@ -2,6 +2,8 @@
#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)
{
@ -24,7 +26,17 @@ bool GameListView::input(InputConfig* config, Input input)
{
// open menu
mWindow->pushGui(new GuiMenu(mWindow));
}else if(config->isMappedTo("select", input) && input.value != 0)
{
// open fast select
mWindow->pushGui(new GuiFastSelect(mWindow, this));
}
return GuiComponent::input(config, input);
}
void GameListView::setTheme(const std::shared_ptr<ThemeData>& theme)
{
mTheme = theme;
onThemeChanged(theme);
}

View file

@ -20,17 +20,23 @@ public:
virtual ~GameListView() {}
// Called when a new file is added, a file is removed, or a file's metadata changes.
// 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) = 0;
// Called to set or update theme.
virtual void setTheme(const std::shared_ptr<ThemeData>& theme) = 0;
// Called whenever the theme changes.
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) = 0;
virtual bool input(InputConfig* config, Input input) override;
void setTheme(const std::shared_ptr<ThemeData>& theme);
inline const std::shared_ptr<ThemeData>& getTheme() const { return mTheme; }
virtual FileData* getCursor() = 0;
virtual void setCursor(FileData*) = 0;
virtual bool input(InputConfig* config, Input input) override;
protected:
FileData* mRoot;
std::shared_ptr<ThemeData> mTheme;
};