diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index 5f83cf420..9b7e6fd42 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -446,7 +446,8 @@ const bool FileData::isArcadeGame() const void FileData::addChild(FileData* file) { assert(mType == FOLDER); - assert(file->getParent() == nullptr); + if (!mSystem->getFlattenFolders()) + assert(file->getParent() == nullptr); const std::string key = file->getKey(); if (mChildrenByFilename.find(key) == mChildrenByFilename.cend()) { diff --git a/es-app/src/GamelistFileParser.cpp b/es-app/src/GamelistFileParser.cpp index 01ef73b84..632f3d2b8 100644 --- a/es-app/src/GamelistFileParser.cpp +++ b/es-app/src/GamelistFileParser.cpp @@ -85,12 +85,14 @@ namespace GamelistFileParser return nullptr; } - // Create missing folder. - FileData* folder = new FileData( - FOLDER, Utils::FileSystem::getStem(treeNode->getPath()) + "/" + *path_it, - system->getSystemEnvData(), system); - treeNode->addChild(folder); - treeNode = folder; + if (!system->getFlattenFolders()) { + // Create missing folder. + FileData* folder {new FileData( + FOLDER, Utils::FileSystem::getStem(treeNode->getPath()) + "/" + *path_it, + system->getSystemEnvData(), system)}; + treeNode->addChild(folder); + treeNode = folder; + } } ++path_it; diff --git a/es-app/src/SystemData.cpp b/es-app/src/SystemData.cpp index 7e5697da3..b65694ce4 100644 --- a/es-app/src/SystemData.cpp +++ b/es-app/src/SystemData.cpp @@ -185,17 +185,18 @@ SystemData::SystemData(const std::string& name, const std::string& themeFolder, bool CollectionSystem, bool CustomCollectionSystem) - : mName(name) - , mFullName(fullName) - , mSortName(sortName) - , mEnvData(envData) - , mThemeFolder(themeFolder) - , mIsCollectionSystem(CollectionSystem) - , mIsCustomCollectionSystem(CustomCollectionSystem) - , mIsGroupedCustomCollectionSystem(false) - , mIsGameSystem(true) - , mScrapeFlag(false) - , mPlaceholder(nullptr) + : mName {name} + , mFullName {fullName} + , mSortName {sortName} + , mEnvData {envData} + , mThemeFolder {themeFolder} + , mIsCollectionSystem {CollectionSystem} + , mIsCustomCollectionSystem {CustomCollectionSystem} + , mIsGroupedCustomCollectionSystem {false} + , mIsGameSystem {true} + , mScrapeFlag {false} + , mFlattenFolders {false} + , mPlaceholder {nullptr} { mFilterIndex = new FileFilterIndex(); @@ -271,6 +272,13 @@ bool SystemData::populateFolder(FileData* folder) if (dirContent.size() == 0) return false; + if (std::find(dirContent.cbegin(), dirContent.cend(), mEnvData->mStartPath + "/flatten.txt") != + dirContent.cend()) { + LOG(LogInfo) << "A flatten.txt file is present for the \"" << mName + << "\" system, folder flattening will be applied"; + mFlattenFolders = true; + } + for (Utils::FileSystem::StringList::const_iterator it = dirContent.cbegin(); it != dirContent.cend(); ++it) { filePath = *it; @@ -344,11 +352,17 @@ bool SystemData::populateFolder(FileData* folder) FileData* newFolder = new FileData(FOLDER, filePath, mEnvData, this); populateFolder(newFolder); - // Ignore folders that do not contain games. - if (newFolder->getChildrenByFilename().size() == 0) - delete newFolder; - else - folder->addChild(newFolder); + if (mFlattenFolders) { + for (auto& entry : newFolder->getChildrenByFilename()) + folder->addChild(entry.second); + } + else { + // Ignore folders that do not contain games. + if (newFolder->getChildrenByFilename().size() == 0) + delete newFolder; + else + folder->addChild(newFolder); + } } } return true; diff --git a/es-app/src/SystemData.h b/es-app/src/SystemData.h index c22d84d71..53573308b 100644 --- a/es-app/src/SystemData.h +++ b/es-app/src/SystemData.h @@ -97,6 +97,7 @@ public: std::string getThemePath() const; std::pair getDisplayedGameCount() const; + const bool getFlattenFolders() const { return mFlattenFolders; } const bool getScrapeFlag() const { return mScrapeFlag; } void setScrapeFlag(bool scrapeflag) { mScrapeFlag = scrapeflag; } @@ -156,6 +157,7 @@ private: bool mIsGroupedCustomCollectionSystem; bool mIsGameSystem; bool mScrapeFlag; // Only used by scraper GUI to remember which systems to scrape. + bool mFlattenFolders; bool populateFolder(FileData* folder); void indexAllGameFilters(const FileData* folder);