Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View 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

View 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
View 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
View 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
View 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
View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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
View 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