mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 06:05:38 +00:00
Added an offline miximage generator.
This commit is contained in:
parent
c9cd282b7f
commit
a1fd0959c1
|
@ -24,6 +24,7 @@ set(ES_HEADERS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMediaViewerOptions.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMediaViewerOptions.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMenu.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMenu.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMetaDataEd.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMetaDataEd.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiOfflineGenerator.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMenu.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMenu.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMulti.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMulti.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperSearch.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperSearch.h
|
||||||
|
@ -75,6 +76,7 @@ set(ES_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMenu.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMenu.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMediaViewerOptions.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMediaViewerOptions.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMetaDataEd.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiMetaDataEd.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiOfflineGenerator.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMenu.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMenu.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMulti.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperMulti.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperSearch.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/guis/GuiScraperSearch.cpp
|
||||||
|
|
339
es-app/src/guis/GuiOfflineGenerator.cpp
Normal file
339
es-app/src/guis/GuiOfflineGenerator.cpp
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
|
// GuiOfflineGenerator.cpp
|
||||||
|
//
|
||||||
|
// User interface for the miximage offline generator.
|
||||||
|
// Calls MiximageGenerator to do the actual work.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "guis/GuiOfflineGenerator.h"
|
||||||
|
|
||||||
|
#include "components/MenuComponent.h"
|
||||||
|
#include "views/ViewController.h"
|
||||||
|
#include "SystemData.h"
|
||||||
|
|
||||||
|
GuiOfflineGenerator::GuiOfflineGenerator(
|
||||||
|
Window* window,
|
||||||
|
const std::queue<FileData*>& gameQueue)
|
||||||
|
: GuiComponent(window),
|
||||||
|
mBackground(window, ":/graphics/frame.svg"),
|
||||||
|
mGrid(window, Vector2i(5, 13)),
|
||||||
|
mGameQueue(gameQueue)
|
||||||
|
{
|
||||||
|
addChild(&mBackground);
|
||||||
|
addChild(&mGrid);
|
||||||
|
|
||||||
|
mProcessing = false;
|
||||||
|
mPaused = false;
|
||||||
|
mOverwriting = false;
|
||||||
|
|
||||||
|
mTotalGames = static_cast<int>(mGameQueue.size());
|
||||||
|
mGamesProcessed = 0;
|
||||||
|
mImagesGenerated = 0;
|
||||||
|
mImagesOverwritten = 0;
|
||||||
|
mGamesSkipped = 0;
|
||||||
|
mGamesFailed = 0;
|
||||||
|
|
||||||
|
mGame = nullptr;
|
||||||
|
|
||||||
|
// Header.
|
||||||
|
mTitle = std::make_shared<TextComponent>(mWindow, "MIXIMAGE OFFLINE GENERATOR",
|
||||||
|
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
||||||
|
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true, Vector2i(5, 1));
|
||||||
|
|
||||||
|
mStatus = std::make_shared<TextComponent>(mWindow, "NOT STARTED",
|
||||||
|
Font::get(FONT_SIZE_MEDIUM), 0x777777FF, ALIGN_CENTER);
|
||||||
|
mGrid.setEntry(mStatus, Vector2i(0, 1), false, true, Vector2i(5, 1));
|
||||||
|
|
||||||
|
mGameCounter = std::make_shared<TextComponent>(mWindow,
|
||||||
|
std::to_string(mGamesProcessed) + " OF " + std::to_string(mTotalGames) +
|
||||||
|
(mTotalGames == 1 ? " GAME " : " GAMES ") + "PROCESSED",
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_CENTER);
|
||||||
|
mGrid.setEntry(mGameCounter, Vector2i(0, 2), false, true, Vector2i(5, 1));
|
||||||
|
|
||||||
|
// Spacer row with top border.
|
||||||
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 3),
|
||||||
|
false, false, Vector2i(5, 1), GridFlags::BORDER_TOP);
|
||||||
|
|
||||||
|
// Left spacer.
|
||||||
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 4),
|
||||||
|
false, false, Vector2i(1, 7));
|
||||||
|
|
||||||
|
// Generated label.
|
||||||
|
mGeneratedLbl = std::make_shared<TextComponent>(mWindow, "Generated:",
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mGeneratedLbl, Vector2i(1, 4), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Generated value/counter.
|
||||||
|
mGeneratedVal = std::make_shared<TextComponent>(mWindow,
|
||||||
|
std::to_string(mGamesProcessed),
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mGeneratedVal, Vector2i(2, 4), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Overwritten label.
|
||||||
|
mOverwrittenLbl = std::make_shared<TextComponent>(mWindow, "Overwritten:",
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mOverwrittenLbl, Vector2i(1, 5), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Overwritten value/counter.
|
||||||
|
mOverwrittenVal = std::make_shared<TextComponent>(mWindow,
|
||||||
|
std::to_string(mImagesOverwritten),
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mOverwrittenVal, Vector2i(2, 5), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Skipping label.
|
||||||
|
mSkippedLbl = std::make_shared<TextComponent>(mWindow, "Skipped (existing):",
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mSkippedLbl, Vector2i(1, 6), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Skipping value/counter.
|
||||||
|
mSkippedVal= std::make_shared<TextComponent>(mWindow,
|
||||||
|
std::to_string(mGamesSkipped),
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mSkippedVal, Vector2i(2, 6), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Failed label.
|
||||||
|
mFailedLbl = std::make_shared<TextComponent>(mWindow, "Failed:",
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mFailedLbl, Vector2i(1, 7), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Failed value/counter.
|
||||||
|
mFailedVal = std::make_shared<TextComponent>(mWindow,
|
||||||
|
std::to_string(mGamesFailed),
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mFailedVal, Vector2i(2, 7), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Processing label.
|
||||||
|
mProcessingLbl = std::make_shared<TextComponent>(mWindow, "Processing: ",
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mProcessingLbl, Vector2i(3, 4), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Processing value.
|
||||||
|
mProcessingVal = std::make_shared<TextComponent>(mWindow, "",
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mProcessingVal, Vector2i(4, 4), false, true, Vector2i(1, 1));
|
||||||
|
|
||||||
|
// Spacer row.
|
||||||
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(1, 8),
|
||||||
|
false, false, Vector2i(5, 1));
|
||||||
|
|
||||||
|
// Last error message label.
|
||||||
|
mLastErrorLbl = std::make_shared<TextComponent>(mWindow, "Last error message:",
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mLastErrorLbl, Vector2i(1, 9), false, true, Vector2i(4, 1));
|
||||||
|
|
||||||
|
// Last error message value.
|
||||||
|
mLastErrorVal = std::make_shared<TextComponent>(mWindow, "",
|
||||||
|
Font::get(FONT_SIZE_SMALL), 0x888888FF, ALIGN_LEFT);
|
||||||
|
mGrid.setEntry(mLastErrorVal, Vector2i(1, 10), false, true, Vector2i(4, 1));
|
||||||
|
|
||||||
|
// Spacer row with bottom border.
|
||||||
|
mGrid.setEntry(std::make_shared<GuiComponent>(mWindow), Vector2i(0, 11),
|
||||||
|
false, false, Vector2i(5, 1), GridFlags::BORDER_BOTTOM);
|
||||||
|
|
||||||
|
// Buttons.
|
||||||
|
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
||||||
|
|
||||||
|
mStartPauseButton = std::make_shared<ButtonComponent>(mWindow, "START",
|
||||||
|
"start processing", [this](){
|
||||||
|
if (!mProcessing) {
|
||||||
|
mProcessing = true;
|
||||||
|
mPaused = false;
|
||||||
|
mStartPauseButton->setText("PAUSE", "pause processing");
|
||||||
|
mCloseButton->setText("CLOSE", "close (abort processing)");
|
||||||
|
mStatus->setText("RUNNING...");
|
||||||
|
if (mGamesProcessed == 0) {
|
||||||
|
LOG(LogInfo) << "GuiOfflineGenerator: Processing " << mTotalGames << " games";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (mMiximageGeneratorThread.joinable())
|
||||||
|
mMiximageGeneratorThread.join();
|
||||||
|
mPaused = true;
|
||||||
|
update(1);
|
||||||
|
mProcessing = false;
|
||||||
|
this->mStartPauseButton->setText("START", "start processing");
|
||||||
|
this->mCloseButton->setText("CLOSE", "close (abort processing)");
|
||||||
|
mStatus->setText("PAUSED");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
buttons.push_back(mStartPauseButton);
|
||||||
|
|
||||||
|
mCloseButton = std::make_shared<ButtonComponent>(mWindow, "CLOSE", "close", [this](){
|
||||||
|
if (mGamesProcessed != 0 && mGamesProcessed != mTotalGames) {
|
||||||
|
LOG(LogInfo) << "GuiOfflineGenerator: Aborted after processing " <<
|
||||||
|
mGamesProcessed << (mGamesProcessed == 1 ? " game (" : " games (") <<
|
||||||
|
mImagesGenerated << (mImagesGenerated == 1 ? " image " : " images ") <<
|
||||||
|
"generated, " << mGamesSkipped <<
|
||||||
|
(mGamesSkipped == 1 ? " game " : " games ") << "skipped, " << mGamesFailed <<
|
||||||
|
(mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
||||||
|
}
|
||||||
|
delete this;
|
||||||
|
});
|
||||||
|
|
||||||
|
buttons.push_back(mCloseButton);
|
||||||
|
mButtonGrid = makeButtonGrid(mWindow, buttons);
|
||||||
|
|
||||||
|
mGrid.setEntry(mButtonGrid, Vector2i(0, 12), true, false, Vector2i(5, 1));
|
||||||
|
|
||||||
|
// For narrower displays (e.g. in 4:3 ratio), allow the window to fill 95% of the screen
|
||||||
|
// width rather than the 85% allowed for wider displays.
|
||||||
|
float width = Renderer::getScreenWidth() *
|
||||||
|
((Renderer::getScreenAspectRatio() < 1.4f) ? 0.95f : 0.85f);
|
||||||
|
|
||||||
|
setSize(width, Renderer::getScreenHeight() * 0.75f);
|
||||||
|
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2.0f,
|
||||||
|
(Renderer::getScreenHeight() - mSize.y()) / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiOfflineGenerator::~GuiOfflineGenerator()
|
||||||
|
{
|
||||||
|
// Let the miximage generator thread complete.
|
||||||
|
if (mMiximageGeneratorThread.joinable())
|
||||||
|
mMiximageGeneratorThread.join();
|
||||||
|
|
||||||
|
mMiximageGenerator.reset();
|
||||||
|
|
||||||
|
if (mImagesGenerated > 0)
|
||||||
|
ViewController::get()->reloadAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiOfflineGenerator::onSizeChanged()
|
||||||
|
{
|
||||||
|
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32.0f, -32.0f));
|
||||||
|
|
||||||
|
// Set row heights.
|
||||||
|
mGrid.setRowHeightPerc(0, mTitle->getFont()->getLetterHeight() * 1.9725f / mSize.y(), false);
|
||||||
|
mGrid.setRowHeightPerc(1, (mStatus->getFont()->getLetterHeight() + 2.0f) / mSize.y(), false);
|
||||||
|
mGrid.setRowHeightPerc(2, mGameCounter->getFont()->getHeight() * 1.75f / mSize.y(), false);
|
||||||
|
mGrid.setRowHeightPerc(3, (mStatus->getFont()->getLetterHeight() + 3.0f) / mSize.y(), false);
|
||||||
|
mGrid.setRowHeightPerc(4, 0.07f, false);
|
||||||
|
mGrid.setRowHeightPerc(5, 0.07f, false);
|
||||||
|
mGrid.setRowHeightPerc(6, 0.07f, false);
|
||||||
|
mGrid.setRowHeightPerc(7, 0.07f, false);
|
||||||
|
mGrid.setRowHeightPerc(8, 0.02f, false);
|
||||||
|
mGrid.setRowHeightPerc(9, 0.07f, false);
|
||||||
|
mGrid.setRowHeightPerc(10, 0.07f, false);
|
||||||
|
mGrid.setRowHeightPerc(12, mButtonGrid->getSize().y() / mSize.y(), false);
|
||||||
|
|
||||||
|
// Set column widths.
|
||||||
|
mGrid.setColWidthPerc(0, 0.03f);
|
||||||
|
mGrid.setColWidthPerc(1, 0.20f);
|
||||||
|
mGrid.setColWidthPerc(2, 0.145f);
|
||||||
|
|
||||||
|
// Adjust the width slightly depending on the aspect ratio of the screen to make sure
|
||||||
|
// that the label does not get abbreviated.
|
||||||
|
if (Renderer::getScreenAspectRatio() <= 1.4f)
|
||||||
|
mGrid.setColWidthPerc(3, 0.13f);
|
||||||
|
else if (Renderer::getScreenAspectRatio() <= 1.6f)
|
||||||
|
mGrid.setColWidthPerc(3, 0.12f);
|
||||||
|
else
|
||||||
|
mGrid.setColWidthPerc(3, 0.113f);
|
||||||
|
|
||||||
|
mGrid.setSize(mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuiOfflineGenerator::update(int deltaTime)
|
||||||
|
{
|
||||||
|
if (!mProcessing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check if a miximage generator thread was started, and if the processing has been completed.
|
||||||
|
if (mMiximageGenerator && mGeneratorFuture.valid()) {
|
||||||
|
// Only wait one millisecond as this update() function runs very frequently.
|
||||||
|
if (mGeneratorFuture.wait_for(std::chrono::milliseconds(1)) == std::future_status::ready) {
|
||||||
|
// We always let the miximage generator thread complete.
|
||||||
|
if (mMiximageGeneratorThread.joinable())
|
||||||
|
mMiximageGeneratorThread.join();
|
||||||
|
mMiximageGenerator.reset();
|
||||||
|
if (!mGeneratorFuture.get()) {
|
||||||
|
mImagesGenerated++;
|
||||||
|
TextureResource::manualUnload(mGame->getMiximagePath(), false);
|
||||||
|
mProcessingVal->setText("");
|
||||||
|
if (mOverwriting) {
|
||||||
|
mImagesOverwritten++;
|
||||||
|
mOverwriting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::string errorMessage = mResultMessage + " (" + mGameName + ")";
|
||||||
|
mLastErrorVal->setText(errorMessage);
|
||||||
|
LOG(LogInfo) << "GuiOfflineGenerator: " << errorMessage;
|
||||||
|
mGamesFailed++;
|
||||||
|
}
|
||||||
|
mGame = nullptr;
|
||||||
|
mGamesProcessed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is simply to retain the name of the last processed game on-screen while paused.
|
||||||
|
if (mPaused)
|
||||||
|
mProcessingVal->setText(mGameName);
|
||||||
|
|
||||||
|
if (!mPaused && !mGameQueue.empty() && !mMiximageGenerator) {
|
||||||
|
mGame = mGameQueue.front();
|
||||||
|
mGameQueue.pop();
|
||||||
|
|
||||||
|
mGameName = mGame->getName() + " [" +
|
||||||
|
Utils::String::toUpper(mGame->getSystem()->getName()) + "]";
|
||||||
|
mProcessingVal->setText(mGameName);
|
||||||
|
|
||||||
|
if (!Settings::getInstance()->getBool("MiximageOverwrite") &&
|
||||||
|
mGame->getMiximagePath() != "") {
|
||||||
|
mGamesProcessed++;
|
||||||
|
mGamesSkipped++;
|
||||||
|
mSkippedVal->setText(std::to_string(mGamesSkipped));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (mGame->getMiximagePath() != "")
|
||||||
|
mOverwriting = true;
|
||||||
|
|
||||||
|
mMiximageGenerator = std::make_unique<MiximageGenerator>(mGame, mResultMessage);
|
||||||
|
|
||||||
|
// The promise/future mechanism is used as signaling for the thread to indicate
|
||||||
|
// that processing has been completed.
|
||||||
|
std::promise<bool>().swap(mGeneratorPromise);
|
||||||
|
mGeneratorFuture = mGeneratorPromise.get_future();
|
||||||
|
|
||||||
|
mMiximageGeneratorThread = std::thread(&MiximageGenerator::startThread,
|
||||||
|
mMiximageGenerator.get(), &mGeneratorPromise);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the statistics.
|
||||||
|
mStatus->setText("RUNNING...");
|
||||||
|
mGameCounter->setText(std::to_string(mGamesProcessed) + " OF " + std::to_string(mTotalGames) +
|
||||||
|
(mTotalGames == 1 ? " GAME " : " GAMES ") + "PROCESSED");
|
||||||
|
|
||||||
|
mGeneratedVal->setText(std::to_string(mImagesGenerated));
|
||||||
|
mFailedVal->setText(std::to_string(mGamesFailed));
|
||||||
|
mOverwrittenVal->setText(std::to_string(mImagesOverwritten));
|
||||||
|
|
||||||
|
if (mGamesProcessed == mTotalGames) {
|
||||||
|
mStatus->setText("COMPLETED");
|
||||||
|
mStartPauseButton->setText("DONE", "done (close)");
|
||||||
|
mStartPauseButton->setPressedFunc([this](){ delete this; });
|
||||||
|
mCloseButton->setText("CLOSE", "close");
|
||||||
|
mProcessingVal->setText("");
|
||||||
|
LOG(LogInfo) << "GuiOfflineGenerator: Completed processing (" << mImagesGenerated <<
|
||||||
|
(mImagesGenerated == 1 ? " image " : " images ") << "generated, " <<
|
||||||
|
mGamesSkipped << (mGamesSkipped == 1 ? " game " : " games ") << "skipped, " <<
|
||||||
|
mGamesFailed << (mGamesFailed == 1 ? " game " : " games ") << "failed)";
|
||||||
|
mProcessing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<HelpPrompt> GuiOfflineGenerator::getHelpPrompts()
|
||||||
|
{
|
||||||
|
std::vector<HelpPrompt> prompts = mGrid.getHelpPrompts();
|
||||||
|
return prompts;
|
||||||
|
}
|
||||||
|
|
||||||
|
HelpStyle GuiOfflineGenerator::getHelpStyle()
|
||||||
|
{
|
||||||
|
HelpStyle style = HelpStyle();
|
||||||
|
style.applyTheme(ViewController::get()->getState().getSystem()->getTheme(), "system");
|
||||||
|
return style;
|
||||||
|
}
|
87
es-app/src/guis/GuiOfflineGenerator.h
Normal file
87
es-app/src/guis/GuiOfflineGenerator.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
|
// GuiOfflineGenerator.h
|
||||||
|
//
|
||||||
|
// User interface for the miximage offline generator.
|
||||||
|
// Calls MiximageGenerator to do the actual work.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ES_APP_GUIS_GUI_OFFLINE_GENERATOR_H
|
||||||
|
#define ES_APP_GUIS_GUI_OFFLINE_GENERATOR_H
|
||||||
|
|
||||||
|
#include "components/ButtonComponent.h"
|
||||||
|
#include "components/ComponentGrid.h"
|
||||||
|
#include "GuiComponent.h"
|
||||||
|
#include "MiximageGenerator.h"
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
class TextComponent;
|
||||||
|
|
||||||
|
class GuiOfflineGenerator : public GuiComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GuiOfflineGenerator(Window* window, const std::queue<FileData*>& gameQueue);
|
||||||
|
~GuiOfflineGenerator();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onSizeChanged() override;
|
||||||
|
void update(int deltaTime) override;
|
||||||
|
|
||||||
|
virtual std::vector<HelpPrompt> getHelpPrompts() override;
|
||||||
|
HelpStyle getHelpStyle() override;
|
||||||
|
|
||||||
|
std::queue<FileData*> mGameQueue;
|
||||||
|
|
||||||
|
std::unique_ptr<MiximageGenerator> mMiximageGenerator;
|
||||||
|
std::thread mMiximageGeneratorThread;
|
||||||
|
std::promise<bool> mGeneratorPromise;
|
||||||
|
std::future<bool> mGeneratorFuture;
|
||||||
|
|
||||||
|
FileData* mGame;
|
||||||
|
|
||||||
|
bool mProcessing;
|
||||||
|
bool mPaused;
|
||||||
|
bool mOverwriting;
|
||||||
|
std::string mResultMessage;
|
||||||
|
|
||||||
|
unsigned int mTotalGames;
|
||||||
|
unsigned int mGamesProcessed;
|
||||||
|
unsigned int mImagesGenerated;
|
||||||
|
unsigned int mImagesOverwritten;
|
||||||
|
unsigned int mGamesSkipped;
|
||||||
|
unsigned int mGamesFailed;
|
||||||
|
|
||||||
|
NinePatchComponent mBackground;
|
||||||
|
ComponentGrid mGrid;
|
||||||
|
|
||||||
|
std::shared_ptr<TextComponent> mTitle;
|
||||||
|
std::shared_ptr<TextComponent> mStatus;
|
||||||
|
std::shared_ptr<TextComponent> mGameCounter;
|
||||||
|
|
||||||
|
std::shared_ptr<TextComponent> mGeneratedLbl;
|
||||||
|
std::shared_ptr<TextComponent> mGeneratedVal;
|
||||||
|
|
||||||
|
std::shared_ptr<TextComponent> mOverwrittenLbl;
|
||||||
|
std::shared_ptr<TextComponent> mOverwrittenVal;
|
||||||
|
|
||||||
|
std::shared_ptr<TextComponent> mSkippedLbl;
|
||||||
|
std::shared_ptr<TextComponent> mSkippedVal;
|
||||||
|
|
||||||
|
std::shared_ptr<TextComponent> mFailedLbl;
|
||||||
|
std::shared_ptr<TextComponent> mFailedVal;
|
||||||
|
|
||||||
|
std::shared_ptr<TextComponent> mProcessingLbl;
|
||||||
|
std::shared_ptr<TextComponent> mProcessingVal;
|
||||||
|
std::string mGameName;
|
||||||
|
|
||||||
|
std::shared_ptr<TextComponent> mLastErrorLbl;
|
||||||
|
std::shared_ptr<TextComponent> mLastErrorVal;
|
||||||
|
|
||||||
|
std::shared_ptr<ComponentGrid> mButtonGrid;
|
||||||
|
std::shared_ptr<ButtonComponent> mStartPauseButton;
|
||||||
|
std::shared_ptr<ButtonComponent> mCloseButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ES_APP_GUIS_GUI_OFFLINE_GENERATOR_H
|
|
@ -13,10 +13,11 @@
|
||||||
#include "components/OptionListComponent.h"
|
#include "components/OptionListComponent.h"
|
||||||
#include "components/SwitchComponent.h"
|
#include "components/SwitchComponent.h"
|
||||||
#include "guis/GuiMsgBox.h"
|
#include "guis/GuiMsgBox.h"
|
||||||
|
#include "guis/GuiOfflineGenerator.h"
|
||||||
#include "guis/GuiScraperMulti.h"
|
#include "guis/GuiScraperMulti.h"
|
||||||
#include "guis/GuiSettings.h"
|
|
||||||
#include "views/ViewController.h"
|
#include "views/ViewController.h"
|
||||||
#include "FileData.h"
|
#include "FileData.h"
|
||||||
|
#include "FileSorts.h"
|
||||||
#include "SystemData.h"
|
#include "SystemData.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -439,9 +440,53 @@ void GuiScraperMenu::openMiximageOptions()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Miximage offline generator.
|
||||||
|
ComponentListRow offline_generator_row;
|
||||||
|
offline_generator_row.elements.clear();
|
||||||
|
offline_generator_row.addElement(std::make_shared<TextComponent>
|
||||||
|
(mWindow, "OFFLINE GENERATOR", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
|
||||||
|
offline_generator_row.addElement(makeArrow(mWindow), false);
|
||||||
|
offline_generator_row.makeAcceptInputHandler(
|
||||||
|
std::bind(&GuiScraperMenu::openOfflineGenerator, this, s));
|
||||||
|
s->addRow(offline_generator_row);
|
||||||
|
|
||||||
mWindow->pushGui(s);
|
mWindow->pushGui(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GuiScraperMenu::openOfflineGenerator(GuiSettings* settings)
|
||||||
|
{
|
||||||
|
if (mSystems->getSelectedObjects().empty()) {
|
||||||
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||||
|
"THE MIXIMAGE GENERATOR USES THE SAME SYSTEM\n"
|
||||||
|
"SELECTIONS AS THE SCRAPER, SO PLEASE SELECT\n"
|
||||||
|
"AT LEAST ONE SYSTEM TO GENERATE IMAGES FOR"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always save the settings before starting the generator, in case any of the
|
||||||
|
// miximage settings were modified.
|
||||||
|
settings->save();
|
||||||
|
// Also unset the save flag so that a double saving does not take place when closing
|
||||||
|
// the miximage options menu later on.
|
||||||
|
settings->setNeedsSaving(false);
|
||||||
|
|
||||||
|
// Build the queue of games to process.
|
||||||
|
std::queue<FileData*> gameQueue;
|
||||||
|
std::vector<SystemData*> systems = mSystems->getSelectedObjects();
|
||||||
|
|
||||||
|
for (auto sys = systems.cbegin(); sys != systems.cend(); sys++) {
|
||||||
|
std::vector<FileData*> games = (*sys)->getRootFolder()->getChildrenRecursive();
|
||||||
|
|
||||||
|
// Sort the games by "filename, ascending".
|
||||||
|
std::stable_sort(games.begin(), games.end(), FileSorts::SortTypes.at(0).comparisonFunction);
|
||||||
|
|
||||||
|
for (FileData* game : games)
|
||||||
|
gameQueue.push(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
mWindow->pushGui(new GuiOfflineGenerator(mWindow, gameQueue));
|
||||||
|
}
|
||||||
|
|
||||||
void GuiScraperMenu::openOtherOptions()
|
void GuiScraperMenu::openOtherOptions()
|
||||||
{
|
{
|
||||||
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
|
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
|
||||||
|
@ -731,7 +776,7 @@ void GuiScraperMenu::start()
|
||||||
{
|
{
|
||||||
if (mSystems->getSelectedObjects().empty()) {
|
if (mSystems->getSelectedObjects().empty()) {
|
||||||
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
||||||
"PLEASE SELECT AT LEAST ONE SYSTEM TO SCRAPE"));
|
"PLEASE SELECT AT LEAST ONE SYSTEM TO SCRAPE"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#define ES_APP_GUIS_GUI_SCRAPER_MENU_H
|
#define ES_APP_GUIS_GUI_SCRAPER_MENU_H
|
||||||
|
|
||||||
#include "components/MenuComponent.h"
|
#include "components/MenuComponent.h"
|
||||||
|
#include "guis/GuiSettings.h"
|
||||||
#include "scrapers/Scraper.h"
|
#include "scrapers/Scraper.h"
|
||||||
|
|
||||||
class FileData;
|
class FileData;
|
||||||
|
@ -42,6 +43,7 @@ private:
|
||||||
void openAccountOptions();
|
void openAccountOptions();
|
||||||
void openContentOptions();
|
void openContentOptions();
|
||||||
void openMiximageOptions();
|
void openMiximageOptions();
|
||||||
|
void openOfflineGenerator(GuiSettings* settings);
|
||||||
void openOtherOptions();
|
void openOtherOptions();
|
||||||
|
|
||||||
std::queue<ScraperSearchParams> getSearches(
|
std::queue<ScraperSearchParams> getSearches(
|
||||||
|
|
|
@ -662,7 +662,7 @@ void GuiScraperSearch::update(int deltaTime)
|
||||||
|
|
||||||
// Check if a miximage generator thread was started, and if the processing has been completed.
|
// Check if a miximage generator thread was started, and if the processing has been completed.
|
||||||
if (mMiximageGenerator && mGeneratorFuture.valid()) {
|
if (mMiximageGenerator && mGeneratorFuture.valid()) {
|
||||||
// Only wait one millisecond, this update() function runs very frequently.
|
// Only wait one millisecond as this update() function runs very frequently.
|
||||||
if (mGeneratorFuture.wait_for(std::chrono::milliseconds(1)) == std::future_status::ready) {
|
if (mGeneratorFuture.wait_for(std::chrono::milliseconds(1)) == std::future_status::ready) {
|
||||||
mMDResolveHandle.reset();
|
mMDResolveHandle.reset();
|
||||||
// We always let the miximage generator thread complete.
|
// We always let the miximage generator thread complete.
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
bool isPassword = false);
|
bool isPassword = false);
|
||||||
inline void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); };
|
inline void addSaveFunc(const std::function<void()>& func) { mSaveFuncs.push_back(func); };
|
||||||
|
|
||||||
void setNeedsSaving() { mNeedsSaving = true; };
|
void setNeedsSaving(bool state = true) { mNeedsSaving = state; };
|
||||||
void setNeedsReloadHelpPrompts() { mNeedsReloadHelpPrompts = true; };
|
void setNeedsReloadHelpPrompts() { mNeedsReloadHelpPrompts = true; };
|
||||||
void setNeedsCollectionsUpdate() { mNeedsCollectionsUpdate = true; };
|
void setNeedsCollectionsUpdate() { mNeedsCollectionsUpdate = true; };
|
||||||
void setNeedsSorting() { mNeedsSorting = true; };
|
void setNeedsSorting() { mNeedsSorting = true; };
|
||||||
|
|
Loading…
Reference in a new issue