A base class, Window, will be used to ensure all the UI containers work in a similar way.
282 lines
7.9 KiB
C++
282 lines
7.9 KiB
C++
/* ResidualVM - A 3D game interpreter
|
|
*
|
|
* ResidualVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the AUTHORS
|
|
* 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 "common/system.h"
|
|
#include "common/events.h"
|
|
|
|
#include "engines/stark/ui.h"
|
|
|
|
#include "engines/stark/actionmenu.h"
|
|
#include "engines/stark/cursor.h"
|
|
|
|
#include "engines/stark/gfx/driver.h"
|
|
#include "engines/stark/gfx/renderentry.h"
|
|
|
|
#include "engines/stark/resources/object.h"
|
|
#include "engines/stark/resources/item.h"
|
|
|
|
#include "engines/stark/services/fmvplayer.h"
|
|
#include "engines/stark/services/services.h"
|
|
#include "engines/stark/services/userinterface.h"
|
|
|
|
#include "engines/stark/ui/topmenu.h"
|
|
#include "engines/stark/ui/dialoginterface.h"
|
|
#include "engines/stark/ui/inventoryinterface.h"
|
|
|
|
namespace Stark {
|
|
|
|
UI::UI(Gfx::Driver *gfx, Cursor *cursor) :
|
|
_gfx(gfx),
|
|
_cursor(cursor),
|
|
_objectUnderCursor(nullptr),
|
|
_hasClicked(false),
|
|
_topMenu(nullptr),
|
|
_dialogInterface(nullptr),
|
|
_inventoryInterface(nullptr),
|
|
_selectedInventoryItem(-1),
|
|
_exitGame(false),
|
|
_fmvPlayer(nullptr),
|
|
_actionMenu(nullptr)
|
|
{
|
|
}
|
|
|
|
UI::~UI() {
|
|
delete _actionMenu;
|
|
delete _topMenu;
|
|
delete _dialogInterface;
|
|
delete _inventoryInterface;
|
|
delete _fmvPlayer;
|
|
}
|
|
|
|
void UI::init() {
|
|
_topMenu = new TopMenu();
|
|
_dialogInterface = new DialogInterface();
|
|
_inventoryInterface = new InventoryInterface(_gfx, _cursor);
|
|
_fmvPlayer = new FMVPlayer();
|
|
_actionMenu = new ActionMenu(_gfx, _cursor);
|
|
}
|
|
|
|
void UI::update(Gfx::RenderEntryArray renderEntries) {
|
|
Common::Point pos = _cursor->getMousePosition();
|
|
|
|
if (_actionMenu->isVisible() && _actionMenu->isMouseInside()) {
|
|
_actionMenu->handleMouseMove();
|
|
return;
|
|
}
|
|
|
|
// Check for inventory to avoid mouse-overs from the world poking through.
|
|
if (_inventoryInterface->isVisible() && _inventoryInterface->isMouseInside()) {
|
|
renderEntries = _inventoryInterface->getRenderEntries();
|
|
}
|
|
|
|
// Check for UI mouse overs
|
|
if (_topMenu->containsPoint(pos)) {
|
|
_cursor->setCursorType(Cursor::kActive);
|
|
_cursor->setMouseHint(_selectedInventoryItemText + _topMenu->getMouseHintAtPosition(pos));
|
|
return;
|
|
}
|
|
|
|
if (_dialogInterface->containsPoint(pos)) {
|
|
_dialogInterface->handleMouseOver(pos);
|
|
return;
|
|
}
|
|
|
|
pos -= Common::Point(0, Gfx::Driver::kTopBorderHeight);
|
|
|
|
// Check for game world mouse overs
|
|
UserInterface *ui = StarkServices::instance().userInterface;
|
|
|
|
_objectUnderCursor = ui->getItemAtPosition(pos, renderEntries);
|
|
|
|
Common::String mouseHint = ui->getMouseHintForItem(_objectUnderCursor);
|
|
|
|
if (_objectUnderCursor) {
|
|
Resources::ActionArray actionsPossible = ui->getActionsPossibleForObject(_objectUnderCursor, pos);
|
|
setCursorDependingOnActionsAvailable(actionsPossible);
|
|
} else {
|
|
// Not an object
|
|
_cursor->setCursorType(Cursor::kPassive);
|
|
}
|
|
_cursor->setMouseHint(_selectedInventoryItemText + mouseHint);
|
|
}
|
|
|
|
void UI::setCursorDependingOnActionsAvailable(Resources::ActionArray actionsAvailable) {
|
|
if (actionsAvailable.empty()) {
|
|
_cursor->setCursorType(Cursor::kPassive);
|
|
return;
|
|
}
|
|
|
|
uint32 count = 0;
|
|
Cursor::CursorType cursorType;
|
|
for (uint i = 0; i < actionsAvailable.size(); i++) {
|
|
switch (actionsAvailable[i]) {
|
|
case Resources::PATTable::kActionLook:
|
|
cursorType = Cursor::kEye;
|
|
count++;
|
|
break;
|
|
case Resources::PATTable::kActionTalk:
|
|
cursorType = Cursor::kMouth;
|
|
count++;
|
|
break;
|
|
case Resources::PATTable::kActionUse:
|
|
cursorType = Cursor::kHand;
|
|
count++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (count == 1) {
|
|
_cursor->setCursorType(cursorType);
|
|
} else {
|
|
_cursor->setCursorType(Cursor::kActive);
|
|
}
|
|
}
|
|
|
|
void UI::handleClick() {
|
|
UserInterface *ui = StarkServices::instance().userInterface;
|
|
|
|
if (_actionMenu->isVisible()) {
|
|
if (_actionMenu->isMouseInside()) {
|
|
_actionMenu->handleClick();
|
|
} else {
|
|
_actionMenu->close();
|
|
}
|
|
} else if (_objectUnderCursor) {
|
|
Common::Point pos = _cursor->getMousePosition();
|
|
pos -= Common::Point(0, Gfx::Driver::kTopBorderHeight);
|
|
|
|
// Possibilites:
|
|
// * Click on something that doesn't take an action
|
|
// * Click on something that takes exactly 1 action.
|
|
// * Click on something that takes more than 1 action (open action menu)
|
|
// * Click in the action menu, which has 0 available actions (TODO)
|
|
if (_selectedInventoryItem != -1) {
|
|
if (!ui->itemDoActionAt(_objectUnderCursor, _selectedInventoryItem, pos)) {
|
|
warning("Could not perform action %d on %s", _selectedInventoryItem, _objectUnderCursor->getName().c_str());
|
|
}
|
|
} else {
|
|
Resources::ActionArray actions = ui->getStockActionsPossibleForObject(_objectUnderCursor, pos);
|
|
if (actions.size() == 1) {
|
|
for (uint i = 0; i < actions.size(); i++) {
|
|
if (actions[i] == Resources::PATTable::kActionLook) {
|
|
ui->itemDoActionAt(_objectUnderCursor, Resources::PATTable::kActionLook, pos);
|
|
break;
|
|
} else if (actions[i] == Resources::PATTable::kActionTalk) {
|
|
ui->itemDoActionAt(_objectUnderCursor, Resources::PATTable::kActionTalk, pos);
|
|
break;
|
|
} else if (actions[i] == Resources::PATTable::kActionUse) {
|
|
ui->itemDoActionAt(_objectUnderCursor, Resources::PATTable::kActionUse, pos);
|
|
break;
|
|
}
|
|
}
|
|
} else if (actions.size() > 1) {
|
|
_actionMenu->open(_objectUnderCursor, pos);
|
|
}
|
|
}
|
|
} else {
|
|
ui->walkTo(g_system->getEventManager()->getMousePos());
|
|
|
|
// // Assume all inventory objects need action menu.
|
|
// if (isInventoryObject(item)) {
|
|
// return false;
|
|
// }
|
|
|
|
// {
|
|
// if (_selectedInventoryItem != -1) {
|
|
// _inventoryInterface->update();
|
|
// _selectedInventoryItem = -1;
|
|
// _selectedInventoryItemText = "";
|
|
// }
|
|
// }
|
|
}
|
|
|
|
// Check this before handling the menu clicks, otherwise it closes again on the same event.
|
|
if (_inventoryInterface->isVisible() && !_inventoryInterface->isMouseInside()) {
|
|
_inventoryInterface->close();
|
|
}
|
|
if (_topMenu->containsPoint(_cursor->getMousePosition())) {
|
|
_topMenu->handleClick(_cursor->getMousePosition());
|
|
}
|
|
if (_dialogInterface->containsPoint(_cursor->getMousePosition())) {
|
|
_dialogInterface->handleClick(_cursor->getMousePosition());
|
|
}
|
|
_hasClicked = false;
|
|
}
|
|
|
|
void UI::notifyClick() {
|
|
_hasClicked = true;
|
|
}
|
|
|
|
void UI::notifySubtitle(const Common::String &subtitle) {
|
|
_dialogInterface->notifySubtitle(subtitle);
|
|
}
|
|
|
|
void UI::notifyDialogOptions(const Common::StringArray &options) {
|
|
_dialogInterface->notifyDialogOptions(options);
|
|
}
|
|
|
|
void UI::notifyShouldOpenInventory() {
|
|
// Make the inventory update it's contents.
|
|
_inventoryInterface->open();
|
|
}
|
|
|
|
void UI::notifyFMVRequest(const Common::String &name) {
|
|
_fmvPlayer->play(name);
|
|
}
|
|
|
|
void UI::notifySelectedInventoryItem(Resources::Item *selectedItem) {
|
|
_selectedInventoryItem = selectedItem->getIndex();
|
|
_selectedInventoryItemText = selectedItem->getName() + " -> ";
|
|
}
|
|
|
|
bool UI::isPlayingFMV() const {
|
|
return _fmvPlayer->isPlaying();
|
|
}
|
|
|
|
void UI::stopPlayingFMV() {
|
|
_fmvPlayer->stop();
|
|
}
|
|
|
|
void UI::render() {
|
|
if (_fmvPlayer->isPlaying()) {
|
|
_fmvPlayer->render();
|
|
return;
|
|
}
|
|
|
|
// Can't handle clicks before this point, since we need to have updated the mouse-over state to include the UI.
|
|
if (_hasClicked) {
|
|
handleClick();
|
|
}
|
|
|
|
// TODO: Unhardcode
|
|
if (_cursor->getMousePosition().y < 40) {
|
|
_topMenu->render();
|
|
}
|
|
|
|
_inventoryInterface->render();
|
|
|
|
_dialogInterface->render();
|
|
_actionMenu->render();
|
|
}
|
|
|
|
} // End of namespace Stark
|
|
|