2020-05-26 16:34:33 +00:00
|
|
|
//
|
2020-06-21 12:25:28 +00:00
|
|
|
// GuiMetaDataEd.cpp
|
2020-05-26 16:34:33 +00:00
|
|
|
//
|
2020-06-21 12:25:28 +00:00
|
|
|
// Game metadata edit user interface.
|
|
|
|
// This interface is triggered from the GuiGamelistOptions menu.
|
|
|
|
// The scraping interface is handled by GuiGameScraper which calls
|
|
|
|
// GuiScraperSearch.
|
2020-05-26 16:34:33 +00:00
|
|
|
//
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
#include "guis/GuiMetaDataEd.h"
|
|
|
|
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "components/ButtonComponent.h"
|
|
|
|
#include "components/ComponentList.h"
|
2018-10-13 01:08:15 +00:00
|
|
|
#include "components/DateTimeEditComponent.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "components/MenuComponent.h"
|
2014-06-25 16:29:58 +00:00
|
|
|
#include "components/RatingComponent.h"
|
2017-06-12 16:38:59 +00:00
|
|
|
#include "components/SwitchComponent.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "components/TextComponent.h"
|
|
|
|
#include "guis/GuiGameScraper.h"
|
|
|
|
#include "guis/GuiMsgBox.h"
|
2014-06-25 16:29:58 +00:00
|
|
|
#include "guis/GuiTextEditPopup.h"
|
2020-05-19 15:52:11 +00:00
|
|
|
#include "guis/GuiComplexTextEditPopup.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "resources/Font.h"
|
2018-01-27 17:04:28 +00:00
|
|
|
#include "utils/StringUtil.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "views/ViewController.h"
|
|
|
|
#include "CollectionSystemManager.h"
|
|
|
|
#include "FileData.h"
|
|
|
|
#include "FileFilterIndex.h"
|
2020-07-26 20:19:29 +00:00
|
|
|
#include "Gamelist.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "SystemData.h"
|
|
|
|
#include "Window.h"
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-05-26 16:34:33 +00:00
|
|
|
GuiMetaDataEd::GuiMetaDataEd(
|
2020-06-21 12:25:28 +00:00
|
|
|
Window* window,
|
|
|
|
MetaDataList* md,
|
|
|
|
const std::vector<MetaDataDecl>& mdd,
|
|
|
|
ScraperSearchParams scraperParams,
|
|
|
|
const std::string& /*header*/,
|
|
|
|
std::function<void()> saveCallback,
|
2020-07-30 18:05:57 +00:00
|
|
|
std::function<void()> deleteGameFunc,
|
|
|
|
std::function<void()> deleteMediaFunc)
|
2020-06-21 12:25:28 +00:00
|
|
|
: GuiComponent(window),
|
|
|
|
mScraperParams(scraperParams),
|
2020-06-21 17:35:43 +00:00
|
|
|
mBackground(window, ":/graphics/frame.png"),
|
2020-06-21 12:25:28 +00:00
|
|
|
mGrid(window, Vector2i(1, 3)),
|
|
|
|
mMetaDataDecl(mdd),
|
|
|
|
mMetaData(md),
|
|
|
|
mSavedCallback(saveCallback),
|
2020-07-30 18:05:57 +00:00
|
|
|
mDeleteGameFunc(deleteGameFunc),
|
|
|
|
mDeleteMediaFunc(deleteMediaFunc)
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
addChild(&mBackground);
|
|
|
|
addChild(&mGrid);
|
|
|
|
|
|
|
|
mHeaderGrid = std::make_shared<ComponentGrid>(mWindow, Vector2i(1, 5));
|
|
|
|
|
|
|
|
mTitle = std::make_shared<TextComponent>(mWindow, "EDIT METADATA",
|
|
|
|
Font::get(FONT_SIZE_LARGE), 0x555555FF, ALIGN_CENTER);
|
|
|
|
mSubtitle = std::make_shared<TextComponent>(mWindow,
|
2020-07-28 19:08:17 +00:00
|
|
|
Utils::FileSystem::getFileName(scraperParams.game->
|
2020-08-05 13:27:03 +00:00
|
|
|
getPath()) + " [" + Utils::String::toUpper(scraperParams.system->getName()) + "]",
|
|
|
|
Font::get(FONT_SIZE_SMALL), 0x777777FF, ALIGN_CENTER);
|
2020-06-21 12:25:28 +00:00
|
|
|
mHeaderGrid->setEntry(mTitle, Vector2i(0, 1), false, true);
|
|
|
|
mHeaderGrid->setEntry(mSubtitle, Vector2i(0, 3), false, true);
|
|
|
|
|
|
|
|
mGrid.setEntry(mHeaderGrid, Vector2i(0, 0), false, true);
|
|
|
|
|
|
|
|
mList = std::make_shared<ComponentList>(mWindow);
|
|
|
|
mGrid.setEntry(mList, Vector2i(0, 1), true, true);
|
|
|
|
|
|
|
|
// Populate list.
|
|
|
|
for (auto iter = mdd.cbegin(); iter != mdd.cend(); iter++) {
|
|
|
|
std::shared_ptr<GuiComponent> ed;
|
2020-08-02 09:45:59 +00:00
|
|
|
std::string currentKey = iter->key;
|
|
|
|
std::string originalValue = mMetaData->get(iter->key);
|
|
|
|
std::string gamePath;
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Don't add statistics.
|
|
|
|
if (iter->isStatistic)
|
|
|
|
continue;
|
|
|
|
|
2020-07-10 18:58:53 +00:00
|
|
|
// Don't show the launch command override entry if this option has been disabled.
|
2020-07-08 15:06:34 +00:00
|
|
|
if (!Settings::getInstance()->getBool("LaunchCommandOverride") &&
|
|
|
|
iter->type == MD_LAUNCHCOMMAND) {
|
2020-06-21 12:25:28 +00:00
|
|
|
ed = std::make_shared<TextComponent>(window, "", Font::get(FONT_SIZE_SMALL,
|
|
|
|
FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
|
|
|
assert(ed);
|
|
|
|
ed->setValue(mMetaData->get(iter->key));
|
|
|
|
mEditors.push_back(ed);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create ed and add it (and any related components) to mMenu.
|
|
|
|
// ed's value will be set below.
|
|
|
|
// It's very important to put the element with the help prompt as the last row
|
|
|
|
// entry instead of for instance the spacer. That is so because ComponentList
|
|
|
|
// always looks for the help prompt at the back of the element stack.
|
|
|
|
ComponentListRow row;
|
|
|
|
auto lbl = std::make_shared<TextComponent>(mWindow,
|
|
|
|
Utils::String::toUpper(iter->displayName), Font::get(FONT_SIZE_SMALL), 0x777777FF);
|
|
|
|
row.addElement(lbl, true); // Label.
|
|
|
|
|
|
|
|
switch (iter->type) {
|
|
|
|
case MD_BOOL: {
|
|
|
|
ed = std::make_shared<SwitchComponent>(window);
|
2020-07-15 15:44:27 +00:00
|
|
|
ed->setChangedColor(ICONCOLOR_USERMARKED);
|
2020-06-21 12:25:28 +00:00
|
|
|
row.addElement(ed, false, true);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MD_RATING: {
|
|
|
|
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
|
|
|
spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0);
|
|
|
|
row.addElement(spacer, false);
|
|
|
|
|
2020-07-15 15:44:27 +00:00
|
|
|
ed = std::make_shared<RatingComponent>(window, true);
|
|
|
|
ed->setChangedColor(ICONCOLOR_USERMARKED);
|
2020-06-21 12:25:28 +00:00
|
|
|
const float height = lbl->getSize().y() * 0.71f;
|
|
|
|
ed->setSize(0, height);
|
|
|
|
row.addElement(ed, false, true);
|
|
|
|
|
|
|
|
// Pass input to the actual RatingComponent instead of the spacer.
|
|
|
|
row.input_handler = std::bind(&GuiComponent::input,
|
|
|
|
ed.get(), std::placeholders::_1, std::placeholders::_2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MD_DATE: {
|
|
|
|
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
|
|
|
spacer->setSize(Renderer::getScreenWidth() * 0.0025f, 0);
|
|
|
|
row.addElement(spacer, false);
|
|
|
|
|
|
|
|
ed = std::make_shared<DateTimeEditComponent>(window);
|
2020-08-02 13:56:32 +00:00
|
|
|
ed->setOriginalColor(DEFAULT_TEXTCOLOR);
|
2020-07-15 15:44:27 +00:00
|
|
|
ed->setChangedColor(TEXTCOLOR_USERMARKED);
|
2020-06-21 12:25:28 +00:00
|
|
|
row.addElement(ed, false);
|
|
|
|
|
|
|
|
// Pass input to the actual DateTimeEditComponent instead of the spacer.
|
|
|
|
row.input_handler = std::bind(&GuiComponent::input, ed.get(),
|
|
|
|
std::placeholders::_1, std::placeholders::_2);
|
|
|
|
break;
|
|
|
|
}
|
2020-07-15 15:44:27 +00:00
|
|
|
// Not in use as 'lastplayed' is flagged as statistics and these are skipped.
|
|
|
|
// Let's still keep the code because it may be needed in the future.
|
|
|
|
// case MD_TIME: {
|
|
|
|
// ed = std::make_shared<DateTimeEditComponent>(window,
|
|
|
|
// DateTimeEditComponent::DISP_RELATIVE_TO_NOW);
|
|
|
|
// row.addElement(ed, false);
|
|
|
|
// break;
|
|
|
|
// }
|
2020-07-08 15:06:34 +00:00
|
|
|
case MD_LAUNCHCOMMAND: {
|
2020-06-21 12:25:28 +00:00
|
|
|
ed = std::make_shared<TextComponent>(window, "",
|
|
|
|
Font::get(FONT_SIZE_SMALL, FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
|
|
|
row.addElement(ed, true);
|
|
|
|
|
|
|
|
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
|
|
|
spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0);
|
|
|
|
row.addElement(spacer, false);
|
|
|
|
|
|
|
|
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
2020-06-21 17:35:43 +00:00
|
|
|
bracket->setImage(":/graphics/arrow.svg");
|
2020-06-21 12:25:28 +00:00
|
|
|
bracket->setResize(Vector2f(0, lbl->getFont()->getLetterHeight()));
|
|
|
|
row.addElement(bracket, false);
|
|
|
|
|
|
|
|
bool multiLine = false;
|
|
|
|
const std::string title = iter->displayPrompt;
|
2020-07-15 15:44:27 +00:00
|
|
|
|
|
|
|
// OK callback (apply new value to ed).
|
|
|
|
auto updateVal = [ed, originalValue](const std::string& newVal) {
|
|
|
|
ed->setValue(newVal);
|
|
|
|
if (newVal == originalValue)
|
|
|
|
ed->setColor(DEFAULT_TEXTCOLOR);
|
|
|
|
else
|
|
|
|
ed->setColor(TEXTCOLOR_USERMARKED);
|
|
|
|
};
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
std::string staticTextString = "Default value from es_systems.cfg:";
|
2020-07-08 15:06:34 +00:00
|
|
|
std::string defaultLaunchCommand = scraperParams.system->
|
2020-06-21 12:25:28 +00:00
|
|
|
getSystemEnvData()->mLaunchCommand;
|
|
|
|
|
|
|
|
row.makeAcceptInputHandler([this, title, staticTextString,
|
2020-07-08 15:06:34 +00:00
|
|
|
defaultLaunchCommand, ed, updateVal, multiLine] {
|
2020-06-21 12:25:28 +00:00
|
|
|
mWindow->pushGui(new GuiComplexTextEditPopup(mWindow, getHelpStyle(),
|
2020-07-08 15:06:34 +00:00
|
|
|
title, staticTextString, defaultLaunchCommand, ed->getValue(),
|
2020-06-21 12:25:28 +00:00
|
|
|
updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MD_MULTILINE_STRING:
|
|
|
|
default: {
|
|
|
|
// MD_STRING.
|
|
|
|
ed = std::make_shared<TextComponent>(window, "", Font::get(FONT_SIZE_SMALL,
|
|
|
|
FONT_PATH_LIGHT), 0x777777FF, ALIGN_RIGHT);
|
|
|
|
row.addElement(ed, true);
|
|
|
|
|
|
|
|
auto spacer = std::make_shared<GuiComponent>(mWindow);
|
|
|
|
spacer->setSize(Renderer::getScreenWidth() * 0.005f, 0);
|
|
|
|
row.addElement(spacer, false);
|
|
|
|
|
|
|
|
auto bracket = std::make_shared<ImageComponent>(mWindow);
|
2020-06-21 17:35:43 +00:00
|
|
|
bracket->setImage(":/graphics/arrow.svg");
|
2020-06-21 12:25:28 +00:00
|
|
|
bracket->setResize(Vector2f(0, lbl->getFont()->getLetterHeight()));
|
|
|
|
row.addElement(bracket, false);
|
|
|
|
|
|
|
|
bool multiLine = iter->type == MD_MULTILINE_STRING;
|
|
|
|
const std::string title = iter->displayPrompt;
|
|
|
|
|
2020-08-02 09:45:59 +00:00
|
|
|
gamePath = Utils::FileSystem::getStem(mScraperParams.game->getPath());
|
2020-07-15 15:44:27 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// OK callback (apply new value to ed).
|
2020-08-02 09:45:59 +00:00
|
|
|
auto updateVal = [ed, currentKey, originalValue, gamePath]
|
|
|
|
(const std::string& newVal) {
|
|
|
|
// If the user has entered a blank game name, then set the name to the ROM
|
|
|
|
// filename (minus the extension).
|
|
|
|
if (currentKey == "name" && newVal == "") {
|
|
|
|
ed->setValue(gamePath);
|
|
|
|
if (gamePath == originalValue)
|
|
|
|
ed->setColor(DEFAULT_TEXTCOLOR);
|
|
|
|
else
|
|
|
|
ed->setColor(TEXTCOLOR_USERMARKED);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ed->setValue(newVal);
|
|
|
|
if (newVal == originalValue)
|
|
|
|
ed->setColor(DEFAULT_TEXTCOLOR);
|
|
|
|
else
|
|
|
|
ed->setColor(TEXTCOLOR_USERMARKED);
|
|
|
|
}
|
2020-07-15 15:44:27 +00:00
|
|
|
};
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
row.makeAcceptInputHandler([this, title, ed, updateVal, multiLine] {
|
|
|
|
mWindow->pushGui(new GuiTextEditPopup(mWindow, getHelpStyle(), title,
|
|
|
|
ed->getValue(), updateVal, multiLine, "APPLY", "APPLY CHANGES?"));
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(ed);
|
|
|
|
mList->addRow(row);
|
|
|
|
ed->setValue(mMetaData->get(iter->key));
|
|
|
|
mEditors.push_back(ed);
|
|
|
|
}
|
|
|
|
|
2020-07-15 15:44:27 +00:00
|
|
|
std::vector<std::shared_ptr<ButtonComponent>> buttons;
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-07-28 19:08:17 +00:00
|
|
|
if (!scraperParams.system->hasPlatformId(PlatformIds::PLATFORM_IGNORE))
|
|
|
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SCRAPE", "scrape",
|
|
|
|
std::bind(&GuiMetaDataEd::fetch, this)));
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "SAVE", "save metadata",
|
|
|
|
[&] { save(); delete this; }));
|
|
|
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "CANCEL", "cancel changes",
|
|
|
|
[&] { delete this; }));
|
|
|
|
|
2020-07-30 18:05:57 +00:00
|
|
|
if (scraperParams.game->getType() == FOLDER) {
|
|
|
|
if (mDeleteGameFunc) {
|
|
|
|
auto deleteFilesAndSelf = [&] { mDeleteGameFunc(); delete this; };
|
|
|
|
auto deleteGameBtnFunc = [this, deleteFilesAndSelf] {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
|
|
|
"THIS WILL DELETE THE MEDIA FILES AND\n"
|
|
|
|
"THE GAMELIST.XML ENTRY FOR THIS FOLDER.\n"
|
|
|
|
"HOWEVER NEITHER THE FOLDER ITSELF OR\n"
|
|
|
|
"ANY DATA FOR THE FILES INSIDE THE FOLDER\n"
|
|
|
|
"WILL BE DELETED. ARE YOU SURE?",
|
|
|
|
"YES", deleteFilesAndSelf, "NO", nullptr)); };
|
|
|
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE",
|
|
|
|
"delete game", deleteGameBtnFunc));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mDeleteMediaFunc) {
|
|
|
|
auto deleteFilesAndSelf = [&] { mDeleteMediaFunc(); delete this; };
|
|
|
|
auto deleteMediaBtnFunc = [this, deleteFilesAndSelf] {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
|
|
|
"THIS WILL DELETE ALL THE MEDIA FILES\n"
|
|
|
|
"FOR THE ACTUAL FOLDER, BUT NO MEDIA\n"
|
|
|
|
"FOR ANY FILES INSIDE THE FOLDER WILL\n"
|
|
|
|
"BE DELETED. ARE YOU SURE?",
|
|
|
|
"YES", deleteFilesAndSelf, "NO", nullptr)); };
|
|
|
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE MEDIA",
|
|
|
|
"delete game", deleteMediaBtnFunc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (mDeleteGameFunc) {
|
|
|
|
auto deleteFilesAndSelf = [&] { mDeleteGameFunc(); delete this; };
|
|
|
|
auto deleteGameBtnFunc = [this, deleteFilesAndSelf] {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
|
|
|
"THIS WILL DELETE THE GAME\n"
|
|
|
|
"FILE, ANY MEDIA FILES AND\n"
|
|
|
|
"THE GAMELIST.XML ENTRY.\n"
|
|
|
|
"ARE YOU SURE?",
|
|
|
|
"YES", deleteFilesAndSelf, "NO", nullptr)); };
|
|
|
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE",
|
|
|
|
"delete game", deleteGameBtnFunc));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mDeleteMediaFunc) {
|
|
|
|
auto deleteFilesAndSelf = [&] { mDeleteMediaFunc(); delete this; };
|
|
|
|
auto deleteMediaBtnFunc = [this, deleteFilesAndSelf] {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
|
|
|
"THIS WILL DELETE ALL GAME\n"
|
|
|
|
"MEDIA FILES, BUT WILL KEEP\n"
|
|
|
|
"THE ACTUAL GAME FILE AND\n"
|
|
|
|
"THE GAMELIST.XML ENTRY.\n"
|
|
|
|
"ARE YOU SURE?",
|
|
|
|
"YES", deleteFilesAndSelf, "NO", nullptr)); };
|
|
|
|
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "DELETE MEDIA",
|
|
|
|
"delete game", deleteMediaBtnFunc));
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mButtons = makeButtonGrid(mWindow, buttons);
|
|
|
|
mGrid.setEntry(mButtons, Vector2i(0, 2), true, false);
|
|
|
|
|
|
|
|
// Resize + center.
|
|
|
|
float width = (float)Math::min(Renderer::getScreenHeight(),
|
|
|
|
(int)(Renderer::getScreenWidth() * 0.90f));
|
|
|
|
setSize(width, Renderer::getScreenHeight() * 0.82f);
|
|
|
|
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2,
|
|
|
|
(Renderer::getScreenHeight() - mSize.y()) / 2);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GuiMetaDataEd::onSizeChanged()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mGrid.setSize(mSize);
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
const float titleHeight = mTitle->getFont()->getLetterHeight();
|
|
|
|
const float subtitleHeight = mSubtitle->getFont()->getLetterHeight();
|
|
|
|
const float titleSubtitleSpacing = mSize.y() * 0.03f;
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mGrid.setRowHeightPerc(0, (titleHeight + titleSubtitleSpacing + subtitleHeight +
|
|
|
|
TITLE_VERT_PADDING) / mSize.y());
|
|
|
|
mGrid.setRowHeightPerc(2, mButtons->getSize().y() / mSize.y());
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mHeaderGrid->setRowHeightPerc(1, titleHeight / mHeaderGrid->getSize().y());
|
|
|
|
mHeaderGrid->setRowHeightPerc(2, titleSubtitleSpacing / mHeaderGrid->getSize().y());
|
|
|
|
mHeaderGrid->setRowHeightPerc(3, subtitleHeight / mHeaderGrid->getSize().y());
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GuiMetaDataEd::save()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Remove game from index.
|
|
|
|
mScraperParams.system->getIndex()->removeFromIndex(mScraperParams.game);
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-07-26 20:19:29 +00:00
|
|
|
// We need this to handle the special situation where the user sets a game to hidden while
|
|
|
|
// ShowHiddenGames is set to false, meaning it will immediately disappear from the gamelist.
|
|
|
|
bool showHiddenGames = Settings::getInstance()->getBool("ShowHiddenGames");
|
|
|
|
bool hideGameWhileHidden = false;
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
for (unsigned int i = 0; i < mEditors.size(); i++) {
|
|
|
|
if (mMetaDataDecl.at(i).isStatistic)
|
|
|
|
continue;
|
2020-05-19 15:52:11 +00:00
|
|
|
|
2020-07-26 20:19:29 +00:00
|
|
|
if (!showHiddenGames && mMetaDataDecl.at(i).key == "hidden" &&
|
|
|
|
mEditors.at(i)->getValue() != mMetaData->get("hidden"))
|
|
|
|
hideGameWhileHidden = true;
|
|
|
|
|
2020-08-02 09:45:59 +00:00
|
|
|
mMetaData->set(mMetaDataDecl.at(i).key, mEditors.at(i)->getValue());
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-07-26 20:19:29 +00:00
|
|
|
// If hidden games are not shown and the hide flag was set for the game, then write the
|
|
|
|
// metadata immediately regardless of the SaveGamelistsMode setting. Otherwise the file
|
|
|
|
// will never be written as the game will be filtered from the gamelist. This solution is not
|
|
|
|
// really good as the gamelist will be written twice, but it's a very special and hopefully
|
|
|
|
// rare situation.
|
|
|
|
if (hideGameWhileHidden)
|
|
|
|
updateGamelist(mScraperParams.system);
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Enter game in index.
|
|
|
|
mScraperParams.system->getIndex()->addToIndex(mScraperParams.game);
|
2017-03-18 17:54:39 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mSavedCallback)
|
|
|
|
mSavedCallback();
|
2017-06-12 16:38:59 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Update respective Collection Entries.
|
|
|
|
CollectionSystemManager::get()->refreshCollectionSystems(mScraperParams.game);
|
2019-08-24 14:22:02 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mScraperParams.system->onMetaDataSavePoint();
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GuiMetaDataEd::fetch()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
GuiGameScraper* scr = new GuiGameScraper(mWindow, mScraperParams,
|
|
|
|
std::bind(&GuiMetaDataEd::fetchDone, this, std::placeholders::_1));
|
|
|
|
mWindow->pushGui(scr);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GuiMetaDataEd::fetchDone(const ScraperSearchResult& result)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Clone the mMetaData object.
|
|
|
|
MetaDataList* metadata = nullptr;
|
|
|
|
metadata = new MetaDataList(*mMetaData);
|
|
|
|
|
2020-08-05 20:38:44 +00:00
|
|
|
mMediaFilesUpdated = result.savedNewMedia;
|
2020-07-13 18:10:09 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Check if any values were manually changed before starting the scraping.
|
|
|
|
// If so, it's these values we should compare against when scraping, not
|
|
|
|
// the values previously saved for the game.
|
|
|
|
for (unsigned int i = 0; i < mEditors.size(); i++) {
|
|
|
|
const std::string& key = mMetaDataDecl.at(i).key;
|
|
|
|
if (metadata->get(key) != mEditors[i]->getValue())
|
|
|
|
metadata->set(key, mEditors[i]->getValue());
|
|
|
|
}
|
|
|
|
|
2020-07-15 15:44:27 +00:00
|
|
|
GuiScraperSearch::saveMetadata(result, *metadata);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Update the list with the scraped metadata values.
|
|
|
|
for (unsigned int i = 0; i < mEditors.size(); i++) {
|
|
|
|
const std::string& key = mMetaDataDecl.at(i).key;
|
|
|
|
if (mEditors.at(i)->getValue() != metadata->get(key)) {
|
2020-07-15 15:44:27 +00:00
|
|
|
if (key == "rating")
|
|
|
|
mEditors.at(i)->setOriginalColor(ICONCOLOR_SCRAPERMARKED);
|
|
|
|
else
|
|
|
|
mEditors.at(i)->setColor(TEXTCOLOR_SCRAPERMARKED);
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2020-07-15 15:44:27 +00:00
|
|
|
// Save all the keys, except the following which can't be scraped.
|
|
|
|
if (key != "favorite" && key != "completed" && key != "broken" &&
|
|
|
|
key != "hidden" && key != "kidgame")
|
|
|
|
mEditors.at(i)->setValue(metadata->get(key));
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
delete metadata;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2020-06-09 18:03:31 +00:00
|
|
|
void GuiMetaDataEd::close()
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Find out if the user made any changes.
|
2020-07-15 15:44:27 +00:00
|
|
|
bool metadataUpdated = false;
|
2020-06-21 12:25:28 +00:00
|
|
|
for (unsigned int i = 0; i < mEditors.size(); i++) {
|
|
|
|
const std::string& key = mMetaDataDecl.at(i).key;
|
|
|
|
std::string mMetaDataValue = mMetaData->get(key);
|
|
|
|
std::string mEditorsValue = mEditors.at(i)->getValue();
|
|
|
|
|
|
|
|
if (mMetaDataValue != mEditorsValue) {
|
2020-07-15 15:44:27 +00:00
|
|
|
metadataUpdated = true;
|
2020-06-21 12:25:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-09 18:03:31 +00:00
|
|
|
// Keep code for potential future use.
|
|
|
|
// std::function<void()> closeFunc;
|
|
|
|
// if (!closeAllWindows) {
|
|
|
|
// closeFunc = [this] { delete this; };
|
|
|
|
// }
|
|
|
|
// else {
|
|
|
|
// Window* window = mWindow;
|
|
|
|
// closeFunc = [window, this] {
|
|
|
|
// while (window->peekGui() != ViewController::get())
|
|
|
|
// delete window->peekGui();
|
|
|
|
// };
|
|
|
|
// }
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
std::function<void()> closeFunc;
|
|
|
|
closeFunc = [this] { delete this; };
|
|
|
|
|
2020-07-15 15:44:27 +00:00
|
|
|
if (metadataUpdated) {
|
2020-06-21 12:25:28 +00:00
|
|
|
// Changes were made, ask if the user wants to save them.
|
|
|
|
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
|
|
|
|
"SAVE CHANGES?",
|
|
|
|
"YES", [this, closeFunc] { save(); closeFunc(); },
|
|
|
|
"NO", closeFunc
|
|
|
|
));
|
|
|
|
}
|
|
|
|
else {
|
2020-07-13 18:10:09 +00:00
|
|
|
// Always save if the media files have been changed (i.e. newly scraped images).
|
|
|
|
if (mMediaFilesUpdated)
|
|
|
|
save();
|
2020-06-21 12:25:28 +00:00
|
|
|
closeFunc();
|
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GuiMetaDataEd::input(InputConfig* config, Input input)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (GuiComponent::input(config, input))
|
|
|
|
return true;
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (input.value != 0 && (config->isMappedTo("b", input))) {
|
|
|
|
close();
|
|
|
|
return true;
|
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return false;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<HelpPrompt> GuiMetaDataEd::getHelpPrompts()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
std::vector<HelpPrompt> prompts = mGrid.getHelpPrompts();
|
|
|
|
prompts.push_back(HelpPrompt("b", "back"));
|
|
|
|
return prompts;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
2020-06-07 18:09:02 +00:00
|
|
|
|
|
|
|
HelpStyle GuiMetaDataEd::getHelpStyle()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
HelpStyle style = HelpStyle();
|
|
|
|
style.applyTheme(ViewController::get()->getState().getSystem()->getTheme(), "system");
|
|
|
|
return style;
|
2020-06-07 18:09:02 +00:00
|
|
|
}
|