[Scummvm-git-logs] scummvm master -> 1855d1cf13de5c9f4cf84fc07ab4b5053cae5295

peterkohaut peterkohaut at users.noreply.github.com
Wed Dec 5 18:20:53 CET 2018


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
1855d1cf13 BLADERUNNER: Add in-game saving screen


Commit: 1855d1cf13de5c9f4cf84fc07ab4b5053cae5295
    https://github.com/scummvm/scummvm/commit/1855d1cf13de5c9f4cf84fc07ab4b5053cae5295
Author: Peter Kohaut (peter.kohaut at gmail.com)
Date: 2018-12-05T18:18:49+01:00

Commit Message:
BLADERUNNER: Add in-game saving screen

Changed paths:
  A engines/bladerunner/ui/kia_section_save.cpp
    engines/bladerunner/bladerunner.cpp
    engines/bladerunner/detection.cpp
    engines/bladerunner/module.mk
    engines/bladerunner/savefile.cpp
    engines/bladerunner/savefile.h
    engines/bladerunner/ui/kia.h
    engines/bladerunner/ui/kia_section_clues.h
    engines/bladerunner/ui/kia_section_load.cpp
    engines/bladerunner/ui/kia_section_load.h
    engines/bladerunner/ui/kia_section_save.h
    engines/bladerunner/ui/ui_component.h
    engines/bladerunner/ui/ui_container.cpp
    engines/bladerunner/ui/ui_container.h
    engines/bladerunner/ui/ui_input_box.cpp
    engines/bladerunner/ui/ui_input_box.h


diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index 3d9ba34..61b45e9 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -221,9 +221,7 @@ bool BladeRunnerEngine::canLoadGameStateCurrently() {
 }
 
 Common::Error BladeRunnerEngine::loadGameState(int slot) {
-	const Common::String saveName = Common::String::format("%s.%03d", _targetName.c_str(), slot);
-
-	Common::InSaveFile *saveFile = getSaveFileManager()->openForLoading(saveName);
+	Common::InSaveFile *saveFile = BladeRunner::SaveFileManager::openForLoading(_targetName, slot);
 	if (saveFile == nullptr || saveFile->err()) {
 		delete saveFile;
 		return Common::kReadingFailed;
@@ -253,9 +251,7 @@ bool BladeRunnerEngine::canSaveGameStateCurrently() {
 }
 
 Common::Error BladeRunnerEngine::saveGameState(int slot, const Common::String &desc) {
-	const Common::String saveName = Common::String::format("%s.%03d", _targetName.c_str(), slot);
-
-	Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(saveName);
+	Common::OutSaveFile *saveFile = BladeRunner::SaveFileManager::openForSaving(_targetName, slot);
 	if (saveFile == nullptr || saveFile->err()) {
 		delete saveFile;
 		return Common::kReadingFailed;
@@ -1097,6 +1093,7 @@ void BladeRunnerEngine::handleKeyDown(Common::Event &event) {
 
 	if (_kia->isOpen()) {
 		_kia->handleKeyDown(event.kbd);
+		return;
 	}
 
 	if (_spinner->isOpen()) {
diff --git a/engines/bladerunner/detection.cpp b/engines/bladerunner/detection.cpp
index 46285e5..5293d76 100644
--- a/engines/bladerunner/detection.cpp
+++ b/engines/bladerunner/detection.cpp
@@ -95,8 +95,7 @@ int BladeRunnerMetaEngine::getMaximumSaveSlot() const {
 }
 
 void BladeRunnerMetaEngine::removeSaveState(const char *target, int slot) const {
-	Common::String filename = Common::String::format("%s.%03d", target, slot);
-	g_system->getSavefileManager()->removeSavefile(filename);
+	BladeRunner::SaveFileManager::remove(target, slot);
 }
 
 SaveStateDescriptor BladeRunnerMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk
index 29b6fd2..243f426 100644
--- a/engines/bladerunner/module.mk
+++ b/engines/bladerunner/module.mk
@@ -259,6 +259,7 @@ MODULE_OBJS = \
 	ui/kia_section_help.o \
 	ui/kia_section_load.o \
 	ui/kia_section_pogo.o \
+	ui/kia_section_save.o \
 	ui/kia_section_settings.o \
 	ui/kia_section_suspects.o \
 	ui/kia_shapes.o \
diff --git a/engines/bladerunner/savefile.cpp b/engines/bladerunner/savefile.cpp
index fc0073c..55670a1 100644
--- a/engines/bladerunner/savefile.cpp
+++ b/engines/bladerunner/savefile.cpp
@@ -78,6 +78,21 @@ SaveStateDescriptor SaveFileManager::queryMetaInfos(const Common::String &target
 	return desc;
 }
 
+Common::InSaveFile *SaveFileManager::openForLoading(const Common::String &target, int slot) {
+	Common::String filename = Common::String::format("%s.%03d", target.c_str(), slot);
+	return g_system->getSavefileManager()->openForLoading(filename);
+}
+
+Common::OutSaveFile *SaveFileManager::openForSaving(const Common::String &target, int slot) {
+	Common::String filename = Common::String::format("%s.%03d", target.c_str(), slot);
+	return g_system->getSavefileManager()->openForSaving(filename);
+}
+
+void SaveFileManager::remove(const Common::String &target, int slot) {
+	Common::String filename = Common::String::format("%s.%03d", target.c_str(), slot);
+	g_system->getSavefileManager()->removeSavefile(filename);
+}
+
 bool SaveFileManager::readHeader(Common::SeekableReadStream &in, SaveFileHeader &header, bool skipThumbnail) {
 	SaveFileReadStream s(in);
 
diff --git a/engines/bladerunner/savefile.h b/engines/bladerunner/savefile.h
index 64fb0b4..32b1fc1 100644
--- a/engines/bladerunner/savefile.h
+++ b/engines/bladerunner/savefile.h
@@ -25,6 +25,7 @@
 
 #include "common/array.h"
 #include "common/memstream.h"
+#include "common/savefile.h"
 #include "common/types.h"
 
 #include "graphics/surface.h"
@@ -67,8 +68,14 @@ public:
 	static SaveStateList list(const Common::String &target);
 	static SaveStateDescriptor queryMetaInfos(const Common::String &target, int slot);
 
+	static Common::InSaveFile *openForLoading(const Common::String &target, int slot);
+	static Common::OutSaveFile *openForSaving(const Common::String &target, int slot);
+
+	static void remove(const Common::String &target, int slot);
+
 	static bool readHeader(Common::SeekableReadStream &in, SaveFileHeader &header, bool skipThumbnail = true);
 	static bool writeHeader(Common::WriteStream &out, SaveFileHeader &header);
+
 };
 
 class SaveFileWriteStream : public Common::WriteStream {
diff --git a/engines/bladerunner/ui/kia.h b/engines/bladerunner/ui/kia.h
index b5be9a7..c6d612f 100644
--- a/engines/bladerunner/ui/kia.h
+++ b/engines/bladerunner/ui/kia.h
@@ -115,14 +115,15 @@ class KIA {
 
 	int                   _pogoPos;
 
-	Graphics::Surface     _thumbnail;
 
 public:
-	bool        _forceOpen;
+	bool              _forceOpen;
 
-	KIALog     *_log;
-	KIAScript  *_script;
-	KIAShapes  *_shapes;
+	KIALog           *_log;
+	KIAScript        *_script;
+	KIAShapes        *_shapes;
+
+	Graphics::Surface _thumbnail;
 
 public:
 	KIA(BladeRunnerEngine *vm);
diff --git a/engines/bladerunner/ui/kia_section_clues.h b/engines/bladerunner/ui/kia_section_clues.h
index afd8b67..1061e63 100644
--- a/engines/bladerunner/ui/kia_section_clues.h
+++ b/engines/bladerunner/ui/kia_section_clues.h
@@ -45,10 +45,10 @@ class KIASectionClues : public KIASectionBase {
 		int flags;
 	};
 
-	UIContainer         *_uiContainer;
-	UIImagePicker       *_buttons;
-	UIScrollBox         *_cluesScrollBox;
-	UIScrollBox         *_filterScrollBox;
+	UIContainer        *_uiContainer;
+	UIImagePicker      *_buttons;
+	UIScrollBox        *_cluesScrollBox;
+	UIScrollBox        *_filterScrollBox;
 
 	bool                _isOpen;
 	bool                _debugIntangible;
diff --git a/engines/bladerunner/ui/kia_section_load.cpp b/engines/bladerunner/ui/kia_section_load.cpp
index ba746ca..bbc3c74 100644
--- a/engines/bladerunner/ui/kia_section_load.cpp
+++ b/engines/bladerunner/ui/kia_section_load.cpp
@@ -35,8 +35,6 @@
 #include "common/error.h"
 #include "common/system.h"
 
-#include "engines/savestate.h"
-
 namespace BladeRunner {
 
 KIASectionLoad::KIASectionLoad(BladeRunnerEngine *vm) : KIASectionBase(vm) {
@@ -56,34 +54,35 @@ void KIASectionLoad::open() {
 	_scrollBox->show();
 	_scrollBox->clearLines();
 
-	SaveStateList saveList = SaveFileManager::list(_vm->getTargetName());
-
-	_saveSlotMax = -1;
+	_saveList = SaveFileManager::list(_vm->getTargetName());
 
-	if (!saveList.empty()) {
+	if (!_saveList.empty()) {
 		_scrollBox->addLine(_vm->_textOptions->getText(36), -1, 4); // Load game:
-		for (Common::Array<SaveStateDescriptor>::iterator save = saveList.begin(); save != saveList.end(); save++) {
-			_scrollBox->addLine(save->getDescription(), save->getSaveSlot(), 0);
-			_saveSlotMax = MAX(_saveSlotMax, save->getSaveSlot());
+		for (uint i = 0; i < _saveList.size(); ++i) {
+			_scrollBox->addLine(_saveList[i].getDescription(), i, 0);
 		}
 		_scrollBox->addLine("", -1, 4);
 	}
 
+	_newGameEasyLineId = _saveList.size();
+	_newGameMediumLineId = _saveList.size() + 1;
+	_newGameHardLineId = _saveList.size() + 2;
 
 	_scrollBox->addLine(_vm->_textOptions->getText(37), -1, 4); // New game:
-	_scrollBox->addLine(_vm->_textOptions->getText(20), _saveSlotMax + 1, 0); // Easy
-	_scrollBox->addLine(_vm->_textOptions->getText(28), _saveSlotMax + 2, 0); // Medium
-	_scrollBox->addLine(_vm->_textOptions->getText(29), _saveSlotMax + 3, 0); // Hard
+	_scrollBox->addLine(_vm->_textOptions->getText(20), _newGameEasyLineId, 0); // Easy
+	_scrollBox->addLine(_vm->_textOptions->getText(28), _newGameMediumLineId, 0); // Medium
+	_scrollBox->addLine(_vm->_textOptions->getText(29), _newGameHardLineId, 0); // Hard
 
-	_hoveredSaveSlot = -1;
+	_hoveredLineId = -1;
 	_timeLast = _vm->getTotalPlayTime();
 	_timeLeft = 800;
 }
 
 void KIASectionLoad::close() {
 	_scrollBox->hide();
-
 	_vm->_kia->playerReset();
+
+	_saveList.clear();
 }
 
 void KIASectionLoad::draw(Graphics::Surface &surface){
@@ -91,12 +90,12 @@ void KIASectionLoad::draw(Graphics::Surface &surface){
 
 	_uiContainer->draw(surface);
 
-	int selectedSaveSlot = _scrollBox->getSelectedLineData();
+	int selectedLineId = _scrollBox->getSelectedLineData();
 
-	if (_hoveredSaveSlot != selectedSaveSlot) {
-		if (selectedSaveSlot >= 0) {
+	if (_hoveredLineId != selectedLineId) {
+		if (selectedLineId >= 0 && selectedLineId < (int)_saveList.size()) {
 			if (_timeLeft == 0) {
-				SaveStateDescriptor desc = SaveFileManager::queryMetaInfos(_vm->getTargetName(), selectedSaveSlot);
+				SaveStateDescriptor desc = SaveFileManager::queryMetaInfos(_vm->getTargetName(), selectedLineId);
 				const Graphics::Surface *thumbnail = desc.getThumbnail();
 				if (thumbnail != nullptr) {
 					_vm->_kia->playImage(*thumbnail);
@@ -106,15 +105,15 @@ void KIASectionLoad::draw(Graphics::Surface &surface){
 			_vm->_kia->playerReset();
 			_timeLeft = 800;
 		}
-		_hoveredSaveSlot = selectedSaveSlot;
+		_hoveredLineId = selectedLineId;
 	}
 
 	uint32 now = _vm->getTotalPlayTime();
-	if (selectedSaveSlot >= 0) {
+	if (selectedLineId >= 0 && selectedLineId < (int)_saveList.size()) {
 		if (_timeLeft) {
 			uint32 timeDiff = now - _timeLast;
 			if (timeDiff >= _timeLeft) {
-				SaveStateDescriptor desc = SaveFileManager::queryMetaInfos(_vm->getTargetName(), selectedSaveSlot);
+				SaveStateDescriptor desc = SaveFileManager::queryMetaInfos(_vm->getTargetName(), _saveList[selectedLineId].getSaveSlot());
 				const Graphics::Surface *thumbnail = desc.getThumbnail();
 				if (thumbnail != nullptr) {
 					_vm->_kia->playImage(*thumbnail);
@@ -144,11 +143,11 @@ void KIASectionLoad::scrollBoxCallback(void *callbackData, void *source, int lin
 	KIASectionLoad *self = (KIASectionLoad *)callbackData;
 
 	if (mouseButton == 0 && source == self->_scrollBox && lineData >= 0) {
-		if (lineData == self->_saveSlotMax + 1) {
+		if (lineData == self->_newGameEasyLineId) {
 			self->_vm->newGame(0);
-		} else if (lineData == self->_saveSlotMax + 2) {
+		} else if (lineData == self->_newGameMediumLineId) {
 			self->_vm->newGame(1);
-		} else if (lineData == self->_saveSlotMax + 3) {
+		} else if (lineData == self->_newGameHardLineId) {
 			self->_vm->newGame(2);
 		} else {
 			self->_vm->loadGameState(lineData);
diff --git a/engines/bladerunner/ui/kia_section_load.h b/engines/bladerunner/ui/kia_section_load.h
index 040fc09..820b39f 100644
--- a/engines/bladerunner/ui/kia_section_load.h
+++ b/engines/bladerunner/ui/kia_section_load.h
@@ -28,6 +28,8 @@
 #include "common/scummsys.h"
 #include "common/str.h"
 
+#include "engines/savestate.h"
+
 namespace Graphics {
 struct Surface;
 }
@@ -38,33 +40,31 @@ class UIContainer;
 class UIScrollBox;
 
 class KIASectionLoad : public KIASectionBase {
+	UIContainer  *_uiContainer;
+	UIScrollBox  *_scrollBox;
 
-	struct Save {
-		Common::String name;
-		int slotNum;
-	};
-
-	UIContainer *_uiContainer;
-	UIScrollBox *_scrollBox;
+	uint32        _timeLast;
+	uint32        _timeLeft;
 
-	uint32       _timeLast;
-	uint32       _timeLeft;
+	SaveStateList _saveList;
 
-	int          _hoveredSaveSlot;
-	int          _saveSlotMax;
+	int           _hoveredLineId;
+	int           _newGameEasyLineId;
+	int           _newGameMediumLineId;
+	int           _newGameHardLineId;
 
 public:
 	KIASectionLoad(BladeRunnerEngine *vm);
 	~KIASectionLoad();
 
-	void open();
-	void close();
+	void open() override;
+	void close() override;
 
-	void draw(Graphics::Surface &surface);
+	void draw(Graphics::Surface &surface) override;
 
-	void handleMouseMove(int mouseX, int mouseY);
-	void handleMouseDown(bool mainButton);
-	void handleMouseUp(bool mainButton);
+	void handleMouseMove(int mouseX, int mouseY) override;
+	void handleMouseDown(bool mainButton) override;
+	void handleMouseUp(bool mainButton) override;
 
 private:
 	static void scrollBoxCallback(void *callbackData, void *source, int lineData, int mouseButton);
diff --git a/engines/bladerunner/ui/kia_section_save.cpp b/engines/bladerunner/ui/kia_section_save.cpp
new file mode 100644
index 0000000..997cb75
--- /dev/null
+++ b/engines/bladerunner/ui/kia_section_save.cpp
@@ -0,0 +1,407 @@
+/* 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 "bladerunner/ui/kia_section_save.h"
+
+#include "bladerunner/audio_player.h"
+#include "bladerunner/bladerunner.h"
+#include "bladerunner/font.h"
+#include "bladerunner/game_info.h"
+#include "bladerunner/savefile.h"
+#include "bladerunner/text_resource.h"
+#include "bladerunner/ui/kia.h"
+#include "bladerunner/ui/kia_shapes.h"
+#include "bladerunner/ui/ui_container.h"
+#include "bladerunner/ui/ui_image_picker.h"
+#include "bladerunner/ui/ui_input_box.h"
+#include "bladerunner/ui/ui_scroll_box.h"
+
+#include "common/error.h"
+#include "common/keyboard.h"
+#include "common/system.h"
+
+namespace BladeRunner {
+
+KIASectionSave::KIASectionSave(BladeRunnerEngine *vm) : KIASectionBase(vm) {
+	_uiContainer = new UIContainer(_vm);
+
+	_scrollBox = new UIScrollBox(_vm, scrollBoxCallback, this, 1024, 0, true, Common::Rect(155, 158, 461, 346), Common::Rect(506, 160, 506, 350));
+	_uiContainer->add(_scrollBox);
+
+	_inputBox = new UIInputBox(_vm, inputBoxCallback, this, Common::Rect(155, 367, 461, 376), 41, "");
+	_uiContainer->add(_inputBox);
+	_inputBox->hide();
+
+	_buttons = new UIImagePicker(_vm, 3);
+
+	_mouseX = 0;
+	_mouseY = 0;
+
+	_selectedLineId = -1;
+	_hoveredLineId = -1;
+	_newSaveLineId = -1;
+}
+
+KIASectionSave::~KIASectionSave() {
+	delete _buttons;
+
+	_uiContainer->clear();
+	delete _inputBox;
+	delete _scrollBox;
+	delete _uiContainer;
+}
+
+void KIASectionSave::open() {
+	_scheduledSwitch = false;
+	_state = kStateNormal;
+
+	_buttons->resetImages();
+	_buttons->defineImage(
+		0,
+		Common::Rect(460, 366, 497, 402),
+		_vm->_kia->_shapes->get(82),
+		_vm->_kia->_shapes->get(83),
+		_vm->_kia->_shapes->get(84),
+		_vm->_textOptions->getText(22) // Save
+	);
+
+	_scrollBox->show();
+
+	_saveList = SaveFileManager::list(_vm->getTargetName());
+
+	bool ableToSaveGame = true;
+
+	_newSaveLineId = _saveList.size();
+
+	if (!_saveList.empty() || ableToSaveGame) {
+
+		_buttons->activate(nullptr, nullptr, nullptr, onButtonPressed, this);
+		_inputBox->show();
+
+		_scrollBox->clearLines();
+
+		if (ableToSaveGame) {
+			_scrollBox->addLine(_vm->_textOptions->getText(23), _newSaveLineId, 0);
+		}
+
+		for (uint i = 0; i < _saveList.size(); ++i) {
+			_scrollBox->addLine(_saveList[i].getDescription(), i, 0);
+		}
+
+		if (ableToSaveGame) {
+			// New save
+			_selectedLineId = _newSaveLineId;
+			_inputBox->setText("");
+		} else {
+			// Overwrite first save
+			_selectedLineId = 0;
+			_inputBox->setText(_saveList[_selectedLineId].getDescription());
+		}
+
+		_scrollBox->setFlags(_selectedLineId, 8);
+	}
+
+	_hoveredLineId = -1;
+	_timeLast = _vm->getTotalPlayTime();
+	_timeLeft = 800;
+}
+
+void KIASectionSave::close() {
+	_inputBox->hide();
+	_scrollBox->hide();
+	_buttons->deactivate();
+
+	_vm->_kia->playerReset();
+
+	_saveList.clear();
+}
+
+void KIASectionSave::draw(Graphics::Surface &surface){
+	_vm->_kia->_shapes->get(69)->draw(surface, 501, 123);
+	_buttons->draw(surface);
+
+	if (_state == kStateNormal) {
+		const char *textChooseSlot = _vm->_textOptions->getText(24); // Choose a slot ...
+		int textChooseSlotWidth = _vm->_mainFont->getTextWidth(textChooseSlot);
+		_vm->_mainFont->drawColor(textChooseSlot, surface, 308 - textChooseSlotWidth / 2, 143, 0x7BB8);
+
+		// Original game shows warnings/error here, but we don't have any
+
+		const char *textTypeName = _vm->_textOptions->getText(24); // Type a name ...
+		int textTypeNameWidth = _vm->_mainFont->getTextWidth(textTypeName);
+		_vm->_mainFont->drawColor(textTypeName, surface, 308 - textTypeNameWidth / 2, 352, 0x7BB8);
+
+		_uiContainer->draw(surface);
+	} else if (_state == kStateOverwrite) {
+		surface.fillRect(Common::Rect(155, 230, 462, 239), 0x28E4);
+
+		const Common::String &saveName = _saveList[_selectedLineId].getDescription();
+		int saveNameWidth = _vm->_mainFont->getTextWidth(saveName);
+		_vm->_mainFont->drawColor(saveName, surface, 308 - saveNameWidth / 2, 230, 0x7751);
+
+		const char *textOverwrite = _vm->_textOptions->getText(35); // Overwrite previously saved game?
+		int textOverwriteWidth = _vm->_mainFont->getTextWidth(textOverwrite);
+		_vm->_mainFont->drawColor(textOverwrite, surface, 308 - textOverwriteWidth / 2, 240, 0x7BB8);
+	} else if (_state == kStateDelete) {
+		surface.fillRect(Common::Rect(155, 230, 462, 239), 0x28E4);
+
+		const Common::String &saveName = _saveList[_selectedLineId].getDescription();
+		int saveNameWidth = _vm->_mainFont->getTextWidth(saveName); // Delete this game?
+		_vm->_mainFont->drawColor(saveName, surface, 308 - saveNameWidth / 2, 230, 0x7751);
+
+		const char *textDelete = _vm->_textOptions->getText(40);
+		int textDeleteWidth = _vm->_mainFont->getTextWidth(textDelete);
+		_vm->_mainFont->drawColor(textDelete, surface, 308 - textDeleteWidth / 2, 240, 0x7BB8);
+	}
+
+	int selectedLineId = _scrollBox->getSelectedLineData();
+
+	if (selectedLineId != _hoveredLineId) {
+		if (selectedLineId >= 0 && selectedLineId < (int)_saveList.size()) {
+			if (_timeLeft == 0) {
+				SaveStateDescriptor desc = SaveFileManager::queryMetaInfos(_vm->getTargetName(), selectedLineId);
+				const Graphics::Surface *thumbnail = desc.getThumbnail();
+				if (thumbnail != nullptr) {
+					_vm->_kia->playImage(*thumbnail);
+				}
+			}
+		} else {
+			_vm->_kia->playerReset();
+			_timeLeft = 800;
+		}
+		_hoveredLineId = selectedLineId;
+	}
+
+	uint32 now = _vm->getTotalPlayTime();
+	if (selectedLineId >= 0 && selectedLineId < (int)_saveList.size()) {
+		if (_timeLeft) {
+			uint32 timeDiff = now - _timeLast;
+			if (timeDiff >= _timeLeft) {
+				SaveStateDescriptor desc = SaveFileManager::queryMetaInfos(_vm->getTargetName(), _saveList[selectedLineId].getSaveSlot());
+				const Graphics::Surface *thumbnail = desc.getThumbnail();
+				if (thumbnail != nullptr) {
+					_vm->_kia->playImage(*thumbnail);
+				}
+			} else {
+				_timeLeft -= timeDiff;
+			}
+		}
+	}
+
+	_timeLast = now;
+	_buttons->drawTooltip(surface, _mouseX, _mouseY);
+}
+
+void KIASectionSave::handleKeyUp(const Common::KeyState &kbd) {
+	if (_state == kStateNormal) {
+		_uiContainer->handleKeyUp(kbd);
+	} else if (_state == kStateOverwrite) {
+		if (kbd.keycode == Common::KEYCODE_RETURN) {
+			save();
+			changeState(kStateNormal);
+		}
+	} else if (_state == kStateDelete) {
+		if (kbd.keycode == Common::KEYCODE_RETURN) {
+			deleteSave();
+			changeState(kStateNormal);
+		}
+	}
+}
+
+void KIASectionSave::handleKeyDown(const Common::KeyState &kbd) {
+	if (_state == kStateNormal) {
+		if (kbd.keycode == Common::KEYCODE_DELETE && _selectedLineId != _newSaveLineId) {
+			changeState(kStateDelete);
+		}
+
+		_uiContainer->handleKeyDown(kbd);
+	}
+}
+
+void KIASectionSave::handleMouseMove(int mouseX, int mouseY) {
+	_mouseX = mouseX;
+	_mouseY = mouseY;
+
+	_buttons->handleMouseAction(_mouseX, _mouseY, false, false, false);
+
+	if (_state == kStateNormal) {
+		_uiContainer->handleMouseMove(_mouseX, _mouseY);
+	}
+}
+
+void KIASectionSave::handleMouseDown(bool mainButton) {
+	if (mainButton) {
+		if (_state == kStateNormal) {
+			_uiContainer->handleMouseDown(false);
+		}
+
+		_buttons->handleMouseAction(_mouseX, _mouseY, true, false, false);
+	}
+}
+
+void KIASectionSave::handleMouseUp(bool mainButton) {
+	if (mainButton) {
+		_buttons->handleMouseAction(_mouseX, _mouseY, false, true, false);
+
+		if (_state == kStateNormal) {
+			_uiContainer->handleMouseUp(false);
+		}
+	}
+}
+
+void KIASectionSave::scrollBoxCallback(void *callbackData, void *source, int lineData, int mouseButton) {
+	KIASectionSave *self = (KIASectionSave *)callbackData;
+
+	if (mouseButton == 0 && source == self->_scrollBox && lineData >= 0 && lineData <= (int)self->_saveList.size()) {
+		self->_scrollBox->resetFlags(self->_selectedLineId, 8);
+		self->_selectedLineId = lineData;
+		self->_scrollBox->setFlags(self->_selectedLineId, 8);
+
+		if (self->_selectedLineId == self->_newSaveLineId) {
+			self->_inputBox->setText("");
+		} else {
+			self->_inputBox->setText(self->_saveList[self->_selectedLineId].getDescription());
+		}
+
+		self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(131), 40, 0, 0, 50, 0);
+		self->_vm->_kia->resume();
+	}
+}
+
+void  KIASectionSave::inputBoxCallback(void *callbackData, void *source) {
+	KIASectionSave *self = (KIASectionSave *)callbackData;
+	if (source == self->_inputBox) {
+		if (self->_selectedLineId == self->_newSaveLineId) {
+			self->save();
+		} else {
+			self->changeState(kStateOverwrite);
+		}
+	}
+}
+
+void KIASectionSave::onButtonPressed(int buttonId, void *callbackData) {
+	KIASectionSave *self = (KIASectionSave *)callbackData;
+
+	if (buttonId == 0) {
+		if (self->_selectedLineId == self->_newSaveLineId)
+		{
+			self->save();
+		}
+		else
+		{
+			self->changeState(kStateOverwrite);
+		}
+	} else if (buttonId == 1) {
+		self->changeState(kStateNormal);
+		self->_vm->_audioPlayer->playAud(self->_vm->_gameInfo->getSfxTrack(134), 90, -50, -50, 50, 0);
+	} else if (buttonId == 2) {
+		if (self->_state == kStateOverwrite)
+		{
+			self->save();
+		}
+		else if (self->_state == kStateDelete)
+		{
+			self->deleteSave();
+		}
+	}
+}
+
+void KIASectionSave::changeState(State state) {
+	_state = state;
+	if (state == kStateNormal) {
+		_buttons->resetImages();
+		_buttons->defineImage(
+			0,
+			Common::Rect(460, 366, 497, 402),
+			_vm->_kia->_shapes->get(82),
+			_vm->_kia->_shapes->get(83),
+			_vm->_kia->_shapes->get(84),
+			_vm->_textOptions->getText(22) // Save
+		);
+	} else {
+		_buttons->resetImages();
+		_buttons->defineImage(
+			1,
+			Common::Rect(318, 260, 357, 299),
+			_vm->_kia->_shapes->get(126),
+			_vm->_kia->_shapes->get(127),
+			_vm->_kia->_shapes->get(128),
+			_vm->_textOptions->getText(38) // No
+		);
+		_buttons->defineImage(
+			2,
+			Common::Rect(258, 260, 297, 299),
+			_vm->_kia->_shapes->get(129),
+			_vm->_kia->_shapes->get(130),
+			_vm->_kia->_shapes->get(131),
+			_vm->_textOptions->getText(39) // Yes
+		);
+		_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(135), 90, 0, 0, 50, 0);
+	}
+}
+
+void KIASectionSave::save() {
+	int slot = -1;
+
+	if (_selectedLineId < (int)_saveList.size()) {
+		slot = _saveList[_selectedLineId].getSaveSlot();
+	} else {
+		// Find first available save slot
+		for (int i = 0; i < (int)_saveList.size(); ++i) {
+			if (_saveList[i].getSaveSlot() != i) {
+				slot = i;
+				break;
+			}
+		}
+
+		if (slot == -1) {
+			slot = _saveList.size();
+		}
+	}
+
+	Common::OutSaveFile *saveFile = BladeRunner::SaveFileManager::openForSaving(_vm->getTargetName(), slot);
+	if (saveFile == nullptr || saveFile->err()) {
+		delete saveFile;
+	}
+
+	BladeRunner::SaveFileHeader header;
+	header._name = _inputBox->getText();
+
+	BladeRunner::SaveFileManager::writeHeader(*saveFile, header);
+
+	_vm->saveGame(*saveFile, _vm->_kia->_thumbnail);
+
+	saveFile->finalize();
+
+	delete saveFile;
+
+	_vm->_audioPlayer->playAud(_vm->_gameInfo->getSfxTrack(513), 90, 0, 0, 50, 0);
+
+	_scheduledSwitch = true;
+}
+void KIASectionSave::deleteSave() {
+	BladeRunner::SaveFileManager::remove(_vm->getTargetName(), _saveList[_selectedLineId].getSaveSlot());
+	close();
+	open();
+}
+
+} // End of namespace BladeRunner
diff --git a/engines/bladerunner/ui/kia_section_save.h b/engines/bladerunner/ui/kia_section_save.h
index 5e2f5f2..d3af652 100644
--- a/engines/bladerunner/ui/kia_section_save.h
+++ b/engines/bladerunner/ui/kia_section_save.h
@@ -25,13 +25,72 @@
 
 #include "bladerunner/ui/kia_section_base.h"
 
+#include "common/scummsys.h"
+#include "common/str.h"
+
+#include "engines/savestate.h"
+
+namespace Graphics {
+struct Surface;
+}
+
 namespace BladeRunner {
 
+class UIContainer;
+class UIScrollBox;
+class UIInputBox;
+class UIImagePicker;
+
 class KIASectionSave : public KIASectionBase {
+	enum State {
+		kStateNormal    = 0,
+		kStateOverwrite = 1,
+		kStateDelete    = 2
+	};
+
+	UIContainer   *_uiContainer;
+	UIScrollBox   *_scrollBox;
+	UIInputBox    *_inputBox;
+	UIImagePicker *_buttons;
+
+	uint32        _timeLast;
+	uint32        _timeLeft;
+
+	SaveStateList _saveList;
+
+	State         _state;
+
+	int           _mouseX;
+	int           _mouseY;
+
+	int           _hoveredLineId;
+	int           _selectedLineId;
+	int           _newSaveLineId;
 
 public:
-	KIASectionSave(BladeRunnerEngine *vm): KIASectionBase(vm){}
+	KIASectionSave(BladeRunnerEngine *vm);
+	~KIASectionSave();
+
+	void open() override;
+	void close() override;
+
+	void draw(Graphics::Surface &surface) override;
+
+	void handleKeyUp(const Common::KeyState &kbd) override;
+	void handleKeyDown(const Common::KeyState &kbd) override;
+	void handleMouseMove(int mouseX, int mouseY) override;
+	void handleMouseDown(bool mainButton) override;
+	void handleMouseUp(bool mainButton) override;
+
+private:
+	static void scrollBoxCallback(void *callbackData, void *source, int lineData, int mouseButton);
+	static void inputBoxCallback(void *callbackData, void *source);
+
+	static void onButtonPressed(int buttonId, void *callbackData);
 
+	void changeState(State state);
+	void save();
+	void deleteSave();
 };
 
 } // End of namespace BladeRunner
diff --git a/engines/bladerunner/ui/ui_component.h b/engines/bladerunner/ui/ui_component.h
index c3a8c21..aae944d 100644
--- a/engines/bladerunner/ui/ui_component.h
+++ b/engines/bladerunner/ui/ui_component.h
@@ -54,6 +54,7 @@ public:
 	virtual void handleMouseDown(bool alternateButton) {}
 	virtual void handleMouseUp(bool alternateButton) {}
 	virtual void handleKeyUp(const Common::KeyState &kbd) {}
+	virtual void handleKeyDown(const Common::KeyState &kbd) {}
 };
 
 } // End of namespace BladeRunner
diff --git a/engines/bladerunner/ui/ui_container.cpp b/engines/bladerunner/ui/ui_container.cpp
index e84809d..34a8cec 100644
--- a/engines/bladerunner/ui/ui_container.cpp
+++ b/engines/bladerunner/ui/ui_container.cpp
@@ -56,6 +56,12 @@ void UIContainer::handleKeyUp(const Common::KeyState &kbd) {
 	}
 }
 
+void UIContainer::handleKeyDown(const Common::KeyState &kbd) {
+	for (Common::Array<UIComponent*>::iterator component = _components.begin(); component != _components.end(); component++) {
+		(*component)->handleKeyDown(kbd);
+	}
+}
+
 void UIContainer::add(UIComponent *component) {
 	_components.push_back(component);
 }
diff --git a/engines/bladerunner/ui/ui_container.h b/engines/bladerunner/ui/ui_container.h
index 8e49d36..6d5a207 100644
--- a/engines/bladerunner/ui/ui_container.h
+++ b/engines/bladerunner/ui/ui_container.h
@@ -43,6 +43,7 @@ public:
 	void handleMouseDown(bool alternateButton);
 	void handleMouseUp(bool alternateButton);
 	void handleKeyUp(const Common::KeyState &kbd);
+	void handleKeyDown(const Common::KeyState &kbd);
 
 	void add(UIComponent *component);
 	void clear();
diff --git a/engines/bladerunner/ui/ui_input_box.cpp b/engines/bladerunner/ui/ui_input_box.cpp
index fb46ec8..466238f 100644
--- a/engines/bladerunner/ui/ui_input_box.cpp
+++ b/engines/bladerunner/ui/ui_input_box.cpp
@@ -40,7 +40,6 @@ UIInputBox::UIInputBox(BladeRunnerEngine *vm, UIComponentCallback *valueChangedC
 	_rect = rect;
 
 	_maxLength = maxLength;
-	_length    = 0;
 	setText(text);
 
 	_cursorIsVisible = false;
@@ -85,11 +84,9 @@ void UIInputBox::hide() {
 
 void UIInputBox::handleKeyUp(const Common::KeyState &kbd) {
 	if (_isVisible) {
-		if (charIsValid(kbd)) {
-			_text += kbd.ascii;
-		} else if (kbd.keycode == Common::KEYCODE_BACKSPACE) {
-			_text.deleteLastChar();
-		} else if (kbd.keycode == Common::KEYCODE_RETURN && !_text.empty()) {
+		// Check for "Enter" in keyUp instead of in keyDown as keyDown is repeating characters
+		// and that can screw up UX (which is not great in the original game either).
+		if (kbd.keycode == Common::KEYCODE_RETURN && !_text.empty()) {
 			if (_valueChangedCallback) {
 				_valueChangedCallback(_callbackData, this);
 			}
@@ -97,6 +94,16 @@ void UIInputBox::handleKeyUp(const Common::KeyState &kbd) {
 	}
 }
 
+void UIInputBox::handleKeyDown(const Common::KeyState &kbd) {
+	if (_isVisible) {
+		if (charIsValid(kbd) && _text.size() < _maxLength) {
+			_text += kbd.ascii;
+		} else if (kbd.keycode == Common::KEYCODE_BACKSPACE) {
+			_text.deleteLastChar();
+		}
+	}
+}
+
 bool UIInputBox::charIsValid(const Common::KeyState &kbd) {
 	return kbd.ascii >= ' '
 		&& kbd.ascii != '<'
diff --git a/engines/bladerunner/ui/ui_input_box.h b/engines/bladerunner/ui/ui_input_box.h
index 4dfe078..e3aee99 100644
--- a/engines/bladerunner/ui/ui_input_box.h
+++ b/engines/bladerunner/ui/ui_input_box.h
@@ -37,8 +37,7 @@ class UIInputBox : public UIComponent {
 	bool                 _isVisible;
 	Common::Rect         _rect;
 
-	int                  _maxLength;
-	int                  _length;
+	uint                 _maxLength;
 	Common::String       _text;
 
 	bool                 _cursorIsVisible;
@@ -48,7 +47,7 @@ class UIInputBox : public UIComponent {
 public:
 	UIInputBox(BladeRunnerEngine *vm, UIComponentCallback *valueChangedCallback, void *callbackData, Common::Rect rect, int maxLength, const Common::String &text);
 
-	void draw(Graphics::Surface &surface);
+	void draw(Graphics::Surface &surface) override;
 
 	void setText(const Common::String &text);
 	const Common::String &getText();
@@ -56,7 +55,8 @@ public:
 	void show();
 	void hide();
 
-	void handleKeyUp(const Common::KeyState &kbd);
+	void handleKeyUp(const Common::KeyState &kbd) override;
+	void handleKeyDown(const Common::KeyState &kbd) override;
 
 private:
 	bool charIsValid(const Common::KeyState &kbd);





More information about the Scummvm-git-logs mailing list