aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Horn2008-09-01 17:30:03 +0000
committerMax Horn2008-09-01 17:30:03 +0000
commit027ae0a6f6bd7e7dfbfe6f7df0824596894f51ae (patch)
tree205993ffb25dcb2311e62b1871431eb6cf62185e
parent2db5747642446bad3e1824afd0358f51c1965c20 (diff)
parent852bc9dbb750b9995d31e70f4158c97d3758c46f (diff)
downloadscummvm-rg350-027ae0a6f6bd7e7dfbfe6f7df0824596894f51ae.tar.gz
scummvm-rg350-027ae0a6f6bd7e7dfbfe6f7df0824596894f51ae.tar.bz2
scummvm-rg350-027ae0a6f6bd7e7dfbfe6f7df0824596894f51ae.zip
First part of GSoC2008 RTL branch merge
svn-id: r34241
-rw-r--r--README125
-rw-r--r--backends/events/default/default-events.cpp60
-rw-r--r--backends/events/default/default-events.h4
-rw-r--r--base/commandLine.cpp1
-rw-r--r--base/main.cpp8
-rw-r--r--common/events.h22
-rw-r--r--engines/dialogs.cpp224
-rw-r--r--engines/dialogs.h74
-rw-r--r--engines/engine.cpp56
-rw-r--r--engines/engine.h30
-rw-r--r--engines/metaengine.h39
-rw-r--r--engines/module.mk4
-rw-r--r--gui/launcher.cpp221
-rw-r--r--gui/launcher.h7
-rw-r--r--gui/newgui.cpp6
-rw-r--r--gui/theme-config.cpp33
-rw-r--r--gui/themes/classic080.ini5
-rw-r--r--gui/themes/modern.ini2
18 files changed, 885 insertions, 36 deletions
diff --git a/README b/README
index 6f59e172bc..5a94749d3e 100644
--- a/README
+++ b/README
@@ -39,10 +39,12 @@ Table of Contents:
* 5.1 Command Line Options
* 5.2 Language Options
* 5.3 Graphics Filters
- * 5.4 Hotkeys
+ * 5.4 Global Menu
+ * 5.5 Hotkeys
6.0) Savegames
* 6.1 Autosaves
* 6.2 Converting savegames
+ * 6.3 Viewing/Loading savegames from the command line
7.0) Music and Sound
* 7.1 Adlib emulation
* 7.2 FluidSynth MIDI emulation
@@ -781,6 +783,7 @@ arguments -- see the next section.
-h, --help Display a brief help text and exit
-z, --list-games Display list of supported games and exit
-t, --list-targets Display list of configured targets and exit
+ --list-saves=TARGET Display a list of savegames for the game (TARGET) specified
-c, --config=CONFIG Use alternate configuration file
-p, --path=PATH Path to where the game is installed
@@ -968,7 +971,38 @@ Likewise, games that originally were using 640x480 (such as COMI or Broken Sword
will be scaled to 1280x960 and 1920x1440.
-5.4) Hot Keys:
+5.4) Global Menu:
+---- ------------
+
+The Global Menu is a general menu which is available to all of the game engines
+by pressing F6. From this menu there are the following buttons: Resume,
+Options, About, Return to Launcher, and Quit. Selecting 'Options' will display
+a dialog where basic audio settings, such as volume levels, can be adjusted.
+Selecting 'Return to Launcher' will close the current game and return the user
+back to the ScummVM Launcher, where another game may be selected to play.
+
+Note: Returning to the Launcher is not supported by all of the engines,
+ and the button will be disabled in the Global Menu if it is not supported.
+
+Engines which currently support Returning to the Launcher are:
+
+ AGI
+ AGOS
+ CINE
+ GOB
+ KYRA
+ LURE
+ PARALLACTION
+ QUEEN
+ SAGA
+ SCUMM
+ SKY
+ SWORD1
+ SWORD2
+ TOUCHE
+
+
+5.5) Hot Keys:
---- ---------
TODO
TODO: Rework this section to clearly state which hotkeys are implemented in *all*
@@ -982,7 +1016,8 @@ ScummVM supports various in-game hotkeys. They differ between SCUMM games and
other games.
Common:
- Cmd-q - Quit (Mac OS X)
+ F6 - Displays the Global Menu
+ Cmd-q - Quit (Mac OS X)
Ctrl-q - Quit (other unices including Linux)
Ctrl-z OR Alt-x - Quit (other platforms)
Ctrl-m - Toggle mouse capture
@@ -1138,45 +1173,93 @@ The platforms that currently have a different default directory are:
6.1) Autosaves:
---- ----------
-For some games (namely "Beneath a Steel Sky", "Flight of the Amazon
-Queen" and all SCUMM games), ScummVM will by default automatically
-save the current state every five minutes (adjustable via the
-"autosave_period" config setting). For the SCUMM engine, it will save
-in Slot 0. This savestate can then be loaded again via Ctrl-0, or the
-F5 menu.
+For some games, (namely "Beneath a Steel Sky", "Flight of the Amazon Queen",
+all AGI games, and all SCUMM games), ScummVM will by default automatically
+save the current state every five minutes (adjustable via the "autosave_period"
+config setting). For the AGI and SCUMM engines, it will save in Slot 0. For the
+SCUMM engine, this savestate can then be loaded again via Ctrl-0, or the F5
+menu.
6.2) Converting Savegames:
----- ----------
-Using savegames from original versions, isn't supported by all game engines. Only
-the following games, can use savedgames from their original versions.
+---- ---------------------
+Using savegames from original versions, isn't supported by all game engines.
+Only the following games, can use savegames from their original versions.
Elvira 1
- - Add 8 bytes (savedgame name) to the start of the savegame file
- - Rename the savedgame to 'elvira1.xxx'
+ - Add 8 bytes (savegame name) to the start of the savegame file
+ - Rename the savegame to 'elvira1.xxx'
Elvira 2
- - Add 8 bytes (savedgame name) to the start of the savegame file
- - Rename the savedgame to 'elvira2-pc.xxx' (DOS version) or
+ - Add 8 bytes (savegame name) to the start of the savegame file
+ - Rename the savegame to 'elvira2-pc.xxx' (DOS version) or
'elvira2.xxx' (Other versions)
Waxworks
- - Add 8 bytes (savedgame name) to the start of the savegame file
- - Rename the savedgame to 'waxworks-pc.xxx' (DOS version) or
+ - Add 8 bytes (savegame name) to the start of the savegame file
+ - Rename the savegame to 'waxworks-pc.xxx' (DOS version) or
'waxworks.xxx' (Other versions)
Simon the Sorcerer 1
- - Rename the savedgame to 'simon1.xxx'
+ - Rename the savegame to 'simon1.xxx'
Simon the Sorcerer 1
- - Rename the savedgame to 'simon2.xxx'
+ - Rename the savegame to 'simon2.xxx'
The Feeble Files
- - Rename the savedgame to 'feeble.xxx'
+ - Rename the savegame to 'feeble.xxx'
Where 'xxx' is exact the saved game slot (ie 001) under ScummVM
+6.3) Viewing/Loading savegames from the command line:
+---- ------------------------------------------------
+
+--list-saves:
+
+ This switch may be used to display a list of the current savegames
+ of the specified target game and their corresponding save slots.
+
+ Usage: --list-saves=[TARGET], where [TARGET] is the target game.
+
+ Engines which currently support --list-saves are:
+
+ AGI
+ AGOS
+ CINE
+ KYRA
+ LURE
+ PARALLACTION
+ QUEEN
+ SAGA
+ SCUMM
+ SKY
+ SWORD1
+ SWORD2
+ TOUCHE
+
+--save-slot/-x:
+
+ This switch may be used to load a savegame directly from the command line.
+
+ Usage: --save-slot[SLOT] or -x[SLOT], where [SLOT] is the save slot number.
+
+ Engines which currently support --save-slot/-x are:
+
+ AGI
+ CINE
+ KYRA
+ LURE
+ PARALLACTION
+ QUEEN
+ SAGA
+ SCUMM
+ SKY
+ SWORD1
+ SWORD2
+ TOUCHE
+
+
7.0) Music and Sound:
---- ----------------
diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp
index 0caba25792..65b375605b 100644
--- a/backends/events/default/default-events.cpp
+++ b/backends/events/default/default-events.cpp
@@ -93,7 +93,8 @@ DefaultEventManager::DefaultEventManager(OSystem *boss) :
_boss(boss),
_buttonState(0),
_modifierState(0),
- _shouldQuit(false) {
+ _shouldQuit(false),
+ _shouldRTL(false) {
assert(_boss);
@@ -200,6 +201,9 @@ DefaultEventManager::~DefaultEventManager() {
_boss->unlockMutex(_timeMutex);
_boss->unlockMutex(_recorderMutex);
+ if (!artificialEventQueue.empty())
+ artificialEventQueue.clear();
+
if (_playbackFile != NULL) {
delete _playbackFile;
}
@@ -349,7 +353,11 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
uint32 time = _boss->getMillis();
bool result;
- result = _boss->pollEvent(event);
+ if (!artificialEventQueue.empty()) {
+ event = artificialEventQueue.pop();
+ result = true;
+ } else
+ result = _boss->pollEvent(event);
if (_recordMode != kPassthrough) {
@@ -375,7 +383,6 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
switch (event.type) {
case Common::EVENT_KEYDOWN:
_modifierState = event.kbd.flags;
-
// init continuous event stream
// not done on PalmOS because keyboard is emulated and keyup is not generated
#if !defined(PALMOS_MODE)
@@ -384,7 +391,27 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_currentKeyDown.flags = event.kbd.flags;
_keyRepeatTime = time + kKeyRepeatInitialDelay;
#endif
+ // Global Main Menu
+ // FIXME: F6 is not the best trigger, it conflicts with some games!!!
+ if (event.kbd.keycode == Common::KEYCODE_F6)
+ if (g_engine && !g_engine->isPaused()) {
+ Common::Event menuEvent;
+ menuEvent.type = Common::EVENT_MAINMENU;
+
+ // FIXME: GSoC RTL branch passes the F6 key event to the
+ // engine, and also enqueues a EVENT_MAINMENU. For now,
+ // we just drop the key event and return an EVENT_MAINMENU
+ // instead. This way, we don't have to add special cases
+ // to engines (like it was the case for LURE in the RTL branch).
+ //
+ // However, this has other consequences, possibly negative ones.
+ // Like, what happens with key repeat for the trigger key?
+
+ //pushEvent(menuEvent);
+ event = menuEvent;
+ }
break;
+
case Common::EVENT_KEYUP:
_modifierState = event.kbd.flags;
if (event.kbd.keycode == _currentKeyDown.keycode) {
@@ -401,6 +428,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_mousePos = event.mouse;
_buttonState |= LBUTTON;
break;
+
case Common::EVENT_LBUTTONUP:
_mousePos = event.mouse;
_buttonState &= ~LBUTTON;
@@ -410,11 +438,26 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
_mousePos = event.mouse;
_buttonState |= RBUTTON;
break;
+
case Common::EVENT_RBUTTONUP:
_mousePos = event.mouse;
_buttonState &= ~RBUTTON;
break;
+ case Common::EVENT_MAINMENU:
+ if (g_engine && !g_engine->isPaused())
+ g_engine->mainMenuDialog();
+
+ if (_shouldQuit)
+ event.type = Common::EVENT_QUIT;
+ else if (_shouldRTL)
+ event.type = Common::EVENT_RTL;
+ break;
+
+ case Common::EVENT_RTL:
+ _shouldRTL = true;
+ break;
+
case Common::EVENT_QUIT:
if (ConfMan.getBool("confirm_exit")) {
if (g_engine)
@@ -425,6 +468,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
g_engine->pauseEngine(false);
} else
_shouldQuit = true;
+
break;
default:
@@ -447,4 +491,14 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
return result;
}
+void DefaultEventManager::pushEvent(Common::Event event) {
+
+ // If already received an EVENT_QUIT, don't add another one
+ if (event.type == Common::EVENT_QUIT) {
+ if (!_shouldQuit)
+ artificialEventQueue.push(event);
+ } else
+ artificialEventQueue.push(event);
+}
+
#endif // !defined(DISABLE_DEFAULT_EVENTMANAGER)
diff --git a/backends/events/default/default-events.h b/backends/events/default/default-events.h
index 98dcd4b3de..b2cd1354cc 100644
--- a/backends/events/default/default-events.h
+++ b/backends/events/default/default-events.h
@@ -48,6 +48,7 @@ class DefaultEventManager : public Common::EventManager {
int _buttonState;
int _modifierState;
bool _shouldQuit;
+ bool _shouldRTL;
class RandomSourceRecord {
public:
@@ -107,6 +108,7 @@ public:
~DefaultEventManager();
virtual bool pollEvent(Common::Event &event);
+ virtual void pushEvent(Common::Event event);
virtual void registerRandomSource(Common::RandomSource &rnd, const char *name);
virtual void processMillis(uint32 &millis);
@@ -114,6 +116,8 @@ public:
virtual int getButtonState() const { return _buttonState; }
virtual int getModifierState() const { return _modifierState; }
virtual int shouldQuit() const { return _shouldQuit; }
+ virtual int shouldRTL() const { return _shouldRTL; }
+ virtual void resetRTL() { _shouldRTL = false; }
};
#endif
diff --git a/base/commandLine.cpp b/base/commandLine.cpp
index f8ca8a90cd..47ba3cb9ed 100644
--- a/base/commandLine.cpp
+++ b/base/commandLine.cpp
@@ -56,6 +56,7 @@ static const char HELP_STRING[] =
" -h, --help Display a brief help text and exit\n"
" -z, --list-games Display list of supported games and exit\n"
" -t, --list-targets Display list of configured targets and exit\n"
+ " --list-saves=TARGET Display a list of savegames for the game (TARGET) specified\n"
"\n"
" -c, --config=CONFIG Use alternate configuration file\n"
" -p, --path=PATH Path to where the game is installed\n"
diff --git a/base/main.cpp b/base/main.cpp
index 115a920f36..4283b6cacf 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -38,6 +38,7 @@
#include "base/version.h"
#include "common/config-manager.h"
+#include "common/events.h"
#include "common/file.h"
#include "common/fs.h"
#include "common/system.h"
@@ -200,7 +201,8 @@ static int runGame(const EnginePlugin *plugin, OSystem &system, const Common::St
// Reset the file/directory mappings
Common::File::resetDefaultDirectories();
- return 0;
+ // If result=1 return to the launcher, else quit ScummVM
+ return result;
}
@@ -286,6 +288,10 @@ extern "C" int scummvm_main(int argc, char *argv[]) {
// TODO: We should keep running if starting the selected game failed
// (so instead of just quitting, show a nice error dialog to the
// user and let him pick another game).
+
+ // Reset RTL flag in case we want to load another engine
+ g_system->getEventManager()->resetRTL();
+
if (result == 0)
break;
diff --git a/common/events.h b/common/events.h
index d0cb740692..3e4fdbf5ef 100644
--- a/common/events.h
+++ b/common/events.h
@@ -27,6 +27,7 @@
#define COMMON_EVENTS_H
#include "common/keyboard.h"
+#include "common/queue.h"
#include "common/rect.h"
#include "common/system.h"
#include "common/noncopyable.h"
@@ -58,6 +59,9 @@ enum EventType {
EVENT_MBUTTONDOWN = 13,
EVENT_MBUTTONUP = 14,
+ EVENT_MAINMENU = 15,
+ EVENT_RTL = 16,
+
EVENT_QUIT = 10,
EVENT_SCREEN_CHANGED = 11,
/**
@@ -142,6 +146,11 @@ public:
*/
virtual bool pollEvent(Common::Event &event) = 0;
+ /**
+ * Pushes a "fake" event of the specified type into the event queue
+ */
+ virtual void pushEvent(Common::Event event) = 0;
+
/** Register random source so it can be serialized in game test purposes **/
virtual void registerRandomSource(Common::RandomSource &rnd, const char *name) = 0;
@@ -166,6 +175,16 @@ public:
*/
virtual int shouldQuit() const = 0;
+ /**
+ * Should we return to the launcher?
+ */
+ virtual int shouldRTL() const = 0;
+
+ /**
+ * We have returned to the launcher, and the _shouldRTL should be reset to false
+ */
+ virtual void resetRTL() = 0;
+
// Optional: check whether a given key is currently pressed ????
//virtual bool isKeyPressed(int keycode) = 0;
@@ -173,6 +192,9 @@ public:
// TODO: Consider removing OSystem::getScreenChangeID and
// replacing it by a generic getScreenChangeID method here
+protected:
+
+ Common::Queue<Common::Event> artificialEventQueue;
};
} // End of namespace Common
diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp
new file mode 100644
index 0000000000..4f95b12143
--- /dev/null
+++ b/engines/dialogs.cpp
@@ -0,0 +1,224 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#include "base/version.h"
+
+#include "common/config-manager.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/events.h"
+
+#include "graphics/scaler.h"
+
+#include "gui/about.h"
+#include "gui/eval.h"
+#include "gui/newgui.h"
+#include "gui/ListWidget.h"
+
+#include "engines/dialogs.h"
+#include "engines/engine.h"
+#include "engines/metaengine.h"
+
+#ifdef SMALL_SCREEN_DEVICE
+#include "gui/KeysDialog.h"
+#endif
+
+using GUI::CommandSender;
+using GUI::StaticTextWidget;
+using GUI::kButtonWidth;
+using GUI::kButtonHeight;
+using GUI::kBigButtonWidth;
+using GUI::kBigButtonHeight;
+using GUI::kCloseCmd;
+using GUI::kTextAlignCenter;
+using GUI::kTextAlignLeft;
+using GUI::WIDGET_ENABLED;
+
+typedef GUI::OptionsDialog GUI_OptionsDialog;
+typedef GUI::Dialog GUI_Dialog;
+
+GlobalDialog::GlobalDialog(String name)
+ : GUI::Dialog(name) {
+_drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;}
+
+enum {
+ kSaveCmd = 'SAVE',
+ kLoadCmd = 'LOAD',
+ kPlayCmd = 'PLAY',
+ kOptionsCmd = 'OPTN',
+ kHelpCmd = 'HELP',
+ kAboutCmd = 'ABOU',
+ kQuitCmd = 'QUIT',
+ kRTLCmd = 'RTL',
+ kChooseCmd = 'CHOS'
+};
+
+MainMenuDialog::MainMenuDialog(Engine *engine)
+ : GlobalDialog("globalmain"), _engine(engine) {
+
+ new StaticTextWidget(this, "global_title", "ScummVM");
+
+ new StaticTextWidget(this, "global_version", gScummVMVersionDate);
+
+ new GUI::ButtonWidget(this, "globalmain_resume", "Resume", kPlayCmd, 'P');
+
+// new GUI::ButtonWidget(this, "globalmain_load", "Load", kLoadCmd, 'L');
+// new GUI::ButtonWidget(this, "globalmain_save", "Save", kSaveCmd, 'S');
+
+ new GUI::ButtonWidget(this, "globalmain_options", "Options", kOptionsCmd, 'O');
+
+ new GUI::ButtonWidget(this, "globalmain_about", "About", kAboutCmd, 'A');
+
+ _rtlButton = new GUI::ButtonWidget(this, "globalmain_rtl", "Return to Launcher", kRTLCmd, 'R');
+ // '0' corresponds to the kSupportsRTL MetaEngineFeature
+ _rtlButton->setEnabled(_engine->hasFeature(0));
+
+
+ new GUI::ButtonWidget(this, "globalmain_quit", "Quit", kQuitCmd, 'Q');
+
+ _aboutDialog = new GUI::AboutDialog();
+ _optionsDialog = new ConfigDialog();
+}
+
+MainMenuDialog::~MainMenuDialog() {
+ delete _aboutDialog;
+ delete _optionsDialog;
+}
+
+void MainMenuDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kPlayCmd:
+ close();
+ break;
+ case kOptionsCmd:
+ _optionsDialog->runModal();
+ break;
+ case kAboutCmd:
+ _aboutDialog->runModal();
+ break;
+ case kRTLCmd: {
+ Common::Event eventRTL;
+ eventRTL.type = Common::EVENT_RTL;
+ g_system->getEventManager()->pushEvent(eventRTL);
+ close();
+ }
+ break;
+ case kQuitCmd: {
+ Common::Event eventQ;
+ eventQ.type = Common::EVENT_QUIT;
+ g_system->getEventManager()->pushEvent(eventQ);
+ close();
+ }
+ break;
+ default:
+ GlobalDialog::handleCommand(sender, cmd, data);
+ }
+}
+
+enum {
+ kOKCmd = 'ok '
+};
+
+enum {
+ kKeysCmd = 'KEYS'
+};
+
+// FIXME: We use the empty string as domain name here. This tells the
+// ConfigManager to use the 'default' domain for all its actions. We do that
+// to get as close as possible to editing the 'active' settings.
+//
+// However, that requires bad & evil hacks in the ConfigManager code,
+// and even then still doesn't work quite correctly.
+// For example, if the transient domain contains 'false' for the 'fullscreen'
+// flag, but the user used a hotkey to switch to windowed mode, then the dialog
+// will display the wrong value anyway.
+//
+// Proposed solution consisting of multiple steps:
+// 1) Add special code to the open() code that reads out everything stored
+// in the transient domain that is controlled by this dialog, and updates
+// the dialog accordingly.
+// 2) Even more code is added to query the backend for current settings, like
+// the fullscreen mode flag etc., and also updates the dialog accordingly.
+// 3) The domain being edited is set to the active game domain.
+// 4) If the dialog is closed with the "OK" button, then we remove everything
+// stored in the transient domain (or at least everything corresponding to
+// switches in this dialog.
+// If OTOH the dialog is closed with "Cancel" we do no such thing.
+//
+// These changes will achieve two things at once: Allow us to get rid of using
+// "" as value for the domain, and in fact provide a somewhat better user
+// experience at the same time.
+ConfigDialog::ConfigDialog()
+ : GUI::OptionsDialog("", "scummconfig") {
+
+ //
+ // Sound controllers
+ //
+
+ addVolumeControls(this, "scummconfig_");
+
+ //
+ // Some misc options
+ //
+
+ // SCUMM has a talkspeed range of 0-9
+ addSubtitleControls(this, "scummconfig_", 9);
+
+ //
+ // Add the buttons
+ //
+
+ new GUI::ButtonWidget(this, "scummconfig_ok", "OK", GUI::OptionsDialog::kOKCmd, 'O');
+ new GUI::ButtonWidget(this, "scummconfig_cancel", "Cancel", kCloseCmd, 'C');
+
+#ifdef SMALL_SCREEN_DEVICE
+ new GUI::ButtonWidget(this, "scummconfig_keys", "Keys", kKeysCmd, 'K');
+
+ //
+ // Create the sub dialog(s)
+ //
+
+ _keysDialog = new GUI::KeysDialog();
+#endif
+}
+
+ConfigDialog::~ConfigDialog() {
+#ifdef SMALL_SCREEN_DEVICE
+ delete _keysDialog;
+#endif
+}
+
+void ConfigDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ switch (cmd) {
+ case kKeysCmd:
+
+#ifdef SMALL_SCREEN_DEVICE
+ _keysDialog->runModal();
+#endif
+ break;
+ default:
+ GUI_OptionsDialog::handleCommand (sender, cmd, data);
+ }
+}
+
diff --git a/engines/dialogs.h b/engines/dialogs.h
new file mode 100644
index 0000000000..61c06006cb
--- /dev/null
+++ b/engines/dialogs.h
@@ -0,0 +1,74 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#ifndef GLOBAL_DIALOGS_H
+#define GLOBAL_DIALOGS_H
+
+#include "common/str.h"
+#include "gui/dialog.h"
+#include "gui/options.h"
+#include "gui/widget.h"
+
+#include "engines/engine.h"
+
+
+class GlobalDialog : public GUI::Dialog {
+public:
+ GlobalDialog(Common::String name);
+
+protected:
+ typedef Common::String String;
+};
+
+
+class MainMenuDialog : public GlobalDialog {
+public:
+ MainMenuDialog(Engine *engine);
+ ~MainMenuDialog();
+
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+
+protected:
+ Engine *_engine;
+
+ GUI::ButtonWidget *_rtlButton;
+ GUI::Dialog *_aboutDialog;
+ GUI::Dialog *_optionsDialog;
+
+};
+
+class ConfigDialog : public GUI::OptionsDialog {
+protected:
+#ifdef SMALL_SCREEN_DEVICE
+ GUI::Dialog *_keysDialog;
+#endif
+
+public:
+ ConfigDialog();
+ ~ConfigDialog();
+
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+};
+
+#endif
diff --git a/engines/engine.cpp b/engines/engine.cpp
index 757a77f82b..4840b19838 100644
--- a/engines/engine.cpp
+++ b/engines/engine.cpp
@@ -36,7 +36,10 @@
#include "common/savefile.h"
#include "common/system.h"
#include "gui/message.h"
+#include "gui/newgui.h"
#include "sound/mixer.h"
+#include "engines/dialogs.h"
+#include "engines/metaengine.h"
#ifdef _WIN32_WCE
extern bool isSmartphone(void);
@@ -54,7 +57,8 @@ Engine::Engine(OSystem *syst)
_saveFileMan(_system->getSavefileManager()),
_targetName(ConfMan.getActiveDomainName()),
_gameDataPath(ConfMan.get("path")),
- _pauseLevel(0) {
+ _pauseLevel(0),
+ _mainMenuDialog(NULL) {
g_engine = this;
_autosavePeriod = ConfMan.getInt("autosave_period");
@@ -72,7 +76,8 @@ Engine::Engine(OSystem *syst)
Engine::~Engine() {
_mixer->stopAll();
-
+
+ delete _mainMenuDialog;
g_engine = NULL;
}
@@ -210,3 +215,50 @@ void Engine::pauseEngineIntern(bool pause) {
// By default, just (un)pause all digital sounds
_mixer->pauseAll(pause);
}
+
+void Engine::mainMenuDialog() {
+ if (!_mainMenuDialog)
+ _mainMenuDialog = new MainMenuDialog(this);
+ runDialog(*_mainMenuDialog);
+ syncSoundSettings();
+}
+
+int Engine::runDialog(Dialog &dialog) {
+
+ pauseEngine(true);
+
+ int result = dialog.runModal();
+
+ pauseEngine(false);
+
+ return result;
+}
+
+void Engine::syncSoundSettings() {
+
+ // Sync the engine with the config manager
+ int soundVolumeMusic = ConfMan.getInt("music_volume");
+ int soundVolumeSFX = ConfMan.getInt("sfx_volume");
+ int soundVolumeSpeech = ConfMan.getInt("speech_volume");
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSFX);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech);
+}
+
+void Engine::quitGame() {
+ Common::Event event;
+
+ event.type = Common::EVENT_QUIT;
+ _eventMan->pushEvent(event);
+}
+
+bool Engine::hasFeature(int f) {
+ const EnginePlugin *plugin = 0;
+ Common::String gameid = ConfMan.get("gameid");
+ gameid.toLowercase();
+ EngineMan.findGame(gameid, &plugin);
+
+ return ( (*plugin)->hasFeature((MetaEngine::MetaEngineFeature)f) );
+}
+
diff --git a/engines/engine.h b/engines/engine.h
index 73d529cc62..d2f0849b51 100644
--- a/engines/engine.h
+++ b/engines/engine.h
@@ -25,10 +25,12 @@
#ifndef ENGINES_ENGINE_H
#define ENGINES_ENGINE_H
+#include "common/events.h"
#include "common/scummsys.h"
#include "common/str.h"
class OSystem;
+
namespace Audio {
class Mixer;
}
@@ -39,8 +41,11 @@ namespace Common {
}
namespace GUI {
class Debugger;
+ class Dialog;
}
+using GUI::Dialog;
+
class Engine {
public:
OSystem *_system;
@@ -50,6 +55,9 @@ public:
protected:
Common::EventManager *_eventMan;
Common::SaveFileManager *_saveFileMan;
+
+ Dialog *_mainMenuDialog;
+ virtual int runDialog(Dialog &dialog);
const Common::String _targetName; // target name for saves
const Common::String _gameDataPath;
@@ -109,10 +117,32 @@ public:
void pauseEngine(bool pause);
/**
+ * Quit the engine, sends a Quit event to the Event Manager
+ */
+ void quitGame();
+
+ /**
* Return whether the engine is currently paused or not.
*/
bool isPaused() const { return _pauseLevel != 0; }
+ /**
+ * Return whether or not the ENGINE should quit
+ */
+ bool quit() const { return (_eventMan->shouldQuit() || _eventMan->shouldRTL()); }
+
+ /** Run the Global Main Menu Dialog
+ */
+ virtual void mainMenuDialog();
+
+ /** Sync the engine's sound settings with the config manager
+ */
+ virtual void syncSoundSettings();
+
+ /** Determine whether the engine supports the specified MetaEngine feature
+ */
+ virtual bool hasFeature(int f);
+
public:
/** Setup the backend's graphics mode. */
diff --git a/engines/metaengine.h b/engines/metaengine.h
index aef860e0f9..c911e1c2ae 100644
--- a/engines/metaengine.h
+++ b/engines/metaengine.h
@@ -91,6 +91,45 @@ public:
virtual SaveStateList listSaves(const char *target) const {
return SaveStateList();
}
+
+ /**
+ * Remove the specified save state.
+ *
+ * For most engines this just involves a call removeSaveFile().
+ * Engines which keep an index file will also update it accordingly.
+ *
+ * @param slot slot number of the save state to be removed
+ * @param saveNames a list of all the save state description names
+ */
+ virtual void removeSaveState(int slot, Common::StringList saveNames) const {};
+
+
+ /** @name MetaEngineFeature flags */
+ //@{
+
+ /**
+ * A feature in this context means an ability of the engine which can be
+ * either on or off. Examples include:
+ * - Listing Save States (--list-saves)
+ * - Loading from the Launcher (-x)
+ * - Deleting Saves from the Launcher
+ *
+ * These determine whether the features will be available to the engine
+ * in the launcher.
+ */
+ enum MetaEngineFeature {
+ kSupportsRTL = 0,
+ kSupportsListSaves = 1,
+ kSupportsDirectLoad = 2,
+ kSupportsDeleteSave = 3
+ };
+
+ /**
+ * Determine whether the engine supports the specified MetaEngine feature
+ */
+ virtual bool hasFeature(MetaEngineFeature f) const { return false; };
+
+ //@}
};
diff --git a/engines/module.mk b/engines/module.mk
index 6cfe9b36fa..f7dd71f403 100644
--- a/engines/module.mk
+++ b/engines/module.mk
@@ -1,7 +1,7 @@
MODULE := engines
MODULE_OBJS := \
- engine.o
-
+ engine.o \
+ dialogs.o
# Include common rules
include $(srcdir)/rules.mk
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index 7cfe3943a7..40e0c3685e 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -29,6 +29,7 @@
#include "common/events.h"
#include "common/fs.h"
#include "common/util.h"
+#include "common/savefile.h"
#include "common/system.h"
#include "gui/about.h"
@@ -61,7 +62,10 @@ enum {
kAddGameCmd = 'ADDG',
kEditGameCmd = 'EDTG',
kRemoveGameCmd = 'REMG',
+ kLoadGameCmd = 'LOAD',
kQuitCmd = 'QUIT',
+ kChooseCmd = 'CHOS',
+ kDelCmd = 'DEL',
kCmdGlobalGraphicsOverride = 'OGFX',
@@ -468,6 +472,140 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
}
}
+class SaveLoadChooser : public GUI::Dialog {
+ typedef Common::String String;
+ typedef Common::StringList StringList;
+protected:
+ bool _delSave;
+ bool _delSupport;
+ GUI::ListWidget *_list;
+ GUI::ButtonWidget *_chooseButton;
+ GUI::ButtonWidget *_deleteButton;
+ GUI::GraphicsWidget *_gfxWidget;
+ GUI::ContainerWidget *_container;
+
+ uint8 _fillR, _fillG, _fillB;
+
+ void updateInfos(bool redraw);
+public:
+ SaveLoadChooser(const String &title, const String &buttonLabel);
+ ~SaveLoadChooser();
+
+ virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
+ const String &getResultString() const;
+ void setList(const StringList& list);
+ int runModal(bool delSupport);
+
+ virtual void reflowLayout();
+
+ bool delSave() { return _delSave; };
+};
+
+SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel)
+ : Dialog("scummsaveload"), _delSave(0), _delSupport(0), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0) {
+
+ _drawingHints |= GUI::THEME_HINT_SPECIAL_COLOR;
+
+ new StaticTextWidget(this, "scummsaveload_title", title);
+
+ // Add choice list
+ _list = new GUI::ListWidget(this, "scummsaveload_list");
+ _list->setNumberingMode(GUI::kListNumberingZero);
+
+ _container = new GUI::ContainerWidget(this, 0, 0, 10, 10);
+ _container->setHints(GUI::THEME_HINT_USE_SHADOW);
+
+ _gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10);
+
+ // Buttons
+ new GUI::ButtonWidget(this, "scummsaveload_cancel", "Cancel", kCloseCmd, 0);
+ _chooseButton = new GUI::ButtonWidget(this, "scummsaveload_choose", buttonLabel, kChooseCmd, 0);
+ _chooseButton->setEnabled(false);
+
+ _deleteButton = new GUI::ButtonWidget(this, "scummsaveload_delete", "Delete", kDelCmd, 0);
+ _deleteButton->setEnabled(false);
+}
+
+SaveLoadChooser::~SaveLoadChooser() {
+}
+
+const Common::String &SaveLoadChooser::getResultString() const {
+ return _list->getSelectedString();
+}
+
+void SaveLoadChooser::setList(const StringList& list) {
+ _list->setList(list);
+}
+
+int SaveLoadChooser::runModal(bool delSupport) {
+ if (_gfxWidget)
+ _gfxWidget->setGfx(0);
+ _delSave = false;
+ _delSupport = delSupport;
+ int ret = Dialog::runModal();
+ return ret;
+}
+
+void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+ int selItem = _list->getSelected();
+ switch (cmd) {
+ case GUI::kListItemActivatedCmd:
+ case GUI::kListItemDoubleClickedCmd:
+ if (selItem >= 0) {
+ if (!getResultString().empty()) {
+ _list->endEditMode();
+ setResult(selItem);
+ close();
+ }
+ }
+ break;
+ case kChooseCmd:
+ _list->endEditMode();
+ setResult(selItem);
+ close();
+ break;
+ case GUI::kListSelectionChangedCmd: {
+ if (_gfxWidget) {
+ updateInfos(true);
+ }
+
+ // Disable these buttons if nothing is selected, or if an empty
+ // list item is selected.
+ _chooseButton->setEnabled(selItem >= 0 && (!getResultString().empty()));
+ _chooseButton->draw();
+ // Delete will always be disabled if the engine doesn't support it.
+ _deleteButton->setEnabled(_delSupport && (selItem >= 0) && (!getResultString().empty()));
+ _deleteButton->draw();
+ } break;
+ case kDelCmd:
+ setResult(selItem);
+ _delSave = true;
+
+ // Disable these buttons again after deleteing a selection
+ _chooseButton->setEnabled(false);
+ _deleteButton->setEnabled(false);
+
+ close();
+ break;
+ case kCloseCmd:
+ setResult(-1);
+ default:
+ Dialog::handleCommand(sender, cmd, data);
+ }
+}
+
+void SaveLoadChooser::reflowLayout() {
+ _container->setFlags(GUI::WIDGET_INVISIBLE);
+ _gfxWidget->setFlags(GUI::WIDGET_INVISIBLE);
+ Dialog::reflowLayout();
+}
+
+void SaveLoadChooser::updateInfos(bool redraw) {
+ _gfxWidget->setGfx(-1, -1, _fillR, _fillG, _fillB);
+ if (redraw)
+ _gfxWidget->draw();
+}
+
#pragma mark -
@@ -501,6 +639,8 @@ LauncherDialog::LauncherDialog()
new ButtonWidget(this, "launcher_options_button", "Options", kOptionsCmd, 'O');
_startButton =
new ButtonWidget(this, "launcher_start_button", "Start", kStartCmd, 'S');
+
+ new ButtonWidget(this, "launcher_loadGame_button", "Load", kLoadGameCmd, 'L');
// Above the lowest button rows: two more buttons (directly below the list box)
_addButton =
@@ -529,6 +669,9 @@ LauncherDialog::LauncherDialog()
// Create file browser dialog
_browser = new BrowserDialog("Select directory with game data", true);
+
+ // Create Load dialog
+ _loadDialog = new SaveLoadChooser("Load game:", "Load");
}
void LauncherDialog::selectGame(const String &name) {
@@ -546,6 +689,7 @@ void LauncherDialog::selectGame(const String &name) {
LauncherDialog::~LauncherDialog() {
delete _browser;
+ delete _loadDialog;
}
void LauncherDialog::open() {
@@ -795,6 +939,80 @@ void LauncherDialog::editGame(int item) {
}
}
+void LauncherDialog::loadGame(int item) {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ String gameId = ConfMan.get("gameid", _domains[item]);
+ if (gameId.empty())
+ gameId = _domains[item];
+
+ const EnginePlugin *plugin = 0;
+ GameDescriptor game = EngineMan.findGame(gameId, &plugin);
+
+ String description = _domains[item];
+ description.toLowercase();
+
+ int idx;
+ if (plugin) {
+ bool delSupport = (*plugin)->hasFeature(MetaEngine::kSupportsDeleteSave);
+
+ if ((*plugin)->hasFeature(MetaEngine::kSupportsListSaves) &&
+ (*plugin)->hasFeature(MetaEngine::kSupportsDirectLoad))
+ {
+ do {
+ Common::StringList saveNames = generateSavegameList(item, plugin);
+ _loadDialog->setList(saveNames);
+ SaveStateList saveList = (*plugin)->listSaves(description.c_str());
+ idx = _loadDialog->runModal(delSupport);
+ if (idx >= 0) {
+ // Delete the savegame
+ if (_loadDialog->delSave()) {
+ String filename = saveList[idx].filename();
+ //printf("Deleting file: %s\n", filename.c_str());
+ MessageDialog alert("Do you really want to delete this savegame?",
+ "Yes", "No");
+ if (alert.runModal() == GUI::kMessageOK) {
+ saveFileMan->removeSavefile(filename.c_str());
+ if ((saveList.size() - 1) == 0)
+ ConfMan.setInt("save_slot", -1);
+ }
+ }
+ // Load the savegame
+ else {
+ int slot = atoi(saveList[idx].save_slot().c_str());
+ //const char *file = saveList[idx].filename().c_str();
+ //printf("Loading slot: %d\n", slot);
+ //printf("Loading file: %s\n", file);
+ ConfMan.setActiveDomain(_domains[item]);
+ ConfMan.setInt("save_slot", slot);
+ close();
+ }
+ }
+ }
+ while (_loadDialog->delSave());
+ } else {
+ MessageDialog dialog
+ ("Sorry, this game does not yet 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();
+ }
+}
+
+Common::StringList LauncherDialog::generateSavegameList(int item, const EnginePlugin *plugin) {
+ String description = _domains[item];
+ description.toLowercase();
+
+ StringList saveNames;
+ SaveStateList saveList = (*plugin)->listSaves(description.c_str());
+
+ for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x)
+ saveNames.push_back(x->description().c_str());
+
+ return saveNames;
+}
+
void LauncherDialog::handleKeyDown(Common::KeyState state) {
Dialog::handleKeyDown(state);
updateButtons();
@@ -818,6 +1036,9 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
case kEditGameCmd:
editGame(item);
break;
+ case kLoadGameCmd:
+ loadGame(item);
+ break;
case kOptionsCmd: {
GlobalOptionsDialog options;
options.runModal();
diff --git a/gui/launcher.h b/gui/launcher.h
index a9d09bf109..a26651eef5 100644
--- a/gui/launcher.h
+++ b/gui/launcher.h
@@ -34,11 +34,10 @@ namespace GUI {
class BrowserDialog;
class ListWidget;
class GraphicsWidget;
-
+class SaveLoadChooser;
Common::String addGameToConf(const GameDescriptor &result);
-
class LauncherDialog : public Dialog {
typedef Common::String String;
typedef Common::StringList StringList;
@@ -62,6 +61,7 @@ protected:
#endif
StringList _domains;
BrowserDialog *_browser;
+ SaveLoadChooser *_loadDialog;
virtual void reflowLayout();
@@ -73,6 +73,9 @@ protected:
virtual void addGame();
void removeGame(int item);
void editGame(int item);
+ void loadGame(int item);
+
+ StringList generateSavegameList(int item, const EnginePlugin *plugin);
void selectGame(const String &name);
};
diff --git a/gui/newgui.cpp b/gui/newgui.cpp
index 618c7bc873..b892fe076a 100644
--- a/gui/newgui.cpp
+++ b/gui/newgui.cpp
@@ -25,6 +25,7 @@
#include "common/events.h"
#include "common/system.h"
#include "common/util.h"
+#include "engines/engine.h"
#include "graphics/cursorman.h"
#include "gui/newgui.h"
#include "gui/dialog.h"
@@ -255,7 +256,7 @@ void NewGui::runLoop() {
Common::Event event;
while (eventMan->pollEvent(event)) {
- if (activeDialog != getTopDialog() && event.type != Common::EVENT_QUIT && event.type != Common::EVENT_SCREEN_CHANGED)
+ if (activeDialog != getTopDialog() && event.type != Common::EVENT_SCREEN_CHANGED)
continue;
Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y);
@@ -313,7 +314,8 @@ void NewGui::runLoop() {
activeDialog->handleMouseWheel(mouse.x, mouse.y, 1);
break;
case Common::EVENT_QUIT:
- _system->quit();
+ if (!g_engine)
+ _system->quit();
return;
case Common::EVENT_SCREEN_CHANGED:
screenChange();
diff --git a/gui/theme-config.cpp b/gui/theme-config.cpp
index 47f60d3d7b..9fc23c5e7d 100644
--- a/gui/theme-config.cpp
+++ b/gui/theme-config.cpp
@@ -95,6 +95,7 @@ const char *Theme::_defaultConfigINI =
"scummsaveload_thumbnail=(parent.w - (kThumbnailWidth + 22)) 18\n"
"scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight\n"
"scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h\n"
+"scummsaveload_delete=prev.x2 prev.y prev.w prev.h\n"
"scummsaveload_extinfo.visible=false\n"
"\n"
"# MM NES resolution\n"
@@ -118,6 +119,7 @@ const char *Theme::_defaultConfigINI =
"def_aboutXOff=8\n"
"def_aboutYOff=5\n"
"def_aboutOuterBorder=80\n"
+"def_globalmainHOffset=52\n"
"def_scummmainHOffset=12\n"
"def_scummmainVSpace=7\n"
"def_scummmainVAddOff=3\n"
@@ -171,10 +173,11 @@ const char *Theme::_defaultConfigINI =
"launcher_options_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_start_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"top=(top - buttonHeight * 2)\n"
-"numButtons=3\n"
+"numButtons=4\n"
"space=10\n"
"butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)\n"
-"launcher_addGame_button=hBorder top butWidth buttonHeight\n"
+"launcher_loadGame_button=hBorder top butWidth buttonHeight\n"
+"launcher_addGame_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_editGame_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_removeGame_button=(prev.x2 + space) prev.y prev.w prev.h\n"
"launcher_list=hBorder (kLineHeight + 16) (w - 2 * hBorder) (top - kLineHeight - 20)\n"
@@ -371,6 +374,7 @@ const char *Theme::_defaultConfigINI =
"scummsaveload_thumbnail.fillB=0\n"
"scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight\n"
"scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h\n"
+"scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h\n"
"scummsaveload_extinfo.visible=true\n"
"\n"
"############################################\n"
@@ -482,6 +486,31 @@ const char *Theme::_defaultConfigINI =
"smH=(smY + scummmainVSpace)\n"
"scummmain=((w - smW) / 2) ((h - smH) / 2) smW smH\n"
"\n"
+"#### Global Main Menu Dialog"
+"[globalmain]\n"
+"# note that globalmain size depends on overall height\n"
+"hBorder=10\n"
+"gmW=(scummmainButtonWidth + (2 * scummmainHOffset) + 80)\n"
+"global_title=hBorder 8 (gmW - 2 * hBorder) kLineHeight\n"
+"global_title.align=kTextAlignCenter\n"
+"global_version=hBorder 25 (gmW - 2 * hBorder) kLineHeight\n"
+"global_version.align=kTextAlignCenter\n"
+"gmY=((scummmainVSpace * 7)+ scummmainVAddOff)\n"
+"globalmain_resume=globalmainHOffset gmY scummmainButtonWidth scummmainButtonHeight\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"gmY=(gmY + scummmainVSpace)\n"
+"globalmain_options=prev.x gmY prev.w prev.h\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"globalmain_about=prev.x gmY prev.w prev.h\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"gmY=(gmY + scummmainVSpace)\n"
+"globalmain_rtl=prev.x gmY prev.w prev.h\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"globalmain_quit=prev.x gmY prev.w prev.h\n"
+"gmY=(gmY + scummmainButtonHeight + scummmainVAddOff)\n"
+"gmH=(gmY + scummmainVSpace)\n"
+"globalmain=((w - gmW) / 2) ((h - gmH) / 2) gmW gmH\n"
+"\n"
"# PSP GUI\n"
"[480x272]\n"
"def_buttonWidth=100\n"
diff --git a/gui/themes/classic080.ini b/gui/themes/classic080.ini
index b5c911bada..766059ecb5 100644
--- a/gui/themes/classic080.ini
+++ b/gui/themes/classic080.ini
@@ -82,13 +82,14 @@ hBorder=10
launcher_version=hBorder 8 (w - 2 * hBorder) kLineHeight
launcher_version.align=kTextAlignCenter
top=(h - 8 - buttonHeight)
-numButtons=4
+numButtons=3
space=8
butWidth=((w - 2 * hBorder - space * (numButtons - 1)) / numButtons)
launcher_quit_button=hBorder top butWidth buttonHeight
launcher_about_button=(prev.x2 + space) prev.y prev.w prev.h
launcher_options_button=(prev.x2 + space) prev.y prev.w prev.h
launcher_start_button=(prev.x2 + space) prev.y prev.w prev.h
+launcher_loadGame_button=(prev.x2 + space) prev.y prev.w prev.h
top=(top - buttonHeight * 2)
numButtons=3
space=10
@@ -289,6 +290,7 @@ scummsaveload_thumbnail.fillG=0
scummsaveload_thumbnail.fillB=0
scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
+scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
scummsaveload_extinfo.visible=true
############################################
@@ -441,6 +443,7 @@ scummsaveload_list=10 18 prev.w (parent.h - 17 - buttonHeight - 8 - self.y)
scummsaveload_thumbnail=(parent.w - (kThumbnailWidth + 22)) 18
scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
+scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
scummsaveload_extinfo.visible=false
# MM NES resolution
diff --git a/gui/themes/modern.ini b/gui/themes/modern.ini
index 87ef0bcbb9..8dbe7331f8 100644
--- a/gui/themes/modern.ini
+++ b/gui/themes/modern.ini
@@ -250,6 +250,7 @@ space1=20
space2=5
launcher_list=insetX insetY insetW insetH
launcher_start_button=(prev.x2 + 17) prev.y buttonWidth buttonHeight
+launcher_loadGame_button=prev.x (prev.y2 + space2) prev.w prev.h
launcher_addGame_button=prev.x (prev.y2 + space1) prev.w prev.h
launcher_editGame_button=prev.x (prev.y2 + space2) prev.w prev.h
launcher_removeGame_button=prev.x (prev.y2 + space2) prev.w prev.h
@@ -456,6 +457,7 @@ scummsaveload_thumbnail.fillG=0
scummsaveload_thumbnail.fillB=0
scummsaveload_cancel=(parent.w - 2 * (buttonWidth + 10)) (parent.h - buttonHeight - 8) buttonWidth buttonHeight
scummsaveload_choose=(prev.x2 + 10) prev.y prev.w prev.h
+scummsaveload_delete=prev.x (prev.y - 30) prev.w prev.h
scummsaveload_extinfo.visible=true
############################################