ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

dialogs.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "base/version.h"
00024 
00025 #include "common/config-manager.h"
00026 #include "common/events.h"
00027 #include "common/str.h"
00028 #include "common/system.h"
00029 #include "common/translation.h"
00030 
00031 #include "gui/about.h"
00032 #include "gui/gui-manager.h"
00033 #include "gui/message.h"
00034 #include "gui/options.h"
00035 #include "gui/saveload.h"
00036 #include "gui/ThemeEngine.h"
00037 #include "gui/ThemeEval.h"
00038 #include "gui/widget.h"
00039 #include "gui/widgets/tab.h"
00040 
00041 #include "graphics/font.h"
00042 
00043 #include "engines/dialogs.h"
00044 #include "engines/engine.h"
00045 #include "engines/metaengine.h"
00046 
00047 #ifdef GUI_ENABLE_KEYSDIALOG
00048 #include "gui/KeysDialog.h"
00049 #endif
00050 
00051 MainMenuDialog::MainMenuDialog(Engine *engine)
00052     : GUI::Dialog("GlobalMenu"), _engine(engine) {
00053     _backgroundType = GUI::ThemeEngine::kDialogBackgroundSpecial;
00054 
00055 #ifndef DISABLE_FANCY_THEMES
00056     _logo = 0;
00057     if (g_gui.xmlEval()->getVar("Globals.ShowGlobalMenuLogo", 0) == 1 && g_gui.theme()->supportsImages()) {
00058         _logo = new GUI::GraphicsWidget(this, "GlobalMenu.Logo");
00059         _logo->useThemeTransparency(true);
00060         _logo->setGfx(g_gui.theme()->getImageSurface(GUI::ThemeEngine::kImageLogoSmall));
00061     } else {
00062         GUI::StaticTextWidget *title = new GUI::StaticTextWidget(this, "GlobalMenu.Title", "ResidualVM");
00063         title->setAlign(Graphics::kTextAlignCenter);
00064     }
00065 #else
00066     GUI::StaticTextWidget *title = new GUI::StaticTextWidget(this, "GlobalMenu.Title", "ResidualVM");
00067     title->setAlign(Graphics::kTextAlignCenter);
00068 #endif
00069 
00070     GUI::StaticTextWidget *version = new GUI::StaticTextWidget(this, "GlobalMenu.Version", gScummVMVersionDate);
00071     version->setAlign(Graphics::kTextAlignCenter);
00072 
00073     new GUI::ButtonWidget(this, "GlobalMenu.Resume", _("~R~esume"), 0, kPlayCmd, 'P');
00074 
00075     _loadButton = new GUI::ButtonWidget(this, "GlobalMenu.Load", _("~L~oad"), 0, kLoadCmd);
00076     _loadButton->setVisible(_engine->hasFeature(Engine::kSupportsLoadingDuringRuntime));
00077     _loadButton->setEnabled(_engine->hasFeature(Engine::kSupportsLoadingDuringRuntime));
00078 
00079     _saveButton = new GUI::ButtonWidget(this, "GlobalMenu.Save", _("~S~ave"), 0, kSaveCmd);
00080     _saveButton->setVisible(_engine->hasFeature(Engine::kSupportsSavingDuringRuntime));
00081     _saveButton->setEnabled(_engine->hasFeature(Engine::kSupportsSavingDuringRuntime));
00082 
00083     new GUI::ButtonWidget(this, "GlobalMenu.Options", _("~O~ptions"), 0, kOptionsCmd);
00084 
00085     // The help button is disabled by default.
00086     // To enable "Help", an engine needs to use a subclass of MainMenuDialog
00087     // (at least for now, we might change how this works in the future).
00088     _helpButton = new GUI::ButtonWidget(this, "GlobalMenu.Help", _("~H~elp"), 0, kHelpCmd);
00089 
00090     new GUI::ButtonWidget(this, "GlobalMenu.About", _("~A~bout"), 0, kAboutCmd);
00091 
00092     if (g_system->getOverlayWidth() > 320)
00093         _rtlButton = new GUI::ButtonWidget(this, "GlobalMenu.RTL", _("~R~eturn to Launcher"), 0, kRTLCmd);
00094     else
00095         _rtlButton = new GUI::ButtonWidget(this, "GlobalMenu.RTL", _c("~R~eturn to Launcher", "lowres"), 0, kRTLCmd);
00096     _rtlButton->setEnabled(_engine->hasFeature(Engine::kSupportsRTL));
00097 
00098     if (!g_system->hasFeature(OSystem::kFeatureNoQuit))
00099         new GUI::ButtonWidget(this, "GlobalMenu.Quit", _("~Q~uit"), 0, kQuitCmd);
00100 
00101     _aboutDialog = new GUI::AboutDialog();
00102     _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false);
00103     _saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
00104 }
00105 
00106 MainMenuDialog::~MainMenuDialog() {
00107     delete _aboutDialog;
00108     delete _loadDialog;
00109     delete _saveDialog;
00110 }
00111 
00112 void MainMenuDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
00113     switch (cmd) {
00114     case kPlayCmd:
00115         close();
00116         break;
00117     case kLoadCmd:
00118         load();
00119         break;
00120     case kSaveCmd:
00121         save();
00122         break;
00123     case kOptionsCmd: {
00124         GUI::ConfigDialog configDialog;
00125         configDialog.runModal();
00126         break;
00127     }
00128     case kAboutCmd:
00129         _aboutDialog->runModal();
00130         break;
00131     case kHelpCmd: {
00132         GUI::MessageDialog dialog(
00133                     _("Sorry, this engine does not currently provide in-game help. "
00134                     "Please consult the README for basic information, and for "
00135                     "instructions on how to obtain further assistance."));
00136         dialog.runModal();
00137         }
00138         break;
00139     case kRTLCmd: {
00140         Common::Event eventRTL;
00141         eventRTL.type = Common::EVENT_RTL;
00142         g_system->getEventManager()->pushEvent(eventRTL);
00143         close();
00144         }
00145         break;
00146     case kQuitCmd: {
00147         Common::Event eventQ;
00148         eventQ.type = Common::EVENT_QUIT;
00149         g_system->getEventManager()->pushEvent(eventQ);
00150         close();
00151         }
00152         break;
00153     default:
00154         GUI::Dialog::handleCommand(sender, cmd, data);
00155     }
00156 }
00157 
00158 void MainMenuDialog::reflowLayout() {
00159     if (_engine->hasFeature(Engine::kSupportsLoadingDuringRuntime))
00160         _loadButton->setEnabled(_engine->canLoadGameStateCurrently());
00161     if (_engine->hasFeature(Engine::kSupportsSavingDuringRuntime))
00162         _saveButton->setEnabled(_engine->canSaveGameStateCurrently());
00163 
00164     // Overlay size might have changed since the construction of the dialog.
00165     // Update labels when it might be needed
00166     // FIXME: it might be better to declare GUI::StaticTextWidget::setLabel() virtual
00167     // and to reimplement it in GUI::ButtonWidget to handle the hotkey.
00168     if (g_system->getOverlayWidth() > 320)
00169         _rtlButton->setLabel(_rtlButton->cleanupHotkey(_("~R~eturn to Launcher")));
00170     else
00171         _rtlButton->setLabel(_rtlButton->cleanupHotkey(_c("~R~eturn to Launcher", "lowres")));
00172 
00173 #ifndef DISABLE_FANCY_THEMES
00174     if (g_gui.xmlEval()->getVar("Globals.ShowGlobalMenuLogo", 0) == 1 && g_gui.theme()->supportsImages()) {
00175         if (!_logo)
00176             _logo = new GUI::GraphicsWidget(this, "GlobalMenu.Logo");
00177         _logo->useThemeTransparency(true);
00178         _logo->setGfx(g_gui.theme()->getImageSurface(GUI::ThemeEngine::kImageLogoSmall));
00179 
00180         GUI::StaticTextWidget *title = (GUI::StaticTextWidget *)findWidget("GlobalMenu.Title");
00181         if (title) {
00182             removeWidget(title);
00183             title->setNext(0);
00184             delete title;
00185         }
00186     } else {
00187         GUI::StaticTextWidget *title = (GUI::StaticTextWidget *)findWidget("GlobalMenu.Title");
00188         if (!title) {
00189             title = new GUI::StaticTextWidget(this, "GlobalMenu.Title", "ResidualVM");
00190             title->setAlign(Graphics::kTextAlignCenter);
00191         }
00192 
00193         if (_logo) {
00194             removeWidget(_logo);
00195             _logo->setNext(0);
00196             delete _logo;
00197             _logo = 0;
00198         }
00199     }
00200 #endif
00201 
00202     Dialog::reflowLayout();
00203 }
00204 
00205 void MainMenuDialog::save() {
00206     int slot = _saveDialog->runModalWithCurrentTarget();
00207 
00208     #if defined(__PLAYSTATION2__) && defined(DYNAMIC_MODULES)
00209     char pokeme[32];
00210     snprintf(pokeme,32,"hack");
00211     #endif
00212 
00213     if (slot >= 0) {
00214         Common::String result(_saveDialog->getResultString());
00215         if (result.empty()) {
00216             // If the user was lazy and entered no save name, come up with a default name.
00217             result = _saveDialog->createDefaultSaveDescription(slot);
00218         }
00219 
00220         Common::Error status = _engine->saveGameState(slot, result);
00221         if (status.getCode() != Common::kNoError) {
00222             Common::String failMessage = Common::String::format(_("Failed to save game (%s)! "
00223                   "Please consult the README for basic information, and for "
00224                   "instructions on how to obtain further assistance."), status.getDesc().c_str());
00225             GUI::MessageDialog dialog(failMessage);
00226             dialog.runModal();
00227         }
00228 
00229         close();
00230     }
00231 }
00232 
00233 void MainMenuDialog::load() {
00234     int slot = _loadDialog->runModalWithCurrentTarget();
00235 
00236     _engine->setGameToLoadSlot(slot);
00237 
00238     if (slot >= 0)
00239         close();
00240 }
00241 
00242 enum {
00243     kKeysCmd = 'KEYS'
00244 };
00245 
00246 namespace GUI {
00247 
00248 // FIXME: We use the empty string as domain name here. This tells the
00249 // ConfigManager to use the 'default' domain for all its actions. We do that
00250 // to get as close as possible to editing the 'active' settings.
00251 //
00252 // However, that requires bad & evil hacks in the ConfigManager code,
00253 // and even then still doesn't work quite correctly.
00254 // For example, if the transient domain contains 'false' for the 'fullscreen'
00255 // flag, but the user used a hotkey to switch to windowed mode, then the dialog
00256 // will display the wrong value anyway.
00257 //
00258 // Proposed solution consisting of multiple steps:
00259 // 1) Add special code to the open() code that reads out everything stored
00260 //    in the transient domain that is controlled by this dialog, and updates
00261 //    the dialog accordingly.
00262 // 2) Even more code is added to query the backend for current settings, like
00263 //    the fullscreen mode flag etc., and also updates the dialog accordingly.
00264 // 3) The domain being edited is set to the active game domain.
00265 // 4) If the dialog is closed with the "OK" button, then we remove everything
00266 //    stored in the transient domain (or at least everything corresponding to
00267 //    switches in this dialog.
00268 //    If OTOH the dialog is closed with "Cancel" we do no such thing.
00269 //
00270 // These changes will achieve two things at once: Allow us to get rid of using
00271 //  "" as value for the domain, and in fact provide a somewhat better user
00272 // experience at the same time.
00273 ConfigDialog::ConfigDialog() :
00274         GUI::OptionsDialog("", "GlobalConfig"),
00275         _engineOptions(nullptr) {
00276     assert(g_engine);
00277 
00278     const Common::String &gameDomain = ConfMan.getActiveDomainName();
00279     const MetaEngine &metaEngine = g_engine->getMetaEngine();
00280 
00281     // GUI:  Add tab widget
00282     GUI::TabWidget *tab = new GUI::TabWidget(this, "GlobalConfig.TabWidget");
00283 
00284     //
00285     // The game specific options tab
00286     //
00287 
00288     int tabId = tab->addTab(_("Game"), "GlobalConfig_Engine");
00289 
00290     if (g_engine->hasFeature(Engine::kSupportsChangingOptionsDuringRuntime)) {
00291         _engineOptions = metaEngine.buildEngineOptionsWidget(tab, "GlobalConfig_Engine.Container", gameDomain);
00292     }
00293 
00294     if (_engineOptions) {
00295         _engineOptions->setParentDialog(this);
00296     } else {
00297         tab->removeTab(tabId);
00298     }
00299 
00300     //
00301     // The Audio / Subtitles tab
00302     //
00303 
00304     tab->addTab(_("Audio"), "GlobalConfig_Audio");
00305 
00306     //
00307     // Sound controllers
00308     //
00309 
00310     addVolumeControls(tab, "GlobalConfig_Audio.");
00311     setVolumeSettingsState(true); // could disable controls by GUI options
00312 
00313     //
00314     // Subtitle speed and toggle controllers
00315     //
00316 
00317     if (g_engine->hasFeature(Engine::kSupportsSubtitleOptions)) {
00318         // Global talkspeed range of 0-255
00319         addSubtitleControls(tab, "GlobalConfig_Audio.", 255);
00320         setSubtitleSettingsState(true); // could disable controls by GUI options
00321     }
00322 
00323     //
00324     // The Keymap tab
00325     //
00326 
00327     Common::KeymapArray keymaps = metaEngine.initKeymaps(gameDomain.c_str());
00328     if (!keymaps.empty()) {
00329         tab->addTab(_("Keymaps"), "GlobalConfig_KeyMapper");
00330         addKeyMapperControls(tab, "GlobalConfig_KeyMapper.", keymaps, gameDomain);
00331     }
00332 
00333     //
00334     // The Achievements tab
00335     //
00336     Common::AchievementsInfo achievementsInfo = metaEngine.getAchievementsInfo(gameDomain);
00337     if (achievementsInfo.descriptions.size() > 0) {
00338         tab->addTab(_("Achievements"), "GlobalConfig_Achievements");
00339         addAchievementsControls(tab, "GlobalConfig_Achievements.", achievementsInfo);
00340     }
00341 
00342     // Activate the first tab
00343     tab->setActiveTab(0);
00344 
00345     //
00346     // Add the buttons
00347     //
00348 
00349     new GUI::ButtonWidget(this, "GlobalConfig.Ok", _("~O~K"), 0, GUI::kOKCmd);
00350     new GUI::ButtonWidget(this, "GlobalConfig.Cancel", _("~C~ancel"), 0, GUI::kCloseCmd);
00351 
00352 #ifdef GUI_ENABLE_KEYSDIALOG
00353     new GUI::ButtonWidget(this, "GlobalConfig.Keys", _("~K~eys"), 0, kKeysCmd);
00354     _keysDialog = NULL;
00355 #endif
00356 }
00357 
00358 ConfigDialog::~ConfigDialog() {
00359 #ifdef GUI_ENABLE_KEYSDIALOG
00360     delete _keysDialog;
00361 #endif
00362 }
00363 
00364 void ConfigDialog::build() {
00365     OptionsDialog::build();
00366 
00367     // Engine options
00368     if (_engineOptions) {
00369         _engineOptions->load();
00370     }
00371 }
00372 
00373 void ConfigDialog::apply() {
00374     if (_engineOptions) {
00375         _engineOptions->save();
00376     }
00377 
00378     OptionsDialog::apply();
00379 }
00380 
00381 void ConfigDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) {
00382     switch (cmd) {
00383     case kKeysCmd:
00384 
00385 #ifdef GUI_ENABLE_KEYSDIALOG
00386     //
00387     // Create the sub dialog(s)
00388     //
00389     _keysDialog = new GUI::KeysDialog();
00390     _keysDialog->runModal();
00391     delete _keysDialog;
00392     _keysDialog = NULL;
00393 #endif
00394         break;
00395     default:
00396         GUI::OptionsDialog::handleCommand (sender, cmd, data);
00397     }
00398 }
00399 
00400 ExtraGuiOptionsWidget::ExtraGuiOptionsWidget(GuiObject *containerBoss, const Common::String &name, const Common::String &domain, const ExtraGuiOptions &options) :
00401         OptionsContainerWidget(containerBoss, name, dialogLayout(domain), false, domain),
00402         _options(options) {
00403 
00404     // Note: up to 7 engine options can currently fit on screen (the most that
00405     // can fit in a 320x200 screen with the classic theme).
00406     // TODO: Increase this number by including the checkboxes inside a scroll
00407     // widget. The appropriate number of checkboxes will need to be added to
00408     // the theme files.
00409 
00410     uint i = 1;
00411     ExtraGuiOptions::const_iterator iter;
00412     for (iter = _options.begin(); iter != _options.end(); ++iter, ++i) {
00413         Common::String id = Common::String::format("%d", i);
00414         _checkboxes.push_back(new CheckboxWidget(widgetsBoss(),
00415             _dialogLayout + ".customOption" + id + "Checkbox", _(iter->label), _(iter->tooltip)));
00416     }
00417 }
00418 
00419 ExtraGuiOptionsWidget::~ExtraGuiOptionsWidget() {
00420 }
00421 
00422 Common::String ExtraGuiOptionsWidget::dialogLayout(const Common::String &domain) {
00423     if (ConfMan.getActiveDomainName().equals(domain)) {
00424         return "GlobalConfig_Engine_Container";
00425     } else {
00426         return "GameOptions_Engine_Container";
00427     }
00428 }
00429 
00430 void ExtraGuiOptionsWidget::load() {
00431     // Set the state of engine-specific checkboxes
00432     for (uint j = 0; j < _options.size(); ++j) {
00433         // The default values for engine-specific checkboxes are not set when
00434         // ScummVM starts, as this would require us to load and poll all of the
00435         // engine plugins on startup. Thus, we set the state of each custom
00436         // option checkbox to what is specified by the engine plugin, and
00437         // update it only if a value has been set in the configuration of the
00438         // currently selected game.
00439         bool isChecked = _options[j].defaultState;
00440         if (ConfMan.hasKey(_options[j].configOption, _domain))
00441             isChecked = ConfMan.getBool(_options[j].configOption, _domain);
00442         _checkboxes[j]->setState(isChecked);
00443     }
00444 }
00445 
00446 bool ExtraGuiOptionsWidget::save() {
00447     // Set the state of engine-specific checkboxes
00448     for (uint i = 0; i < _options.size(); i++) {
00449         ConfMan.setBool(_options[i].configOption, _checkboxes[i]->getState(), _domain);
00450     }
00451 
00452     return true;
00453 }
00454 
00455 } // End of namespace GUI


Generated on Sat May 30 2020 05:00:43 for ResidualVM by doxygen 1.7.1
curved edge   curved edge