mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-16 23:19:49 +00:00
8b0b9f11c6
Some platforms should not allow quitting ScummVM. For example the Apple's HUG for iOS state that we should "Never quit an iOS applications programmatically". Adding the kFeatureNoQuit allows those backend that need it to remove the possibility to quit the application.
784 lines
23 KiB
C++
784 lines
23 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "base/version.h"
|
|
|
|
#include "common/config-manager.h"
|
|
#include "common/events.h"
|
|
#include "common/fs.h"
|
|
#include "common/gui_options.h"
|
|
#include "common/util.h"
|
|
#include "common/system.h"
|
|
#include "common/translation.h"
|
|
|
|
#include "gui/about.h"
|
|
#include "gui/browser.h"
|
|
#include "gui/chooser.h"
|
|
#include "gui/editgamedialog.h"
|
|
#include "gui/launcher.h"
|
|
#include "gui/massadd.h"
|
|
#include "gui/message.h"
|
|
#include "gui/gui-manager.h"
|
|
#include "gui/options.h"
|
|
#ifdef ENABLE_EVENTRECORDER
|
|
#include "gui/onscreendialog.h"
|
|
#include "gui/recorderdialog.h"
|
|
#include "gui/EventRecorder.h"
|
|
#endif
|
|
#include "gui/saveload.h"
|
|
#include "gui/unknown-game-dialog.h"
|
|
#include "gui/widgets/edittext.h"
|
|
#include "gui/widgets/list.h"
|
|
#include "gui/widgets/tab.h"
|
|
#include "gui/widgets/popup.h"
|
|
#include "gui/ThemeEval.h"
|
|
|
|
#include "graphics/cursorman.h"
|
|
#if defined(USE_CLOUD) && defined(USE_LIBCURL)
|
|
#include "backends/cloud/cloudmanager.h"
|
|
#endif
|
|
|
|
using Common::ConfigManager;
|
|
|
|
namespace GUI {
|
|
|
|
enum {
|
|
kStartCmd = 'STRT',
|
|
kAboutCmd = 'ABOU',
|
|
kOptionsCmd = 'OPTN',
|
|
kAddGameCmd = 'ADDG',
|
|
kMassAddGameCmd = 'MADD',
|
|
kEditGameCmd = 'EDTG',
|
|
kRemoveGameCmd = 'REMG',
|
|
kLoadGameCmd = 'LOAD',
|
|
kRecordGameCmd = 'RECG',
|
|
kQuitCmd = 'QUIT',
|
|
kSearchCmd = 'SRCH',
|
|
kListSearchCmd = 'LSSR',
|
|
kSearchClearCmd = 'SRCL',
|
|
|
|
kCmdGlobalGraphicsOverride = 'OGFX',
|
|
kCmdGlobalAudioOverride = 'OSFX',
|
|
kCmdGlobalMIDIOverride = 'OMID',
|
|
kCmdGlobalMT32Override = 'OM32',
|
|
kCmdGlobalVolumeOverride = 'OVOL',
|
|
|
|
kCmdChooseSoundFontCmd = 'chsf',
|
|
|
|
kCmdExtraBrowser = 'PEXT',
|
|
kCmdExtraPathClear = 'PEXC',
|
|
kCmdGameBrowser = 'PGME',
|
|
kCmdSaveBrowser = 'PSAV',
|
|
kCmdSavePathClear = 'PSAC'
|
|
};
|
|
|
|
#pragma mark -
|
|
|
|
LauncherDialog::LauncherDialog()
|
|
: Dialog("Launcher") {
|
|
|
|
_backgroundType = GUI::ThemeEngine::kDialogBackgroundMain;
|
|
|
|
build();
|
|
|
|
GUI::GuiManager::instance()._launched = true;
|
|
}
|
|
|
|
void LauncherDialog::selectTarget(const String &target) {
|
|
if (!target.empty()) {
|
|
int itemToSelect = 0;
|
|
StringArray::const_iterator iter;
|
|
for (iter = _domains.begin(); iter != _domains.end(); ++iter, ++itemToSelect) {
|
|
if (target == *iter) {
|
|
_list->setSelected(itemToSelect);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LauncherDialog::~LauncherDialog() {
|
|
delete _browser;
|
|
delete _loadDialog;
|
|
}
|
|
|
|
void LauncherDialog::build() {
|
|
#ifndef DISABLE_FANCY_THEMES
|
|
_logo = nullptr;
|
|
if (g_gui.xmlEval()->getVar("Globals.ShowLauncherLogo") == 1 && g_gui.theme()->supportsImages()) {
|
|
_logo = new GraphicsWidget(this, "Launcher.Logo");
|
|
_logo->useThemeTransparency(true);
|
|
_logo->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageLogo));
|
|
|
|
new StaticTextWidget(this, "Launcher.Version", gScummVMVersionDate);
|
|
} else
|
|
new StaticTextWidget(this, "Launcher.Version", gScummVMFullVersion);
|
|
#else
|
|
// Show ScummVM version
|
|
new StaticTextWidget(this, "Launcher.Version", gScummVMFullVersion);
|
|
#endif
|
|
if (!g_system->hasFeature(OSystem::kFeatureNoQuit))
|
|
new ButtonWidget(this, "Launcher.QuitButton", _("~Q~uit"), _("Quit ScummVM"), kQuitCmd);
|
|
new ButtonWidget(this, "Launcher.AboutButton", _("A~b~out..."), _("About ScummVM"), kAboutCmd);
|
|
new ButtonWidget(this, "Launcher.OptionsButton", _("~O~ptions..."), _("Change global ScummVM options"), kOptionsCmd);
|
|
_startButton =
|
|
new ButtonWidget(this, "Launcher.StartButton", _("~S~tart"), _("Start selected game"), kStartCmd);
|
|
|
|
DropdownButtonWidget *loadButton =
|
|
new DropdownButtonWidget(this, "Launcher.LoadGameButton", _("~L~oad..."), _("Load saved game for selected game"), kLoadGameCmd);
|
|
#ifdef ENABLE_EVENTRECORDER
|
|
loadButton->appendEntry(_("Record..."), kRecordGameCmd);
|
|
#endif
|
|
_loadButton = loadButton;
|
|
|
|
// Above the lowest button rows: two more buttons (directly below the list box)
|
|
if (g_system->getOverlayWidth() > 320) {
|
|
DropdownButtonWidget *addButton =
|
|
new DropdownButtonWidget(this, "Launcher.AddGameButton", _("~A~dd Game..."), _("Add games to the list"), kAddGameCmd);
|
|
addButton->appendEntry(_("Mass Add..."), kMassAddGameCmd);
|
|
_addButton = addButton;
|
|
|
|
_editButton =
|
|
new ButtonWidget(this, "Launcher.EditGameButton", _("~E~dit Game..."), _("Change game options"), kEditGameCmd);
|
|
_removeButton =
|
|
new ButtonWidget(this, "Launcher.RemoveGameButton", _("~R~emove Game"), _("Remove game from the list. The game data files stay intact"), kRemoveGameCmd);
|
|
} else {
|
|
DropdownButtonWidget *addButton =
|
|
new DropdownButtonWidget(this, "Launcher.AddGameButton", _c("~A~dd Game...", "lowres"), _("Add games to the list"), kAddGameCmd);
|
|
addButton->appendEntry(_c("Mass Add...", "lowres"), kMassAddGameCmd);
|
|
_addButton = addButton;
|
|
|
|
_editButton =
|
|
new ButtonWidget(this, "Launcher.EditGameButton", _c("~E~dit Game...", "lowres"), _("Change game options"), kEditGameCmd);
|
|
_removeButton =
|
|
new ButtonWidget(this, "Launcher.RemoveGameButton", _c("~R~emove Game", "lowres"), _("Remove game from the list. The game data files stay intact"), kRemoveGameCmd);
|
|
}
|
|
|
|
// Search box
|
|
_searchDesc = nullptr;
|
|
#ifndef DISABLE_FANCY_THEMES
|
|
_searchPic = nullptr;
|
|
if (g_gui.xmlEval()->getVar("Globals.ShowSearchPic") == 1 && g_gui.theme()->supportsImages()) {
|
|
_searchPic = new GraphicsWidget(this, "Launcher.SearchPic", _("Search in game list"));
|
|
_searchPic->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSearch));
|
|
} else
|
|
#endif
|
|
_searchDesc = new StaticTextWidget(this, "Launcher.SearchDesc", _("Search:"));
|
|
|
|
_searchWidget = new EditTextWidget(this, "Launcher.Search", _search, nullptr, kSearchCmd);
|
|
_searchClearButton = addClearButton(this, "Launcher.SearchClearButton", kSearchClearCmd);
|
|
|
|
// Add list with game titles
|
|
_list = new ListWidget(this, "Launcher.GameList", nullptr, kListSearchCmd);
|
|
_list->setEditable(false);
|
|
_list->enableDictionarySelect(true);
|
|
_list->setNumberingMode(kListNumberingOff);
|
|
|
|
// Populate the list
|
|
updateListing();
|
|
|
|
// Restore last selection
|
|
String last(ConfMan.get("lastselectedgame", ConfigManager::kApplicationDomain));
|
|
selectTarget(last);
|
|
|
|
// En-/disable the buttons depending on the list selection
|
|
updateButtons();
|
|
|
|
// Create file browser dialog
|
|
_browser = new BrowserDialog(_("Select directory with game data"), true);
|
|
|
|
// Create Load dialog
|
|
_loadDialog = new SaveLoadChooser(_("Load game:"), _("Load"), false);
|
|
}
|
|
|
|
void LauncherDialog::clean() {
|
|
while (_firstWidget) {
|
|
Widget* w = _firstWidget;
|
|
removeWidget(w);
|
|
// This is called from rebuild() which may result from handleCommand being called by
|
|
// a child widget sendCommand call. In such a case sendCommand is still being executed
|
|
// so we should not delete yet the child widget. Thus delay the deletion.
|
|
g_gui.addToTrash(w, this);
|
|
}
|
|
delete _browser;
|
|
delete _loadDialog;
|
|
}
|
|
|
|
void LauncherDialog::rebuild() {
|
|
clean();
|
|
build();
|
|
reflowLayout();
|
|
setDefaultFocusedWidget();
|
|
}
|
|
|
|
void LauncherDialog::open() {
|
|
// Clear the active domain, in case we return to the dialog from a
|
|
// failure to launch a game. Otherwise, pressing ESC will attempt to
|
|
// re-launch the same game again.
|
|
ConfMan.setActiveDomain("");
|
|
|
|
CursorMan.popAllCursors();
|
|
Dialog::open();
|
|
|
|
updateButtons();
|
|
}
|
|
|
|
void LauncherDialog::close() {
|
|
// Save last selection
|
|
const int sel = _list->getSelected();
|
|
if (sel >= 0)
|
|
ConfMan.set("lastselectedgame", _domains[sel], ConfigManager::kApplicationDomain);
|
|
else
|
|
ConfMan.removeKey("lastselectedgame", ConfigManager::kApplicationDomain);
|
|
|
|
ConfMan.flushToDisk();
|
|
Dialog::close();
|
|
}
|
|
|
|
void LauncherDialog::updateListing() {
|
|
StringArray l;
|
|
ListWidget::ColorList colors;
|
|
ThemeEngine::FontColor color;
|
|
|
|
// Retrieve a list of all games defined in the config file
|
|
_domains.clear();
|
|
const ConfigManager::DomainMap &domains = ConfMan.getGameDomains();
|
|
ConfigManager::DomainMap::const_iterator iter;
|
|
for (iter = domains.begin(); iter != domains.end(); ++iter) {
|
|
#ifdef __DS__
|
|
// DS port uses an extra section called 'ds'. This prevents the section from being
|
|
// detected as a game.
|
|
if (iter->_key == "ds") {
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
String gameid(iter->_value.getVal("gameid"));
|
|
String description(iter->_value.getVal("description"));
|
|
Common::FSNode path(iter->_value.getVal("path"));
|
|
|
|
if (gameid.empty())
|
|
gameid = iter->_key;
|
|
|
|
if (description.empty()) {
|
|
QualifiedGameDescriptor g = EngineMan.findTarget(iter->_key);
|
|
if (!g.description.empty())
|
|
description = g.description;
|
|
}
|
|
|
|
if (description.empty()) {
|
|
description = Common::String::format("Unknown (target %s, gameid %s)", iter->_key.c_str(), gameid.c_str());
|
|
}
|
|
|
|
if (!gameid.empty() && !description.empty()) {
|
|
// Insert the game into the launcher list
|
|
int pos = 0, size = l.size();
|
|
|
|
while (pos < size && (scumm_compareDictionary(description.c_str(), l[pos].c_str()) > 0))
|
|
pos++;
|
|
|
|
color = ThemeEngine::kFontColorNormal;
|
|
if (!path.isDirectory()) {
|
|
color = ThemeEngine::kFontColorAlternate;
|
|
// If more conditions which grey out entries are added we should consider
|
|
// enabling this so that it is easy to spot why a certain game entry cannot
|
|
// be started.
|
|
|
|
// description += Common::String::format(" (%s)", _("Not found"));
|
|
}
|
|
|
|
l.insert_at(pos, description);
|
|
colors.insert_at(pos, color);
|
|
_domains.insert_at(pos, iter->_key);
|
|
}
|
|
}
|
|
|
|
const int oldSel = _list->getSelected();
|
|
_list->setList(l, &colors);
|
|
if (oldSel < (int)l.size())
|
|
_list->setSelected(oldSel); // Restore the old selection
|
|
else if (oldSel != -1)
|
|
// Select the last entry if the list has been reduced
|
|
_list->setSelected(_list->getList().size() - 1);
|
|
updateButtons();
|
|
|
|
// Update the filter settings, those are lost when "setList"
|
|
// is called.
|
|
_list->setFilter(_searchWidget->getEditString());
|
|
}
|
|
|
|
void LauncherDialog::addGame() {
|
|
// Allow user to add a new game to the list.
|
|
// 1) show a dir selection dialog which lets the user pick the directory
|
|
// the game data resides in.
|
|
// 2) try to auto detect which game is in the directory, if we cannot
|
|
// determine it uniquely present a list of candidates to the user
|
|
// to pick from
|
|
// 3) Display the 'Edit' dialog for that item, letting the user specify
|
|
// an alternate description (to distinguish multiple versions of the
|
|
// game, e.g. 'Monkey German' and 'Monkey English') and set default
|
|
// options for that game
|
|
// 4) If no game is found in the specified directory, return to the
|
|
// dialog.
|
|
|
|
bool looping;
|
|
do {
|
|
looping = false;
|
|
|
|
if (_browser->runModal() > 0) {
|
|
// User made his choice...
|
|
#if defined(USE_CLOUD) && defined(USE_LIBCURL)
|
|
String selectedDirectory = _browser->getResult().getPath();
|
|
String bannedDirectory = CloudMan.getDownloadLocalDirectory();
|
|
if (selectedDirectory.size() && selectedDirectory.lastChar() != '/' && selectedDirectory.lastChar() != '\\')
|
|
selectedDirectory += '/';
|
|
if (bannedDirectory.size() && bannedDirectory.lastChar() != '/' && bannedDirectory.lastChar() != '\\') {
|
|
if (selectedDirectory.size()) {
|
|
bannedDirectory += selectedDirectory.lastChar();
|
|
} else {
|
|
bannedDirectory += '/';
|
|
}
|
|
}
|
|
if (selectedDirectory.size() && bannedDirectory.size() && selectedDirectory.equalsIgnoreCase(bannedDirectory)) {
|
|
MessageDialog alert(_("This directory cannot be used yet, it is being downloaded into!"));
|
|
alert.runModal();
|
|
return;
|
|
}
|
|
#endif
|
|
looping = !doGameDetection(_browser->getResult().getPath());
|
|
}
|
|
} while (looping);
|
|
}
|
|
|
|
void LauncherDialog::massAddGame() {
|
|
MessageDialog alert(_("Do you really want to run the mass game detector? "
|
|
"This could potentially add a huge number of games."), _("Yes"), _("No"));
|
|
if (alert.runModal() == GUI::kMessageOK && _browser->runModal() > 0) {
|
|
MassAddDialog massAddDlg(_browser->getResult());
|
|
|
|
massAddDlg.runModal();
|
|
|
|
// Update the ListWidget and force a redraw
|
|
|
|
// If new target(s) were added, update the ListWidget and move
|
|
// the selection to to first newly detected game.
|
|
Common::String newTarget = massAddDlg.getFirstAddedTarget();
|
|
if (!newTarget.empty()) {
|
|
updateListing();
|
|
selectTarget(newTarget);
|
|
}
|
|
|
|
g_gui.scheduleTopDialogRedraw();
|
|
}
|
|
}
|
|
|
|
void LauncherDialog::removeGame(int item) {
|
|
MessageDialog alert(_("Do you really want to remove this game configuration?"), _("Yes"), _("No"));
|
|
|
|
if (alert.runModal() == GUI::kMessageOK) {
|
|
// Remove the currently selected game from the list
|
|
assert(item >= 0);
|
|
ConfMan.removeGameDomain(_domains[item]);
|
|
|
|
// Write config to disk
|
|
ConfMan.flushToDisk();
|
|
|
|
// Update the ListWidget and force a redraw
|
|
updateListing();
|
|
g_gui.scheduleTopDialogRedraw();
|
|
}
|
|
}
|
|
|
|
void LauncherDialog::editGame(int item) {
|
|
// Set game specific options. Most of these should be "optional", i.e. by
|
|
// default set nothing and use the global ScummVM settings. E.g. the user
|
|
// can set here an optional alternate music volume, or for specific games
|
|
// a different music driver etc.
|
|
// This is useful because e.g. MonkeyVGA needs AdLib music to have decent
|
|
// music support etc.
|
|
assert(item >= 0);
|
|
|
|
EditGameDialog editDialog(_domains[item]);
|
|
if (editDialog.runModal() > 0) {
|
|
// User pressed OK, so make changes permanent
|
|
|
|
// Write config to disk
|
|
ConfMan.flushToDisk();
|
|
|
|
// Update the ListWidget, reselect the edited game and force a redraw
|
|
updateListing();
|
|
selectTarget(editDialog.getDomain());
|
|
g_gui.scheduleTopDialogRedraw();
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_EVENTRECORDER
|
|
void LauncherDialog::recordGame(int item) {
|
|
RecorderDialog recorderDialog;
|
|
MessageDialog alert(_("Do you want to load saved game?"),
|
|
_("Yes"), _("No"));
|
|
switch(recorderDialog.runModal(_domains[item])) {
|
|
default:
|
|
// fallthrough intended
|
|
case RecorderDialog::kRecordDialogClose:
|
|
break;
|
|
case RecorderDialog::kRecordDialogPlayback:
|
|
ConfMan.setActiveDomain(_domains[item]);
|
|
close();
|
|
ConfMan.set("record_mode", "playback", ConfigManager::kTransientDomain);
|
|
ConfMan.set("record_file_name", recorderDialog.getFileName(), ConfigManager::kTransientDomain);
|
|
break;
|
|
case RecorderDialog::kRecordDialogRecord:
|
|
ConfMan.setActiveDomain(_domains[item]);
|
|
if (alert.runModal() == GUI::kMessageOK) {
|
|
loadGame(item);
|
|
}
|
|
close();
|
|
g_eventRec.setAuthor(recorderDialog._author);
|
|
g_eventRec.setName(recorderDialog._name);
|
|
g_eventRec.setNotes(recorderDialog._notes);
|
|
ConfMan.set("record_mode", "record", ConfigManager::kTransientDomain);
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void LauncherDialog::loadGame(int item) {
|
|
String target = _domains[item];
|
|
target.toLowercase();
|
|
|
|
EngineMan.upgradeTargetIfNecessary(target);
|
|
|
|
// Look for the plugin
|
|
const Plugin *plugin = nullptr;
|
|
EngineMan.findTarget(target, &plugin);
|
|
|
|
if (plugin) {
|
|
const MetaEngine &metaEngine = plugin->get<MetaEngine>();
|
|
if (metaEngine.hasFeature(MetaEngine::kSupportsListSaves) &&
|
|
metaEngine.hasFeature(MetaEngine::kSupportsLoadingDuringStartup)) {
|
|
int slot = _loadDialog->runModalWithPluginAndTarget(plugin, target);
|
|
if (slot >= 0) {
|
|
ConfMan.setActiveDomain(_domains[item]);
|
|
ConfMan.setInt("save_slot", slot, Common::ConfigManager::kTransientDomain);
|
|
close();
|
|
}
|
|
} else {
|
|
MessageDialog dialog
|
|
(_("This game does not support loading games from the launcher."), _("OK"));
|
|
dialog.runModal();
|
|
}
|
|
} else {
|
|
MessageDialog dialog(_("ScummVM could not find any engine capable of running the selected game!"), _("OK"));
|
|
dialog.runModal();
|
|
}
|
|
}
|
|
|
|
void LauncherDialog::handleKeyDown(Common::KeyState state) {
|
|
if (state.keycode == Common::KEYCODE_TAB) {
|
|
// Toggle between the game list and the quick search field.
|
|
if (getFocusWidget() == _searchWidget) {
|
|
setFocusWidget(_list);
|
|
} else if (getFocusWidget() == _list) {
|
|
setFocusWidget(_searchWidget);
|
|
}
|
|
}
|
|
Dialog::handleKeyDown(state);
|
|
updateButtons();
|
|
}
|
|
|
|
void LauncherDialog::handleKeyUp(Common::KeyState state) {
|
|
Dialog::handleKeyUp(state);
|
|
updateButtons();
|
|
}
|
|
|
|
void LauncherDialog::handleOtherEvent(const Common::Event &evt) {
|
|
Dialog::handleOtherEvent(evt);
|
|
if (evt.type == Common::EVENT_DROP_FILE) {
|
|
doGameDetection(evt.path);
|
|
}
|
|
}
|
|
|
|
bool LauncherDialog::doGameDetection(const Common::String &path) {
|
|
// Allow user to add a new game to the list.
|
|
// 2) try to auto detect which game is in the directory, if we cannot
|
|
// determine it uniquely present a list of candidates to the user
|
|
// to pick from
|
|
// 3) Display the 'Edit' dialog for that item, letting the user specify
|
|
// an alternate description (to distinguish multiple versions of the
|
|
// game, e.g. 'Monkey German' and 'Monkey English') and set default
|
|
// options for that game
|
|
// 4) If no game is found in the specified directory, return to the
|
|
// dialog.
|
|
|
|
// User made his choice...
|
|
Common::FSNode dir(path);
|
|
Common::FSList files;
|
|
if (!dir.getChildren(files, Common::FSNode::kListAll)) {
|
|
MessageDialog alert(_("ScummVM couldn't open the specified directory!"));
|
|
alert.runModal();
|
|
return true;
|
|
}
|
|
|
|
// ...so let's determine a list of candidates, games that
|
|
// could be contained in the specified directory.
|
|
DetectionResults detectionResults = EngineMan.detectGames(files);
|
|
|
|
if (detectionResults.foundUnknownGames()) {
|
|
Common::String report = detectionResults.generateUnknownGameReport(false, 80);
|
|
g_system->logMessage(LogMessageType::kInfo, report.c_str());
|
|
}
|
|
|
|
Common::Array<DetectedGame> candidates = detectionResults.listDetectedGames();
|
|
|
|
int idx;
|
|
if (candidates.empty()) {
|
|
// No game was found in the specified directory
|
|
MessageDialog alert(_("ScummVM could not find any game in the specified directory!"));
|
|
alert.runModal();
|
|
idx = -1;
|
|
return false;
|
|
} else if (candidates.size() == 1) {
|
|
// Exact match
|
|
idx = 0;
|
|
} else {
|
|
// Display the candidates to the user and let her/him pick one
|
|
StringArray list;
|
|
for (idx = 0; idx < (int)candidates.size(); idx++) {
|
|
Common::String description = candidates[idx].description;
|
|
|
|
if (candidates[idx].hasUnknownFiles) {
|
|
description += " - ";
|
|
description += _("Unknown variant");
|
|
}
|
|
|
|
list.push_back(description);
|
|
}
|
|
|
|
ChooserDialog dialog(_("Pick the game:"));
|
|
dialog.setList(list);
|
|
idx = dialog.runModal();
|
|
}
|
|
|
|
if (0 <= idx && idx < (int)candidates.size()) {
|
|
const DetectedGame &result = candidates[idx];
|
|
|
|
if (result.hasUnknownFiles) {
|
|
UnknownGameDialog dialog(result);
|
|
|
|
bool cancel = dialog.runModal() == -1;
|
|
if (cancel) {
|
|
idx = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 <= idx && idx < (int)candidates.size()) {
|
|
const DetectedGame &result = candidates[idx];
|
|
Common::String domain = EngineMan.createTargetForGame(result);
|
|
|
|
// Display edit dialog for the new entry
|
|
EditGameDialog editDialog(domain);
|
|
if (editDialog.runModal() > 0) {
|
|
// User pressed OK, so make changes permanent
|
|
|
|
// Write config to disk
|
|
ConfMan.flushToDisk();
|
|
|
|
// Update the ListWidget, select the new item, and force a redraw
|
|
updateListing();
|
|
selectTarget(editDialog.getDomain());
|
|
g_gui.scheduleTopDialogRedraw();
|
|
} else {
|
|
// User aborted, remove the the new domain again
|
|
ConfMan.removeGameDomain(domain);
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
|
|
int item = _list->getSelected();
|
|
|
|
switch (cmd) {
|
|
case kAddGameCmd:
|
|
addGame();
|
|
break;
|
|
case kMassAddGameCmd:
|
|
massAddGame();
|
|
break;
|
|
case kRemoveGameCmd:
|
|
removeGame(item);
|
|
break;
|
|
case kEditGameCmd:
|
|
editGame(item);
|
|
break;
|
|
case kLoadGameCmd:
|
|
loadGame(item);
|
|
break;
|
|
#ifdef ENABLE_EVENTRECORDER
|
|
case kRecordGameCmd:
|
|
recordGame(item);
|
|
break;
|
|
#endif
|
|
case kOptionsCmd: {
|
|
GlobalOptionsDialog options(this);
|
|
options.runModal();
|
|
}
|
|
break;
|
|
case kAboutCmd: {
|
|
AboutDialog about;
|
|
about.runModal();
|
|
}
|
|
break;
|
|
case kStartCmd:
|
|
case kListItemActivatedCmd:
|
|
case kListItemDoubleClickedCmd:
|
|
// Start the selected game.
|
|
assert(item >= 0);
|
|
ConfMan.setActiveDomain(_domains[item]);
|
|
close();
|
|
break;
|
|
case kListItemRemovalRequestCmd:
|
|
removeGame(item);
|
|
break;
|
|
case kListSelectionChangedCmd:
|
|
updateButtons();
|
|
break;
|
|
case kQuitCmd:
|
|
ConfMan.setActiveDomain("");
|
|
setResult(-1);
|
|
close();
|
|
break;
|
|
case kSearchCmd:
|
|
// Update the active search filter.
|
|
_list->setFilter(_searchWidget->getEditString());
|
|
break;
|
|
case kSearchClearCmd:
|
|
// Reset the active search filter, thus showing all games again
|
|
_searchWidget->setEditString("");
|
|
_list->setFilter("");
|
|
break;
|
|
default:
|
|
Dialog::handleCommand(sender, cmd, data);
|
|
}
|
|
}
|
|
|
|
void LauncherDialog::updateButtons() {
|
|
bool enable = (_list->getSelected() >= 0);
|
|
if (enable != _startButton->isEnabled()) {
|
|
_startButton->setEnabled(enable);
|
|
_startButton->markAsDirty();
|
|
}
|
|
if (enable != _editButton->isEnabled()) {
|
|
_editButton->setEnabled(enable);
|
|
_editButton->markAsDirty();
|
|
}
|
|
if (enable != _removeButton->isEnabled()) {
|
|
_removeButton->setEnabled(enable);
|
|
_removeButton->markAsDirty();
|
|
}
|
|
|
|
int item = _list->getSelected();
|
|
bool en = enable;
|
|
|
|
if (item >= 0)
|
|
en = !(Common::checkGameGUIOption(GUIO_NOLAUNCHLOAD, ConfMan.get("guioptions", _domains[item])));
|
|
|
|
if (en != _loadButton->isEnabled()) {
|
|
_loadButton->setEnabled(en);
|
|
_loadButton->markAsDirty();
|
|
}
|
|
}
|
|
|
|
void LauncherDialog::reflowLayout() {
|
|
#ifndef DISABLE_FANCY_THEMES
|
|
if (g_gui.xmlEval()->getVar("Globals.ShowLauncherLogo") == 1 && g_gui.theme()->supportsImages()) {
|
|
StaticTextWidget *ver = (StaticTextWidget *)findWidget("Launcher.Version");
|
|
if (ver) {
|
|
ver->setAlign(g_gui.xmlEval()->getWidgetTextHAlign("Launcher.Version"));
|
|
ver->setLabel(gScummVMVersionDate);
|
|
}
|
|
|
|
if (!_logo)
|
|
_logo = new GraphicsWidget(this, "Launcher.Logo");
|
|
_logo->useThemeTransparency(true);
|
|
_logo->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageLogo));
|
|
} else {
|
|
StaticTextWidget *ver = (StaticTextWidget *)findWidget("Launcher.Version");
|
|
if (ver) {
|
|
ver->setAlign(g_gui.xmlEval()->getWidgetTextHAlign("Launcher.Version"));
|
|
ver->setLabel(gScummVMFullVersion);
|
|
}
|
|
|
|
if (_logo) {
|
|
removeWidget(_logo);
|
|
_logo->setNext(nullptr);
|
|
delete _logo;
|
|
_logo = nullptr;
|
|
}
|
|
}
|
|
|
|
if (g_gui.xmlEval()->getVar("Globals.ShowSearchPic") == 1 && g_gui.theme()->supportsImages()) {
|
|
if (!_searchPic)
|
|
_searchPic = new GraphicsWidget(this, "Launcher.SearchPic");
|
|
_searchPic->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSearch));
|
|
|
|
if (_searchDesc) {
|
|
removeWidget(_searchDesc);
|
|
_searchDesc->setNext(nullptr);
|
|
delete _searchDesc;
|
|
_searchDesc = nullptr;
|
|
}
|
|
} else {
|
|
if (!_searchDesc)
|
|
_searchDesc = new StaticTextWidget(this, "Launcher.SearchDesc", _("Search:"));
|
|
|
|
if (_searchPic) {
|
|
removeWidget(_searchPic);
|
|
_searchPic->setNext(nullptr);
|
|
delete _searchPic;
|
|
_searchPic = nullptr;
|
|
}
|
|
}
|
|
|
|
removeWidget(_searchClearButton);
|
|
_searchClearButton->setNext(nullptr);
|
|
delete _searchClearButton;
|
|
_searchClearButton = addClearButton(this, "Launcher.SearchClearButton", kSearchClearCmd);
|
|
#endif
|
|
|
|
_w = g_system->getOverlayWidth();
|
|
_h = g_system->getOverlayHeight();
|
|
|
|
Dialog::reflowLayout();
|
|
}
|
|
|
|
bool LauncherDialog::checkModifier(int checkedModifier) {
|
|
int modifiers = g_system->getEventManager()->getModifierState();
|
|
return (modifiers & checkedModifier) != 0;
|
|
}
|
|
|
|
} // End of namespace GUI
|