scummvm/engines/wintermute/ui/ui_object.cpp
2014-02-18 02:39:40 +01:00

730 lines
18 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/*
* This file is based on WME Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/ui/ui_object.h"
#include "engines/wintermute/ui/ui_tiled_image.h"
#include "engines/wintermute/ui/ui_window.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/font/base_font_storage.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(UIObject, false)
//////////////////////////////////////////////////////////////////////////
UIObject::UIObject(BaseGame *inGame) : BaseObject(inGame) {
_back = nullptr;
_image = nullptr;
_font = nullptr;
_text = nullptr;
_sharedFonts = _sharedImages = false;
_width = _height = 0;
_listenerObject = nullptr;
_listenerParamObject = nullptr;
_listenerParamDWORD = 0;
_disable = false;
_visible = true;
_type = UI_UNKNOWN;
_parent = nullptr;
_parentNotify = false;
_focusedWidget = nullptr;
_canFocus = false;
_nonIntMouseEvents = true;
}
//////////////////////////////////////////////////////////////////////////
UIObject::~UIObject() {
if (!_gameRef->_loadInProgress) {
SystemClassRegistry::getInstance()->enumInstances(BaseGame::invalidateValues, "ScValue", (void *)this);
}
if (_back) {
delete _back;
}
if (_font && !_sharedFonts) {
_gameRef->_fontStorage->removeFont(_font);
}
if (_image && !_sharedImages) {
delete _image;
}
if (_text) {
delete[] _text;
}
_focusedWidget = nullptr; // ref only
}
//////////////////////////////////////////////////////////////////////////
void UIObject::setText(const char *text) {
if (_text) {
delete[] _text;
}
_text = new char [strlen(text) + 1];
if (_text) {
strcpy(_text, text);
for (uint32 i = 0; i < strlen(_text); i++) {
if (_text[i] == '|') {
_text[i] = '\n';
}
}
}
}
//////////////////////////////////////////////////////////////////////////
bool UIObject::display(int offsetX, int offsetY) {
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void UIObject::setListener(BaseScriptHolder *object, BaseScriptHolder *listenerObject, uint32 listenerParam) {
_listenerObject = object;
_listenerParamObject = listenerObject;
_listenerParamDWORD = listenerParam;
}
//////////////////////////////////////////////////////////////////////////
void UIObject::correctSize() {
Rect32 rect;
if (_width <= 0) {
if (_image) {
_image->getBoundingRect(&rect, 0, 0);
_width = rect.right - rect.left;
} else {
_width = 100;
}
}
if (_height <= 0) {
if (_image) {
_image->getBoundingRect(&rect, 0, 0);
_height = rect.bottom - rect.top;
}
}
if (_back) {
_back->correctSize(&_width, &_height);
}
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool UIObject::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// SetFont
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "SetFont") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
if (_font) {
_gameRef->_fontStorage->removeFont(_font);
}
if (val->isNULL()) {
_font = nullptr;
stack->pushBool(true);
} else {
_font = _gameRef->_fontStorage->addFont(val->getString());
stack->pushBool(_font != nullptr);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// SetImage
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "SetImage") == 0) {
stack->correctParams(1);
ScValue *val = stack->pop();
/* const char *filename = */ val->getString();
delete _image;
_image = nullptr;
if (val->isNULL()) {
stack->pushBool(true);
return STATUS_OK;
}
_image = new BaseSprite(_gameRef);
if (!_image || DID_FAIL(_image->loadFile(val->getString()))) {
delete _image;
_image = nullptr;
stack->pushBool(false);
} else {
stack->pushBool(true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetImage
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetImage") == 0) {
stack->correctParams(0);
if (!_image || !_image->getFilename()) {
stack->pushNULL();
} else {
stack->pushString(_image->getFilename());
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// GetImageObject
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "GetImageObject") == 0) {
stack->correctParams(0);
if (!_image) {
stack->pushNULL();
} else {
stack->pushNative(_image, true);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Focus
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Focus") == 0) {
stack->correctParams(0);
focus();
stack->pushNULL();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// MoveAfter / MoveBefore
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MoveAfter") == 0 || strcmp(name, "MoveBefore") == 0) {
stack->correctParams(1);
if (_parent && _parent->_type == UI_WINDOW) {
UIWindow *win = (UIWindow *)_parent;
uint32 i;
bool found = false;
ScValue *val = stack->pop();
// find directly
if (val->isNative()) {
UIObject *widget = (UIObject *)val->getNative();
for (i = 0; i < win->_widgets.size(); i++) {
if (win->_widgets[i] == widget) {
found = true;
break;
}
}
}
// find by name
else {
const char *findName = val->getString();
for (i = 0; i < win->_widgets.size(); i++) {
if (scumm_stricmp(win->_widgets[i]->getName(), findName) == 0) {
found = true;
break;
}
}
}
if (found) {
bool done = false;
for (uint32 j = 0; j < win->_widgets.size(); j++) {
if (win->_widgets[j] == this) {
if (strcmp(name, "MoveAfter") == 0) {
i++;
}
if (j >= i) {
j++;
}
win->_widgets.insert_at(i, this);
win->_widgets.remove_at(j);
done = true;
stack->pushBool(true);
break;
}
}
if (!done) {
stack->pushBool(false);
}
} else {
stack->pushBool(false);
}
} else {
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// MoveToBottom
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MoveToBottom") == 0) {
stack->correctParams(0);
if (_parent && _parent->_type == UI_WINDOW) {
UIWindow *win = (UIWindow *)_parent;
for (uint32 i = 0; i < win->_widgets.size(); i++) {
if (win->_widgets[i] == this) {
win->_widgets.remove_at(i);
win->_widgets.insert_at(0, this);
break;
}
}
stack->pushBool(true);
} else {
stack->pushBool(false);
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// MoveToTop
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "MoveToTop") == 0) {
stack->correctParams(0);
if (_parent && _parent->_type == UI_WINDOW) {
UIWindow *win = (UIWindow *)_parent;
for (uint32 i = 0; i < win->_widgets.size(); i++) {
if (win->_widgets[i] == this) {
win->_widgets.remove_at(i);
win->_widgets.add(this);
break;
}
}
stack->pushBool(true);
} else {
stack->pushBool(false);
}
return STATUS_OK;
} else {
return BaseObject::scCallMethod(script, stack, thisStack, name);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *UIObject::scGetProperty(const Common::String &name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (name == "Type") {
_scValue->setString("ui_object");
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
else if (name == "Name") {
_scValue->setString(getName());
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Parent (RO)
//////////////////////////////////////////////////////////////////////////
else if (name == "Parent") {
_scValue->setNative(_parent, true);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// ParentNotify
//////////////////////////////////////////////////////////////////////////
else if (name == "ParentNotify") {
_scValue->setBool(_parentNotify);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Width
//////////////////////////////////////////////////////////////////////////
else if (name == "Width") {
_scValue->setInt(_width);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Height
//////////////////////////////////////////////////////////////////////////
else if (name == "Height") {
_scValue->setInt(_height);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Visible
//////////////////////////////////////////////////////////////////////////
else if (name == "Visible") {
_scValue->setBool(_visible);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Disabled
//////////////////////////////////////////////////////////////////////////
else if (name == "Disabled") {
_scValue->setBool(_disable);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// Text
//////////////////////////////////////////////////////////////////////////
else if (name == "Text") {
_scValue->setString(_text);
return _scValue;
}
//////////////////////////////////////////////////////////////////////////
// NextSibling (RO) / PrevSibling (RO)
//////////////////////////////////////////////////////////////////////////
else if (name == "NextSibling" || name == "PrevSibling") {
_scValue->setNULL();
if (_parent && _parent->_type == UI_WINDOW) {
UIWindow *win = (UIWindow *)_parent;
for (uint32 i = 0; i < win->_widgets.size(); i++) {
if (win->_widgets[i] == this) {
if (name == "NextSibling") {
if (i < win->_widgets.size() - 1) {
_scValue->setNative(win->_widgets[i + 1], true);
}
} else {
if (i > 0) {
_scValue->setNative(win->_widgets[i - 1], true);
}
}
break;
}
}
}
return _scValue;
} else {
return BaseObject::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool UIObject::scSetProperty(const char *name, ScValue *value) {
//////////////////////////////////////////////////////////////////////////
// Name
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Name") == 0) {
setName(value->getString());
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// ParentNotify
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "ParentNotify") == 0) {
_parentNotify = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Width
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Width") == 0) {
_width = value->getInt();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Height
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Height") == 0) {
_height = value->getInt();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Visible
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Visible") == 0) {
_visible = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Disabled
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Disabled") == 0) {
_disable = value->getBool();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
// Text
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "Text") == 0) {
setText(value->getString());
return STATUS_OK;
} else {
return BaseObject::scSetProperty(name, value);
}
}
//////////////////////////////////////////////////////////////////////////
const char *UIObject::scToString() {
return "[ui_object]";
}
//////////////////////////////////////////////////////////////////////////
bool UIObject::isFocused() {
if (!_gameRef->_focusedWindow) {
return false;
}
if (_gameRef->_focusedWindow == this) {
return true;
}
UIObject *obj = _gameRef->_focusedWindow;
while (obj) {
if (obj == this) {
return true;
} else {
obj = obj->_focusedWidget;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool UIObject::handleMouse(TMouseEvent event, TMouseButton button) {
// handle focus change
if (event == MOUSE_CLICK && button == MOUSE_BUTTON_LEFT) {
focus();
}
return BaseObject::handleMouse(event, button);
}
//////////////////////////////////////////////////////////////////////////
bool UIObject::focus() {
UIObject *obj = this;
bool disabled = false;
while (obj) {
if (obj->_disable && obj->_type == UI_WINDOW) {
disabled = true;
break;
}
obj = obj->_parent;
}
if (!disabled) {
obj = this;
while (obj) {
if (obj->_parent) {
if (!obj->_disable && obj->_canFocus) {
obj->_parent->_focusedWidget = obj;
}
} else {
if (obj->_type == UI_WINDOW) {
_gameRef->focusWindow((UIWindow *)obj);
}
}
obj = obj->_parent;
}
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool UIObject::getTotalOffset(int *offsetX, int *offsetY) {
int offX = 0, offY = 0;
UIObject *obj = _parent;
while (obj) {
offX += obj->_posX;
offY += obj->_posY;
obj = obj->_parent;
}
if (offsetX) {
*offsetX = offX;
}
if (offsetY) {
*offsetY = offY;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool UIObject::persist(BasePersistenceManager *persistMgr) {
BaseObject::persist(persistMgr);
persistMgr->transferPtr(TMEMBER_PTR(_back));
persistMgr->transferBool(TMEMBER(_canFocus));
persistMgr->transferBool(TMEMBER(_disable));
persistMgr->transferPtr(TMEMBER_PTR(_focusedWidget));
persistMgr->transferPtr(TMEMBER_PTR(_font));
persistMgr->transferSint32(TMEMBER(_height));
persistMgr->transferPtr(TMEMBER_PTR(_image));
persistMgr->transferPtr(TMEMBER_PTR(_listenerObject));
persistMgr->transferPtr(TMEMBER_PTR(_listenerParamObject));
persistMgr->transferUint32(TMEMBER(_listenerParamDWORD));
persistMgr->transferPtr(TMEMBER_PTR(_parent));
persistMgr->transferBool(TMEMBER(_parentNotify));
persistMgr->transferBool(TMEMBER(_sharedFonts));
persistMgr->transferBool(TMEMBER(_sharedImages));
persistMgr->transferCharPtr(TMEMBER(_text));
persistMgr->transferSint32(TMEMBER_INT(_type));
persistMgr->transferBool(TMEMBER(_visible));
persistMgr->transferSint32(TMEMBER(_width));
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool UIObject::saveAsText(BaseDynamicBuffer *buffer, int indent) {
return STATUS_FAILED;
}
int32 UIObject::getWidth() const {
return _width;
}
// Has to be non-const to allow the virtual override to work,
// as other getHeight()-functions currently have the potential
// of having side-effects.
int32 UIObject::getHeight() {
return _height;
}
void UIObject::setWidth(int32 width) {
assert(width >= 0);
_width = width;
}
void UIObject::setHeight(int32 height) {
assert(height >= 0);
_height = height;
}
bool UIObject::isDisabled() const {
return _disable;
}
bool UIObject::isVisible() const {
return _visible;
}
void UIObject::setVisible(bool visible) {
_visible = visible;
}
void UIObject::setDisabled(bool disable) {
_disable = disable;
}
bool UIObject::hasSharedFonts() const {
return _sharedFonts;
}
void UIObject::setSharedFonts(bool shared) {
_sharedFonts = shared;
}
bool UIObject::hasSharedImages() const {
return _sharedImages;
}
void UIObject::setSharedImages(bool shared) {
_sharedImages = shared;
}
BaseSprite *UIObject::getImage() const {
return _image;
}
void UIObject::setImage(BaseSprite *image) {
_image = image;
}
bool UIObject::canFocus() const {
return _canFocus;
}
void UIObject::setFont(BaseFont *font) {
_font = font;
}
BaseFont *UIObject::getFont() {
return _font;
}
BaseScriptHolder *UIObject::getListener() const {
return _listenerObject;
}
} // End of namespace Wintermute