Initial commit
This commit is contained in:
122
engines/nancy/ui/animatedbutton.cpp
Normal file
122
engines/nancy/ui/animatedbutton.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/nancy/cursor.h"
|
||||
#include "engines/nancy/input.h"
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/sound.h"
|
||||
#include "engines/nancy/util.h"
|
||||
|
||||
#include "engines/nancy/state/scene.h"
|
||||
|
||||
#include "engines/nancy/ui/animatedbutton.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
AnimatedButton::AnimatedButton(uint zOrder) :
|
||||
RenderObject(zOrder),
|
||||
_frameTime(0),
|
||||
_currentFrame(-1),
|
||||
_nextFrameTime(0),
|
||||
_isOpen(false),
|
||||
_alwaysHighlightCursor(false) {}
|
||||
|
||||
void AnimatedButton::init() {
|
||||
setTransparent(true);
|
||||
}
|
||||
|
||||
void AnimatedButton::updateGraphics() {
|
||||
uint32 currentTime = g_nancy->getTotalPlayTime();
|
||||
if (currentTime > _nextFrameTime) {
|
||||
if (_isOpen && _currentFrame < (int)_srcRects.size()) {
|
||||
setFrame(++_currentFrame);
|
||||
_nextFrameTime = currentTime + _frameTime;
|
||||
setVisible(true);
|
||||
if (_currentFrame == (int)_srcRects.size()) {
|
||||
onTrigger();
|
||||
}
|
||||
} else if (!_isOpen && _currentFrame > -1) {
|
||||
setFrame(--_currentFrame);
|
||||
_nextFrameTime = currentTime + _frameTime;
|
||||
if (_currentFrame == -1) {
|
||||
onTrigger();
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimatedButton::handleInput(NancyInput &input) {
|
||||
if (_hotspot.contains(input.mousePos)) {
|
||||
if (_alwaysHighlightCursor || _currentFrame == -1 || _currentFrame == (int)_srcRects.size()) {
|
||||
g_nancy->_cursor->setCursorType(g_nancy->getGameType() == kGameTypeVampire ? CursorManager::kHotspot : CursorManager::kHotspotArrow);
|
||||
}
|
||||
|
||||
if (isPlaying()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_highlightSrcRect.isEmpty() && !isVisible()) {
|
||||
_drawSurface.create(g_nancy->_graphics->_object0, _highlightSrcRect);
|
||||
moveTo(_highlightDestRect);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
if (input.input & NancyInput::kLeftMouseButtonUp) {
|
||||
if (_currentFrame == -1) {
|
||||
onClick();
|
||||
setOpen(true);
|
||||
} else if (_currentFrame == (int)_srcRects.size()) {
|
||||
onClick();
|
||||
setOpen(false);
|
||||
}
|
||||
}
|
||||
|
||||
// This breaks TowerPuzzle in nancy2, so we only enable it for TVD
|
||||
if (g_nancy->getGameType() == kGameTypeVampire) {
|
||||
input.eatMouseInput();
|
||||
}
|
||||
} else if (!_highlightSrcRect.isEmpty() && isVisible() && !(isPlaying() || _isOpen)) {
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimatedButton::setFrame(int frame) {
|
||||
if (frame > -1 && frame < (int)_srcRects.size()) {
|
||||
_drawSurface.create(g_nancy->_graphics->_object0, _srcRects[frame]);
|
||||
setTransparent(true);
|
||||
|
||||
if (_destRects.size()) {
|
||||
moveTo(_destRects[frame]);
|
||||
}
|
||||
|
||||
_needsRedraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool AnimatedButton::isPlaying() const {
|
||||
return _isOpen ? _currentFrame < (int)_srcRects.size() : _currentFrame > -1;
|
||||
}
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
67
engines/nancy/ui/animatedbutton.h
Normal file
67
engines/nancy/ui/animatedbutton.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NANCY_UI_ANIMATEDBUTTON_H
|
||||
#define NANCY_UI_ANIMATEDBUTTON_H
|
||||
|
||||
#include "engines/nancy/renderobject.h"
|
||||
|
||||
namespace Nancy {
|
||||
|
||||
struct NancyInput;
|
||||
|
||||
namespace UI {
|
||||
|
||||
class AnimatedButton : public RenderObject {
|
||||
public:
|
||||
AnimatedButton(uint zOrder);
|
||||
virtual ~AnimatedButton() = default;
|
||||
|
||||
void init() override;
|
||||
void updateGraphics() override;
|
||||
void handleInput(NancyInput &input);
|
||||
|
||||
void setOpen(bool open) { _isOpen = open; }
|
||||
void setFrame(int frame);
|
||||
int getCurrentFrame() const { return _currentFrame; }
|
||||
bool isPlaying() const;
|
||||
virtual void onClick() = 0;
|
||||
virtual void onTrigger() = 0;
|
||||
|
||||
protected:
|
||||
Common::Array<Common::Rect> _srcRects;
|
||||
Common::Array<Common::Rect> _destRects;
|
||||
Common::Rect _highlightSrcRect;
|
||||
Common::Rect _highlightDestRect;
|
||||
|
||||
uint32 _frameTime;
|
||||
bool _alwaysHighlightCursor;
|
||||
|
||||
int _currentFrame;
|
||||
uint32 _nextFrameTime;
|
||||
bool _isOpen;
|
||||
Common::Rect _hotspot;
|
||||
};
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_UI_ANIMATEDBUTTON_H
|
||||
155
engines/nancy/ui/button.cpp
Normal file
155
engines/nancy/ui/button.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/input.h"
|
||||
#include "engines/nancy/cursor.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/sound.h"
|
||||
#include "engines/nancy/util.h"
|
||||
|
||||
#include "engines/nancy/state/scene.h"
|
||||
|
||||
#include "engines/nancy/ui/button.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
Button::Button(uint16 zOrder,
|
||||
Graphics::ManagedSurface &surface,
|
||||
const Common::Rect &clickSrcBounds,
|
||||
const Common::Rect &destBounds,
|
||||
const Common::Rect &hoverSrcBounds,
|
||||
const Common::Rect &disabledSrcBounds,
|
||||
const Common::Rect &baseSrcBounds) :
|
||||
RenderObject(zOrder, surface, clickSrcBounds, destBounds),
|
||||
surf(surface),
|
||||
_clickSrc(clickSrcBounds),
|
||||
_hoverSrc(hoverSrcBounds),
|
||||
_disabledSrc(disabledSrcBounds),
|
||||
_baseSrc(baseSrcBounds),
|
||||
_isClicked(false),
|
||||
_isDisabled(false) {
|
||||
if (!_baseSrc.isEmpty()) {
|
||||
_drawSurface.create(surf, _baseSrc);
|
||||
setVisible(true);
|
||||
} else {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
setTransparent(true);
|
||||
}
|
||||
|
||||
void Button::handleInput(NancyInput &input) {
|
||||
if (_isDisabled && !_disabledSrc.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_screenPosition.contains(input.mousePos)) {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kHotspotArrow);
|
||||
|
||||
if (!_hoverSrc.isEmpty() && !_isClicked) {
|
||||
_drawSurface.create(surf, _hoverSrc);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
if (input.input & NancyInput::kLeftMouseButtonUp) {
|
||||
_isClicked = true;
|
||||
if (_hoverSrc.isEmpty() && !_isDisabled) {
|
||||
setVisible(true);
|
||||
} else {
|
||||
_drawSurface.create(surf, _clickSrc);
|
||||
}
|
||||
}
|
||||
} else if (!_isClicked && _isVisible) {
|
||||
if (!_baseSrc.isEmpty()) {
|
||||
_drawSurface.create(surf, _baseSrc);
|
||||
setVisible(true);
|
||||
} else {
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Button::setDisabled(bool disabled) {
|
||||
if (disabled) {
|
||||
_isDisabled = true;
|
||||
if (!_disabledSrc.isEmpty()) {
|
||||
_drawSurface.create(surf, _disabledSrc);
|
||||
setVisible(true);
|
||||
} else {
|
||||
if (!_baseSrc.isEmpty()) {
|
||||
_drawSurface.create(surf, _baseSrc);
|
||||
setVisible(true);
|
||||
} else {
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!_baseSrc.isEmpty()) {
|
||||
_drawSurface.create(surf, _baseSrc);
|
||||
setVisible(true);
|
||||
} else {
|
||||
setVisible(false);
|
||||
}
|
||||
_isDisabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
Toggle::Toggle(uint16 zOrder, Graphics::ManagedSurface &surface, const Common::Rect &srcRect, const Common::Rect &destRect) :
|
||||
RenderObject(zOrder, surface, srcRect, destRect),
|
||||
surf(surface),
|
||||
_clickSrc(srcRect),
|
||||
_toggleState(false),
|
||||
_stateChanged(false) {
|
||||
setVisible(false);
|
||||
setTransparent(true);
|
||||
}
|
||||
|
||||
void Toggle::handleInput(NancyInput &input) {
|
||||
_stateChanged = false;
|
||||
|
||||
if (_screenPosition.contains(input.mousePos)) {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kHotspotArrow);
|
||||
|
||||
if (input.input & NancyInput::kLeftMouseButtonUp) {
|
||||
setState(!_toggleState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Toggle::setState(bool toggleState) {
|
||||
if (_toggleState == toggleState) {
|
||||
return;
|
||||
}
|
||||
|
||||
_toggleState = toggleState;
|
||||
_stateChanged = true;
|
||||
|
||||
if (toggleState) {
|
||||
setVisible(true);
|
||||
} else {
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
75
engines/nancy/ui/button.h
Normal file
75
engines/nancy/ui/button.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NANCY_UI_BUTTON_H
|
||||
#define NANCY_UI_BUTTON_H
|
||||
|
||||
#include "engines/nancy/renderobject.h"
|
||||
|
||||
namespace Nancy {
|
||||
|
||||
struct NancyInput;
|
||||
|
||||
namespace UI {
|
||||
|
||||
class Button : public RenderObject {
|
||||
public:
|
||||
Button(uint16 zOrder, Graphics::ManagedSurface &surface,
|
||||
const Common::Rect &clickSrcBounds,
|
||||
const Common::Rect &destBounds,
|
||||
const Common::Rect &hoverSrcBounds = Common::Rect(),
|
||||
const Common::Rect &disabledSrcBounds = Common::Rect(),
|
||||
const Common::Rect &baseSrcBounds = Common::Rect());
|
||||
virtual ~Button() = default;
|
||||
|
||||
void handleInput(NancyInput &input);
|
||||
|
||||
void setDisabled(bool disabled);
|
||||
|
||||
Graphics::ManagedSurface &surf;
|
||||
Common::Rect _clickSrc;
|
||||
Common::Rect _hoverSrc;
|
||||
Common::Rect _disabledSrc;
|
||||
Common::Rect _baseSrc;
|
||||
|
||||
bool _isClicked;
|
||||
bool _isDisabled;
|
||||
};
|
||||
|
||||
class Toggle : public RenderObject {
|
||||
public:
|
||||
Toggle(uint16 zOrder, Graphics::ManagedSurface &surface, const Common::Rect &srcRect, const Common::Rect &destRect);
|
||||
virtual ~Toggle() = default;
|
||||
|
||||
void handleInput(NancyInput &input);
|
||||
void setState(bool toggleState);
|
||||
|
||||
Graphics::ManagedSurface &surf;
|
||||
Common::Rect _clickSrc;
|
||||
|
||||
bool _stateChanged;
|
||||
bool _toggleState;
|
||||
};
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_UI_BUTTON_H
|
||||
236
engines/nancy/ui/clock.cpp
Normal file
236
engines/nancy/ui/clock.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/nancy/cursor.h"
|
||||
#include "engines/nancy/input.h"
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/sound.h"
|
||||
#include "engines/nancy/time.h"
|
||||
#include "engines/nancy/util.h"
|
||||
|
||||
#include "engines/nancy/state/scene.h"
|
||||
|
||||
#include "engines/nancy/ui/clock.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
Clock::Clock() : RenderObject(g_nancy->getGameType() == kGameTypeVampire ? 11 : 10),
|
||||
_animation(g_nancy->getGameType() == kGameTypeVampire ? 10 : 11, this),
|
||||
_staticImage(9),
|
||||
_clockData(nullptr),
|
||||
_locked(false) {}
|
||||
|
||||
void Clock::init() {
|
||||
Graphics::ManagedSurface &object0 = g_nancy->_graphics->_object0;
|
||||
|
||||
_clockData = (const CLOK *)g_nancy->getEngineData("CLOK");
|
||||
assert(_clockData);
|
||||
|
||||
// Calculate the size and location of the surface we'll need to draw the clock hands,
|
||||
// since their dest rects are in absolute screen space
|
||||
Common::Rect clockSurfaceScreenBounds;
|
||||
|
||||
for (const Common::Rect &r : _clockData->hoursHandDests) {
|
||||
clockSurfaceScreenBounds.extend(r);
|
||||
}
|
||||
|
||||
for (const Common::Rect &r : _clockData->minutesHandDests) {
|
||||
clockSurfaceScreenBounds.extend(r);
|
||||
}
|
||||
|
||||
_drawSurface.create(clockSurfaceScreenBounds.width(), clockSurfaceScreenBounds.height(), g_nancy->_graphics->getInputPixelFormat());
|
||||
moveTo(clockSurfaceScreenBounds);
|
||||
|
||||
_staticImage._drawSurface.create(object0, _clockData->staticImageSrc);
|
||||
_staticImage.moveTo(_clockData->staticImageDest);
|
||||
_staticImage.setVisible(false);
|
||||
_staticImage.setTransparent(g_nancy->getGameType() == kGameTypeVampire);
|
||||
|
||||
_animation.setTransparent(true);
|
||||
_animation.setVisible(false);
|
||||
if (g_nancy->getGameType() == kGameTypeVampire) {
|
||||
GraphicsManager::loadSurfacePalette(_drawSurface, "OBJECT0");
|
||||
}
|
||||
|
||||
setTransparent(true);
|
||||
|
||||
_animation.init();
|
||||
}
|
||||
|
||||
void Clock::registerGraphics() {
|
||||
_staticImage.registerGraphics();
|
||||
_animation.registerGraphics();
|
||||
RenderObject::registerGraphics();
|
||||
}
|
||||
|
||||
void Clock::updateGraphics() {
|
||||
setVisible(_animation.getCurrentFrame() >= (g_nancy->getGameType() == kGameTypeVampire ? 5 : 1));
|
||||
|
||||
if (_isVisible) {
|
||||
Time newPlayerTime = NancySceneState.getPlayerTime();
|
||||
|
||||
if (newPlayerTime == _playerTime ||
|
||||
newPlayerTime.getMinutes() / 15 != _playerTime.getMinutes() / 15 ||
|
||||
newPlayerTime.getHours() != _playerTime.getHours()) {
|
||||
|
||||
_playerTime = newPlayerTime;
|
||||
drawClockHands();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Clock::handleInput(NancyInput &input) {
|
||||
if (!_locked) {
|
||||
_animation.handleInput(input);
|
||||
}
|
||||
}
|
||||
|
||||
void Clock::drawClockHands() {
|
||||
Graphics::ManagedSurface &object0 = g_nancy->_graphics->_object0;
|
||||
uint hours = _playerTime.getHours();
|
||||
if (hours >= 12) {
|
||||
hours -= 12;
|
||||
}
|
||||
uint minutesHand = _playerTime.getMinutes() / 15;
|
||||
|
||||
Common::Rect hoursDest = _clockData->hoursHandDests[hours];
|
||||
Common::Rect minutesDest = _clockData->minutesHandDests[minutesHand];
|
||||
|
||||
hoursDest.translate(-_screenPosition.left, -_screenPosition.top);
|
||||
minutesDest.translate(-_screenPosition.left, -_screenPosition.top);
|
||||
|
||||
_drawSurface.clear(g_nancy->_graphics->getTransColor());
|
||||
_drawSurface.blitFrom(object0, _clockData->hoursHandSrcs[hours], hoursDest);
|
||||
_drawSurface.blitFrom(object0, _clockData->minutesHandSrcs[minutesHand], minutesDest);
|
||||
}
|
||||
|
||||
void Clock::ClockAnim::init() {
|
||||
auto *bootSummary = GetEngineData(BSUM);
|
||||
assert(bootSummary);
|
||||
|
||||
_srcRects = _owner->_clockData->animSrcs;
|
||||
_destRects = _owner->_clockData->animDests;
|
||||
_highlightSrcRect = bootSummary->clockHighlightSrc;
|
||||
_highlightDestRect = bootSummary->extraButtonHighlightDest;
|
||||
|
||||
if (_destRects.size()) {
|
||||
moveTo(bootSummary->extraButtonHotspot);
|
||||
} else {
|
||||
moveTo(_owner->_clockData->screenPosition);
|
||||
}
|
||||
|
||||
_timeToKeepOpen = _owner->_clockData->timeToKeepOpen;
|
||||
_frameTime = _owner->_clockData->frameTime;
|
||||
|
||||
_alwaysHighlightCursor = true;
|
||||
_hotspot = _screenPosition;
|
||||
}
|
||||
|
||||
void Clock::ClockAnim::updateGraphics() {
|
||||
AnimatedButton::updateGraphics();
|
||||
if (_isOpen && !isPlaying() && (g_nancy->getTotalPlayTime() > _closeTime || _owner->_locked) && _isVisible) {
|
||||
setOpen(false);
|
||||
if (g_nancy->getGameType() == kGameTypeVampire) {
|
||||
_owner->_staticImage.setVisible(false);
|
||||
}
|
||||
g_nancy->_sound->playSound("GLOB");
|
||||
}
|
||||
}
|
||||
|
||||
void Clock::ClockAnim::onClick() {
|
||||
if (!isPlaying()) {
|
||||
setOpen(!_isOpen);
|
||||
|
||||
if (!_isOpen) {
|
||||
if (g_nancy->getGameType() == kGameTypeVampire) {
|
||||
_owner->_staticImage.setVisible(false);
|
||||
}
|
||||
} else if (g_nancy->getGameType() != kGameTypeVampire) {
|
||||
_owner->_staticImage.setVisible(true);
|
||||
}
|
||||
|
||||
_owner->_playerTime = NancySceneState.getPlayerTime();
|
||||
g_nancy->_sound->playSound("GLOB");
|
||||
}
|
||||
}
|
||||
|
||||
void Clock::ClockAnim::onTrigger() {
|
||||
if (_isOpen) {
|
||||
_closeTime = g_nancy->getTotalPlayTime() + _timeToKeepOpen;
|
||||
if (g_nancy->getGameType() == kGameTypeVampire) {
|
||||
_owner->_staticImage.setVisible(true);
|
||||
}
|
||||
} else {
|
||||
_owner->setVisible(false);
|
||||
_owner->_staticImage.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Nancy5Clock::init() {
|
||||
_clockData = GetEngineData(CLOK);
|
||||
assert(_clockData);
|
||||
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
void Nancy5Clock::updateGraphics() {
|
||||
// Show current day
|
||||
if (_currentDay < 3) {
|
||||
if (NancySceneState.getEventFlag(59, true) && _currentDay == 1) {
|
||||
_currentDay = 2;
|
||||
_drawSurface.create(g_nancy->_graphics->_object0, _clockData->daySrcs[2]);
|
||||
moveTo(_clockData->staticImageDest);
|
||||
setVisible(true);
|
||||
setTransparent(true);
|
||||
} else if (NancySceneState.getEventFlag(58, true) && _currentDay == 0) {
|
||||
_currentDay = 1;
|
||||
_drawSurface.create(g_nancy->_graphics->_object0, _clockData->daySrcs[1]);
|
||||
moveTo(_clockData->staticImageDest);
|
||||
setVisible(true);
|
||||
setTransparent(true);
|
||||
} else if (NancySceneState.getEventFlag(57, true) && _currentDay == -1) {
|
||||
_currentDay = 0;
|
||||
_drawSurface.create(g_nancy->_graphics->_object0, _clockData->daySrcs[0]);
|
||||
moveTo(_clockData->staticImageDest);
|
||||
setVisible(true);
|
||||
setTransparent(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Show demolition countdown
|
||||
if (NancySceneState.getEventFlag(320, true)) {
|
||||
_currentDay = 3;
|
||||
Time timerTime = NancySceneState.getTimerTime();
|
||||
int32 countdownFrameID = MIN<int32>((uint32)timerTime / (_clockData->countdownTime / 12), 13);
|
||||
if (countdownFrameID != _countdownProgress) {
|
||||
_countdownProgress = countdownFrameID;
|
||||
|
||||
_drawSurface.create(g_nancy->_graphics->_object0, _clockData->countdownSrcs[_countdownProgress]);
|
||||
moveTo(_clockData->staticImageDest);
|
||||
setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
101
engines/nancy/ui/clock.h
Normal file
101
engines/nancy/ui/clock.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NANCY_UI_CLOCK_H
|
||||
#define NANCY_UI_CLOCK_H
|
||||
|
||||
#include "engines/nancy/renderobject.h"
|
||||
#include "engines/nancy/enginedata.h"
|
||||
#include "engines/nancy/time.h"
|
||||
|
||||
#include "engines/nancy/ui/animatedbutton.h"
|
||||
|
||||
namespace Nancy {
|
||||
|
||||
struct NancyInput;
|
||||
|
||||
namespace UI {
|
||||
|
||||
class Clock : public RenderObject {
|
||||
friend class ClockAnim;
|
||||
public:
|
||||
Clock();
|
||||
virtual ~Clock() = default;
|
||||
|
||||
void init() override;
|
||||
void registerGraphics() override;
|
||||
void updateGraphics() override;
|
||||
void handleInput(NancyInput &input);
|
||||
|
||||
// Used to disable the UI clock when a scene can change the in-game time (e.g. SetPlayerClock)
|
||||
void lockClock(bool val) { _locked = val; }
|
||||
|
||||
void drawClockHands();
|
||||
|
||||
protected:
|
||||
class ClockAnim : public AnimatedButton {
|
||||
public:
|
||||
ClockAnim(uint zOrder, Clock *owner) : AnimatedButton(zOrder), _owner(owner), _closeTime(0), _timeToKeepOpen(0) {}
|
||||
virtual ~ClockAnim() = default;
|
||||
|
||||
void init() override;
|
||||
void updateGraphics() override;
|
||||
void onClick() override;
|
||||
void onTrigger() override;
|
||||
|
||||
private:
|
||||
Clock *_owner;
|
||||
|
||||
uint32 _closeTime;
|
||||
uint32 _timeToKeepOpen;
|
||||
};
|
||||
|
||||
const CLOK *_clockData;
|
||||
ClockAnim _animation;
|
||||
|
||||
// Used for gargoyle eyes in TVD, inside of watch in nancy2 and up
|
||||
RenderObject _staticImage;
|
||||
|
||||
Time _playerTime;
|
||||
bool _locked;
|
||||
};
|
||||
|
||||
// Separate class since it's not actually a clock, and is non-interactable. Instead, this shows which
|
||||
// in-game day it currently is, and also displays a countdown during the endgame
|
||||
class Nancy5Clock : public RenderObject {
|
||||
public:
|
||||
Nancy5Clock() : RenderObject(10) {}
|
||||
virtual ~Nancy5Clock() = default;
|
||||
|
||||
void init() override;
|
||||
void updateGraphics() override;
|
||||
|
||||
private:
|
||||
int32 _currentDay = -1;
|
||||
int32 _countdownProgress = -1;
|
||||
|
||||
const CLOK *_clockData = nullptr;
|
||||
};
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_UI_CLOCK_H
|
||||
42
engines/nancy/ui/fullscreenimage.cpp
Normal file
42
engines/nancy/ui/fullscreenimage.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/resource.h"
|
||||
|
||||
#include "engines/nancy/ui/fullscreenimage.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
void FullScreenImage::init(const Common::Path &imageName) {
|
||||
if (!g_nancy->_resource->loadImage(imageName, _drawSurface)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Common::Rect srcBounds = Common::Rect(0,0, _drawSurface.w, _drawSurface.h);
|
||||
_screenPosition = srcBounds;
|
||||
|
||||
RenderObject::init();
|
||||
}
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
44
engines/nancy/ui/fullscreenimage.h
Normal file
44
engines/nancy/ui/fullscreenimage.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NANCY_UI_FULLSCREENIMAGE_H
|
||||
#define NANCY_UI_FULLSCREENIMAGE_H
|
||||
|
||||
#include "engines/nancy/renderobject.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
class FullScreenImage : public RenderObject {
|
||||
public:
|
||||
FullScreenImage() : RenderObject(0) {}
|
||||
virtual ~FullScreenImage() = default;
|
||||
|
||||
void init(const Common::Path &imageName);
|
||||
|
||||
protected:
|
||||
void init() override {}
|
||||
};
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_UI_FULLSCREENIMAGE_H
|
||||
346
engines/nancy/ui/inventorybox.cpp
Normal file
346
engines/nancy/ui/inventorybox.cpp
Normal file
@@ -0,0 +1,346 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/resource.h"
|
||||
#include "engines/nancy/cursor.h"
|
||||
#include "engines/nancy/sound.h"
|
||||
#include "engines/nancy/input.h"
|
||||
#include "engines/nancy/util.h"
|
||||
|
||||
#include "engines/nancy/ui/inventorybox.h"
|
||||
|
||||
#include "engines/nancy/state/scene.h"
|
||||
|
||||
#include "engines/nancy/ui/scrollbar.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
InventoryBox::InventoryBox() :
|
||||
RenderObject(6),
|
||||
_scrollbarPos(0),
|
||||
_highlightedHotspot(-1),
|
||||
_inventoryData(nullptr) {}
|
||||
|
||||
void InventoryBox::init() {
|
||||
auto *bootSummary = GetEngineData(BSUM);
|
||||
assert(bootSummary);
|
||||
|
||||
_inventoryData = GetEngineData(INV);
|
||||
assert(_inventoryData);
|
||||
|
||||
_order.clear();
|
||||
|
||||
moveTo(bootSummary->inventoryBoxScreenPosition);
|
||||
g_nancy->_resource->loadImage(_inventoryData->inventoryBoxIconsImageName, _iconsSurface);
|
||||
|
||||
_fullInventorySurface.create(_screenPosition.width(), _screenPosition.height() * ((g_nancy->getStaticData().numItems / 4) + 1), g_nancy->_graphics->getScreenPixelFormat());
|
||||
Common::Rect sourceRect = _screenPosition;
|
||||
sourceRect.moveTo(0, 0);
|
||||
_drawSurface.create(_fullInventorySurface, sourceRect);
|
||||
|
||||
for (uint i = 0; i < 4; ++i) {
|
||||
Common::Rect &r = _itemHotspots[i].hotspot;
|
||||
r = _screenPosition;
|
||||
r.setWidth(r.width() / 2);
|
||||
r.setHeight(r.height() / 2);
|
||||
r.translate((i % 2) * r.width(), (i / 2) * r.height());
|
||||
}
|
||||
|
||||
RenderObject::init();
|
||||
|
||||
_scrollbar.reset(new Scrollbar( 9,
|
||||
_inventoryData->scrollbarSrcBounds,
|
||||
_inventoryData->scrollbarDefaultPos,
|
||||
_inventoryData->scrollbarMaxScroll - _inventoryData->scrollbarDefaultPos.y));
|
||||
_scrollbar->init();
|
||||
_curtains.init();
|
||||
}
|
||||
|
||||
void InventoryBox::updateGraphics() {
|
||||
if (_scrollbarPos != _scrollbar->getPos()) {
|
||||
_scrollbarPos = _scrollbar->getPos();
|
||||
|
||||
onScrollbarMove();
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryBox::registerGraphics() {
|
||||
RenderObject::registerGraphics();
|
||||
_scrollbar->registerGraphics();
|
||||
_curtains.registerGraphics();
|
||||
}
|
||||
|
||||
void InventoryBox::handleInput(NancyInput &input) {
|
||||
// Disable input when primary video is playing
|
||||
if (NancySceneState.getActiveConversation()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_order.size()) {
|
||||
_scrollbar->handleInput(input);
|
||||
}
|
||||
|
||||
int hoveredHotspot = -1;
|
||||
|
||||
for (uint i = 0; i < 4; ++i) {
|
||||
if (_itemHotspots[i].hotspot.contains(input.mousePos)) {
|
||||
if (NancySceneState.getHeldItem() != -1) {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kHotspotArrow);
|
||||
if (input.input & NancyInput::kLeftMouseButtonUp) {
|
||||
NancySceneState.addItemToInventory(NancySceneState.getHeldItem());
|
||||
g_nancy->_sound->playSound("BULS");
|
||||
}
|
||||
} else if (_itemHotspots[i].itemID != -1) {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kHotspotArrow);
|
||||
|
||||
hoveredHotspot = i;
|
||||
|
||||
if (input.input & NancyInput::kLeftMouseButtonUp) {
|
||||
uint16 itemID = _itemHotspots[i].itemID;
|
||||
INV::ItemDescription item = _inventoryData->itemDescriptions[itemID];
|
||||
byte disabled = NancySceneState.getItemDisabledState(itemID);
|
||||
|
||||
if (!disabled) {
|
||||
// Item is not disabled
|
||||
NancySceneState.removeItemFromInventory(itemID, item.keepItem != kInvItemNewSceneView);
|
||||
_highlightedHotspot = -1;
|
||||
hoveredHotspot = -1;
|
||||
|
||||
if (item.keepItem == kInvItemNewSceneView) {
|
||||
// Transport the player to a close-up scene, temporarily remove the item from the inventory
|
||||
NancySceneState.pushScene(itemID);
|
||||
SceneChangeDescription sceneChange;
|
||||
sceneChange.sceneID = item.sceneID;
|
||||
sceneChange.continueSceneSound = item.sceneSoundFlag;
|
||||
NancySceneState.changeScene(sceneChange);
|
||||
}
|
||||
} else {
|
||||
// Item is disabled
|
||||
if (disabled == 2) {
|
||||
// ...and set so it plays the "can't" sound when you click it
|
||||
NancySceneState.playItemCantSound(itemID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_highlightedHotspot != hoveredHotspot) {
|
||||
if (_highlightedHotspot != -1) {
|
||||
// Un-highlight last hovered item
|
||||
drawItemInSlot(_itemHotspots[_highlightedHotspot].itemID, _itemHotspots[_highlightedHotspot].itemOrder, false);
|
||||
_highlightedHotspot = -1;
|
||||
}
|
||||
|
||||
if (hoveredHotspot != -1) {
|
||||
// Highlight hovered item
|
||||
drawItemInSlot(_itemHotspots[hoveredHotspot].itemID, _itemHotspots[hoveredHotspot].itemOrder, true);
|
||||
_highlightedHotspot = hoveredHotspot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryBox::addItem(const int16 itemID) {
|
||||
if (_order.size() == 0) {
|
||||
// Adds first item, start curtains animation
|
||||
_curtains.setOpen(true);
|
||||
}
|
||||
Common::Array<int16> back = _order;
|
||||
_order.clear();
|
||||
_order.push_back(itemID);
|
||||
_order.push_back(back);
|
||||
|
||||
onReorder();
|
||||
}
|
||||
|
||||
void InventoryBox::removeItem(const int16 itemID) {
|
||||
for (auto &i : _order) {
|
||||
if (i == itemID) {
|
||||
_order.erase(&i);
|
||||
onReorder();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryBox::onReorder() {
|
||||
onScrollbarMove();
|
||||
|
||||
_fullInventorySurface.clear();
|
||||
for (uint i = 0; i < _order.size(); ++i) {
|
||||
drawItemInSlot(_order[i], i);
|
||||
}
|
||||
|
||||
if (_order.size() > 0) {
|
||||
_curtains.setOpen(true);
|
||||
} else {
|
||||
_curtains.setOpen(false);
|
||||
}
|
||||
|
||||
_needsRedraw = true;
|
||||
}
|
||||
|
||||
void InventoryBox::setHotspots(const uint pageNr) {
|
||||
for (uint i = 0; i < 4; ++i) {
|
||||
if (i + pageNr * 4 < _order.size()) {
|
||||
_itemHotspots[i].itemID = _order[i + pageNr * 4];
|
||||
_itemHotspots[i].itemOrder = i + pageNr * 4;
|
||||
} else {
|
||||
_itemHotspots[i].itemID = -1;
|
||||
_itemHotspots[i].itemOrder = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryBox::drawItemInSlot(const uint itemID, const uint slotID, const bool highlighted) {
|
||||
auto &item = _inventoryData->itemDescriptions[itemID];
|
||||
Common::Rect dest;
|
||||
|
||||
dest.setWidth(_screenPosition.width() / 2);
|
||||
dest.setHeight(_screenPosition.height() / 2);
|
||||
dest.moveTo((slotID % 2) * dest.width(), (slotID / 2) * dest.height());
|
||||
Common::Point destPoint = Common::Point (dest.left, dest.top);
|
||||
|
||||
_fullInventorySurface.blitFrom(_iconsSurface, highlighted ? item.highlightedSourceRect : item.sourceRect, destPoint);
|
||||
_needsRedraw = true;
|
||||
}
|
||||
|
||||
void InventoryBox::onScrollbarMove() {
|
||||
float scrollPos = _scrollbar->getPos();
|
||||
|
||||
float numPages = (_order.size() - 1) / 4 + 1;
|
||||
float pageFrac = 1 / numPages;
|
||||
uint curPage = MIN<uint>(scrollPos / pageFrac, numPages - 1);
|
||||
|
||||
Common::Rect sourceRect = _screenPosition;
|
||||
sourceRect.moveTo(0, curPage * (sourceRect.height() - 1));
|
||||
_drawSurface.create(_fullInventorySurface, sourceRect);
|
||||
|
||||
setHotspots(curPage);
|
||||
|
||||
_needsRedraw = true;
|
||||
}
|
||||
|
||||
InventoryBox::Curtains::Curtains() :
|
||||
RenderObject(10),
|
||||
_soundTriggered(false),
|
||||
_areOpen(false),
|
||||
_curFrame(0),
|
||||
_numFrames(g_nancy->getGameType() == kGameTypeVampire ? 10 : 7) {}
|
||||
|
||||
void InventoryBox::Curtains::init() {
|
||||
auto *inventoryData = GetEngineData(INV);
|
||||
assert(inventoryData);
|
||||
|
||||
moveTo(inventoryData->curtainsScreenPosition);
|
||||
Common::Rect bounds = _screenPosition;
|
||||
bounds.moveTo(0, 0);
|
||||
_drawSurface.create(bounds.width(), bounds.height(), g_nancy->_graphics->getInputPixelFormat());
|
||||
|
||||
if (g_nancy->getGameType() == kGameTypeVampire) {
|
||||
uint8 palette[256 * 3];
|
||||
g_nancy->_graphics->_object0.grabPalette(palette, 0, 256);
|
||||
_drawSurface.setPalette(palette, 0, 256);
|
||||
}
|
||||
|
||||
_nextFrameTime = 0;
|
||||
setAnimationFrame(_curFrame);
|
||||
|
||||
setTransparent(true);
|
||||
|
||||
RenderObject::init();
|
||||
}
|
||||
|
||||
void InventoryBox::Curtains::updateGraphics() {
|
||||
Time time = g_nancy->getTotalPlayTime();
|
||||
if (_areOpen) {
|
||||
if (_curFrame < _numFrames && time > _nextFrameTime) {
|
||||
auto *inventoryData = GetEngineData(INV);
|
||||
assert(inventoryData);
|
||||
|
||||
setAnimationFrame(++_curFrame);
|
||||
_nextFrameTime = time + inventoryData->curtainsFrameTime;
|
||||
|
||||
if (!_soundTriggered) {
|
||||
_soundTriggered = true;
|
||||
g_nancy->_sound->playSound("CURT");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_curFrame > 0 && time > _nextFrameTime) {
|
||||
auto *inventoryData = GetEngineData(INV);
|
||||
assert(inventoryData);
|
||||
|
||||
setAnimationFrame(--_curFrame);
|
||||
_nextFrameTime = time + inventoryData->curtainsFrameTime;
|
||||
|
||||
if (!_soundTriggered) {
|
||||
_soundTriggered = true;
|
||||
g_nancy->_sound->playSound("CURT");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_curFrame == 0 || _curFrame == _numFrames) {
|
||||
_soundTriggered = false;
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryBox::Curtains::setAnimationFrame(uint frame) {
|
||||
Graphics::ManagedSurface &_object0 = g_nancy->_graphics->_object0;
|
||||
Common::Rect srcRect;
|
||||
Common::Point destPoint;
|
||||
|
||||
if (frame > (uint)(_numFrames - 1)) {
|
||||
// TVD keeps the last frame visible
|
||||
if (g_nancy->getGameType() > kGameTypeVampire) {
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
auto *inventoryData = GetEngineData(INV);
|
||||
assert(inventoryData);
|
||||
|
||||
_drawSurface.clear(g_nancy->_graphics->getTransColor());
|
||||
|
||||
// Draw left curtain
|
||||
srcRect = inventoryData->curtainAnimationSrcs[frame * 2];
|
||||
_drawSurface.blitFrom(_object0, srcRect, destPoint);
|
||||
|
||||
// Draw right curtain
|
||||
srcRect = inventoryData->curtainAnimationSrcs[frame * 2 + 1];
|
||||
destPoint.x = getBounds().width() - srcRect.width();
|
||||
_drawSurface.blitFrom(_object0, srcRect, destPoint);
|
||||
|
||||
_needsRedraw = true;
|
||||
}
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
113
engines/nancy/ui/inventorybox.h
Normal file
113
engines/nancy/ui/inventorybox.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NANCY_UI_INVENTORYBOX_H
|
||||
#define NANCY_UI_INVENTORYBOX_H
|
||||
|
||||
#include "common/ptr.h"
|
||||
|
||||
#include "engines/nancy/time.h"
|
||||
#include "engines/nancy/renderobject.h"
|
||||
#include "engines/nancy/ui/scrollbar.h"
|
||||
|
||||
namespace Nancy {
|
||||
|
||||
class NancyEngine;
|
||||
struct NancyInput;
|
||||
|
||||
namespace State {
|
||||
class Scene;
|
||||
}
|
||||
|
||||
namespace UI {
|
||||
|
||||
class InventoryBox : public RenderObject {
|
||||
friend class Nancy::State::Scene;
|
||||
|
||||
public:
|
||||
struct ItemDescription {
|
||||
Common::String name; // 0x00
|
||||
byte keepItem = kInvItemUseThenLose; // 0x14
|
||||
Common::Rect sourceRect; // 0x16
|
||||
};
|
||||
|
||||
InventoryBox();
|
||||
|
||||
void init() override;
|
||||
void updateGraphics() override;
|
||||
void registerGraphics() override;
|
||||
void handleInput(NancyInput &input);
|
||||
|
||||
void onScrollbarMove();
|
||||
|
||||
private:
|
||||
// These are private since they should only be called from Scene
|
||||
void addItem(const int16 itemID);
|
||||
void removeItem(const int16 itemID);
|
||||
|
||||
void onReorder();
|
||||
void setHotspots(const uint pageNr);
|
||||
void drawItemInSlot(const uint itemID, const uint slotID, const bool highlighted = false);
|
||||
|
||||
class Curtains : public RenderObject {
|
||||
public:
|
||||
Curtains();
|
||||
virtual ~Curtains() = default;
|
||||
|
||||
void init() override;
|
||||
void updateGraphics() override;
|
||||
|
||||
void setOpen(bool open) { _areOpen = open; }
|
||||
|
||||
void setAnimationFrame(uint frame);
|
||||
|
||||
uint _numFrames;
|
||||
uint _curFrame;
|
||||
Time _nextFrameTime;
|
||||
bool _areOpen;
|
||||
bool _soundTriggered;
|
||||
};
|
||||
|
||||
struct ItemHotspot {
|
||||
int16 itemID = -1;
|
||||
int itemOrder = -1; // index of the item into the _order array
|
||||
Common::Rect hotspot; // in screen coordinates
|
||||
};
|
||||
|
||||
Graphics::ManagedSurface _iconsSurface;
|
||||
Graphics::ManagedSurface _fullInventorySurface;
|
||||
|
||||
Common::ScopedPtr<Scrollbar> _scrollbar;
|
||||
Curtains _curtains;
|
||||
|
||||
float _scrollbarPos;
|
||||
|
||||
Common::Array<int16> _order;
|
||||
ItemHotspot _itemHotspots[4];
|
||||
int _highlightedHotspot;
|
||||
|
||||
const struct INV *_inventoryData;
|
||||
};
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_UI_INVENTORYBOX_H
|
||||
136
engines/nancy/ui/ornaments.cpp
Normal file
136
engines/nancy/ui/ornaments.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/nancy/ui/ornaments.h"
|
||||
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/util.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
void ViewportOrnaments::init() {
|
||||
auto *viewportData = GetEngineData(VIEW);
|
||||
assert(viewportData);
|
||||
|
||||
Common::Rect viewportBounds = viewportData->bounds;
|
||||
moveTo(viewportData->screenPosition);
|
||||
|
||||
Graphics::ManagedSurface &object0 = g_nancy->_graphics->_object0;
|
||||
|
||||
_drawSurface.create(viewportBounds.width(), viewportBounds.height(), g_nancy->_graphics->getInputPixelFormat());
|
||||
|
||||
uint8 palette[256 * 3];
|
||||
object0.grabPalette(palette, 0, 256);
|
||||
_drawSurface.setPalette(palette, 0, 256);
|
||||
|
||||
// All values for the viewport ornaments are hardcoded and not stored in a chunk
|
||||
Common::Rect src[6] = {
|
||||
{ 0, 0, 31, 110 },
|
||||
{ 49, 0, 81, 110 },
|
||||
{ 33, 24, 45, 37 },
|
||||
{ 33, 69, 46, 82 },
|
||||
{ 33, 0, 43, 22 },
|
||||
{ 33, 39, 40, 59 }
|
||||
};
|
||||
|
||||
_drawSurface.clear(g_nancy->_graphics->getTransColor());
|
||||
setTransparent(true);
|
||||
|
||||
// Top left
|
||||
_drawSurface.blitFrom(object0, src[0], Common::Point(0, 0));
|
||||
// Top right
|
||||
_drawSurface.blitFrom(object0, src[1], Common::Point(viewportBounds.right - src[1].width(), 0));
|
||||
// Bottom left
|
||||
_drawSurface.blitFrom(object0, src[2], Common::Point(0, viewportBounds.bottom - src[2].height()));
|
||||
// Bottom right
|
||||
_drawSurface.blitFrom(object0, src[3], Common::Point(viewportBounds.right - src[3].width(), viewportBounds.bottom - src[3].height()));
|
||||
// Middle left
|
||||
_drawSurface.blitFrom(object0, src[4], Common::Point(0, 204));
|
||||
// Middle right
|
||||
_drawSurface.blitFrom(object0, src[5], Common::Point(viewportBounds.right - src[5].width(), 205));
|
||||
|
||||
RenderObject::init();
|
||||
}
|
||||
|
||||
void TextboxOrnaments::init() {
|
||||
auto *bootSummary = GetEngineData(BSUM);
|
||||
assert(bootSummary);
|
||||
|
||||
auto *textboxData = GetEngineData(TBOX);
|
||||
assert(textboxData);
|
||||
|
||||
moveTo(bootSummary->textboxScreenPosition);
|
||||
Common::Rect textboxBounds = _screenPosition;
|
||||
textboxBounds.moveTo(0, 0);
|
||||
|
||||
Graphics::ManagedSurface &object0 = g_nancy->_graphics->_object0;
|
||||
|
||||
_drawSurface.create(textboxBounds.width(), textboxBounds.height(), g_nancy->_graphics->getInputPixelFormat());
|
||||
|
||||
uint8 palette[256 * 3];
|
||||
object0.grabPalette(palette, 0, 256);
|
||||
_drawSurface.setPalette(palette, 0, 256);
|
||||
|
||||
_drawSurface.clear(g_nancy->_graphics->getTransColor());
|
||||
setTransparent(true);
|
||||
|
||||
for (uint i = 0; i < 14; ++i) {
|
||||
_drawSurface.blitFrom(object0, textboxData->ornamentSrcs[i],
|
||||
Common::Point( textboxData->ornamentDests[i].left - _screenPosition.left,
|
||||
textboxData->ornamentDests[i].top - _screenPosition.top));
|
||||
}
|
||||
|
||||
RenderObject::init();
|
||||
}
|
||||
|
||||
void InventoryBoxOrnaments::init() {
|
||||
auto *bootSummary = GetEngineData(BSUM);
|
||||
assert(bootSummary);
|
||||
|
||||
auto *inventoryData = GetEngineData(INV);
|
||||
assert(inventoryData);
|
||||
|
||||
moveTo(bootSummary->inventoryBoxScreenPosition);
|
||||
Common::Rect invBoxBounds = _screenPosition;
|
||||
invBoxBounds.moveTo(0, 0);
|
||||
|
||||
Graphics::ManagedSurface &object0 = g_nancy->_graphics->_object0;
|
||||
|
||||
_drawSurface.create(invBoxBounds.width(), invBoxBounds.height(), g_nancy->_graphics->getInputPixelFormat());
|
||||
|
||||
uint8 palette[256 * 3];
|
||||
object0.grabPalette(palette, 0, 256);
|
||||
_drawSurface.setPalette(palette, 0, 256);
|
||||
|
||||
_drawSurface.clear(g_nancy->_graphics->getTransColor());
|
||||
setTransparent(true);
|
||||
|
||||
for (uint i = 0; i < 6; ++i) {
|
||||
_drawSurface.blitFrom(object0, inventoryData->ornamentSrcs[i],
|
||||
Common::Point( inventoryData->ornamentDests[i].left - _screenPosition.left,
|
||||
inventoryData->ornamentDests[i].top - _screenPosition.top));
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
57
engines/nancy/ui/ornaments.h
Normal file
57
engines/nancy/ui/ornaments.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NANCY_UI_ORNAMENTS_H
|
||||
#define NANCY_UI_ORNAMENTS_H
|
||||
|
||||
#include "engines/nancy/renderobject.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
class ViewportOrnaments : public Nancy::RenderObject {
|
||||
public:
|
||||
ViewportOrnaments(uint16 zOrder) : RenderObject(zOrder) {}
|
||||
virtual ~ViewportOrnaments() {}
|
||||
|
||||
void init() override;
|
||||
};
|
||||
|
||||
class TextboxOrnaments : public Nancy::RenderObject {
|
||||
public:
|
||||
TextboxOrnaments(uint16 zOrder) : RenderObject(zOrder) {}
|
||||
virtual ~TextboxOrnaments() {}
|
||||
|
||||
void init() override;
|
||||
};
|
||||
|
||||
class InventoryBoxOrnaments : public Nancy::RenderObject {
|
||||
public:
|
||||
InventoryBoxOrnaments(uint16 zOrder) : RenderObject(zOrder) {}
|
||||
virtual ~InventoryBoxOrnaments() {}
|
||||
|
||||
void init() override;
|
||||
};
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_UI_ORNAMENTS_H
|
||||
135
engines/nancy/ui/scrollbar.cpp
Normal file
135
engines/nancy/ui/scrollbar.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/input.h"
|
||||
#include "engines/nancy/cursor.h"
|
||||
|
||||
#include "engines/nancy/ui/scrollbar.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
Scrollbar::Scrollbar(uint16 zOrder, const Common::Rect &srcBounds, const Common::Point &topPosition, uint16 scrollDistance, bool isVertical) :
|
||||
Scrollbar(zOrder, srcBounds, g_nancy->_graphics->_object0, topPosition, scrollDistance, isVertical) {}
|
||||
|
||||
Scrollbar::Scrollbar(uint16 zOrder, const Common::Rect &srcBounds, Graphics::ManagedSurface &srcSurf, const Common::Point &topPosition, uint16 scrollDistance, bool isVertical) :
|
||||
RenderObject(zOrder),
|
||||
_isVertical(isVertical),
|
||||
_isClicked(false),
|
||||
_currentPosition(0),
|
||||
_maxDist(scrollDistance) {
|
||||
_drawSurface.create(srcSurf, srcBounds);
|
||||
|
||||
_startPosition = topPosition;
|
||||
_startPosition.x -= srcBounds.width() / 2;
|
||||
|
||||
if (!isVertical) {
|
||||
_startPosition.y -= srcBounds.height() / 2;
|
||||
}
|
||||
|
||||
_screenPosition = srcBounds;
|
||||
_screenPosition.moveTo(_startPosition);
|
||||
}
|
||||
|
||||
void Scrollbar::init() {
|
||||
setTransparent(true);
|
||||
RenderObject::init();
|
||||
}
|
||||
|
||||
void Scrollbar::handleInput(NancyInput &input) {
|
||||
// Note: the original engine's scrollbars only work if the cursor is inside
|
||||
// the hotspot (happens if we remove the _isClicked check below). This doesn't make
|
||||
// for great UX, however, so it has been fixed.
|
||||
if (_screenPosition.contains(input.mousePos) || _isClicked) {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kHotspotArrow);
|
||||
|
||||
if (input.input & NancyInput::kLeftMouseButtonDown && !_isClicked) {
|
||||
// Begin click and hold
|
||||
_isClicked = true;
|
||||
_mousePosOnClick = input.mousePos - Common::Point(_screenPosition.left, _screenPosition.top);
|
||||
}
|
||||
|
||||
if (input.input & NancyInput::kRightMouseButtonUp) {
|
||||
// Right click, reset position
|
||||
resetPosition();
|
||||
}
|
||||
|
||||
if (_isClicked) {
|
||||
// Is currently clicked, handle movement
|
||||
Common::Point newMousePos = input.mousePos - Common::Point(_screenPosition.left, _screenPosition.top);
|
||||
|
||||
if (newMousePos != _mousePosOnClick) {
|
||||
|
||||
if (_isVertical) {
|
||||
uint16 minY = _startPosition.y;
|
||||
uint16 maxY = minY + _maxDist;
|
||||
uint16 newTop = CLIP<uint16>((_screenPosition.top + newMousePos.y - _mousePosOnClick.y), minY, maxY);
|
||||
moveTo(Common::Point(_screenPosition.left, newTop));
|
||||
} else {
|
||||
uint16 minX = _startPosition.x;
|
||||
uint16 maxX = minX + _maxDist;
|
||||
uint16 newLeft = CLIP<uint16>((_screenPosition.left + newMousePos.x - _mousePosOnClick.x), minX, maxX);
|
||||
moveTo(Common::Point(newLeft, _screenPosition.top));
|
||||
}
|
||||
|
||||
calculatePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool wasClicked = _isClicked;
|
||||
if (input.input & NancyInput::kLeftMouseButtonUp) {
|
||||
_isClicked = false;
|
||||
}
|
||||
|
||||
// If the mouse is clicked and moves outside the scrollbar's hotspot, we don't want it
|
||||
// to trigger other events. This only works if scrollbars are at the very top of the input priority.
|
||||
// As a result, this effect won't be applied to the scrollbars in SoundEqualizerPuzzle
|
||||
// In the future, this can be fixed by creating an input queue inside InputManager.
|
||||
if (wasClicked) {
|
||||
input.eatMouseInput();
|
||||
}
|
||||
}
|
||||
|
||||
void Scrollbar::setPosition(float pos) {
|
||||
_currentPosition = pos;
|
||||
if (_isVertical) {
|
||||
moveTo(Common::Point(_screenPosition.left, _startPosition.y + (_maxDist * pos)));
|
||||
} else {
|
||||
moveTo(Common::Point(_startPosition.x + (_maxDist * pos), _screenPosition.top));
|
||||
}
|
||||
}
|
||||
|
||||
void Scrollbar::calculatePosition() {
|
||||
uint16 scroll = _isVertical ? _screenPosition.top - _startPosition.y : _screenPosition.left - _startPosition.x;
|
||||
|
||||
_currentPosition = scroll != 0 ? (float)scroll / (float)_maxDist : 0;
|
||||
}
|
||||
|
||||
void Scrollbar::resetPosition() {
|
||||
moveTo(Common::Point(_screenPosition.left, _startPosition.y));
|
||||
calculatePosition();
|
||||
}
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
61
engines/nancy/ui/scrollbar.h
Normal file
61
engines/nancy/ui/scrollbar.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NANCY_UI_SCROLLBAR_H
|
||||
#define NANCY_UI_SCROLLBAR_H
|
||||
|
||||
#include "engines/nancy/renderobject.h"
|
||||
|
||||
namespace Nancy {
|
||||
|
||||
struct NancyInput;
|
||||
|
||||
namespace UI {
|
||||
|
||||
class Scrollbar : public RenderObject {
|
||||
public:
|
||||
Scrollbar(uint16 zOrder, const Common::Rect &srcBounds, const Common::Point &topPosition, uint16 scrollDistance, bool isVertical = true);
|
||||
Scrollbar(uint16 zOrder, const Common::Rect &srcBounds, Graphics::ManagedSurface &srcSurf, const Common::Point &topPosition, uint16 scrollDistance, bool isVertical = true);
|
||||
virtual ~Scrollbar() = default;
|
||||
|
||||
void init() override;
|
||||
|
||||
void handleInput(NancyInput &input);
|
||||
|
||||
void resetPosition();
|
||||
float getPos() const { return _currentPosition; }
|
||||
|
||||
void setPosition(float pos);
|
||||
void calculatePosition();
|
||||
|
||||
Common::Point _startPosition;
|
||||
uint _maxDist;
|
||||
bool _isVertical;
|
||||
|
||||
float _currentPosition;
|
||||
bool _isClicked;
|
||||
Common::Point _mousePosOnClick;
|
||||
};
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_UI_SCROLLBAR_H
|
||||
222
engines/nancy/ui/textbox.cpp
Normal file
222
engines/nancy/ui/textbox.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/tokenizer.h"
|
||||
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/cursor.h"
|
||||
#include "engines/nancy/input.h"
|
||||
#include "engines/nancy/util.h"
|
||||
|
||||
#include "engines/nancy/state/scene.h"
|
||||
|
||||
#include "engines/nancy/ui/textbox.h"
|
||||
#include "engines/nancy/ui/scrollbar.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
Textbox::Textbox() :
|
||||
RenderObject(6),
|
||||
_scrollbar(nullptr),
|
||||
_scrollbarPos(0),
|
||||
_highlightRObj(7),
|
||||
_fontIDOverride(-1),
|
||||
_autoClearTime(0) {}
|
||||
|
||||
Textbox::~Textbox() {
|
||||
delete _scrollbar;
|
||||
}
|
||||
|
||||
void Textbox::init() {
|
||||
auto *bsum = GetEngineData(BSUM);
|
||||
assert(bsum);
|
||||
|
||||
auto *tbox = GetEngineData(TBOX);
|
||||
assert(tbox);
|
||||
|
||||
moveTo(bsum->textboxScreenPosition);
|
||||
_highlightRObj.moveTo(bsum->textboxScreenPosition);
|
||||
initSurfaces(tbox->innerBoundingBox.width(), tbox->innerBoundingBox.height(), g_nancy->_graphics->getScreenPixelFormat(),
|
||||
tbox->textBackground, tbox->highlightTextBackground);
|
||||
|
||||
Common::Rect outerBoundingBox = _screenPosition;
|
||||
outerBoundingBox.moveTo(0, 0);
|
||||
_drawSurface.create(_fullSurface, outerBoundingBox);
|
||||
|
||||
RenderObject::init();
|
||||
|
||||
// zOrder bumped by 2 to avoid overlap with the inventory box curtains in The Vampire Diaries
|
||||
_scrollbar = new Scrollbar( 11,
|
||||
tbox->scrollbarSrcBounds,
|
||||
tbox->scrollbarDefaultPos,
|
||||
tbox->scrollbarMaxScroll - tbox->scrollbarDefaultPos.y);
|
||||
_scrollbar->init();
|
||||
}
|
||||
|
||||
void Textbox::registerGraphics() {
|
||||
RenderObject::registerGraphics();
|
||||
_scrollbar->registerGraphics();
|
||||
_highlightRObj.registerGraphics();
|
||||
_highlightRObj.setVisible(false);
|
||||
}
|
||||
|
||||
void Textbox::updateGraphics() {
|
||||
if (_autoClearTime && g_nancy->getTotalPlayTime() > _autoClearTime) {
|
||||
clear();
|
||||
}
|
||||
|
||||
if (_needsTextRedraw) {
|
||||
drawTextbox();
|
||||
}
|
||||
|
||||
if (_scrollbarPos != _scrollbar->getPos()) {
|
||||
_scrollbarPos = _scrollbar->getPos();
|
||||
|
||||
onScrollbarMove();
|
||||
}
|
||||
|
||||
RenderObject::updateGraphics();
|
||||
}
|
||||
|
||||
void Textbox::handleInput(NancyInput &input) {
|
||||
_scrollbar->handleInput(input);
|
||||
|
||||
bool hasHighlight = false;
|
||||
for (uint i = 0; i < _hotspots.size(); ++i) {
|
||||
Common::Rect hotspot = _hotspots[i];
|
||||
hotspot.translate(0, -_drawSurface.getOffsetFromOwner().y);
|
||||
Common::Rect hotspotOnScreen = convertToScreen(hotspot).findIntersectingRect(_screenPosition);
|
||||
if (hotspotOnScreen.contains(input.mousePos)) {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kHotspotArrow);
|
||||
|
||||
// Highlight the selected response
|
||||
if (g_nancy->getGameType() >= kGameTypeNancy2) {
|
||||
_highlightRObj.setVisible(true);
|
||||
Common::Rect hotspotInside = convertToLocal(hotspotOnScreen);
|
||||
hotspotInside.translate(0, _drawSurface.getOffsetFromOwner().y);
|
||||
_highlightRObj._drawSurface.create(_textHighlightSurface, hotspotInside);
|
||||
_highlightRObj.moveTo(hotspotOnScreen);
|
||||
hasHighlight = true;
|
||||
}
|
||||
|
||||
if (input.input & NancyInput::kLeftMouseButtonUp) {
|
||||
input.input &= ~NancyInput::kLeftMouseButtonUp;
|
||||
NancySceneState.clearLogicConditions();
|
||||
NancySceneState.setLogicCondition(i, g_nancy->_true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasHighlight && _highlightRObj.isVisible()) {
|
||||
_highlightRObj.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Textbox::drawTextbox() {
|
||||
auto *tbox = GetEngineData(TBOX);
|
||||
assert(tbox);
|
||||
|
||||
Common::Rect textBounds = _fullSurface.getBounds();
|
||||
textBounds.top += tbox->upOffset;
|
||||
textBounds.bottom -= tbox->downOffset;
|
||||
textBounds.left += tbox->leftOffset;
|
||||
textBounds.right -= tbox->rightOffset;
|
||||
|
||||
const Font *font = g_nancy->_graphics->getFont(_fontIDOverride != -1 ? _fontIDOverride : tbox->defaultFontID);
|
||||
textBounds.top -= font->getFontHeight();
|
||||
|
||||
HypertextParser::drawAllText( textBounds, 0, // bounds of text within full surface
|
||||
_fontIDOverride != -1 ? _fontIDOverride : tbox->defaultFontID, // font for basic text
|
||||
tbox->highlightConversationFontID); // font for highlight text
|
||||
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
void Textbox::clear() {
|
||||
if (_textLines.size()) {
|
||||
HypertextParser::clear();
|
||||
_scrollbar->resetPosition();
|
||||
onScrollbarMove();
|
||||
_fontIDOverride = -1;
|
||||
_needsRedraw = true;
|
||||
_autoClearTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Textbox::addTextLine(const Common::String &text, uint32 autoClearTime) {
|
||||
HypertextParser::addTextLine(text);
|
||||
|
||||
if (autoClearTime != 0) {
|
||||
// Start a timer, after which the textbox will automatically be cleared.
|
||||
// Currently only used by inventory closed captions
|
||||
_autoClearTime = g_nancy->getTotalPlayTime() + autoClearTime;
|
||||
}
|
||||
|
||||
_scrollbar->resetPosition();
|
||||
onScrollbarMove();
|
||||
}
|
||||
|
||||
void Textbox::setOverrideFont(const uint fontID) {
|
||||
auto *bsum = GetEngineData(BSUM);
|
||||
assert(bsum);
|
||||
|
||||
if (fontID >= bsum->numFonts) {
|
||||
error("Requested invalid override font ID %u in Textbox", fontID);
|
||||
}
|
||||
|
||||
_fontIDOverride = fontID;
|
||||
}
|
||||
|
||||
void Textbox::onScrollbarMove() {
|
||||
_scrollbarPos = CLIP<float>(_scrollbarPos, 0, 1);
|
||||
|
||||
uint16 inner = getInnerHeight();
|
||||
uint16 outer = _screenPosition.height();
|
||||
|
||||
if (inner > outer) {
|
||||
Common::Rect bounds = getBounds();
|
||||
bounds.moveTo(0, (inner - outer) * _scrollbarPos);
|
||||
_drawSurface.create(_fullSurface, bounds);
|
||||
_highlightRObj._drawSurface.create(_textHighlightSurface, bounds);
|
||||
} else {
|
||||
_drawSurface.create(_fullSurface, getBounds());
|
||||
_highlightRObj._drawSurface.create(_textHighlightSurface, getBounds());
|
||||
}
|
||||
|
||||
_needsRedraw = true;
|
||||
}
|
||||
|
||||
uint16 Textbox::getInnerHeight() const {
|
||||
// As early as nancy3 this behavior stopped being relevant, as the original
|
||||
// engine always scrolls down to the bottom of the entire inner surface.
|
||||
// However, that makes the scrollbar almost unusable, so I'm not changing this.
|
||||
auto *tbox = GetEngineData(TBOX);
|
||||
assert(tbox);
|
||||
|
||||
return _drawnTextHeight + tbox->upOffset + tbox->downOffset;
|
||||
}
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
70
engines/nancy/ui/textbox.h
Normal file
70
engines/nancy/ui/textbox.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NANCY_UI_TEXTBOX_H
|
||||
#define NANCY_UI_TEXTBOX_H
|
||||
|
||||
#include "engines/nancy/misc/hypertext.h"
|
||||
#include "engines/nancy/renderobject.h"
|
||||
|
||||
namespace Nancy {
|
||||
|
||||
class NancyEngine;
|
||||
class Scene;
|
||||
struct NancyInput;
|
||||
|
||||
namespace UI {
|
||||
|
||||
class Scrollbar;
|
||||
|
||||
class Textbox : public Nancy::RenderObject, public Misc::HypertextParser {
|
||||
public:
|
||||
Textbox();
|
||||
virtual ~Textbox();
|
||||
|
||||
void init() override;
|
||||
void registerGraphics() override;
|
||||
void updateGraphics() override;
|
||||
void handleInput(NancyInput &input);
|
||||
|
||||
void drawTextbox();
|
||||
void clear() override;
|
||||
|
||||
void addTextLine(const Common::String &text, uint32 autoClearTime = 0);
|
||||
void setOverrideFont(const uint fontID);
|
||||
|
||||
private:
|
||||
uint16 getInnerHeight() const;
|
||||
void onScrollbarMove();
|
||||
|
||||
RenderObject _highlightRObj;
|
||||
Scrollbar *_scrollbar;
|
||||
|
||||
float _scrollbarPos;
|
||||
|
||||
uint32 _autoClearTime;
|
||||
int _fontIDOverride;
|
||||
};
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_UI_TEXTBOX_H
|
||||
352
engines/nancy/ui/viewport.cpp
Normal file
352
engines/nancy/ui/viewport.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
#include "engines/nancy/cursor.h"
|
||||
#include "engines/nancy/input.h"
|
||||
#include "engines/nancy/util.h"
|
||||
|
||||
#include "engines/nancy/state/scene.h"
|
||||
|
||||
#include "engines/nancy/ui/viewport.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace UI {
|
||||
|
||||
// does NOT put the object in a valid state until loadVideo is called
|
||||
void Viewport::init() {
|
||||
auto *bootSummary = GetEngineData(BSUM);
|
||||
assert(bootSummary);
|
||||
|
||||
auto *viewportData = GetEngineData(VIEW);
|
||||
assert(viewportData);
|
||||
|
||||
moveTo(viewportData->screenPosition);
|
||||
|
||||
setEdgesSize( bootSummary->verticalEdgesSize,
|
||||
bootSummary->verticalEdgesSize,
|
||||
bootSummary->horizontalEdgesSize,
|
||||
bootSummary->horizontalEdgesSize);
|
||||
|
||||
RenderObject::init();
|
||||
}
|
||||
|
||||
void Viewport::handleInput(NancyInput &input) {
|
||||
const Nancy::State::Scene::SceneSummary &summary = NancySceneState.getSceneSummary();
|
||||
Time systemTime = g_system->getMillis();
|
||||
byte direction = 0;
|
||||
|
||||
if (summary.slowMoveTimeDelta == kNoAutoScroll) {
|
||||
// Individual scenes may disable auto-move even when it's globally turned on
|
||||
_autoMove = false;
|
||||
} else {
|
||||
_autoMove = ConfMan.getBool("auto_move", ConfMan.getActiveDomainName());
|
||||
}
|
||||
|
||||
// Make cursor sticky when scrolling the viewport
|
||||
if ( g_nancy->getGameType() != kGameTypeVampire &&
|
||||
input.input & (NancyInput::kLeftMouseButton | NancyInput::kRightMouseButton)
|
||||
&& _stickyCursorPos.x > -1) {
|
||||
g_nancy->_cursor->warpCursor(_stickyCursorPos);
|
||||
input.mousePos = _stickyCursorPos;
|
||||
}
|
||||
|
||||
Common::Rect viewportActiveZone;
|
||||
|
||||
if (g_nancy->getGameType() == kGameTypeVampire) {
|
||||
viewportActiveZone = g_nancy->_graphics->getScreen()->getBounds();
|
||||
viewportActiveZone.bottom = _screenPosition.bottom;
|
||||
} else {
|
||||
viewportActiveZone = _screenPosition;
|
||||
}
|
||||
|
||||
if (viewportActiveZone.contains(input.mousePos)) {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kNormal);
|
||||
|
||||
if (input.mousePos.x < _nonScrollZone.left) {
|
||||
direction |= kLeft;
|
||||
}
|
||||
|
||||
if (input.mousePos.x > _nonScrollZone.right) {
|
||||
direction |= kRight;
|
||||
}
|
||||
|
||||
if (input.mousePos.y < _nonScrollZone.top) {
|
||||
direction |= kUp;
|
||||
}
|
||||
|
||||
if (input.mousePos.y > _nonScrollZone.bottom) {
|
||||
// Handle TVD's weird behavior
|
||||
if (_screenPosition.contains(input.mousePos)) {
|
||||
direction |= kDown;
|
||||
} else {
|
||||
direction &= ~(kLeft | kRight);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle diagonals
|
||||
if (direction & (kLeft | kUp) ||
|
||||
direction & (kLeft | kDown) ||
|
||||
direction & (kRight | kUp) ||
|
||||
direction & (kRight | kDown)) {
|
||||
if (direction & _edgesMask) {
|
||||
direction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
direction &= ~_edgesMask;
|
||||
}
|
||||
|
||||
// Set sticky cursor
|
||||
if (input.input & (NancyInput::kLeftMouseButton | NancyInput::kRightMouseButton) && direction) {
|
||||
if (_stickyCursorPos.x <= -1) {
|
||||
_stickyCursorPos = input.mousePos;
|
||||
}
|
||||
} else {
|
||||
_stickyCursorPos.x = -1;
|
||||
}
|
||||
|
||||
if (direction) {
|
||||
if (direction & kLeft) {
|
||||
if (summary.fastMoveTimeDelta == kInvertedNode) {
|
||||
// Support nancy6+ inverted rotation scenes
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kInvertedRotateLeft);
|
||||
} else {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kRotateLeft);
|
||||
}
|
||||
} else if (direction & kRight) {
|
||||
if (summary.fastMoveTimeDelta == kInvertedNode) {
|
||||
// Support nancy6+ inverted rotation scenes
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kInvertedRotateRight);
|
||||
} else {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kRotateRight);
|
||||
}
|
||||
} else if (direction & kUp) {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kMoveUp);
|
||||
} else if (direction & kDown) {
|
||||
g_nancy->_cursor->setCursorType(CursorManager::kMoveDown);
|
||||
}
|
||||
|
||||
if (input.input & NancyInput::kRightMouseButton) {
|
||||
direction |= kMoveFast;
|
||||
} else if ((input.input & NancyInput::kLeftMouseButton) == 0 && _autoMove == false) {
|
||||
direction = 0;
|
||||
}
|
||||
|
||||
// Just pressed RMB down, cancel the timer (removes jank when auto move is on)
|
||||
if (input.input & NancyInput::kRightMouseButtonDown) {
|
||||
_nextMovementTime = 0;
|
||||
}
|
||||
|
||||
// If we hover over an edge we don't want to click an element in the viewport underneath
|
||||
// or to change the cursor, so we make the mouse input invalid
|
||||
input.eatMouseInput();
|
||||
}
|
||||
|
||||
if (!direction) {
|
||||
if (input.input & NancyInput::kMoveUp) {
|
||||
direction |= kUp;
|
||||
}
|
||||
if (input.input & NancyInput::kMoveDown) {
|
||||
direction |= kDown;
|
||||
}
|
||||
if (input.input & NancyInput::kMoveLeft) {
|
||||
direction |= kLeft;
|
||||
}
|
||||
if (input.input & NancyInput::kMoveRight) {
|
||||
direction |= kRight;
|
||||
}
|
||||
if (input.input & NancyInput::kMoveFastModifier) {
|
||||
direction |= kMoveFast;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the movement
|
||||
if (direction) {
|
||||
Time movementDelta = NancySceneState.getMovementTimeDelta(direction & kMoveFast);
|
||||
|
||||
if (systemTime > _nextMovementTime) {
|
||||
if (direction & kLeft) {
|
||||
setNextFrame();
|
||||
}
|
||||
|
||||
if (direction & kRight) {
|
||||
setPreviousFrame();
|
||||
}
|
||||
|
||||
if (direction & kUp) {
|
||||
scrollUp(summary.verticalScrollDelta);
|
||||
}
|
||||
|
||||
if (direction & kDown) {
|
||||
scrollDown(summary.verticalScrollDelta);
|
||||
}
|
||||
|
||||
_nextMovementTime = systemTime + movementDelta;
|
||||
}
|
||||
}
|
||||
|
||||
_movementLastFrame = direction;
|
||||
}
|
||||
|
||||
void Viewport::loadVideo(const Common::Path &filename, uint frameNr, uint verticalScroll, byte panningType, uint16 format, const Common::Path &palette) {
|
||||
if (_decoder.isVideoLoaded()) {
|
||||
_decoder.close();
|
||||
}
|
||||
|
||||
if (!_decoder.loadFile(filename.append(".avf"))) {
|
||||
error("Couldn't load video file %s", filename.toString().c_str());
|
||||
}
|
||||
|
||||
_videoFormat = format;
|
||||
|
||||
enableEdges(kUp | kDown | kLeft | kRight);
|
||||
|
||||
_panningType = panningType;
|
||||
|
||||
setFrame(frameNr);
|
||||
setVerticalScroll(verticalScroll);
|
||||
|
||||
if (!palette.empty()) {
|
||||
GraphicsManager::loadSurfacePalette(_fullFrame, palette);
|
||||
setPalette(palette);
|
||||
}
|
||||
|
||||
_movementLastFrame = 0;
|
||||
_nextMovementTime = 0;
|
||||
}
|
||||
|
||||
void Viewport::setFrame(uint frameNr) {
|
||||
assert(frameNr < _decoder.getFrameCount());
|
||||
|
||||
const Graphics::Surface *newFrame = _decoder.decodeFrame(frameNr);
|
||||
_decoder.seek(frameNr); // Seek to take advantage of caching
|
||||
|
||||
// Format 1 uses quarter-size images, while format 2 uses full-size ones
|
||||
// Videos in TVD are always upside-down
|
||||
GraphicsManager::copyToManaged(*newFrame, _fullFrame, g_nancy->getGameType() == kGameTypeVampire, _videoFormat == kSmallVideoFormat);
|
||||
|
||||
_needsRedraw = true;
|
||||
_currentFrame = frameNr;
|
||||
|
||||
if (_panningType == kPanLeftRight && !((_edgesMask & kLeft) && (_edgesMask & kRight))) {
|
||||
if (_currentFrame == 0) {
|
||||
disableEdges(kRight);
|
||||
} else if (_currentFrame == getFrameCount() - 1) {
|
||||
disableEdges(kLeft);
|
||||
} else {
|
||||
enableEdges(kLeft | kRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::setNextFrame() {
|
||||
uint newFrame = getCurFrame() + 1 >= getFrameCount() ? 0 : getCurFrame() + 1;
|
||||
if (newFrame != _currentFrame) {
|
||||
setFrame(newFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::setPreviousFrame() {
|
||||
uint newFrame = (int)getCurFrame() - 1 < 0 ? getFrameCount() - 1 : getCurFrame() - 1;
|
||||
if (newFrame != _currentFrame) {
|
||||
setFrame(newFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::setVerticalScroll(uint scroll) {
|
||||
assert((int)scroll + _drawSurface.h <= _fullFrame.h);
|
||||
|
||||
Common::Rect sourceBounds = _screenPosition;
|
||||
sourceBounds.moveTo(0, scroll);
|
||||
_drawSurface.create(_fullFrame, sourceBounds);
|
||||
_needsRedraw = true;
|
||||
|
||||
if (getMaxScroll() > 0) {
|
||||
if (scroll == getMaxScroll()) {
|
||||
disableEdges(kDown);
|
||||
enableEdges(kUp);
|
||||
} else if (scroll == 0) {
|
||||
disableEdges(kUp);
|
||||
enableEdges(kDown);
|
||||
} else {
|
||||
enableEdges(kUp | kDown);
|
||||
}
|
||||
} else {
|
||||
disableEdges(kUp | kDown);
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::scrollUp(uint delta) {
|
||||
if (_drawSurface.getOffsetFromOwner().y != 0) {
|
||||
setVerticalScroll(_drawSurface.getOffsetFromOwner().y < (int16)delta ? 0 : _drawSurface.getOffsetFromOwner().y - delta);
|
||||
}
|
||||
}
|
||||
|
||||
void Viewport::scrollDown(uint delta) {
|
||||
if (_drawSurface.getOffsetFromOwner().y != getMaxScroll()) {
|
||||
setVerticalScroll(_drawSurface.getOffsetFromOwner().y + delta > getMaxScroll() ? getMaxScroll() : _drawSurface.getOffsetFromOwner().y + delta);
|
||||
}
|
||||
}
|
||||
|
||||
uint16 Viewport::getMaxScroll() const {
|
||||
return _fullFrame.h - _drawSurface.h - (g_nancy->getGameType() == kGameTypeVampire ? 1 : 0);
|
||||
}
|
||||
|
||||
// Convert a viewport-space rectangle to screen coordinates
|
||||
Common::Rect Viewport::convertViewportToScreen(const Common::Rect &viewportRect) const {
|
||||
Common::Rect ret = convertToScreen(viewportRect);
|
||||
ret.translate(0, -getCurVerticalScroll());
|
||||
ret.clip(_screenPosition);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Convert a screen-space coordinate to viewport coordinates
|
||||
Common::Rect Viewport::convertScreenToViewport(const Common::Rect &viewportRect) const {
|
||||
Common::Rect ret = convertToLocal(viewportRect);
|
||||
ret.translate(0, getCurVerticalScroll());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Viewport::setEdgesSize(uint16 upSize, uint16 downSize, uint16 leftSize, uint16 rightSize) {
|
||||
_nonScrollZone = _screenPosition;
|
||||
uint offset = g_nancy->getGameType() == kGameTypeVampire ? 0 : 1;
|
||||
_nonScrollZone.top += upSize;
|
||||
_nonScrollZone.left += leftSize;
|
||||
_nonScrollZone.bottom -= downSize + offset;
|
||||
_nonScrollZone.right -= rightSize + offset;
|
||||
}
|
||||
|
||||
void Viewport::disableEdges(byte edges) {
|
||||
_edgesMask |= edges;
|
||||
}
|
||||
|
||||
void Viewport::enableEdges(byte edges) {
|
||||
_edgesMask &= ~edges;
|
||||
}
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
105
engines/nancy/ui/viewport.h
Normal file
105
engines/nancy/ui/viewport.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NANCY_UI_VIEWPORT_H
|
||||
#define NANCY_UI_VIEWPORT_H
|
||||
|
||||
#include "engines/nancy/time.h"
|
||||
#include "engines/nancy/video.h"
|
||||
|
||||
#include "engines/nancy/renderobject.h"
|
||||
|
||||
namespace Common {
|
||||
class String;
|
||||
}
|
||||
|
||||
namespace Nancy {
|
||||
|
||||
class Scene;
|
||||
struct NancyInput;
|
||||
|
||||
namespace UI {
|
||||
|
||||
class Viewport : public Nancy::RenderObject {
|
||||
public:
|
||||
Viewport() :
|
||||
RenderObject(6),
|
||||
_movementLastFrame(0),
|
||||
_edgesMask(0),
|
||||
_currentFrame(0),
|
||||
_videoFormat(kLargeVideoFormat),
|
||||
_stickyCursorPos(-1, -1),
|
||||
_panningType(kPanNone),
|
||||
_decoder(AVFDecoder::kLoadBidirectional),
|
||||
_autoMove(false) {}
|
||||
|
||||
virtual ~Viewport() { _decoder.close(); _fullFrame.free(); }
|
||||
|
||||
void init() override;
|
||||
void handleInput(NancyInput &input);
|
||||
|
||||
void loadVideo(const Common::Path &filename, uint frameNr = 0, uint verticalScroll = 0, byte panningType = kPanNone, uint16 format = 2, const Common::Path &palette = Common::Path());
|
||||
|
||||
void setFrame(uint frameNr);
|
||||
void setNextFrame();
|
||||
void setPreviousFrame();
|
||||
|
||||
void setVerticalScroll(uint scroll);
|
||||
void scrollUp(uint delta);
|
||||
void scrollDown(uint delta);
|
||||
|
||||
uint16 getFrameCount() const { return _decoder.isVideoLoaded() ? _decoder.getFrameCount() : 0; }
|
||||
uint16 getCurFrame() const { return _currentFrame; }
|
||||
uint16 getCurVerticalScroll() const { return _drawSurface.getOffsetFromOwner().y; }
|
||||
uint16 getMaxScroll() const;
|
||||
|
||||
Common::Rect convertViewportToScreen(const Common::Rect &viewportRect) const;
|
||||
Common::Rect convertScreenToViewport(const Common::Rect &viewportRect) const;
|
||||
|
||||
void disableEdges(byte edges);
|
||||
void enableEdges(byte edges);
|
||||
|
||||
protected:
|
||||
void setEdgesSize(uint16 upSize, uint16 downSize, uint16 leftSize, uint16 rightSize);
|
||||
|
||||
Common::Rect _nonScrollZone;
|
||||
byte _edgesMask;
|
||||
|
||||
byte _movementLastFrame;
|
||||
Time _nextMovementTime;
|
||||
|
||||
byte _panningType;
|
||||
|
||||
AVFDecoder _decoder;
|
||||
uint16 _currentFrame;
|
||||
uint16 _videoFormat;
|
||||
Graphics::ManagedSurface _fullFrame;
|
||||
Common::Rect _format1Bounds;
|
||||
Common::Rect _format2Bounds;
|
||||
Common::Point _stickyCursorPos;
|
||||
|
||||
bool _autoMove;
|
||||
};
|
||||
|
||||
} // End of namespace UI
|
||||
} // End of namespace Nancy
|
||||
|
||||
#endif // NANCY_UI_VIEWPORT_H
|
||||
Reference in New Issue
Block a user