mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 14:15:38 +00:00
Merge pull request #404 from Koerty/grid-metadata
[GRID 4] Add metadata from the detailed view to the grid view
This commit is contained in:
commit
016956703a
33
THEMES.md
33
THEMES.md
|
@ -472,6 +472,39 @@ Reference
|
|||
* `image name="logo"` - 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.
|
||||
|
||||
* Metadata
|
||||
* Labels
|
||||
* `text name="md_lbl_rating"` - ALL
|
||||
* `text name="md_lbl_releasedate"` - ALL
|
||||
* `text name="md_lbl_developer"` - ALL
|
||||
* `text name="md_lbl_publisher"` - ALL
|
||||
* `text name="md_lbl_genre"` - ALL
|
||||
* `text name="md_lbl_players"` - ALL
|
||||
* `text name="md_lbl_lastplayed"` - ALL
|
||||
* `text name="md_lbl_playcount"` - ALL
|
||||
|
||||
* Values
|
||||
* All values will follow to the right of their labels if a position isn't specified.
|
||||
|
||||
* `rating name="md_rating"` - ALL
|
||||
- The "rating" metadata.
|
||||
* `datetime name="md_releasedate"` - ALL
|
||||
- The "releasedate" metadata.
|
||||
* `text name="md_developer"` - ALL
|
||||
- The "developer" metadata.
|
||||
* `text name="md_publisher"` - ALL
|
||||
- The "publisher" metadata.
|
||||
* `text name="md_genre"` - ALL
|
||||
- The "genre" metadata.
|
||||
* `text name="md_players"` - ALL
|
||||
- The "players" metadata (number of players the game supports).
|
||||
* `datetime name="md_lastplayed"` - ALL
|
||||
- The "lastplayed" metadata. Displayed as a string representing the time relative to "now" (e.g. "3 hours ago").
|
||||
* `text name="md_playcount"` - ALL
|
||||
- The "playcount" metadata (number of times the game has been played).
|
||||
* `text name="md_description"` - POSITION | SIZE | FONT_PATH | FONT_SIZE | COLOR | Z_INDEX
|
||||
- Text is the "desc" metadata. If no `pos`/`size` is specified, will move and resize to fit under the lowest label and reach to the bottom of the screen.
|
||||
|
||||
---
|
||||
|
||||
#### system
|
||||
|
|
|
@ -1,19 +1,73 @@
|
|||
#include "views/gamelist/GridGameListView.h"
|
||||
|
||||
#include "animations/LambdaAnimation.h"
|
||||
#include "views/UIModeController.h"
|
||||
#include "views/ViewController.h"
|
||||
#include "CollectionSystemManager.h"
|
||||
#include "Settings.h"
|
||||
#include "SystemData.h"
|
||||
|
||||
GridGameListView::GridGameListView(Window* window, FileData* root) : ISimpleGameListView(window, root),
|
||||
mGrid(window)
|
||||
GridGameListView::GridGameListView(Window* window, FileData* root) :
|
||||
ISimpleGameListView(window, root),
|
||||
mGrid(window),
|
||||
mDescContainer(window), mDescription(window),
|
||||
|
||||
mLblRating(window), mLblReleaseDate(window), mLblDeveloper(window), mLblPublisher(window),
|
||||
mLblGenre(window), mLblPlayers(window), mLblLastPlayed(window), mLblPlayCount(window),
|
||||
|
||||
mRating(window), mReleaseDate(window), mDeveloper(window), mPublisher(window),
|
||||
mGenre(window), mPlayers(window), mLastPlayed(window), mPlayCount(window)
|
||||
{
|
||||
const float padding = 0.01f;
|
||||
|
||||
mGrid.setPosition(mSize.x() * 0.1f, mSize.y() * 0.1f);
|
||||
// mGrid.setSize(mSize.x(), mSize.y() * 0.8f);
|
||||
mGrid.setCursorChangedCallback([&](const CursorState& /*state*/) { updateInfoPanel(); });
|
||||
addChild(&mGrid);
|
||||
|
||||
populateList(root->getChildrenListToDisplay());
|
||||
|
||||
// metadata labels + values
|
||||
mLblRating.setText("Rating: ");
|
||||
addChild(&mLblRating);
|
||||
addChild(&mRating);
|
||||
mLblReleaseDate.setText("Released: ");
|
||||
addChild(&mLblReleaseDate);
|
||||
addChild(&mReleaseDate);
|
||||
mLblDeveloper.setText("Developer: ");
|
||||
addChild(&mLblDeveloper);
|
||||
addChild(&mDeveloper);
|
||||
mLblPublisher.setText("Publisher: ");
|
||||
addChild(&mLblPublisher);
|
||||
addChild(&mPublisher);
|
||||
mLblGenre.setText("Genre: ");
|
||||
addChild(&mLblGenre);
|
||||
addChild(&mGenre);
|
||||
mLblPlayers.setText("Players: ");
|
||||
addChild(&mLblPlayers);
|
||||
addChild(&mPlayers);
|
||||
mLblLastPlayed.setText("Last played: ");
|
||||
addChild(&mLblLastPlayed);
|
||||
mLastPlayed.setDisplayMode(DateTimeComponent::DISP_RELATIVE_TO_NOW);
|
||||
addChild(&mLastPlayed);
|
||||
mLblPlayCount.setText("Times played: ");
|
||||
addChild(&mLblPlayCount);
|
||||
addChild(&mPlayCount);
|
||||
|
||||
mDescContainer.setPosition(mSize.x() * padding, mSize.y() * 0.65f);
|
||||
mDescContainer.setSize(mSize.x() * (0.50f - 2*padding), mSize.y() - mDescContainer.getPosition().y());
|
||||
mDescContainer.setAutoScroll(true);
|
||||
mDescContainer.setDefaultZIndex(40);
|
||||
addChild(&mDescContainer);
|
||||
|
||||
mDescription.setFont(Font::get(FONT_SIZE_SMALL));
|
||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||
mDescContainer.addChild(&mDescription);
|
||||
|
||||
|
||||
initMDLabels();
|
||||
initMDValues();
|
||||
updateInfoPanel();
|
||||
}
|
||||
|
||||
FileData* GridGameListView::getCursor()
|
||||
|
@ -65,6 +119,164 @@ void GridGameListView::populateList(const std::vector<FileData*>& files)
|
|||
}
|
||||
}
|
||||
|
||||
void GridGameListView::onThemeChanged(const std::shared_ptr<ThemeData>& theme)
|
||||
{
|
||||
ISimpleGameListView::onThemeChanged(theme);
|
||||
|
||||
using namespace ThemeFlags;
|
||||
|
||||
initMDLabels();
|
||||
std::vector<TextComponent*> labels = getMDLabels();
|
||||
assert(labels.size() == 8);
|
||||
const char* lblElements[8] = {
|
||||
"md_lbl_rating", "md_lbl_releasedate", "md_lbl_developer", "md_lbl_publisher",
|
||||
"md_lbl_genre", "md_lbl_players", "md_lbl_lastplayed", "md_lbl_playcount"
|
||||
};
|
||||
|
||||
for(unsigned int i = 0; i < labels.size(); i++)
|
||||
{
|
||||
labels[i]->applyTheme(theme, getName(), lblElements[i], ALL);
|
||||
}
|
||||
|
||||
|
||||
initMDValues();
|
||||
std::vector<GuiComponent*> values = getMDValues();
|
||||
assert(values.size() == 8);
|
||||
const char* valElements[8] = {
|
||||
"md_rating", "md_releasedate", "md_developer", "md_publisher",
|
||||
"md_genre", "md_players", "md_lastplayed", "md_playcount"
|
||||
};
|
||||
|
||||
for(unsigned int i = 0; i < values.size(); i++)
|
||||
{
|
||||
values[i]->applyTheme(theme, getName(), valElements[i], ALL ^ ThemeFlags::TEXT);
|
||||
}
|
||||
|
||||
mDescContainer.applyTheme(theme, getName(), "md_description", POSITION | ThemeFlags::SIZE | Z_INDEX);
|
||||
mDescription.setSize(mDescContainer.getSize().x(), 0);
|
||||
mDescription.applyTheme(theme, getName(), "md_description", ALL ^ (POSITION | ThemeFlags::SIZE | ThemeFlags::ORIGIN | TEXT | ROTATION));
|
||||
|
||||
sortChildren();
|
||||
}
|
||||
|
||||
void GridGameListView::initMDLabels()
|
||||
{
|
||||
std::vector<TextComponent*> components = getMDLabels();
|
||||
|
||||
const unsigned int colCount = 2;
|
||||
const unsigned int rowCount = (int)(components.size() / 2);
|
||||
|
||||
Vector3f start(mSize.x() * 0.01f, mSize.y() * 0.625f, 0.0f);
|
||||
|
||||
const float colSize = (mSize.x() * 0.48f) / colCount;
|
||||
const float rowPadding = 0.01f * mSize.y();
|
||||
|
||||
for(unsigned int i = 0; i < components.size(); i++)
|
||||
{
|
||||
const unsigned int row = i % rowCount;
|
||||
Vector3f pos(0.0f, 0.0f, 0.0f);
|
||||
if(row == 0)
|
||||
{
|
||||
pos = start + Vector3f(colSize * (i / rowCount), 0, 0);
|
||||
}else{
|
||||
// work from the last component
|
||||
GuiComponent* lc = components[i-1];
|
||||
pos = lc->getPosition() + Vector3f(0, lc->getSize().y() + rowPadding, 0);
|
||||
}
|
||||
|
||||
components[i]->setFont(Font::get(FONT_SIZE_SMALL));
|
||||
components[i]->setPosition(pos);
|
||||
components[i]->setDefaultZIndex(40);
|
||||
}
|
||||
}
|
||||
|
||||
void GridGameListView::initMDValues()
|
||||
{
|
||||
std::vector<TextComponent*> labels = getMDLabels();
|
||||
std::vector<GuiComponent*> values = getMDValues();
|
||||
|
||||
std::shared_ptr<Font> defaultFont = Font::get(FONT_SIZE_SMALL);
|
||||
mRating.setSize(defaultFont->getHeight() * 5.0f, (float)defaultFont->getHeight());
|
||||
mReleaseDate.setFont(defaultFont);
|
||||
mDeveloper.setFont(defaultFont);
|
||||
mPublisher.setFont(defaultFont);
|
||||
mGenre.setFont(defaultFont);
|
||||
mPlayers.setFont(defaultFont);
|
||||
mLastPlayed.setFont(defaultFont);
|
||||
mPlayCount.setFont(defaultFont);
|
||||
|
||||
float bottom = 0.0f;
|
||||
|
||||
const float colSize = (mSize.x() * 0.48f) / 2;
|
||||
for(unsigned int i = 0; i < labels.size(); i++)
|
||||
{
|
||||
const float heightDiff = (labels[i]->getSize().y() - values[i]->getSize().y()) / 2;
|
||||
values[i]->setPosition(labels[i]->getPosition() + Vector3f(labels[i]->getSize().x(), heightDiff, 0));
|
||||
values[i]->setSize(colSize - labels[i]->getSize().x(), values[i]->getSize().y());
|
||||
values[i]->setDefaultZIndex(40);
|
||||
|
||||
float testBot = values[i]->getPosition().y() + values[i]->getSize().y();
|
||||
if(testBot > bottom)
|
||||
bottom = testBot;
|
||||
}
|
||||
|
||||
mDescContainer.setPosition(mDescContainer.getPosition().x(), bottom + mSize.y() * 0.01f);
|
||||
mDescContainer.setSize(mDescContainer.getSize().x(), mSize.y() - mDescContainer.getPosition().y());
|
||||
}
|
||||
|
||||
void GridGameListView::updateInfoPanel()
|
||||
{
|
||||
FileData* file = (mGrid.size() == 0 || mGrid.isScrolling()) ? NULL : mGrid.getSelected();
|
||||
|
||||
bool fadingOut;
|
||||
if(file == NULL)
|
||||
{
|
||||
//mDescription.setText("");
|
||||
fadingOut = true;
|
||||
}else{
|
||||
mDescription.setText(file->metadata.get("desc"));
|
||||
mDescContainer.reset();
|
||||
|
||||
mRating.setValue(file->metadata.get("rating"));
|
||||
mReleaseDate.setValue(file->metadata.get("releasedate"));
|
||||
mDeveloper.setValue(file->metadata.get("developer"));
|
||||
mPublisher.setValue(file->metadata.get("publisher"));
|
||||
mGenre.setValue(file->metadata.get("genre"));
|
||||
mPlayers.setValue(file->metadata.get("players"));
|
||||
|
||||
if(file->getType() == GAME)
|
||||
{
|
||||
mLastPlayed.setValue(file->metadata.get("lastplayed"));
|
||||
mPlayCount.setValue(file->metadata.get("playcount"));
|
||||
}
|
||||
|
||||
fadingOut = false;
|
||||
}
|
||||
|
||||
std::vector<GuiComponent*> comps = getMDValues();
|
||||
comps.push_back(&mDescription);
|
||||
std::vector<TextComponent*> labels = getMDLabels();
|
||||
comps.insert(comps.cend(), labels.cbegin(), labels.cend());
|
||||
|
||||
for(auto it = comps.cbegin(); it != comps.cend(); it++)
|
||||
{
|
||||
GuiComponent* comp = *it;
|
||||
// an animation is playing
|
||||
// then animate if reverse != fadingOut
|
||||
// an animation is not playing
|
||||
// then animate if opacity != our target opacity
|
||||
if((comp->isAnimationPlaying(0) && comp->isAnimationReversed(0) != fadingOut) ||
|
||||
(!comp->isAnimationPlaying(0) && comp->getOpacity() != (fadingOut ? 0 : 255)))
|
||||
{
|
||||
auto func = [comp](float t)
|
||||
{
|
||||
comp->setOpacity((unsigned char)(Math::lerp(0.0f, 1.0f, t)*255));
|
||||
};
|
||||
comp->setAnimation(new LambdaAnimation(func, 150), 0, nullptr, fadingOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GridGameListView::addPlaceholder()
|
||||
{
|
||||
// empty grid - add a placeholder
|
||||
|
@ -106,6 +318,34 @@ void GridGameListView::remove(FileData *game, bool deleteFile)
|
|||
onFileChanged(parent, FILE_REMOVED); // update the view, with game removed
|
||||
}
|
||||
|
||||
std::vector<TextComponent*> GridGameListView::getMDLabels()
|
||||
{
|
||||
std::vector<TextComponent*> ret;
|
||||
ret.push_back(&mLblRating);
|
||||
ret.push_back(&mLblReleaseDate);
|
||||
ret.push_back(&mLblDeveloper);
|
||||
ret.push_back(&mLblPublisher);
|
||||
ret.push_back(&mLblGenre);
|
||||
ret.push_back(&mLblPlayers);
|
||||
ret.push_back(&mLblLastPlayed);
|
||||
ret.push_back(&mLblPlayCount);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<GuiComponent*> GridGameListView::getMDValues()
|
||||
{
|
||||
std::vector<GuiComponent*> ret;
|
||||
ret.push_back(&mRating);
|
||||
ret.push_back(&mReleaseDate);
|
||||
ret.push_back(&mDeveloper);
|
||||
ret.push_back(&mPublisher);
|
||||
ret.push_back(&mGenre);
|
||||
ret.push_back(&mPlayers);
|
||||
ret.push_back(&mLastPlayed);
|
||||
ret.push_back(&mPlayCount);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<HelpPrompt> GridGameListView::getHelpPrompts()
|
||||
{
|
||||
std::vector<HelpPrompt> prompts;
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#ifndef ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H
|
||||
#define ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H
|
||||
|
||||
#include "components/DateTimeComponent.h"
|
||||
#include "components/RatingComponent.h"
|
||||
#include "components/ScrollableContainer.h"
|
||||
#include "components/ImageGridComponent.h"
|
||||
#include "views/gamelist/ISimpleGameListView.h"
|
||||
|
||||
|
@ -10,7 +13,7 @@ class GridGameListView : public ISimpleGameListView
|
|||
public:
|
||||
GridGameListView(Window* window, FileData* root);
|
||||
|
||||
//virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
|
||||
virtual void onThemeChanged(const std::shared_ptr<ThemeData>& theme) override;
|
||||
|
||||
virtual FileData* getCursor() override;
|
||||
virtual void setCursor(FileData*) override;
|
||||
|
@ -30,6 +33,29 @@ protected:
|
|||
virtual void addPlaceholder();
|
||||
|
||||
ImageGridComponent<FileData*> mGrid;
|
||||
|
||||
private:
|
||||
void updateInfoPanel();
|
||||
|
||||
void initMDLabels();
|
||||
void initMDValues();
|
||||
|
||||
TextComponent mLblRating, mLblReleaseDate, mLblDeveloper, mLblPublisher, mLblGenre, mLblPlayers, mLblLastPlayed, mLblPlayCount;
|
||||
|
||||
RatingComponent mRating;
|
||||
DateTimeComponent mReleaseDate;
|
||||
TextComponent mDeveloper;
|
||||
TextComponent mPublisher;
|
||||
TextComponent mGenre;
|
||||
TextComponent mPlayers;
|
||||
DateTimeComponent mLastPlayed;
|
||||
TextComponent mPlayCount;
|
||||
|
||||
std::vector<TextComponent*> getMDLabels();
|
||||
std::vector<GuiComponent*> getMDValues();
|
||||
|
||||
ScrollableContainer mDescContainer;
|
||||
TextComponent mDescription;
|
||||
};
|
||||
|
||||
#endif // ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H
|
||||
|
|
|
@ -39,6 +39,8 @@ public:
|
|||
void update(int deltaTime) override;
|
||||
void render(const Transform4x4f& parentTrans) override;
|
||||
|
||||
inline void setCursorChangedCallback(const std::function<void(CursorState state)>& func) { mCursorChangedCallback = func; }
|
||||
|
||||
private:
|
||||
// Calculate how much tiles of size mTileMaxSize we can fit in a grid of size mSize using a margin of size mMargin
|
||||
Vector2i getGridDimension() const
|
||||
|
@ -54,6 +56,8 @@ private:
|
|||
|
||||
virtual void onCursorChanged(const CursorState& state);
|
||||
|
||||
std::function<void(CursorState state)> mCursorChangedCallback;
|
||||
|
||||
bool mEntriesDirty;
|
||||
|
||||
Vector2f mMargin;
|
||||
|
@ -170,9 +174,12 @@ void ImageGridComponent<T>::render(const Transform4x4f& parentTrans)
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void ImageGridComponent<T>::onCursorChanged(const CursorState& /*state*/)
|
||||
void ImageGridComponent<T>::onCursorChanged(const CursorState& state)
|
||||
{
|
||||
updateImages();
|
||||
|
||||
if(mCursorChangedCallback)
|
||||
mCursorChangedCallback(state);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
|
Loading…
Reference in a new issue