mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 14:15:38 +00:00
When marking or unmarking a game as favorite, the cursor position is now retained.
This commit is contained in:
parent
fd92f7f86d
commit
83bae1e963
|
@ -1,4 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
//
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
// BasicGameListView.cpp
|
// BasicGameListView.cpp
|
||||||
//
|
//
|
||||||
// Interface that defines a GameListView of the type 'Basic'.
|
// Interface that defines a GameListView of the type 'Basic'.
|
||||||
|
@ -46,10 +48,15 @@ void BasicGameListView::onFileChanged(FileData* file, FileChangeType change)
|
||||||
|
|
||||||
void BasicGameListView::populateList(const std::vector<FileData*>& files)
|
void BasicGameListView::populateList(const std::vector<FileData*>& files)
|
||||||
{
|
{
|
||||||
|
firstGameEntry = nullptr;
|
||||||
|
|
||||||
mList.clear();
|
mList.clear();
|
||||||
mHeaderText.setText(mRoot->getSystem()->getFullName());
|
mHeaderText.setText(mRoot->getSystem()->getFullName());
|
||||||
if (files.size() > 0) {
|
if (files.size() > 0) {
|
||||||
for (auto it = files.cbegin(); it != files.cend(); it++) {
|
for (auto it = files.cbegin(); it != files.cend(); it++) {
|
||||||
|
if (!firstGameEntry && (*it)->getType() == GAME)
|
||||||
|
firstGameEntry = (*it);
|
||||||
|
|
||||||
if ((*it)->getFavorite() &&
|
if ((*it)->getFavorite() &&
|
||||||
mRoot->getSystem()->getName() != "favorites") {
|
mRoot->getSystem()->getName() != "favorites") {
|
||||||
mList.add(FAVORITE_GAME_CHAR + " " + (*it)->getName(),
|
mList.add(FAVORITE_GAME_CHAR + " " + (*it)->getName(),
|
||||||
|
@ -100,6 +107,16 @@ void BasicGameListView::setCursor(FileData* cursor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileData* BasicGameListView::getNextEntry()
|
||||||
|
{
|
||||||
|
return mList.getNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileData* BasicGameListView::getPreviousEntry()
|
||||||
|
{
|
||||||
|
return mList.getPrevious();
|
||||||
|
}
|
||||||
|
|
||||||
FileData* BasicGameListView::getFirstEntry()
|
FileData* BasicGameListView::getFirstEntry()
|
||||||
{
|
{
|
||||||
return mList.getFirst();
|
return mList.getFirst();
|
||||||
|
@ -110,6 +127,11 @@ FileData* BasicGameListView::getLastEntry()
|
||||||
return mList.getLast();
|
return mList.getLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileData* BasicGameListView::getFirstGameEntry()
|
||||||
|
{
|
||||||
|
return firstGameEntry;
|
||||||
|
}
|
||||||
|
|
||||||
void BasicGameListView::addPlaceholder()
|
void BasicGameListView::addPlaceholder()
|
||||||
{
|
{
|
||||||
// Empty list - add a placeholder.
|
// Empty list - add a placeholder.
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
//
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
// BasicGameListView.h
|
// BasicGameListView.h
|
||||||
//
|
//
|
||||||
// Interface that defines a GameListView of the type 'basic'.
|
// Interface that defines a GameListView of the type 'basic'.
|
||||||
|
@ -22,8 +24,11 @@ public:
|
||||||
|
|
||||||
virtual FileData* getCursor() override;
|
virtual FileData* getCursor() override;
|
||||||
virtual void setCursor(FileData* file) override;
|
virtual void setCursor(FileData* file) override;
|
||||||
|
virtual FileData* getNextEntry() override;
|
||||||
|
virtual FileData* getPreviousEntry() override;
|
||||||
virtual FileData* getFirstEntry() override;
|
virtual FileData* getFirstEntry() override;
|
||||||
virtual FileData* getLastEntry() override;
|
virtual FileData* getLastEntry() override;
|
||||||
|
virtual FileData* getFirstGameEntry() override;
|
||||||
|
|
||||||
virtual const char* getName() const override { return "basic"; }
|
virtual const char* getName() const override { return "basic"; }
|
||||||
|
|
||||||
|
@ -42,6 +47,8 @@ protected:
|
||||||
virtual void addPlaceholder();
|
virtual void addPlaceholder();
|
||||||
|
|
||||||
TextListComponent<FileData*> mList;
|
TextListComponent<FileData*> mList;
|
||||||
|
// Points to the first game in the list, i.e. the first entry which is of the type 'GAME'.
|
||||||
|
FileData* firstGameEntry;
|
||||||
|
|
||||||
const std::string FAVORITE_GAME_CHAR = "\uF005";
|
const std::string FAVORITE_GAME_CHAR = "\uF005";
|
||||||
const std::string FAVORITE_FOLDER_CHAR = "\uF07C";
|
const std::string FAVORITE_FOLDER_CHAR = "\uF07C";
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
//
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
// GridGameListView.cpp
|
// GridGameListView.cpp
|
||||||
//
|
//
|
||||||
// Interface that defines a GameListView of the type 'grid'.
|
// Interface that defines a GameListView of the type 'grid'.
|
||||||
|
@ -11,8 +13,8 @@
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "CollectionSystemManager.h"
|
#include "CollectionSystemManager.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "SystemData.h"
|
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
#include "SystemData.h"
|
||||||
#if defined(_RPI_)
|
#if defined(_RPI_)
|
||||||
#include "components/VideoPlayerComponent.h"
|
#include "components/VideoPlayerComponent.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -159,6 +161,16 @@ void GridGameListView::setCursor(FileData* file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileData* GridGameListView::getNextEntry()
|
||||||
|
{
|
||||||
|
return mGrid.getNext();;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileData* GridGameListView::getPreviousEntry()
|
||||||
|
{
|
||||||
|
return mGrid.getPrevious();
|
||||||
|
}
|
||||||
|
|
||||||
FileData* GridGameListView::getFirstEntry()
|
FileData* GridGameListView::getFirstEntry()
|
||||||
{
|
{
|
||||||
return mGrid.getFirst();;
|
return mGrid.getFirst();;
|
||||||
|
@ -169,6 +181,11 @@ FileData* GridGameListView::getLastEntry()
|
||||||
return mGrid.getLast();
|
return mGrid.getLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileData* GridGameListView::getFirstGameEntry()
|
||||||
|
{
|
||||||
|
return firstGameEntry;
|
||||||
|
}
|
||||||
|
|
||||||
std::string GridGameListView::getQuickSystemSelectRightButton()
|
std::string GridGameListView::getQuickSystemSelectRightButton()
|
||||||
{
|
{
|
||||||
return "rightshoulder";
|
return "rightshoulder";
|
||||||
|
@ -222,11 +239,16 @@ const std::string GridGameListView::getImagePath(FileData* file)
|
||||||
|
|
||||||
void GridGameListView::populateList(const std::vector<FileData*>& files)
|
void GridGameListView::populateList(const std::vector<FileData*>& files)
|
||||||
{
|
{
|
||||||
|
firstGameEntry = nullptr;
|
||||||
|
|
||||||
mGrid.clear();
|
mGrid.clear();
|
||||||
mHeaderText.setText(mRoot->getSystem()->getFullName());
|
mHeaderText.setText(mRoot->getSystem()->getFullName());
|
||||||
if (files.size() > 0) {
|
if (files.size() > 0) {
|
||||||
for (auto it = files.cbegin(); it != files.cend(); it++)
|
for (auto it = files.cbegin(); it != files.cend(); it++) {
|
||||||
|
if (!firstGameEntry && (*it)->getType() == GAME)
|
||||||
|
firstGameEntry = (*it);
|
||||||
mGrid.add((*it)->getName(), getImagePath(*it), *it);
|
mGrid.add((*it)->getName(), getImagePath(*it), *it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addPlaceholder();
|
addPlaceholder();
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
//
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
// GridGameListView.h
|
// GridGameListView.h
|
||||||
//
|
//
|
||||||
// Interface that defines a GameListView of the type 'grid'.
|
// Interface that defines a GameListView of the type 'grid'.
|
||||||
//
|
//
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#ifndef ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H
|
#ifndef ES_APP_VIEWS_GAME_LIST_GRID_GAME_LIST_VIEW_H
|
||||||
#define 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/DateTimeComponent.h"
|
||||||
|
#include "components/ImageGridComponent.h"
|
||||||
#include "components/RatingComponent.h"
|
#include "components/RatingComponent.h"
|
||||||
#include "components/ScrollableContainer.h"
|
#include "components/ScrollableContainer.h"
|
||||||
#include "components/ImageGridComponent.h"
|
|
||||||
#include "components/VideoComponent.h"
|
#include "components/VideoComponent.h"
|
||||||
#include "views/gamelist/ISimpleGameListView.h"
|
#include "views/gamelist/ISimpleGameListView.h"
|
||||||
|
|
||||||
|
@ -27,8 +28,11 @@ public:
|
||||||
|
|
||||||
virtual FileData* getCursor() override;
|
virtual FileData* getCursor() override;
|
||||||
virtual void setCursor(FileData*) override;
|
virtual void setCursor(FileData*) override;
|
||||||
|
virtual FileData* getNextEntry() override;
|
||||||
|
virtual FileData* getPreviousEntry() override;
|
||||||
virtual FileData* getFirstEntry() override;
|
virtual FileData* getFirstEntry() override;
|
||||||
virtual FileData* getLastEntry() override;
|
virtual FileData* getLastEntry() override;
|
||||||
|
virtual FileData* getFirstGameEntry() override;
|
||||||
|
|
||||||
virtual bool input(InputConfig* config, Input input) override;
|
virtual bool input(InputConfig* config, Input input) override;
|
||||||
|
|
||||||
|
@ -47,6 +51,8 @@ protected:
|
||||||
virtual void addPlaceholder();
|
virtual void addPlaceholder();
|
||||||
|
|
||||||
ImageGridComponent<FileData*> mGrid;
|
ImageGridComponent<FileData*> mGrid;
|
||||||
|
// Points to the first game in the list, i.e. the first entry which is of the type 'GAME'.
|
||||||
|
FileData* firstGameEntry;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateInfoPanel();
|
void updateInfoPanel();
|
||||||
|
|
|
@ -44,8 +44,11 @@ public:
|
||||||
|
|
||||||
virtual FileData* getCursor() = 0;
|
virtual FileData* getCursor() = 0;
|
||||||
virtual void setCursor(FileData*) = 0;
|
virtual void setCursor(FileData*) = 0;
|
||||||
|
virtual FileData* getNextEntry() = 0;
|
||||||
|
virtual FileData* getPreviousEntry() = 0;
|
||||||
virtual FileData* getFirstEntry() = 0;
|
virtual FileData* getFirstEntry() = 0;
|
||||||
virtual FileData* getLastEntry() = 0;
|
virtual FileData* getLastEntry() = 0;
|
||||||
|
virtual FileData* getFirstGameEntry() = 0;
|
||||||
|
|
||||||
virtual bool input(InputConfig* config, Input input) override;
|
virtual bool input(InputConfig* config, Input input) override;
|
||||||
virtual void remove(FileData* game, bool deleteFile) = 0;
|
virtual void remove(FileData* game, bool deleteFile) = 0;
|
||||||
|
|
|
@ -182,36 +182,118 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
|
||||||
if (mRoot->getSystem()->isGameSystem()) {
|
if (mRoot->getSystem()->isGameSystem()) {
|
||||||
if (getCursor()->getType() == GAME || getCursor()->getType() == FOLDER)
|
if (getCursor()->getType() == GAME || getCursor()->getType() == FOLDER)
|
||||||
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
NavigationSounds::getInstance()->playThemeNavigationSound(FAVORITESOUND);
|
||||||
|
// When marking or unmarking a game as favorite, don't jump to the new position
|
||||||
|
// it gets after the gamelist sorting. Instead retain the cursor position in the
|
||||||
|
// list using the logic below.
|
||||||
|
FileData* entryToUpdate = getCursor();
|
||||||
|
bool favoritesSorting;
|
||||||
|
bool removedLastFavorite = false;
|
||||||
|
bool foldersOnTop = Settings::getInstance()->getBool("FoldersOnTop");
|
||||||
|
|
||||||
|
if (CollectionSystemManager::get()->getIsCustomCollection(mRoot->getSystem()))
|
||||||
|
favoritesSorting = Settings::getInstance()->getBool("FavFirstCustom");
|
||||||
|
else
|
||||||
|
favoritesSorting = Settings::getInstance()->getBool("FavoritesFirst");
|
||||||
|
|
||||||
|
if (favoritesSorting && static_cast<std::string>(getName()) != "recent") {
|
||||||
|
FileData* entryToSelect;
|
||||||
|
// Add favorite flag.
|
||||||
|
if (!getCursor()->getFavorite()) {
|
||||||
|
// If it's a folder and folders are sorted on top, select the current entry.
|
||||||
|
if (foldersOnTop && getCursor()->getType() == FOLDER)
|
||||||
|
entryToSelect = getCursor();
|
||||||
|
// If it's the first entry to be marked as favorite, select the next entry.
|
||||||
|
else if (getCursor() == getFirstEntry())
|
||||||
|
entryToSelect = getNextEntry();
|
||||||
|
// If we are on the favorite marking boundary, select the next entry.
|
||||||
|
else if (getCursor()->getFavorite() != getPreviousEntry()->getFavorite())
|
||||||
|
entryToSelect = getNextEntry();
|
||||||
|
// For all other scenarios try to select the next entry, and if it doesn't
|
||||||
|
// exist, select the previous entry.
|
||||||
|
else
|
||||||
|
entryToSelect = getCursor() != getNextEntry() ?
|
||||||
|
getNextEntry() : getPreviousEntry();
|
||||||
|
}
|
||||||
|
// Remove favorite flag.
|
||||||
|
else {
|
||||||
|
// If it's a folder and folders are sorted on top, select the current entry.
|
||||||
|
if (foldersOnTop && getCursor()->getType() == FOLDER)
|
||||||
|
entryToSelect = getCursor();
|
||||||
|
// If it's the last entry, select the previous entry.
|
||||||
|
else if (getCursor() == getLastEntry())
|
||||||
|
entryToSelect = getPreviousEntry();
|
||||||
|
// If we are on the favorite marking boundary, select the previous entry,
|
||||||
|
// unless folders are sorted on top and the previous entry is a folder.
|
||||||
|
else if (foldersOnTop &&
|
||||||
|
getCursor()->getFavorite() != getNextEntry()->getFavorite())
|
||||||
|
entryToSelect = getPreviousEntry()->getType() == FOLDER ?
|
||||||
|
getCursor() : getPreviousEntry();
|
||||||
|
// If we are on the favorite marking boundary, select the previous entry.
|
||||||
|
else if (getCursor()->getFavorite() != getNextEntry()->getFavorite())
|
||||||
|
entryToSelect = getPreviousEntry();
|
||||||
|
// For all other scenarios try to select the next entry, and if it doesn't
|
||||||
|
// exist, select the previous entry.
|
||||||
|
else
|
||||||
|
entryToSelect = getCursor() != getNextEntry() ?
|
||||||
|
getNextEntry() : getPreviousEntry();
|
||||||
|
|
||||||
|
// If we removed the last favorite marking, set the flag to jump to the
|
||||||
|
// first list entry after the sorting has been performed.
|
||||||
|
if (foldersOnTop && getCursor() == getFirstGameEntry() &&
|
||||||
|
!getNextEntry()->getFavorite())
|
||||||
|
removedLastFavorite = true;
|
||||||
|
else if (getCursor() == getFirstEntry() && !getNextEntry()->getFavorite())
|
||||||
|
removedLastFavorite = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCursor(entryToSelect);
|
||||||
|
}
|
||||||
|
|
||||||
// Marking folders as favorites is only cosmetic as they're not sorted
|
// Marking folders as favorites is only cosmetic as they're not sorted
|
||||||
// differently and they're not part of any collections. So it makes more
|
// differently and they're not part of any collections. So it makes more
|
||||||
// sense to do it here than to add the function to CollectionSystemManager.
|
// sense to do it here than to add the function to CollectionSystemManager.
|
||||||
if (getCursor()->getType() == FOLDER) {
|
if (entryToUpdate->getType() == FOLDER) {
|
||||||
GuiInfoPopup* s;
|
GuiInfoPopup* s;
|
||||||
MetaDataList* md = &getCursor()->getSourceFileData()->metadata;
|
MetaDataList* md = &entryToUpdate->getSourceFileData()->metadata;
|
||||||
if (md->get("favorite") == "false") {
|
if (md->get("favorite") == "false") {
|
||||||
md->set("favorite", "true");
|
md->set("favorite", "true");
|
||||||
s = new GuiInfoPopup(mWindow, "Marked folder '" +
|
s = new GuiInfoPopup(mWindow, "Marked folder '" +
|
||||||
Utils::String::removeParenthesis(getCursor()->getName()) +
|
Utils::String::removeParenthesis(entryToUpdate->getName()) +
|
||||||
"' as favorite", 4000);
|
"' as favorite", 4000);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
md->set("favorite", "false");
|
md->set("favorite", "false");
|
||||||
s = new GuiInfoPopup(mWindow, "Removed favorite marking for folder '" +
|
s = new GuiInfoPopup(mWindow, "Removed favorite marking for folder '" +
|
||||||
Utils::String::removeParenthesis(getCursor()->getName()) +
|
Utils::String::removeParenthesis(entryToUpdate->getName()) +
|
||||||
"'", 4000);
|
"'", 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
mWindow->setInfoPopup(s);
|
mWindow->setInfoPopup(s);
|
||||||
getCursor()->getSourceFileData()->getSystem()->onMetaDataSavePoint();
|
entryToUpdate->getSourceFileData()->getSystem()->onMetaDataSavePoint();
|
||||||
|
|
||||||
if (!Settings::getInstance()->getBool("FoldersOnTop"))
|
if (!Settings::getInstance()->getBool("FoldersOnTop"))
|
||||||
mRoot->sort(mRoot->getSortTypeFromString(mRoot->getSortTypeString()),
|
mRoot->sort(mRoot->getSortTypeFromString(mRoot->getSortTypeString()),
|
||||||
Settings::getInstance()->getBool("FavoritesFirst"));
|
Settings::getInstance()->getBool("FavoritesFirst"));
|
||||||
|
|
||||||
ViewController::get()->onFileChanged(getCursor(), FILE_METADATA_CHANGED);
|
ViewController::get()->onFileChanged(getCursor(), FILE_METADATA_CHANGED);
|
||||||
|
|
||||||
|
// Always jump to the first entry in the gamelist if the last favorite
|
||||||
|
// was unmarked. We couldn't do this earlier as we didn't have the list
|
||||||
|
// sorted yet.
|
||||||
|
if (removedLastFavorite) {
|
||||||
|
ViewController::get()->getGameListView(mRoot->getSystem())->setCursor(
|
||||||
|
ViewController::get()->getGameListView(mRoot->getSystem())->
|
||||||
|
getFirstEntry());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (CollectionSystemManager::get()->toggleGameInCollection(getCursor())) {
|
else if (CollectionSystemManager::get()->toggleGameInCollection(entryToUpdate)) {
|
||||||
|
// Jump to the first entry in the gamelist if the last favorite was unmarked.
|
||||||
|
if (foldersOnTop && removedLastFavorite)
|
||||||
|
setCursor(getFirstGameEntry());
|
||||||
|
else if (removedLastFavorite)
|
||||||
|
setCursor(getFirstEntry());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,6 +144,24 @@ public:
|
||||||
return mEntries.at(mCursor).object;
|
return mEntries.at(mCursor).object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const UserData& getNext() const
|
||||||
|
{
|
||||||
|
// If there is a next entry, then return it, otherwise return the current entry.
|
||||||
|
if (mCursor + 1 < mEntries.size())
|
||||||
|
return mEntries.at(mCursor+1).object;
|
||||||
|
else
|
||||||
|
return mEntries.at(mCursor).object;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const UserData& getPrevious() const
|
||||||
|
{
|
||||||
|
// If there is a previous entry, then return it, otherwise return the current entry.
|
||||||
|
if (mCursor != 0)
|
||||||
|
return mEntries.at(mCursor-1).object;
|
||||||
|
else
|
||||||
|
return mEntries.at(mCursor).object;
|
||||||
|
}
|
||||||
|
|
||||||
inline const UserData& getFirst() const
|
inline const UserData& getFirst() const
|
||||||
{
|
{
|
||||||
assert(size() > 0);
|
assert(size() > 0);
|
||||||
|
|
Loading…
Reference in a new issue