diff options
Diffstat (limited to 'gui/saveload-dialog.cpp')
| -rw-r--r-- | gui/saveload-dialog.cpp | 881 | 
1 files changed, 881 insertions, 0 deletions
| diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp new file mode 100644 index 0000000000..0b36ff5d59 --- /dev/null +++ b/gui/saveload-dialog.cpp @@ -0,0 +1,881 @@ +/* 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 "gui/saveload-dialog.h" +#include "common/translation.h" +#include "common/config-manager.h" + +#include "gui/message.h" +#include "gui/gui-manager.h" +#include "gui/ThemeEval.h" +#include "gui/widgets/edittext.h" + +#include "graphics/scaler.h" + +namespace GUI { + +#ifndef DISABLE_SAVELOADCHOOSER_GRID +SaveLoadChooserType getRequestedSaveLoadDialog(const MetaEngine &metaEngine) { +	const Common::String &userConfig = ConfMan.get("gui_saveload_chooser", Common::ConfigManager::kApplicationDomain); +	if (g_gui.getWidth() >= 640 && g_gui.getHeight() >= 400 +	    && metaEngine.hasFeature(MetaEngine::kSavesSupportMetaInfo) +	    && metaEngine.hasFeature(MetaEngine::kSavesSupportThumbnail) +	    && userConfig.equalsIgnoreCase("grid")) { +		// In case we are 640x400 or higher, this dialog is not in save mode, +		// the user requested the grid dialog and the engines supports it we +		// try to set it up. +		return kSaveLoadDialogGrid; +	} else { +		// In all other cases we want to use the list dialog. +		return kSaveLoadDialogList; +	} +} + +enum { +	kListSwitchCmd = 'LIST', +	kGridSwitchCmd = 'GRID' +}; +#endif // !DISABLE_SAVELOADCHOOSER_GRID + +SaveLoadChooserDialog::SaveLoadChooserDialog(const Common::String &dialogName, const bool saveMode) +	: Dialog(dialogName), _metaEngine(0), _delSupport(false), _metaInfoSupport(false), +	_thumbnailSupport(false), _saveDateSupport(false), _playTimeSupport(false), _saveMode(saveMode) +#ifndef DISABLE_SAVELOADCHOOSER_GRID +	, _listButton(0), _gridButton(0) +#endif // !DISABLE_SAVELOADCHOOSER_GRID +	{ +#ifndef DISABLE_SAVELOADCHOOSER_GRID +	addChooserButtons(); +#endif // !DISABLE_SAVELOADCHOOSER_GRID +} + +SaveLoadChooserDialog::SaveLoadChooserDialog(int x, int y, int w, int h, const bool saveMode) +	: Dialog(x, y, w, h), _metaEngine(0), _delSupport(false), _metaInfoSupport(false), +	_thumbnailSupport(false), _saveDateSupport(false), _playTimeSupport(false), _saveMode(saveMode) +#ifndef DISABLE_SAVELOADCHOOSER_GRID +	, _listButton(0), _gridButton(0) +#endif // !DISABLE_SAVELOADCHOOSER_GRID +	{ +#ifndef DISABLE_SAVELOADCHOOSER_GRID +	addChooserButtons(); +#endif // !DISABLE_SAVELOADCHOOSER_GRID +} + +void SaveLoadChooserDialog::open() { +	Dialog::open(); + +	// So that quitting ScummVM will not cause the dialog result to say a +	// savegame was selected. +	setResult(-1); +} + +int SaveLoadChooserDialog::run(const Common::String &target, const MetaEngine *metaEngine) { +	_metaEngine = metaEngine; +	_target = target; +	_delSupport = _metaEngine->hasFeature(MetaEngine::kSupportsDeleteSave); +	_metaInfoSupport = _metaEngine->hasFeature(MetaEngine::kSavesSupportMetaInfo); +	_thumbnailSupport = _metaInfoSupport && _metaEngine->hasFeature(MetaEngine::kSavesSupportThumbnail); +	_saveDateSupport = _metaInfoSupport && _metaEngine->hasFeature(MetaEngine::kSavesSupportCreationDate); +	_playTimeSupport = _metaInfoSupport && _metaEngine->hasFeature(MetaEngine::kSavesSupportPlayTime); + +	return runIntern(); +} + +void SaveLoadChooserDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { +#ifndef DISABLE_SAVELOADCHOOSER_GRID +	switch (cmd) { +	case kListSwitchCmd: +		setResult(kSwitchSaveLoadDialog); +		// We save the requested dialog type here to avoid the setting to be +		// overwritten when our reflowLayout logic selects a different dialog +		// type. +		ConfMan.set("gui_saveload_chooser", "list", Common::ConfigManager::kApplicationDomain); +		close(); +		break; + +	case kGridSwitchCmd: +		setResult(kSwitchSaveLoadDialog); +		// See above. +		ConfMan.set("gui_saveload_chooser", "grid", Common::ConfigManager::kApplicationDomain); +		close(); +		break; + +	default: +		break; +	} +#endif // !DISABLE_SAVELOADCHOOSER_GRID + +	return Dialog::handleCommand(sender, cmd, data); +} + +void SaveLoadChooserDialog::reflowLayout() { +#ifndef DISABLE_SAVELOADCHOOSER_GRID +	addChooserButtons(); + +	const SaveLoadChooserType currentType = getType(); +	const SaveLoadChooserType requestedType = getRequestedSaveLoadDialog(*_metaEngine); + +	// Change the dialog type if there is any need for it. +	if (requestedType != currentType) { +		setResult(kSwitchSaveLoadDialog); +		close(); +	} +#endif // !DISABLE_SAVELOADCHOOSER_GRID + +	Dialog::reflowLayout(); +} + +#ifndef DISABLE_SAVELOADCHOOSER_GRID +void SaveLoadChooserDialog::addChooserButtons() { +	if (_listButton) { +		removeWidget(_listButton); +		delete _listButton; +	} + +	if (_gridButton) { +		removeWidget(_gridButton); +		delete _gridButton; +	} + +	_listButton = createSwitchButton("SaveLoadChooser.ListSwitch", "L", _("List view"), ThemeEngine::kImageList, kListSwitchCmd); +	_gridButton = createSwitchButton("SaveLoadChooser.GridSwitch", "G", _("Grid view"), ThemeEngine::kImageGrid, kGridSwitchCmd); +	if (!_metaInfoSupport || !_thumbnailSupport || !(g_gui.getWidth() >= 640 && g_gui.getHeight() >= 400)) { +		_gridButton->setEnabled(false); +		_listButton->setEnabled(false); +	} +} + +ButtonWidget *SaveLoadChooserDialog::createSwitchButton(const Common::String &name, const char *desc, const char *tooltip, const char *image, uint32 cmd) { +	ButtonWidget *button; + +#ifndef DISABLE_FANCY_THEMES +	if (g_gui.xmlEval()->getVar("Globals.ShowChooserPics") == 1 && g_gui.theme()->supportsImages()) { +		button = new PicButtonWidget(this, name, tooltip, cmd); +		((PicButtonWidget *)button)->useThemeTransparency(true); +		((PicButtonWidget *)button)->setGfx(g_gui.theme()->getImageSurface(image)); +	} else +#endif +		button = new ButtonWidget(this, name, desc, tooltip, cmd); + +	return button; +} +#endif // !DISABLE_SAVELOADCHOOSER_GRID + +// SaveLoadChooserSimple implementation + +enum { +	kChooseCmd = 'CHOS', +	kDelCmd = 'DEL ' +}; + +SaveLoadChooserSimple::SaveLoadChooserSimple(const String &title, const String &buttonLabel, bool saveMode) +	: SaveLoadChooserDialog("SaveLoadChooser", saveMode), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0)  { +	_fillR = _fillG = _fillB = 0; + +	_backgroundType = ThemeEngine::kDialogBackgroundSpecial; + +	new StaticTextWidget(this, "SaveLoadChooser.Title", title); + +	// Add choice list +	_list = new ListWidget(this, "SaveLoadChooser.List"); +	_list->setNumberingMode(kListNumberingZero); +	_list->setEditable(saveMode); + +	_gfxWidget = new GraphicsWidget(this, 0, 0, 10, 10); + +	_date = new StaticTextWidget(this, 0, 0, 10, 10, _("No date saved"), Graphics::kTextAlignCenter); +	_time = new StaticTextWidget(this, 0, 0, 10, 10, _("No time saved"), Graphics::kTextAlignCenter); +	_playtime = new StaticTextWidget(this, 0, 0, 10, 10, _("No playtime saved"), Graphics::kTextAlignCenter); + +	// Buttons +	new ButtonWidget(this, "SaveLoadChooser.Cancel", _("Cancel"), 0, kCloseCmd); +	_chooseButton = new ButtonWidget(this, "SaveLoadChooser.Choose", buttonLabel, 0, kChooseCmd); +	_chooseButton->setEnabled(false); + +	_deleteButton = new ButtonWidget(this, "SaveLoadChooser.Delete", _("Delete"), 0, kDelCmd); +	_deleteButton->setEnabled(false); + +	_delSupport = _metaInfoSupport = _thumbnailSupport = false; + +	_container = new ContainerWidget(this, 0, 0, 10, 10); +//	_container->setHints(THEME_HINT_USE_SHADOW); +} + +int SaveLoadChooserSimple::runIntern() { +	if (_gfxWidget) +		_gfxWidget->setGfx(0); + +	_resultString.clear(); +	reflowLayout(); +	updateSaveList(); + +	return Dialog::runModal(); +} + +const Common::String &SaveLoadChooserSimple::getResultString() const { +	int selItem = _list->getSelected(); +	return (selItem >= 0) ? _list->getSelectedString() : _resultString; +} + +void SaveLoadChooserSimple::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { +	int selItem = _list->getSelected(); + +	switch (cmd) { +	case kListItemActivatedCmd: +	case kListItemDoubleClickedCmd: +		if (selItem >= 0 && _chooseButton->isEnabled()) { +			if (_list->isEditable() || !_list->getSelectedString().empty()) { +				_list->endEditMode(); +				if (!_saveList.empty()) { +					setResult(_saveList[selItem].getSaveSlot()); +					_resultString = _list->getSelectedString(); +				} +				close(); +			} +		} +		break; +	case kChooseCmd: +		_list->endEditMode(); +		if (!_saveList.empty()) { +			setResult(_saveList[selItem].getSaveSlot()); +			_resultString = _list->getSelectedString(); +		} +		close(); +		break; +	case kListSelectionChangedCmd: +		updateSelection(true); +		break; +	case kDelCmd: +		if (selItem >= 0 && _delSupport) { +			MessageDialog alert(_("Do you really want to delete this savegame?"), +								_("Delete"), _("Cancel")); +			if (alert.runModal() == kMessageOK) { +				_metaEngine->removeSaveState(_target.c_str(), _saveList[selItem].getSaveSlot()); + +				setResult(-1); +				_list->setSelected(-1); + +				updateSaveList(); +				updateSelection(true); +			} +		} +		break; +	case kCloseCmd: +		setResult(-1); +	default: +		SaveLoadChooserDialog::handleCommand(sender, cmd, data); +	} +} + +void SaveLoadChooserSimple::reflowLayout() { +	if (g_gui.xmlEval()->getVar("Globals.SaveLoadChooser.ExtInfo.Visible") == 1 && _thumbnailSupport) { +		int16 x, y; +		uint16 w, h; + +		if (!g_gui.xmlEval()->getWidgetData("SaveLoadChooser.Thumbnail", x, y, w, h)) +			error("Error when loading position data for Save/Load Thumbnails"); + +		int thumbW = kThumbnailWidth; +		int thumbH = kThumbnailHeight2; +		int thumbX = x + (w >> 1) - (thumbW >> 1); +		int thumbY = y + kLineHeight; + +		int textLines = 0; +		if (!_saveDateSupport) +			textLines++; +		if (!_playTimeSupport) +			textLines++; + +		_container->resize(x, y, w, h - (kLineHeight * textLines)); +		_gfxWidget->resize(thumbX, thumbY, thumbW, thumbH); + +		int height = thumbY + thumbH + kLineHeight; + +		if (_saveDateSupport) { +			_date->resize(thumbX, height, kThumbnailWidth, kLineHeight); +			height += kLineHeight; +			_time->resize(thumbX, height, kThumbnailWidth, kLineHeight); +			height += kLineHeight; +		} + +		if (_playTimeSupport) +			_playtime->resize(thumbX, height, kThumbnailWidth, kLineHeight); + +		_container->setVisible(true); +		_gfxWidget->setVisible(true); + +		_date->setVisible(_saveDateSupport); +		_time->setVisible(_saveDateSupport); + +		_playtime->setVisible(_playTimeSupport); + +		_fillR = 0; +		_fillG = 0; +		_fillB = 0; +		updateSelection(false); +	} else { +		_container->setVisible(false); +		_gfxWidget->setVisible(false); +		_date->setVisible(false); +		_time->setVisible(false); +		_playtime->setVisible(false); +	} + +	SaveLoadChooserDialog::reflowLayout(); +} + +void SaveLoadChooserSimple::updateSelection(bool redraw) { +	int selItem = _list->getSelected(); + +	bool isDeletable = _delSupport; +	bool isWriteProtected = false; +	bool startEditMode = _list->isEditable(); + +	_gfxWidget->setGfx(-1, -1, _fillR, _fillG, _fillB); +	_date->setLabel(_("No date saved")); +	_time->setLabel(_("No time saved")); +	_playtime->setLabel(_("No playtime saved")); + +	if (selItem >= 0 && _metaInfoSupport) { +		SaveStateDescriptor desc = _metaEngine->querySaveMetaInfos(_target.c_str(), _saveList[selItem].getSaveSlot()); + +		isDeletable = desc.getDeletableFlag() && _delSupport; +		isWriteProtected = desc.getWriteProtectedFlag(); + +		// Don't allow the user to change the description of write protected games +		if (isWriteProtected) +			startEditMode = false; + +		if (_thumbnailSupport) { +			const Graphics::Surface *thumb = desc.getThumbnail(); +			if (thumb) { +				_gfxWidget->setGfx(thumb); +				_gfxWidget->useAlpha(256); +			} +		} + +		if (_saveDateSupport) { +			const Common::String &saveDate = desc.getSaveDate(); +			if (!saveDate.empty()) +				_date->setLabel(_("Date: ") + saveDate); + +			const Common::String &saveTime = desc.getSaveTime(); +			if (!saveTime.empty()) +				_time->setLabel(_("Time: ") + saveTime); +		} + +		if (_playTimeSupport) { +			const Common::String &playTime = desc.getPlayTime(); +			if (!playTime.empty()) +				_playtime->setLabel(_("Playtime: ") + playTime); +		} +	} + + +	if (_list->isEditable()) { +		// Disable the save button if nothing is selected, or if the selected +		// game is write protected +		_chooseButton->setEnabled(selItem >= 0 && !isWriteProtected); + +		if (startEditMode) { +			_list->startEditMode(); + +			if (_chooseButton->isEnabled() && _list->getSelectedString() == _("Untitled savestate") && +					_list->getSelectionColor() == ThemeEngine::kFontColorAlternate) { +				_list->setEditString(""); +				_list->setEditColor(ThemeEngine::kFontColorNormal); +			} +		} +	} else { +		// Disable the load button if nothing is selected, or if an empty +		// list item is selected. +		_chooseButton->setEnabled(selItem >= 0 && !_list->getSelectedString().empty()); +	} + +	// Delete will always be disabled if the engine doesn't support it. +	_deleteButton->setEnabled(isDeletable && (selItem >= 0) && (!_list->getSelectedString().empty())); + +	if (redraw) { +		_gfxWidget->draw(); +		_date->draw(); +		_time->draw(); +		_playtime->draw(); +		_chooseButton->draw(); +		_deleteButton->draw(); + +		draw(); +	} +} + +void SaveLoadChooserSimple::close() { +	_metaEngine = 0; +	_target.clear(); +	_saveList.clear(); +	_list->setList(StringArray()); + +	SaveLoadChooserDialog::close(); +} + +void SaveLoadChooserSimple::updateSaveList() { +	_saveList = _metaEngine->listSaves(_target.c_str()); + +	int curSlot = 0; +	int saveSlot = 0; +	StringArray saveNames; +	ListWidget::ColorList colors; +	for (SaveStateList::const_iterator x = _saveList.begin(); x != _saveList.end(); ++x) { +		// Handle gaps in the list of save games +		saveSlot = x->getSaveSlot(); +		if (curSlot < saveSlot) { +			while (curSlot < saveSlot) { +				SaveStateDescriptor dummySave(curSlot, ""); +				_saveList.insert_at(curSlot, dummySave); +				saveNames.push_back(dummySave.getDescription()); +				colors.push_back(ThemeEngine::kFontColorNormal); +				curSlot++; +			} + +			// Sync the save list iterator +			for (x = _saveList.begin(); x != _saveList.end(); ++x) { +				if (x->getSaveSlot() == saveSlot) +					break; +			} +		} + +		// Show "Untitled savestate" for empty/whitespace savegame descriptions +		Common::String description = x->getDescription(); +		Common::String trimmedDescription = description; +		trimmedDescription.trim(); +		if (trimmedDescription.empty()) { +			description = _("Untitled savestate"); +			colors.push_back(ThemeEngine::kFontColorAlternate); +		} else { +			colors.push_back(ThemeEngine::kFontColorNormal); +		} + +		saveNames.push_back(description); +		curSlot++; +	} + +	// Fill the rest of the save slots with empty saves + +	int maximumSaveSlots = _metaEngine->getMaximumSaveSlot(); + +#ifdef __DS__ +	// Low memory on the DS means too many save slots are impractical, so limit +	// the maximum here. +	if (maximumSaveSlots > 99) { +		maximumSaveSlots = 99; +	} +#endif + +	Common::String emptyDesc; +	for (int i = curSlot; i <= maximumSaveSlots; i++) { +		saveNames.push_back(emptyDesc); +		SaveStateDescriptor dummySave(i, ""); +		_saveList.push_back(dummySave); +		colors.push_back(ThemeEngine::kFontColorNormal); +	} + +	_list->setList(saveNames, &colors); +} + +// SaveLoadChooserGrid implementation + +#ifndef DISABLE_SAVELOADCHOOSER_GRID + +enum { +	kNextCmd = 'NEXT', +	kPrevCmd = 'PREV', +	kNewSaveCmd = 'SAVE' +}; + +SaveLoadChooserGrid::SaveLoadChooserGrid(const Common::String &title, bool saveMode) +	: SaveLoadChooserDialog("SaveLoadChooser", saveMode), _lines(0), _columns(0), _entriesPerPage(0), +	_curPage(0), _newSaveContainer(0), _nextFreeSaveSlot(0), _buttons() { +	_backgroundType = ThemeEngine::kDialogBackgroundSpecial; + +	new StaticTextWidget(this, "SaveLoadChooser.Title", title); + +	// Buttons +	new ButtonWidget(this, "SaveLoadChooser.Delete", _("Cancel"), 0, kCloseCmd); +	_nextButton = new ButtonWidget(this, "SaveLoadChooser.Choose", _("Next"), 0, kNextCmd); +	_nextButton->setEnabled(false); + +	_prevButton = new ButtonWidget(this, "SaveLoadChooser.Cancel", _("Prev"), 0, kPrevCmd); +	_prevButton->setEnabled(false); + +	// Page display +	_pageDisplay = new StaticTextWidget(this, "SaveLoadChooser.PageDisplay", Common::String()); +	_pageDisplay->setAlign(Graphics::kTextAlignRight); +} + +SaveLoadChooserGrid::~SaveLoadChooserGrid() { +	removeWidget(_pageDisplay); +	delete _pageDisplay; +} + +const Common::String &SaveLoadChooserGrid::getResultString() const { +	return _resultString; +} + +void SaveLoadChooserGrid::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { +	if (cmd <= _entriesPerPage) { +		const SaveStateDescriptor &desc = _saveList[cmd - 1 + _curPage * _entriesPerPage]; + +		if (_saveMode) { +			_resultString = desc.getDescription(); +		} + +		setResult(desc.getSaveSlot()); +		close(); +	} + +	switch (cmd) { +	case kNextCmd: +		++_curPage; +		updateSaves(); +		draw(); +		break; + +	case kPrevCmd: +		--_curPage; +		updateSaves(); +		draw(); +		break; + +	case kNewSaveCmd: +		setResult(_nextFreeSaveSlot); +		close(); +		break; + +	case kCloseCmd: +		setResult(-1); +	default: +		SaveLoadChooserDialog::handleCommand(sender, cmd, data); +	} +} + +void SaveLoadChooserGrid::handleMouseWheel(int x, int y, int direction) { +	if (direction > 0) { +		if (_nextButton->isEnabled()) { +			++_curPage; +			updateSaves(); +			draw(); +		} +	} else { +		if (_prevButton->isEnabled()) { +			--_curPage; +			updateSaves(); +			draw(); +		} +	} +} + +void SaveLoadChooserGrid::open() { +	SaveLoadChooserDialog::open(); + +	_curPage = 0; +	_saveList = _metaEngine->listSaves(_target.c_str()); +	_resultString.clear(); + +	// Determine the next free save slot for save mode +	if (_saveMode) { +		int lastSlot = -1; +		_nextFreeSaveSlot = -1; +		for (SaveStateList::const_iterator x = _saveList.begin(); x != _saveList.end(); ++x) { +			const int curSlot = x->getSaveSlot(); + +			// In case there was a gap found use the slot. +			if (lastSlot + 1 < curSlot) { +				_nextFreeSaveSlot = lastSlot + 1; +				break; +			} + +			lastSlot = curSlot; +		} + +		// Use the next available slot otherwise. +		if (_nextFreeSaveSlot == -1 && lastSlot + 1 < _metaEngine->getMaximumSaveSlot()) { +			_nextFreeSaveSlot = lastSlot + 1; +		} +	} + +	updateSaves(); +} + +void SaveLoadChooserGrid::reflowLayout() { +	removeWidget(_pageDisplay); +	if (g_gui.xmlEval()->getVar("Globals.ShowChooserPageDisplay") == 1) { +		_pageDisplay->init(); +	} + +	SaveLoadChooserDialog::reflowLayout(); +	destroyButtons(); + +	const uint16 availableWidth = getWidth() - 20; +	uint16 availableHeight; + +	int16 x, y; +	uint16 w; +	g_gui.xmlEval()->getWidgetData("SaveLoadChooser.List", x, y, w, availableHeight); + +	const int16 buttonWidth = kThumbnailWidth + 6; +	const int16 buttonHeight = kThumbnailHeight2 + 6; + +	const int16 containerFrameWidthAdd = 10; +	const int16 containerFrameHeightAdd = 0; +	const int16 containerWidth = buttonWidth + containerFrameWidthAdd; +	const int16 containerHeight = buttonHeight + kLineHeight + containerFrameHeightAdd; + +	const int16 defaultSpacingHorizontal = 4; +	const int16 defaultSpacingVertical = 8; +	const int16 slotAreaWidth = containerWidth + defaultSpacingHorizontal; +	const int16 slotAreaHeight = containerHeight + defaultSpacingVertical; + +	const uint oldEntriesPerPage = _entriesPerPage; +	_columns = MAX<uint>(1, availableWidth / slotAreaWidth); +	_lines = MAX<uint>(1, availableHeight / slotAreaHeight); +	_entriesPerPage = _columns * _lines; + +	// In save mode the first button is always "New Save", thus we need to +	// adjust the entries per page here. +	if (_saveMode) { +		--_entriesPerPage; +	} + +	// Recalculate the page number +	if (!_saveList.empty() && oldEntriesPerPage != 0) { +		if (_entriesPerPage != 0) { +			_curPage = (_curPage * oldEntriesPerPage) / _entriesPerPage; +		} else { +			_curPage = 0; +		} +	} + +	const uint addX = _columns > 1 ? (availableWidth % slotAreaWidth) / (_columns - 1) : 0; +	//const uint addY = _lines > 1 ? (availableHeight % slotAreaHeight) / (_lines - 1) : 0; + +	_buttons.reserve(_lines * _columns); +	y += defaultSpacingVertical / 2; +	for (uint curLine = 0; curLine < _lines; ++curLine, y += slotAreaHeight/* + addY*/) { +		for (uint curColumn = 0, curX = x + defaultSpacingHorizontal / 2; curColumn < _columns; ++curColumn, curX += slotAreaWidth + addX) { +			int dstY = containerFrameHeightAdd / 2; +			int dstX = containerFrameWidthAdd / 2; + +			// In the save mode we will always create a new save button as the first button. +			if (_saveMode && curLine == 0 && curColumn == 0) { +				_newSaveContainer = new ContainerWidget(this, curX, y, containerWidth, containerHeight); +				ButtonWidget *newSave = new ButtonWidget(_newSaveContainer, dstX, dstY, buttonWidth, buttonHeight, _("New Save"), _("Create a new save game"), kNewSaveCmd); +				// In case no more slots are free, we will disable the new save button +				if (_nextFreeSaveSlot == -1) { +					newSave->setEnabled(false); +				} +				continue; +			} + +			ContainerWidget *container = new ContainerWidget(this, curX, y, containerWidth, containerHeight); +			container->setVisible(false); + +			// Command 0 cannot be used, since it won't be send. Thus we will adjust +			// command number here, if required. This is only the case for load mode +			// since for save mode, the first button used is index 1 anyway. +			uint buttonCmd = curLine * _columns + curColumn; +			if (!_saveMode) { +				buttonCmd += 1; +			} +	 +			PicButtonWidget *button = new PicButtonWidget(container, dstX, dstY, buttonWidth, buttonHeight, 0, buttonCmd); +			dstY += buttonHeight; + +			StaticTextWidget *description = new StaticTextWidget(container, dstX, dstY, buttonWidth, kLineHeight, Common::String(), Graphics::kTextAlignLeft); + +			_buttons.push_back(SlotButton(container, button, description)); +		} +	} + +	if (!_target.empty()) +		updateSaves(); +} + +void SaveLoadChooserGrid::close() { +	SaveLoadChooserDialog::close(); +	hideButtons(); +} + +int SaveLoadChooserGrid::runIntern() { +	int slot; +	do { +		const SaveLoadChooserType currentType = getType(); +		const SaveLoadChooserType requestedType = getRequestedSaveLoadDialog(*_metaEngine); + +		// Catch resolution changes when the save name dialog was open. +		if (currentType != requestedType) { +			setResult(kSwitchSaveLoadDialog); +			return kSwitchSaveLoadDialog; +		} + +		slot = runModal(); +	} while (_saveMode && slot >= 0 && !selectDescription()); + +	return slot; +} + +bool SaveLoadChooserGrid::selectDescription() { +	_savenameDialog.setDescription(_resultString); +	_savenameDialog.setTargetSlot(getResult()); +	if (_savenameDialog.runModal() == 0) { +		_resultString = _savenameDialog.getDescription(); +		return true; +	} else { +		return false; +	} +} + +void SaveLoadChooserGrid::destroyButtons() { +	if (_newSaveContainer) { +		removeWidget(_newSaveContainer); +		delete _newSaveContainer; +		_newSaveContainer = 0; +	} + +	for (ButtonArray::iterator i = _buttons.begin(), end = _buttons.end(); i != end; ++i) { +		removeWidget(i->container); +		delete i->container; +	} + +	_buttons.clear(); +} + +void SaveLoadChooserGrid::hideButtons() { +	for (ButtonArray::iterator i = _buttons.begin(), end = _buttons.end(); i != end; ++i) { +		i->button->setGfx(0); +		i->setVisible(false); +	} +} + +void SaveLoadChooserGrid::updateSaves() { +	hideButtons(); + +	for (uint i = _curPage * _entriesPerPage, curNum = 0; i < _saveList.size() && curNum < _entriesPerPage; ++i, ++curNum) { +		const uint saveSlot = _saveList[i].getSaveSlot(); + +		SaveStateDescriptor desc = _metaEngine->querySaveMetaInfos(_target.c_str(), saveSlot); +		SlotButton &curButton = _buttons[curNum]; +		curButton.setVisible(true); +		const Graphics::Surface *thumbnail = desc.getThumbnail(); +		if (thumbnail) { +			curButton.button->setGfx(desc.getThumbnail()); +		} else { +			curButton.button->setGfx(kThumbnailWidth, kThumbnailHeight2, 0, 0, 0); +		} +		curButton.description->setLabel(Common::String::format("%d. %s", saveSlot, desc.getDescription().c_str())); + +		Common::String tooltip(_("Name: ")); +		tooltip += desc.getDescription(); + +		if (_saveDateSupport) { +			const Common::String &saveDate = desc.getSaveDate(); +			if (!saveDate.empty()) { +				tooltip += "\n"; +				tooltip +=  _("Date: ") + saveDate; +			} + +			const Common::String &saveTime = desc.getSaveTime(); +			if (!saveTime.empty()) { +				tooltip += "\n"; +				tooltip += _("Time: ") + saveTime; +			} +		} + +		if (_playTimeSupport) { +			const Common::String &playTime = desc.getPlayTime(); +			if (!playTime.empty()) { +				tooltip += "\n"; +				tooltip += _("Playtime: ") + playTime; +			} +		} + +		curButton.button->setTooltip(tooltip); + +		// In save mode we disable the button, when it's write protected. +		// TODO: Maybe we should not display it at all then? +		if (_saveMode && desc.getWriteProtectedFlag()) { +			curButton.button->setEnabled(false); +		} else { +			curButton.button->setEnabled(true); +		} +	} + +	const uint numPages = (_entriesPerPage != 0) ? (_saveList.size() / _entriesPerPage + 1) : 1; +	_pageDisplay->setLabel(Common::String::format("%u/%u", _curPage + 1, numPages)); + +	if (_curPage > 0) +		_prevButton->setEnabled(true); +	else +		_prevButton->setEnabled(false); + +	if ((_curPage + 1) * _entriesPerPage < _saveList.size()) +		_nextButton->setEnabled(true); +	else +		_nextButton->setEnabled(false); +} + +SavenameDialog::SavenameDialog() +	: Dialog("SavenameDialog") { +	_title = new StaticTextWidget(this, "SavenameDialog.DescriptionText", Common::String()); + +	new ButtonWidget(this, "SavenameDialog.Cancel", _("Cancel"), 0, kCloseCmd); +	new ButtonWidget(this, "SavenameDialog.Ok", _("OK"), 0, kOKCmd); + +	_description = new EditTextWidget(this, "SavenameDialog.Description", Common::String(), 0, 0, kOKCmd); +} + +void SavenameDialog::setDescription(const Common::String &desc) { +	_description->setEditString(desc); +} + +const Common::String &SavenameDialog::getDescription() { +	return _description->getEditString(); +} + +void SavenameDialog::open() { +	Dialog::open(); +	setResult(-1); + +	_title->setLabel(Common::String::format(_("Enter a description for slot %d:"), _targetSlot)); +} + +void SavenameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { +	switch (cmd) { +	case kOKCmd: +		setResult(0); +		close(); +		break; + +	default: +		Dialog::handleCommand(sender, cmd, data); +	} +} + +#endif // !DISABLE_SAVELOADCHOOSER_GRID + +} // End of namespace GUI | 
