From d49bddfec6f4138aea1e44c8e61160276ebe20fd Mon Sep 17 00:00:00 2001 From: Thomas Fach-Pedersen Date: Mon, 31 Jul 2017 00:11:00 +0200 Subject: BLADERUNNER: Add Spinner support --- engines/bladerunner/bladerunner.cpp | 35 +++- engines/bladerunner/bladerunner.h | 6 +- engines/bladerunner/module.mk | 2 + engines/bladerunner/scene.cpp | 4 +- engines/bladerunner/script/script.cpp | 12 +- engines/bladerunner/spinner.cpp | 291 ++++++++++++++++++++++++++++++++ engines/bladerunner/spinner.h | 77 +++++++++ engines/bladerunner/ui_image_picker.cpp | 265 +++++++++++++++++++++++++++++ engines/bladerunner/ui_image_picker.h | 92 ++++++++++ 9 files changed, 768 insertions(+), 16 deletions(-) create mode 100644 engines/bladerunner/spinner.cpp create mode 100644 engines/bladerunner/spinner.h create mode 100644 engines/bladerunner/ui_image_picker.cpp create mode 100644 engines/bladerunner/ui_image_picker.h (limited to 'engines/bladerunner') diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp index 83a07bbd69..348d5f7c1f 100644 --- a/engines/bladerunner/bladerunner.cpp +++ b/engines/bladerunner/bladerunner.cpp @@ -49,6 +49,7 @@ #include "bladerunner/shape.h" #include "bladerunner/slice_animations.h" #include "bladerunner/slice_renderer.h" +#include "bladerunner/spinner.h" #include "bladerunner/text_resource.h" #include "bladerunner/vqa_decoder.h" #include "bladerunner/waypoints.h" @@ -286,6 +287,7 @@ bool BladeRunnerEngine::startup(bool hasSavegames) { // TODO: KIA // TODO: Spinner Interface + _spinner = new Spinner(this); // TODO: Elevators @@ -534,6 +536,10 @@ bool BladeRunnerEngine::init2() { return true; } +Common::Point BladeRunnerEngine::getMousePos() { + return _eventMan->getMousePos(); +} + void BladeRunnerEngine::gameLoop() { _gameIsRunning = true; do { @@ -581,7 +587,13 @@ void BladeRunnerEngine::gameTick() { // TODO: Autosave // TODO: Kia - // TODO: Spinner + + if (_spinner->isOpen()) { + _spinner->tick(); + _ambientSounds->tick(); + return; + } + // TODO: Esper // TODO: VK // TODO: Elevators @@ -636,7 +648,7 @@ void BladeRunnerEngine::gameTick() { // TODO: Draw dialogue menu - Common::Point p = _eventMan->getMousePos(); + Common::Point p = getMousePos(); _mouse->tick(p.x, p.y); _mouse->draw(_surfaceGame, p.x, p.y); @@ -797,17 +809,32 @@ void BladeRunnerEngine::handleEvents() { switch (event.type) { case Common::EVENT_LBUTTONDOWN: case Common::EVENT_RBUTTONDOWN: - handleMouseClick(event.mouse.x, event.mouse.y); + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONUP: { + bool buttonLeft = event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_LBUTTONUP; + bool buttonDown = event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_RBUTTONDOWN; + + handleMouseAction(event.mouse.x, event.mouse.y, buttonLeft, buttonDown); + } default: ; } } } -void BladeRunnerEngine::handleMouseClick(int x, int y) { +void BladeRunnerEngine::handleMouseAction(int x, int y, bool buttonLeft, bool buttonDown) { if (!playerHasControl() || _mouse->isDisabled()) return; + if (_spinner->isOpen()) { + if (buttonDown) { + _spinner->handleMouseDown(x, y); + } else { + _spinner->handleMouseUp(x, y); + } + return; + } + Vector3 mousePosition = _mouse->getXYZ(x, y); int isClickable; diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h index b2e3df08ea..8fd43df211 100644 --- a/engines/bladerunner/bladerunner.h +++ b/engines/bladerunner/bladerunner.h @@ -69,6 +69,7 @@ class Settings; class Shape; class SliceAnimations; class SliceRenderer; +class Spinner; class TextResource; class View; class Waypoints; @@ -105,6 +106,7 @@ public: Settings *_settings; SliceAnimations *_sliceAnimations; SliceRenderer *_sliceRenderer; + Spinner *_spinner; SuspectsDatabase *_suspectsDatabase; View *_view; Waypoints *_waypoints; @@ -164,11 +166,13 @@ public: bool loadSplash(); bool init2(); + Common::Point getMousePos(); + void gameLoop(); void gameTick(); void actorsUpdate(); void handleEvents(); - void handleMouseClick(int x, int y); + void handleMouseAction(int x, int y, bool buttonLeft, bool buttonDown); void handleMouseClickExit(int x, int y, int exitIndex); void handleMouseClickRegion(int x, int y, int regionIndex); void handleMouseClickItem(int x, int y, int itemId); diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk index 3569efab12..9a43ef4457 100644 --- a/engines/bladerunner/module.mk +++ b/engines/bladerunner/module.mk @@ -167,8 +167,10 @@ MODULE_OBJS = \ shape.o \ slice_animations.o \ slice_renderer.o \ + spinner.o \ suspects_database.o \ text_resource.o \ + ui_image_picker.o \ view.o \ vqa_decoder.o \ vqa_player.o \ diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp index 4af2c15d08..1e5297a4bf 100644 --- a/engines/bladerunner/scene.cpp +++ b/engines/bladerunner/scene.cpp @@ -33,6 +33,7 @@ #include "bladerunner/scene_objects.h" #include "bladerunner/script/scene.h" #include "bladerunner/slice_renderer.h" +#include "bladerunner/spinner.h" #include "common/str.h" @@ -306,8 +307,7 @@ void Scene::loopEnded(int frame, int loopId) { _playerWalkedIn = true; } if (_specialLoopMode == 3) { - //TODO: - //spinner::open(Spinner); + _vm->_spinner->setIsOpen(); } _specialLoopMode = -1; _specialLoop = -1; diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp index 9fcfb252c6..ba78a42b4c 100644 --- a/engines/bladerunner/script/script.cpp +++ b/engines/bladerunner/script/script.cpp @@ -43,6 +43,7 @@ #include "bladerunner/scene_objects.h" #include "bladerunner/slice_animations.h" #include "bladerunner/slice_renderer.h" +#include "bladerunner/spinner.h" #include "bladerunner/text_resource.h" #include "bladerunner/vector.h" #include "bladerunner/waypoints.h" @@ -1071,22 +1072,15 @@ bool ScriptBase::SDB_Add_Other_Clue(int suspectId, int clueId) { } void ScriptBase::Spinner_Set_Selectable_Destination_Flag(int a1, int a2) { - //TODO - warning("Spinner_Set_Selectable_Destination_Flag(%d, %d)", a1, a2); + _vm->_spinner->setSelectableDestinationFlag(a1, a2); } // ScriptBase::Spinner_Query_Selectable_Destination_Flag int ScriptBase::Spinner_Interface_Choose_Dest(int a1, int a2) { - //TODO - warning("Spinner_Interface_Choose_Dest(%d, %d)", a1, a2); - return -1; + return _vm->_spinner->interfaceChooseDest(a1, a2); } -// ScriptBase::Spinner_Set_Selectable_Destination_Flag -// ScriptBase::Spinner_Query_Selectable_Destination_Flag -// ScriptBase::Spinner_Interface_Choose_Dest - void ScriptBase::ESPER_Flag_To_Activate() { //TODO warning("ESPER_Flag_To_Activate()"); diff --git a/engines/bladerunner/spinner.cpp b/engines/bladerunner/spinner.cpp new file mode 100644 index 0000000000..6c30a62bac --- /dev/null +++ b/engines/bladerunner/spinner.cpp @@ -0,0 +1,291 @@ +/* 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/spinner.h" + +#include "bladerunner/bladerunner.h" + +#include "bladerunner/scene.h" +#include "bladerunner/shape.h" +#include "bladerunner/mouse.h" +#include "bladerunner/vqa_player.h" +#include "bladerunner/text_resource.h" +#include "bladerunner/ui_image_picker.h" + +#include "common/rect.h" +#include "common/system.h" + +namespace BladeRunner { + +Spinner::Spinner(BladeRunnerEngine *vm) : _vm(vm) { + reset(); + _imagePicker = new UIImagePicker(vm, SPINNER_DESTINATIONS); +} + +Spinner::~Spinner() { + delete _imagePicker; + reset(); +} + +void Spinner::setSelectableDestinationFlag(int destination, bool selectable) { + _isDestinationSelectable[destination] = selectable; +} + +bool Spinner::querySelectableDestinationFlag(int destination) const { + return _isDestinationSelectable[destination]; +} + +SpinnerDestination SpinnerDestinationsNear[] = { + { 0, 0x0D2, 0x107, 0x107, 0x14C }, + { 1, 0x133, 0x14A, 0x169, 0x17D }, + { 2, 0x152, 0x089, 0x16A, 0x0A9 }, + { 3, 0x0F8, 0x087, 0x121, 0x0A8 }, + { 4, 0x160, 0x0DE, 0x17B, 0x0EE }, + { -1, -1, -1, -1, -1 } +}; + +SpinnerDestination SpinnerDestinationsMedium[] = { + { 0, 0x0FC, 0x0F2, 0x117, 0x11B }, + { 1, 0x12D, 0x111, 0x148, 0x130 }, + { 2, 0x13F, 0x0B6, 0x150, 0x0C8 }, + { 3, 0x10D, 0x0B5, 0x125, 0x0C8 }, + { 4, 0x145, 0x0E3, 0x159, 0x0F0 }, + { 5, 0x103, 0x04A, 0x17C, 0x077 }, + { 6, 0x0CB, 0x07C, 0x0E0, 0x088 }, + { 7, 0x0C8, 0x093, 0x0DE, 0x0AA }, + { -1, -1, -1, -1, -1 } +}; + +SpinnerDestination SpinnerDestinationsFar[] = { + { 0, 0x0DC, 0x0E3, 0x0F6, 0x106 }, + { 1, 0x104, 0x0FC, 0x11E, 0x117 }, + { 2, 0x11E, 0x0B2, 0x12E, 0x0C4 }, + { 3, 0x0F4, 0x0B2, 0x107, 0x0C3 }, + { 4, 0x120, 0x0D8, 0x132, 0x0E4 }, + { 5, 0x0F9, 0x04D, 0x161, 0x07C }, + { 6, 0x0BE, 0x07F, 0x0D0, 0x08A }, + { 7, 0x0B9, 0x095, 0x0CE, 0x0AA }, + { 8, 0x18E, 0x0F9, 0x1A3, 0x10C }, + { 9, 0x186, 0x0DA, 0x1A3, 0x0EC }, + { -1, -1, -1, -1, -1 } +}; + +static void spinner_mouseInCallback(int, void*); +static void spinner_mouseOutCallback(int, void*); +static void spinner_mouseDownCallback(int, void*); +static void spinner_mouseUpCallback(int, void*); + +int Spinner::interfaceChooseDest(int loopId, int loopFlag) { + _selectedDestination = 0; + if (!_vm->openArchive("MODE.MIX")) + return 0; + + if (loopId < 0) { + _isOpen = true; + } else { + _vm->playerLosesControl(); + _vm->_scene->loopStartSpecial(3, loopId, loopFlag); + while (!_isOpen) { + _vm->gameTick(); + } + _vm->playerGainsControl(); + } + + _vqaPlayer = new VQAPlayer(_vm, &_vm->_surfaceInterface); + if (!_vqaPlayer->open("SPINNER.VQA")) { + return 0; + } + + _vm->_mouse->setCursor(0); + + // Determine which map we need to show to include the active destinations + uint8 mapmask = 0; + uint8 mapmaskv[SPINNER_DESTINATIONS] = { 1, 1, 1, 1, 1, 3, 3, 3, 7, 7 }; + for (int i = 0; i != SPINNER_DESTINATIONS; ++i) { + if (_isDestinationSelectable[i]) + mapmask |= mapmaskv[i]; + } + + _destinations = nullptr; + int firstShapeId = 0; + int shapeCount = 0; + int spinnerLoopId = 4; + + mapmask = 1; + + if (mapmask & 4) { + _destinations = SpinnerDestinationsFar; + firstShapeId = 26; + shapeCount = 20; + spinnerLoopId = 4; + } else if (mapmask & 2) { + _destinations = SpinnerDestinationsMedium; + firstShapeId = 10; + shapeCount = 16; + spinnerLoopId = 2; + } else if (mapmask & 1) { + _destinations = SpinnerDestinationsNear; + firstShapeId = 0; + shapeCount = 10; + spinnerLoopId = 0; + } else { + return -1; + } + + _vqaPlayer->setLoop(spinnerLoopId, -1, 2, nullptr, nullptr); + _vqaPlayer->setLoop(spinnerLoopId + 1, -1, 0, nullptr, nullptr); + + for (int j = 0; j != shapeCount; ++j) { + _shapes.push_back(new Shape(_vm)); + _shapes[j]->readFromContainer("SPINNER.SHP", firstShapeId + j); + } + + _imagePicker->resetImages(); + + for (SpinnerDestination *dest = _destinations; dest->id != -1; ++dest) { + if (!_isDestinationSelectable[dest->id]) + continue; + + const char *tooltip = _vm->_textSpinnerDestinations->getText(dest->id); + + _imagePicker->defineImage( + dest->id, + dest->left, + dest->top, + dest->right, + dest->bottom, + _shapes[dest->id], + _shapes[dest->id + _shapes.size() / 2], + _shapes[dest->id + _shapes.size() / 2], + tooltip + ); + } + + _imagePicker->setCallbacks( + spinner_mouseInCallback, + spinner_mouseOutCallback, + spinner_mouseDownCallback, + spinner_mouseUpCallback, + this + ); + + // TODO: Freeze game time + _selectedDestination = -1; + do { + _vm->gameTick(); + } while (_selectedDestination == -1); + + // TODO: Unfreeze game time + _isOpen = false; + // TODO: _vm->_scene->resume(); + + for (int i = 0; i != (int)_shapes.size(); ++i) + delete _shapes[i]; + _shapes.clear(); + + return _selectedDestination; +} + +static void spinner_mouseInCallback(int, void*) { +} + +static void spinner_mouseOutCallback(int, void*) { +} + +static void spinner_mouseDownCallback(int, void*) { +} + +static void spinner_mouseUpCallback(int image, void *data) { + if (image >= 0 && image < 10) { + Spinner *spinner = (Spinner *)data; + spinner->setSelectedDestination(image); + } +} + +void Spinner::setIsOpen() { + _isOpen = true; +} + +bool Spinner::isOpen() const { + return _isOpen; +} + +int Spinner::handleMouseUp(int x, int y) { + _imagePicker->handleMouseAction(x, y, false, true, 0); + return false; +} + +int Spinner::handleMouseDown(int x, int y) { + _imagePicker->handleMouseAction(x, y, true, false, 0); + return false; +} + +void Spinner::tick() { + if (!_vm->_gameIsRunning) + return; + + int frame = _vqaPlayer->update(); + assert(frame >= -1); + + // vqaPlayer renders to _surfaceInterface + _vm->_surfaceGame.copyRectToSurface(_vm->_surfaceInterface, 0, 0, Common::Rect(640, 480)); + + _imagePicker->draw(_vm->_surfaceInterface); + + Common::Point p = _vm->getMousePos(); + _imagePicker->handleMouseAction(p.x, p.y, false, false, false); + if (_imagePicker->hasHoveredImage()) { + _vm->_mouse->setCursor(1); + } else { + _vm->_mouse->setCursor(0); + } + _vm->_mouse->draw(_vm->_surfaceGame, p.x, p.y); + + _vm->_system->copyRectToScreen(_vm->_surfaceGame.getPixels(), _vm->_surfaceGame.pitch, 0, 0, 640, 480); + _vm->_system->updateScreen(); + _vm->_system->delayMillis(10); +} + +void Spinner::setSelectedDestination(int destination) { + _selectedDestination = destination; +} + +void Spinner::reset() { + for (int i = 0; i != SPINNER_DESTINATIONS; ++i) { + _isDestinationSelectable[i] = 0; + } + + _isOpen = false; + _destinations = nullptr; + _selectedDestination = -1; + _imagePicker = nullptr; + + for (int i = 0; i != (int)_shapes.size(); ++i) + delete _shapes[i]; + _shapes.clear(); +} + +void Spinner::resume() { + // TODO +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/spinner.h b/engines/bladerunner/spinner.h new file mode 100644 index 0000000000..19021fac1a --- /dev/null +++ b/engines/bladerunner/spinner.h @@ -0,0 +1,77 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_SPINNER_H +#define BLADERUNNER_SPINNER_H + +#include "common/array.h" + +namespace BladeRunner { + +class BladeRunnerEngine; +class Shape; +class VQAPlayer; +class UIImagePicker; + +#define SPINNER_DESTINATIONS 10 + +struct SpinnerDestination { + int id; + int left; + int top; + int right; + int bottom; +}; + +class Spinner { + BladeRunnerEngine *_vm; + bool _isDestinationSelectable[SPINNER_DESTINATIONS]; + bool _isOpen; + VQAPlayer *_vqaPlayer; + SpinnerDestination *_destinations; + int _selectedDestination; + Common::Array _shapes; + UIImagePicker *_imagePicker; + +public: + Spinner(BladeRunnerEngine *vm); + ~Spinner(); + + void setSelectableDestinationFlag(int destination, bool selectable); + bool querySelectableDestinationFlag(int destination) const; + + int interfaceChooseDest(int vqaLoopId, int loopFlag); + + void setIsOpen(); + bool isOpen() const; + + int handleMouseUp(int x, int y); + int handleMouseDown(int x, int y); + void tick(); + void setSelectedDestination(int destination); + void reset(); + void resume(); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/ui_image_picker.cpp b/engines/bladerunner/ui_image_picker.cpp new file mode 100644 index 0000000000..654129754c --- /dev/null +++ b/engines/bladerunner/ui_image_picker.cpp @@ -0,0 +1,265 @@ +/* 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_image_picker.h" + +#include "bladerunner/bladerunner.h" + +#include "bladerunner/shape.h" + +#include "common/rect.h" +#include "graphics/surface.h" + +namespace BladeRunner { + +struct UIImagePickerImage { + int active; + Common::Rect rect; + Shape *shapeUp; + Shape *shapeHovered; + Shape *shapeDown; + const char *tooltip; +}; + +UIImagePicker::UIImagePicker(BladeRunnerEngine *vm, int imageCount) : _vm(vm) { + reset(); + _images = new UIImagePickerImage[imageCount]; + _imageCount = imageCount; + resetImages(); +} + +UIImagePicker::~UIImagePicker() { + delete[] _images; + _images = nullptr; + reset(); +} + +void UIImagePicker::resetImages() { + for (int i = 0; i != _imageCount; i++) { + resetImage(i); + } +} + +bool UIImagePicker::defineImage(int i, int left, int top, int right, int bottom, Shape *shapeUp, Shape *shapeHovered, Shape *shapeDown, const char *tooltip) { + if (i < 0 || i >= _imageCount || _images[i].active) + return false; + + UIImagePickerImage &img = _images[i]; + + img.rect.left = left; + img.rect.top = top; + img.rect.right = right + 1; + img.rect.bottom = bottom + 1; + img.shapeUp = shapeUp; + img.shapeHovered = shapeHovered; + img.shapeDown = shapeDown; + img.active = true; + img.tooltip = tooltip; + + return true; +} + +bool UIImagePicker::setImageTop(int i, int top) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + UIImagePickerImage &img = _images[i]; + + img.rect.moveTo(img.rect.left, top); + + return true; +} + +bool UIImagePicker::setImageLeft(int i, int left) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + UIImagePickerImage &img = _images[i]; + + img.rect.moveTo(left, img.rect.top); + + return true; +} + +bool UIImagePicker::setImageShapeUp(int i, Shape *shapeUp) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + _images[i].shapeUp = shapeUp; + + return true; +} + +bool UIImagePicker::setImageShapeHovered(int i, Shape *shapeHovered) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + _images[i].shapeHovered = shapeHovered; + + return true; +} + +bool UIImagePicker::setImageShapeDown(int i, Shape *shapeDown) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + _images[i].shapeDown = shapeDown; + + return true; +} + +bool UIImagePicker::setImageTooltip(int i, const char *tooltip) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + _images[i].tooltip = tooltip; + + return true; +} + +bool UIImagePicker::resetActiveImage(int i) { + if (i < 0 || i >= _imageCount || !_images[i].active) + return false; + + resetImage(i); + return true; +} + +void UIImagePicker::setCallbacks(UIImagePickerCallback *mouseInCallback, + UIImagePickerCallback *mouseOutCallback, + UIImagePickerCallback *mouseDownCallback, + UIImagePickerCallback *mouseUpCallback, + void *callbackData) +{ + _isButtonDown = false; + _mouseInCallback = mouseInCallback; + _mouseOutCallback = mouseOutCallback; + _mouseDownCallback = mouseDownCallback; + _mouseUpCallback = mouseUpCallback; + _callbackData = callbackData; + _hoverStartTimestamp = 0; + _isVisible = true; + _hoveredImageIndex = -1; + _pressedImageIndex = -1; +} + +void UIImagePicker::resetCallbacks() {} + +// TODO +void UIImagePicker::drawTooltip() {} + +void UIImagePicker::draw(Graphics::Surface &surface) { + if (!_isVisible) + return; + + for (int i = 0; i != _imageCount; ++i) { + UIImagePickerImage &img = _images[i]; + if (!img.active) + continue; + + // TODO: Check interaction with Mouse::isDisabled + if (i == _hoveredImageIndex && i == _pressedImageIndex && _isButtonDown) { + if (img.shapeDown) { + img.shapeDown->draw(surface, img.rect.left, img.rect.top); + } + } else if (i == _hoveredImageIndex && !_isButtonDown) { + if (img.shapeHovered) { + img.shapeHovered->draw(surface, img.rect.left, img.rect.top); + } + } else { + if (img.shapeUp) { + img.shapeUp->draw(surface, img.rect.left, img.rect.top); + } + } + } +} + +void UIImagePicker::handleMouseAction(int x, int y, bool down, bool up, bool ignore) { + if (!_isVisible || ignore) { + return; + } + + int hoveredImageIndex = -1; + for (int i = 0; i != _imageCount; ++i) { + if (_images[i].rect.contains(x, y)) { + hoveredImageIndex = i; + break; + } + } + + // If mouse moved to a new image + if (hoveredImageIndex != _hoveredImageIndex) { + if (!_isButtonDown) { + if (hoveredImageIndex == -1) { + if (_mouseOutCallback) + _mouseOutCallback(hoveredImageIndex, _callbackData); + } else { + if (_mouseInCallback) + _mouseInCallback(hoveredImageIndex, _callbackData); + } + } + _hoveredImageIndex = hoveredImageIndex; + } + + // If mouse button changed to pressed + if (down && !_isButtonDown) { + _isButtonDown = true; + _pressedImageIndex = _hoveredImageIndex; + if (_mouseDownCallback) + _mouseDownCallback(_hoveredImageIndex, _callbackData); + } + + // If mouse button changed to released + if (up) { + if (_isButtonDown) { + if (_hoveredImageIndex == _pressedImageIndex && _pressedImageIndex != -1) { + if (_mouseUpCallback) + _mouseUpCallback(_hoveredImageIndex, _callbackData); + } + } + _isButtonDown = false; + _pressedImageIndex = -1; + } +} + +void UIImagePicker::resetImage(int i) { + assert(i >= 0 && i < _imageCount); + UIImagePickerImage &img = _images[i]; + + img.active = false; + img.rect.left = -1; + img.rect.top = -1; + img.rect.right = -1; + img.rect.bottom = -1; + img.shapeUp = nullptr; + img.shapeHovered = nullptr; + img.shapeDown = nullptr; + img.tooltip = nullptr; +} + +bool UIImagePicker::hasHoveredImage() { + return _hoveredImageIndex >= 0; +} + +void UIImagePicker::reset() {} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/ui_image_picker.h b/engines/bladerunner/ui_image_picker.h new file mode 100644 index 0000000000..c55aa48a64 --- /dev/null +++ b/engines/bladerunner/ui_image_picker.h @@ -0,0 +1,92 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_UI_IMAGE_PICKER_H +#define BLADERUNNER_UI_IMAGE_PICKER_H + +namespace Graphics { +struct Surface; +} + +namespace BladeRunner { + +class BladeRunnerEngine; +class Shape; +struct UIImagePickerImage; + +typedef void UIImagePickerCallback(int, void*); + +class UIImagePicker { + BladeRunnerEngine *_vm; + + int _isVisible; + int _imageCount; + int _hoveredImageIndex; + int _pressedImageIndex; + int _hoverStartTimestamp; + int _isButtonDown; + UIImagePickerImage *_images; + + UIImagePickerCallback *_mouseInCallback; + UIImagePickerCallback *_mouseOutCallback; + UIImagePickerCallback *_mouseDownCallback; + UIImagePickerCallback *_mouseUpCallback; + void *_callbackData; + +public: + UIImagePicker(BladeRunnerEngine *vm, int imageCount); + ~UIImagePicker(); + + void resetImages(); + bool defineImage(int i, int left, int top, int right, int bottom, Shape *shapeUp, Shape *shapeHovered, Shape *shapeDown, const char *tooltip); + + bool setImageTop(int i, int top); + bool setImageLeft(int i, int left); + bool setImageShapeUp(int i, Shape *shapeUp); + bool setImageShapeHovered(int i, Shape *shapeHovered); + bool setImageShapeDown(int i, Shape *shapeDown); + bool setImageTooltip(int i, const char *tooltip); + + bool resetActiveImage(int i); + + void setCallbacks(UIImagePickerCallback *mouseInCallback, + UIImagePickerCallback *mouseOutCallback, + UIImagePickerCallback *mouseDownCallback, + UIImagePickerCallback *mouseUpCallback, + void *callbackData); + + void resetCallbacks(); + + void drawTooltip(); + void draw(Graphics::Surface &surface); + + void handleMouseAction(int x, int y, bool down, bool up, bool ignore = false); + + void resetImage(int i); + bool hasHoveredImage(); + + void reset(); +}; + +} // End of namespace BladeRunner + +#endif -- cgit v1.2.3