scummvm/gui/launcher.cpp
Thierry Crozat 8b0b9f11c6 OSYSTEM: Add kFeatureNoQuit to remove Quit buttons and replace Quit with RTL
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.
2020-04-26 16:19:37 +01:00

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