aboutsummaryrefslogtreecommitdiff
path: root/engines/wintermute/ui
diff options
context:
space:
mode:
Diffstat (limited to 'engines/wintermute/ui')
-rw-r--r--engines/wintermute/ui/UIButton.cpp1046
-rw-r--r--engines/wintermute/ui/UIButton.h79
-rw-r--r--engines/wintermute/ui/UIEdit.cpp857
-rw-r--r--engines/wintermute/ui/UIEdit.h72
-rw-r--r--engines/wintermute/ui/UIEntity.cpp339
-rw-r--r--engines/wintermute/ui/UIEntity.h58
-rw-r--r--engines/wintermute/ui/UIObject.cpp589
-rw-r--r--engines/wintermute/ui/UIObject.h83
-rw-r--r--engines/wintermute/ui/UIText.cpp489
-rw-r--r--engines/wintermute/ui/UIText.h60
-rw-r--r--engines/wintermute/ui/UITiledImage.cpp370
-rw-r--r--engines/wintermute/ui/UITiledImage.h63
-rw-r--r--engines/wintermute/ui/UIWindow.cpp1327
-rw-r--r--engines/wintermute/ui/UIWindow.h93
14 files changed, 5525 insertions, 0 deletions
diff --git a/engines/wintermute/ui/UIButton.cpp b/engines/wintermute/ui/UIButton.cpp
new file mode 100644
index 0000000000..f6c50597bd
--- /dev/null
+++ b/engines/wintermute/ui/UIButton.cpp
@@ -0,0 +1,1046 @@
+/* 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/dcgf.h"
+#include "engines/wintermute/base/BDynBuffer.h"
+#include "engines/wintermute/base/BGame.h"
+#include "engines/wintermute/ui/UIButton.h"
+#include "engines/wintermute/ui/UITiledImage.h"
+#include "engines/wintermute/base/BParser.h"
+#include "engines/wintermute/base/BActiveRect.h"
+#include "engines/wintermute/base/font/BFontStorage.h"
+#include "engines/wintermute/base/font/BFont.h"
+#include "engines/wintermute/base/BStringTable.h"
+#include "engines/wintermute/base/BSprite.h"
+#include "engines/wintermute/base/BFileManager.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "engines/wintermute/base/scriptables/ScValue.h"
+#include "engines/wintermute/base/scriptables/ScScript.h"
+#include "engines/wintermute/base/scriptables/ScStack.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CUIButton, false)
+
+//////////////////////////////////////////////////////////////////////////
+CUIButton::CUIButton(CBGame *inGame): CUIObject(inGame) {
+ _backPress = _backHover = _backDisable = _backFocus = NULL;
+
+ _fontHover = _fontPress = _fontDisable = _fontFocus = NULL;
+
+ _imageDisable = _imagePress = _imageHover = _imageFocus = NULL;
+
+ _align = TAL_CENTER;
+
+ _hover = _press = false;
+
+ _type = UI_BUTTON;
+
+ _canFocus = false;
+ _stayPressed = false;
+
+ _oneTimePress = false;
+ _centerImage = false;
+
+ _pixelPerfect = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CUIButton::~CUIButton() {
+ delete _backPress;
+ delete _backHover;
+ delete _backDisable;
+ delete _backFocus;
+
+ if (!_sharedFonts) {
+ if (_fontHover) _gameRef->_fontStorage->removeFont(_fontHover);
+ if (_fontPress) _gameRef->_fontStorage->removeFont(_fontPress);
+ if (_fontDisable) _gameRef->_fontStorage->removeFont(_fontDisable);
+ if (_fontFocus) _gameRef->_fontStorage->removeFont(_fontFocus);
+ }
+
+ if (!_sharedImages) {
+ delete _imageHover;
+ delete _imagePress;
+ delete _imageDisable;
+ delete _imageFocus;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIButton::loadFile(const char *filename) {
+ byte *buffer = _gameRef->_fileManager->readWholeFile(filename);
+ if (buffer == NULL) {
+ _gameRef->LOG(0, "CUIButton::LoadFile failed for file '%s'", filename);
+ return STATUS_FAILED;
+ }
+
+ bool ret;
+
+ _filename = new char [strlen(filename) + 1];
+ strcpy(_filename, filename);
+
+ if (DID_FAIL(ret = loadBuffer(buffer, true))) _gameRef->LOG(0, "Error parsing BUTTON file '%s'", filename);
+
+ delete [] buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(BUTTON)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(DISABLED)
+TOKEN_DEF(VISIBLE)
+TOKEN_DEF(FOCUSABLE)
+TOKEN_DEF(BACK_HOVER)
+TOKEN_DEF(BACK_PRESS)
+TOKEN_DEF(BACK_DISABLE)
+TOKEN_DEF(BACK_FOCUS)
+TOKEN_DEF(BACK)
+TOKEN_DEF(CENTER_IMAGE)
+TOKEN_DEF(IMAGE_HOVER)
+TOKEN_DEF(IMAGE_PRESS)
+TOKEN_DEF(IMAGE_DISABLE)
+TOKEN_DEF(IMAGE_FOCUS)
+TOKEN_DEF(IMAGE)
+TOKEN_DEF(FONT_HOVER)
+TOKEN_DEF(FONT_PRESS)
+TOKEN_DEF(FONT_DISABLE)
+TOKEN_DEF(FONT_FOCUS)
+TOKEN_DEF(FONT)
+TOKEN_DEF(TEXT_ALIGN)
+TOKEN_DEF(TEXT)
+TOKEN_DEF(X)
+TOKEN_DEF(Y)
+TOKEN_DEF(WIDTH)
+TOKEN_DEF(HEIGHT)
+TOKEN_DEF(CURSOR)
+TOKEN_DEF(NAME)
+TOKEN_DEF(EVENTS)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(PARENT_NOTIFY)
+TOKEN_DEF(PRESSED)
+TOKEN_DEF(PIXEL_PERFECT)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+bool CUIButton::loadBuffer(byte *buffer, bool complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(BUTTON)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(DISABLED)
+ TOKEN_TABLE(VISIBLE)
+ TOKEN_TABLE(FOCUSABLE)
+ TOKEN_TABLE(BACK_HOVER)
+ TOKEN_TABLE(BACK_PRESS)
+ TOKEN_TABLE(BACK_DISABLE)
+ TOKEN_TABLE(BACK_FOCUS)
+ TOKEN_TABLE(BACK)
+ TOKEN_TABLE(CENTER_IMAGE)
+ TOKEN_TABLE(IMAGE_HOVER)
+ TOKEN_TABLE(IMAGE_PRESS)
+ TOKEN_TABLE(IMAGE_DISABLE)
+ TOKEN_TABLE(IMAGE_FOCUS)
+ TOKEN_TABLE(IMAGE)
+ TOKEN_TABLE(FONT_HOVER)
+ TOKEN_TABLE(FONT_PRESS)
+ TOKEN_TABLE(FONT_DISABLE)
+ TOKEN_TABLE(FONT_FOCUS)
+ TOKEN_TABLE(FONT)
+ TOKEN_TABLE(TEXT_ALIGN)
+ TOKEN_TABLE(TEXT)
+ TOKEN_TABLE(X)
+ TOKEN_TABLE(Y)
+ TOKEN_TABLE(WIDTH)
+ TOKEN_TABLE(HEIGHT)
+ TOKEN_TABLE(CURSOR)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(EVENTS)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(PARENT_NOTIFY)
+ TOKEN_TABLE(PRESSED)
+ TOKEN_TABLE(PIXEL_PERFECT)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd = 2;
+ CBParser parser(_gameRef);
+
+ if (complete) {
+ if (parser.getCommand((char **)&buffer, commands, (char **)&params) != TOKEN_BUTTON) {
+ _gameRef->LOG(0, "'BUTTON' keyword expected.");
+ return STATUS_FAILED;
+ }
+ buffer = params;
+ }
+
+ while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (DID_FAIL(loadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ setName((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ setCaption((char *)params);
+ break;
+
+ case TOKEN_BACK:
+ delete _back;
+ _back = new CUITiledImage(_gameRef);
+ if (!_back || DID_FAIL(_back->loadFile((char *)params))) {
+ delete _back;
+ _back = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_BACK_HOVER:
+ delete _backHover;
+ _backHover = new CUITiledImage(_gameRef);
+ if (!_backHover || DID_FAIL(_backHover->loadFile((char *)params))) {
+ delete _backHover;
+ _backHover = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_BACK_PRESS:
+ delete _backPress;
+ _backPress = new CUITiledImage(_gameRef);
+ if (!_backPress || DID_FAIL(_backPress->loadFile((char *)params))) {
+ delete _backPress;
+ _backPress = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_BACK_DISABLE:
+ delete _backDisable;
+ _backDisable = new CUITiledImage(_gameRef);
+ if (!_backDisable || DID_FAIL(_backDisable->loadFile((char *)params))) {
+ delete _backDisable;
+ _backDisable = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_BACK_FOCUS:
+ delete _backFocus;
+ _backFocus = new CUITiledImage(_gameRef);
+ if (!_backFocus || DID_FAIL(_backFocus->loadFile((char *)params))) {
+ delete _backFocus;
+ _backFocus = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE:
+ delete _image;
+ _image = new CBSprite(_gameRef);
+ if (!_image || DID_FAIL(_image->loadFile((char *)params))) {
+ delete _image;
+ _image = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE_HOVER:
+ delete _imageHover;
+ _imageHover = new CBSprite(_gameRef);
+ if (!_imageHover || DID_FAIL(_imageHover->loadFile((char *)params))) {
+ delete _imageHover;
+ _imageHover = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE_PRESS:
+ delete _imagePress;
+ _imagePress = new CBSprite(_gameRef);
+ if (!_imagePress || DID_FAIL(_imagePress->loadFile((char *)params))) {
+ delete _imagePress;
+ _imagePress = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE_DISABLE:
+ delete _imageDisable;
+ _imageDisable = new CBSprite(_gameRef);
+ if (!_imageDisable || DID_FAIL(_imageDisable->loadFile((char *)params))) {
+ delete _imageDisable;
+ _imageDisable = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE_FOCUS:
+ delete _imageFocus;
+ _imageFocus = new CBSprite(_gameRef);
+ if (!_imageFocus || DID_FAIL(_imageFocus->loadFile((char *)params))) {
+ delete _imageFocus;
+ _imageFocus = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_FONT:
+ if (_font) _gameRef->_fontStorage->removeFont(_font);
+ _font = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_font) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_FONT_HOVER:
+ if (_fontHover) _gameRef->_fontStorage->removeFont(_fontHover);
+ _fontHover = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_fontHover) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_FONT_PRESS:
+ if (_fontPress) _gameRef->_fontStorage->removeFont(_fontPress);
+ _fontPress = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_fontPress) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_FONT_DISABLE:
+ if (_fontDisable) _gameRef->_fontStorage->removeFont(_fontDisable);
+ _fontDisable = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_fontDisable) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_FONT_FOCUS:
+ if (_fontFocus) _gameRef->_fontStorage->removeFont(_fontFocus);
+ _fontFocus = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_fontFocus) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_TEXT:
+ setText((char *)params);
+ _gameRef->_stringTable->expand(&_text);
+ break;
+
+ case TOKEN_TEXT_ALIGN:
+ if (scumm_stricmp((char *)params, "left") == 0) _align = TAL_LEFT;
+ else if (scumm_stricmp((char *)params, "right") == 0) _align = TAL_RIGHT;
+ else _align = TAL_CENTER;
+ break;
+
+ case TOKEN_X:
+ parser.scanStr((char *)params, "%d", &_posX);
+ break;
+
+ case TOKEN_Y:
+ parser.scanStr((char *)params, "%d", &_posY);
+ break;
+
+ case TOKEN_WIDTH:
+ parser.scanStr((char *)params, "%d", &_width);
+ break;
+
+ case TOKEN_HEIGHT:
+ parser.scanStr((char *)params, "%d", &_height);
+ break;
+
+ case TOKEN_CURSOR:
+ delete _cursor;
+ _cursor = new CBSprite(_gameRef);
+ if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) {
+ delete _cursor;
+ _cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_SCRIPT:
+ addScript((char *)params);
+ break;
+
+ case TOKEN_PARENT_NOTIFY:
+ parser.scanStr((char *)params, "%b", &_parentNotify);
+ break;
+
+ case TOKEN_DISABLED:
+ parser.scanStr((char *)params, "%b", &_disable);
+ break;
+
+ case TOKEN_VISIBLE:
+ parser.scanStr((char *)params, "%b", &_visible);
+ break;
+
+ case TOKEN_FOCUSABLE:
+ parser.scanStr((char *)params, "%b", &_canFocus);
+ break;
+
+ case TOKEN_CENTER_IMAGE:
+ parser.scanStr((char *)params, "%b", &_centerImage);
+ break;
+
+ case TOKEN_PRESSED:
+ parser.scanStr((char *)params, "%b", &_stayPressed);
+ break;
+
+ case TOKEN_PIXEL_PERFECT:
+ parser.scanStr((char *)params, "%b", &_pixelPerfect);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ parseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ _gameRef->LOG(0, "Syntax error in BUTTON definition");
+ return STATUS_FAILED;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ _gameRef->LOG(0, "Error loading BUTTON definition");
+ return STATUS_FAILED;
+ }
+
+ correctSize();
+
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIButton::saveAsText(CBDynBuffer *buffer, int indent) {
+ buffer->putTextIndent(indent, "BUTTON\n");
+ buffer->putTextIndent(indent, "{\n");
+
+ buffer->putTextIndent(indent + 2, "NAME=\"%s\"\n", _name);
+ buffer->putTextIndent(indent + 2, "CAPTION=\"%s\"\n", getCaption());
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ if (_back && _back->_filename)
+ buffer->putTextIndent(indent + 2, "BACK=\"%s\"\n", _back->_filename);
+ if (_backHover && _backHover->_filename)
+ buffer->putTextIndent(indent + 2, "BACK_HOVER=\"%s\"\n", _backHover->_filename);
+ if (_backPress && _backPress->_filename)
+ buffer->putTextIndent(indent + 2, "BACK_PRESS=\"%s\"\n", _backPress->_filename);
+ if (_backDisable && _backDisable->_filename)
+ buffer->putTextIndent(indent + 2, "BACK_DISABLE=\"%s\"\n", _backDisable->_filename);
+ if (_backFocus && _backFocus->_filename)
+ buffer->putTextIndent(indent + 2, "BACK_FOCUS=\"%s\"\n", _backFocus->_filename);
+
+ if (_image && _image->_filename)
+ buffer->putTextIndent(indent + 2, "IMAGE=\"%s\"\n", _image->_filename);
+ if (_imageHover && _imageHover->_filename)
+ buffer->putTextIndent(indent + 2, "IMAGE_HOVER=\"%s\"\n", _imageHover->_filename);
+ if (_imagePress && _imagePress->_filename)
+ buffer->putTextIndent(indent + 2, "IMAGE_PRESS=\"%s\"\n", _imagePress->_filename);
+ if (_imageDisable && _imageDisable->_filename)
+ buffer->putTextIndent(indent + 2, "IMAGE_DISABLE=\"%s\"\n", _imageDisable->_filename);
+ if (_imageFocus && _imageFocus->_filename)
+ buffer->putTextIndent(indent + 2, "IMAGE_FOCUS=\"%s\"\n", _imageFocus->_filename);
+
+ if (_font && _font->_filename)
+ buffer->putTextIndent(indent + 2, "FONT=\"%s\"\n", _font->_filename);
+ if (_fontHover && _fontHover->_filename)
+ buffer->putTextIndent(indent + 2, "FONT_HOVER=\"%s\"\n", _fontHover->_filename);
+ if (_fontPress && _fontPress->_filename)
+ buffer->putTextIndent(indent + 2, "FONT_PRESS=\"%s\"\n", _fontPress->_filename);
+ if (_fontDisable && _fontDisable->_filename)
+ buffer->putTextIndent(indent + 2, "FONT_DISABLE=\"%s\"\n", _fontDisable->_filename);
+ if (_fontFocus && _fontFocus->_filename)
+ buffer->putTextIndent(indent + 2, "FONT_FOCUS=\"%s\"\n", _fontFocus->_filename);
+
+ if (_cursor && _cursor->_filename)
+ buffer->putTextIndent(indent + 2, "CURSOR=\"%s\"\n", _cursor->_filename);
+
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ if (_text)
+ buffer->putTextIndent(indent + 2, "TEXT=\"%s\"\n", _text);
+
+ switch (_align) {
+ case TAL_LEFT:
+ buffer->putTextIndent(indent + 2, "TEXT_ALIGN=\"%s\"\n", "left");
+ break;
+ case TAL_RIGHT:
+ buffer->putTextIndent(indent + 2, "TEXT_ALIGN=\"%s\"\n", "right");
+ break;
+ case TAL_CENTER:
+ buffer->putTextIndent(indent + 2, "TEXT_ALIGN=\"%s\"\n", "center");
+ break;
+ default:
+ warning("CUIButton::SaveAsText - unhandled enum");
+ break;
+ }
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ buffer->putTextIndent(indent + 2, "X=%d\n", _posX);
+ buffer->putTextIndent(indent + 2, "Y=%d\n", _posY);
+ buffer->putTextIndent(indent + 2, "WIDTH=%d\n", _width);
+ buffer->putTextIndent(indent + 2, "HEIGHT=%d\n", _height);
+
+
+ buffer->putTextIndent(indent + 2, "DISABLED=%s\n", _disable ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "VISIBLE=%s\n", _visible ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "PARENT_NOTIFY=%s\n", _parentNotify ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "FOCUSABLE=%s\n", _canFocus ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "CENTER_IMAGE=%s\n", _centerImage ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "PRESSED=%s\n", _stayPressed ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "PIXEL_PERFECT=%s\n", _pixelPerfect ? "TRUE" : "FALSE");
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ // scripts
+ for (int i = 0; i < _scripts.getSize(); i++) {
+ buffer->putTextIndent(indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
+ }
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ // editor properties
+ CBBase::saveAsText(buffer, indent + 2);
+
+ buffer->putTextIndent(indent, "}\n");
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+void CUIButton::correctSize() {
+ Rect32 rect;
+
+ CBSprite *img = NULL;
+ if (_image) img = _image;
+ else if (_imageDisable) img = _imageDisable;
+ else if (_imageHover) img = _imageHover;
+ else if (_imagePress) img = _imagePress;
+ else if (_imageFocus) img = _imageFocus;
+
+ if (_width <= 0) {
+ if (img) {
+ img->getBoundingRect(&rect, 0, 0);
+ _width = rect.right - rect.left;
+ } else _width = 100;
+ }
+
+ if (_height <= 0) {
+ if (img) {
+ img->getBoundingRect(&rect, 0, 0);
+ _height = rect.bottom - rect.top;
+ }
+ }
+
+ if (_text) {
+ int text_height;
+ if (_font) text_height = _font->getTextHeight((byte *)_text, _width);
+ else text_height = _gameRef->_systemFont->getTextHeight((byte *)_text, _width);
+
+ if (text_height > _height) _height = text_height;
+ }
+
+ if (_height <= 0) _height = 100;
+
+ if (_back) _back->correctSize(&_width, &_height);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIButton::display(int offsetX, int offsetY) {
+ if (!_visible)
+ return STATUS_OK;
+
+ CUITiledImage *back = NULL;
+ CBSprite *image = NULL;
+ CBFont *font = 0;
+
+ //RECT rect;
+ //CBPlatform::setRect(&rect, OffsetX + _posX, OffsetY + _posY, OffsetX+_posX+_width, OffsetY+_posY+_height);
+ //_hover = (!_disable && CBPlatform::ptInRect(&rect, _gameRef->_mousePos)!=FALSE);
+ _hover = (!_disable && _gameRef->_activeObject == this && (_gameRef->_interactive || _gameRef->_state == GAME_SEMI_FROZEN));
+
+ if ((_press && _hover && !_gameRef->_mouseLeftDown) ||
+ (_oneTimePress && CBPlatform::getTime() - _oneTimePressTime >= 100)) press();
+
+
+ if (_disable) {
+ if (_backDisable) back = _backDisable;
+ if (_imageDisable) image = _imageDisable;
+ if (_text && _fontDisable) font = _fontDisable;
+ } else if (_press || _oneTimePress || _stayPressed) {
+ if (_backPress) back = _backPress;
+ if (_imagePress) image = _imagePress;
+ if (_text && _fontPress) font = _fontPress;
+ } else if (_hover) {
+ if (_backHover) back = _backHover;
+ if (_imageHover) image = _imageHover;
+ if (_text && _fontHover) font = _fontHover;
+ } else if (_canFocus && isFocused()) {
+ if (_backFocus) back = _backFocus;
+ if (_imageFocus) image = _imageFocus;
+ if (_text && _fontFocus) font = _fontFocus;
+ }
+
+ if (!back && _back) back = _back;
+ if (!image && _image) image = _image;
+ if (_text && !font) {
+ if (_font) font = _font;
+ else font = _gameRef->_systemFont;
+ }
+
+ int imageX = offsetX + _posX;
+ int imageY = offsetY + _posY;
+
+ if (image && _centerImage) {
+ Rect32 rc;
+ image->getBoundingRect(&rc, 0, 0);
+ imageX += (_width - (rc.right - rc.left)) / 2;
+ imageY += (_height - (rc.bottom - rc.top)) / 2;
+ }
+
+ if (back) back->display(offsetX + _posX, offsetY + _posY, _width, _height);
+ //if(image) image->Draw(ImageX +((_press||_oneTimePress)&&back?1:0), ImageY +((_press||_oneTimePress)&&back?1:0), NULL);
+ if (image) image->draw(imageX + ((_press || _oneTimePress) && back ? 1 : 0), imageY + ((_press || _oneTimePress) && back ? 1 : 0), _pixelPerfect ? this : NULL);
+
+ if (font && _text) {
+ int text_offset = (_height - font->getTextHeight((byte *)_text, _width)) / 2;
+ font->drawText((byte *)_text, offsetX + _posX + ((_press || _oneTimePress) ? 1 : 0), offsetY + _posY + text_offset + ((_press || _oneTimePress) ? 1 : 0), _width, _align);
+ }
+
+ if (!_pixelPerfect || !_image) _gameRef->_renderer->_rectList.add(new CBActiveRect(_gameRef, this, NULL, offsetX + _posX, offsetY + _posY, _width, _height, 100, 100, false));
+
+ // reset unused sprites
+ if (_image && _image != image) _image->reset();
+ if (_imageDisable && _imageDisable != image) _imageDisable->reset();
+ if (_imageFocus && _imageFocus != image) _imageFocus->reset();
+ if (_imagePress && _imagePress != image) _imagePress->reset();
+ if (_imageHover && _imageHover != image) _imageHover->reset();
+
+ _press = _hover && _gameRef->_mouseLeftDown && _gameRef->_capturedObject == this;
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CUIButton::press() {
+ applyEvent("Press");
+ if (_listenerObject) _listenerObject->listen(_listenerParamObject, _listenerParamDWORD);
+ if (_parentNotify && _parent) _parent->applyEvent(_name);
+
+ _oneTimePress = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+bool CUIButton::scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name) {
+ //////////////////////////////////////////////////////////////////////////
+ // SetDisabledFont
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "SetDisabledFont") == 0) {
+ stack->correctParams(1);
+ CScValue *Val = stack->pop();
+
+ if (_fontDisable) _gameRef->_fontStorage->removeFont(_fontDisable);
+ if (Val->isNULL()) {
+ _fontDisable = NULL;
+ stack->pushBool(true);
+ } else {
+ _fontDisable = _gameRef->_fontStorage->addFont(Val->getString());
+ stack->pushBool(_fontDisable != NULL);
+ }
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetHoverFont
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetHoverFont") == 0) {
+ stack->correctParams(1);
+ CScValue *val = stack->pop();
+
+ if (_fontHover) _gameRef->_fontStorage->removeFont(_fontHover);
+ if (val->isNULL()) {
+ _fontHover = NULL;
+ stack->pushBool(true);
+ } else {
+ _fontHover = _gameRef->_fontStorage->addFont(val->getString());
+ stack->pushBool(_fontHover != NULL);
+ }
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetPressedFont
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetPressedFont") == 0) {
+ stack->correctParams(1);
+ CScValue *Val = stack->pop();
+
+ if (_fontPress) _gameRef->_fontStorage->removeFont(_fontPress);
+ if (Val->isNULL()) {
+ _fontPress = NULL;
+ stack->pushBool(true);
+ } else {
+ _fontPress = _gameRef->_fontStorage->addFont(Val->getString());
+ stack->pushBool(_fontPress != NULL);
+ }
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetFocusedFont
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetFocusedFont") == 0) {
+ stack->correctParams(1);
+ CScValue *val = stack->pop();
+
+ if (_fontFocus) _gameRef->_fontStorage->removeFont(_fontFocus);
+ if (val->isNULL()) {
+ _fontFocus = NULL;
+ stack->pushBool(true);
+ } else {
+ _fontFocus = _gameRef->_fontStorage->addFont(val->getString());
+ stack->pushBool(_fontFocus != NULL);
+ }
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetDisabledImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetDisabledImage") == 0) {
+ stack->correctParams(1);
+
+ delete _imageDisable;
+ _imageDisable = new CBSprite(_gameRef);
+ const char *filename = stack->pop()->getString();
+ if (!_imageDisable || DID_FAIL(_imageDisable->loadFile(filename))) {
+ delete _imageDisable;
+ _imageDisable = NULL;
+ stack->pushBool(false);
+ } else stack->pushBool(true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetDisabledImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetDisabledImage") == 0) {
+ stack->correctParams(0);
+ if (!_imageDisable || !_imageDisable->_filename) stack->pushNULL();
+ else stack->pushString(_imageDisable->_filename);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetDisabledImageObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetDisabledImageObject") == 0) {
+ stack->correctParams(0);
+ if (!_imageDisable) stack->pushNULL();
+ else stack->pushNative(_imageDisable, true);
+
+ return STATUS_OK;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetHoverImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetHoverImage") == 0) {
+ stack->correctParams(1);
+
+ delete _imageHover;
+ _imageHover = new CBSprite(_gameRef);
+ const char *filename = stack->pop()->getString();
+ if (!_imageHover || DID_FAIL(_imageHover->loadFile(filename))) {
+ delete _imageHover;
+ _imageHover = NULL;
+ stack->pushBool(false);
+ } else stack->pushBool(true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetHoverImage") == 0) {
+ stack->correctParams(0);
+ if (!_imageHover || !_imageHover->_filename) stack->pushNULL();
+ else stack->pushString(_imageHover->_filename);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetHoverImageObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetHoverImageObject") == 0) {
+ stack->correctParams(0);
+ if (!_imageHover) stack->pushNULL();
+ else stack->pushNative(_imageHover, true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetPressedImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetPressedImage") == 0) {
+ stack->correctParams(1);
+
+ delete _imagePress;
+ _imagePress = new CBSprite(_gameRef);
+ const char *filename = stack->pop()->getString();
+ if (!_imagePress || DID_FAIL(_imagePress->loadFile(filename))) {
+ delete _imagePress;
+ _imagePress = NULL;
+ stack->pushBool(false);
+ } else stack->pushBool(true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetPressedImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetPressedImage") == 0) {
+ stack->correctParams(0);
+ if (!_imagePress || !_imagePress->_filename) stack->pushNULL();
+ else stack->pushString(_imagePress->_filename);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetPressedImageObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetPressedImageObject") == 0) {
+ stack->correctParams(0);
+ if (!_imagePress) stack->pushNULL();
+ else stack->pushNative(_imagePress, true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetFocusedImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetFocusedImage") == 0) {
+ stack->correctParams(1);
+
+ delete _imageFocus;
+ _imageFocus = new CBSprite(_gameRef);
+ const char *filename = stack->pop()->getString();
+ if (!_imageFocus || DID_FAIL(_imageFocus->loadFile(filename))) {
+ delete _imageFocus;
+ _imageFocus = NULL;
+ stack->pushBool(false);
+ } else stack->pushBool(true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetFocusedImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetFocusedImage") == 0) {
+ stack->correctParams(0);
+ if (!_imageFocus || !_imageFocus->_filename) stack->pushNULL();
+ else stack->pushString(_imageFocus->_filename);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetFocusedImageObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetFocusedImageObject") == 0) {
+ stack->correctParams(0);
+ if (!_imageFocus) stack->pushNULL();
+ else stack->pushNative(_imageFocus, true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Press
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Press") == 0) {
+ stack->correctParams(0);
+
+ if (_visible && !_disable) {
+ _oneTimePress = true;
+ _oneTimePressTime = CBPlatform::getTime();
+ }
+ stack->pushNULL();
+
+ return STATUS_OK;
+ }
+
+
+ else return CUIObject::scCallMethod(script, stack, thisStack, name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CUIButton::scGetProperty(const char *name) {
+ _scValue->setNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "Type") == 0) {
+ _scValue->setString("button");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TextAlign
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "TextAlign") == 0) {
+ _scValue->setInt(_align);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Focusable
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Focusable") == 0) {
+ _scValue->setBool(_canFocus);
+ return _scValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Pressed
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Pressed") == 0) {
+ _scValue->setBool(_stayPressed);
+ return _scValue;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // PixelPerfect
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "PixelPerfect") == 0) {
+ _scValue->setBool(_pixelPerfect);
+ return _scValue;
+ }
+
+ else return CUIObject::scGetProperty(name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIButton::scSetProperty(const char *name, CScValue *value) {
+ //////////////////////////////////////////////////////////////////////////
+ // TextAlign
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "TextAlign") == 0) {
+ int i = value->getInt();
+ if (i < 0 || i >= NUM_TEXT_ALIGN) i = 0;
+ _align = (TTextAlign)i;
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Focusable
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Focusable") == 0) {
+ _canFocus = value->getBool();
+ return STATUS_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // Pressed
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Pressed") == 0) {
+ _stayPressed = value->getBool();
+ return STATUS_OK;
+ }
+ //////////////////////////////////////////////////////////////////////////
+ // PixelPerfect
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "PixelPerfect") == 0) {
+ _pixelPerfect = value->getBool();
+ return STATUS_OK;
+ }
+
+ else return CUIObject::scSetProperty(name, value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CUIButton::scToString() {
+ return "[button]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIButton::persist(CBPersistMgr *persistMgr) {
+
+ CUIObject::persist(persistMgr);
+
+ persistMgr->transfer(TMEMBER_INT(_align));
+ persistMgr->transfer(TMEMBER(_backDisable));
+ persistMgr->transfer(TMEMBER(_backFocus));
+ persistMgr->transfer(TMEMBER(_backHover));
+ persistMgr->transfer(TMEMBER(_backPress));
+ persistMgr->transfer(TMEMBER(_centerImage));
+ persistMgr->transfer(TMEMBER(_fontDisable));
+ persistMgr->transfer(TMEMBER(_fontFocus));
+ persistMgr->transfer(TMEMBER(_fontHover));
+ persistMgr->transfer(TMEMBER(_fontPress));
+ persistMgr->transfer(TMEMBER(_hover));
+ persistMgr->transfer(TMEMBER(_image));
+ persistMgr->transfer(TMEMBER(_imageDisable));
+ persistMgr->transfer(TMEMBER(_imageFocus));
+ persistMgr->transfer(TMEMBER(_imageHover));
+ persistMgr->transfer(TMEMBER(_imagePress));
+ persistMgr->transfer(TMEMBER(_pixelPerfect));
+ persistMgr->transfer(TMEMBER(_press));
+ persistMgr->transfer(TMEMBER(_stayPressed));
+
+ if (!persistMgr->_saving) {
+ _oneTimePress = false;
+ _oneTimePressTime = 0;
+ }
+
+ return STATUS_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/ui/UIButton.h b/engines/wintermute/ui/UIButton.h
new file mode 100644
index 0000000000..5bdc075ebc
--- /dev/null
+++ b/engines/wintermute/ui/UIButton.h
@@ -0,0 +1,79 @@
+/* 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
+ */
+
+#ifndef WINTERMUTE_UIBUTTON_H
+#define WINTERMUTE_UIBUTTON_H
+
+
+#include "UIObject.h"
+#include "engines/wintermute/dctypes.h" // Added by ClassView
+
+namespace WinterMute {
+
+class CUIButton : public CUIObject {
+public:
+ bool _pixelPerfect;
+ bool _stayPressed;
+ bool _centerImage;
+ bool _oneTimePress;
+ uint32 _oneTimePressTime;
+ DECLARE_PERSISTENT(CUIButton, CUIObject)
+ void press();
+ virtual bool display(int offsetX = 0, int offsetY = 0);
+ bool _press;
+ bool _hover;
+ void correctSize();
+ TTextAlign _align;
+ CBSprite *_imageHover;
+ CBSprite *_imagePress;
+ CBSprite *_imageDisable;
+ CBSprite *_imageFocus;
+ CBFont *_fontDisable;
+ CBFont *_fontPress;
+ CBFont *_fontHover;
+ CBFont *_fontFocus;
+ CUITiledImage *_backPress;
+ CUITiledImage *_backHover;
+ CUITiledImage *_backDisable;
+ CUITiledImage *_backFocus;
+ CUIButton(CBGame *inGame = NULL);
+ virtual ~CUIButton();
+ bool loadFile(const char *filename);
+ bool loadBuffer(byte *buffer, bool complete = true);
+ virtual bool saveAsText(CBDynBuffer *buffer, int indent);
+
+ // scripting interface
+ virtual CScValue *scGetProperty(const char *name);
+ virtual bool scSetProperty(const char *name, CScValue *value);
+ virtual bool scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name);
+ virtual const char *scToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/ui/UIEdit.cpp b/engines/wintermute/ui/UIEdit.cpp
new file mode 100644
index 0000000000..4825761734
--- /dev/null
+++ b/engines/wintermute/ui/UIEdit.cpp
@@ -0,0 +1,857 @@
+/* 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/ui/UIEdit.h"
+#include "engines/wintermute/ui/UIObject.h"
+#include "engines/wintermute/ui/UITiledImage.h"
+#include "engines/wintermute/utils/StringUtil.h"
+#include "engines/wintermute/base/BActiveRect.h"
+#include "engines/wintermute/base/BFileManager.h"
+#include "engines/wintermute/base/font/BFont.h"
+#include "engines/wintermute/base/font/BFontStorage.h"
+#include "engines/wintermute/base/BKeyboardState.h"
+#include "engines/wintermute/base/BDynBuffer.h"
+#include "engines/wintermute/base/BParser.h"
+#include "engines/wintermute/base/BSprite.h"
+#include "engines/wintermute/base/BStringTable.h"
+#include "engines/wintermute/base/BGame.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "engines/wintermute/base/scriptables/ScValue.h"
+#include "engines/wintermute/base/scriptables/ScStack.h"
+#include "engines/wintermute/base/scriptables/ScScript.h"
+#include "engines/wintermute/utils/utils.h"
+#include "common/util.h"
+#include "common/keyboard.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CUIEdit, false)
+
+//////////////////////////////////////////////////////////////////////////
+CUIEdit::CUIEdit(CBGame *inGame): CUIObject(inGame) {
+ _type = UI_EDIT;
+
+ _fontSelected = NULL;
+
+ _selStart = _selEnd = 10000;
+ _scrollOffset = 0;
+
+ _cursorChar = NULL;
+ setCursorChar("|");
+
+ _cursorBlinkRate = 600;
+
+ _frameWidth = 0;
+
+ setText("");
+
+ _lastBlinkTime = 0;
+ _cursorVisible = true;
+
+ _maxLength = -1;
+
+ _canFocus = true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CUIEdit::~CUIEdit() {
+ if (!_sharedFonts) {
+ if (_fontSelected) _gameRef->_fontStorage->removeFont(_fontSelected);
+ }
+
+ delete[] _cursorChar;
+ _cursorChar = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEdit::loadFile(const char *filename) {
+ byte *buffer = _gameRef->_fileManager->readWholeFile(filename);
+ if (buffer == NULL) {
+ _gameRef->LOG(0, "CUIEdit::LoadFile failed for file '%s'", filename);
+ return STATUS_FAILED;
+ }
+
+ bool ret;
+
+ _filename = new char [strlen(filename) + 1];
+ strcpy(_filename, filename);
+
+ if (DID_FAIL(ret = loadBuffer(buffer, true))) _gameRef->LOG(0, "Error parsing EDIT file '%s'", filename);
+
+ delete [] buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(DISABLED)
+TOKEN_DEF(VISIBLE)
+TOKEN_DEF(BACK)
+TOKEN_DEF(IMAGE)
+TOKEN_DEF(FONT_SELECTED)
+TOKEN_DEF(FONT)
+TOKEN_DEF(TEXT)
+TOKEN_DEF(X)
+TOKEN_DEF(Y)
+TOKEN_DEF(WIDTH)
+TOKEN_DEF(HEIGHT)
+TOKEN_DEF(CURSOR_BLINK_RATE)
+TOKEN_DEF(CURSOR)
+TOKEN_DEF(FRAME_WIDTH)
+TOKEN_DEF(NAME)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(PARENT_NOTIFY)
+TOKEN_DEF(MAX_LENGTH)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF(EDIT)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+bool CUIEdit::loadBuffer(byte *buffer, bool complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(DISABLED)
+ TOKEN_TABLE(VISIBLE)
+ TOKEN_TABLE(BACK)
+ TOKEN_TABLE(IMAGE)
+ TOKEN_TABLE(FONT_SELECTED)
+ TOKEN_TABLE(FONT)
+ TOKEN_TABLE(TEXT)
+ TOKEN_TABLE(X)
+ TOKEN_TABLE(Y)
+ TOKEN_TABLE(WIDTH)
+ TOKEN_TABLE(HEIGHT)
+ TOKEN_TABLE(CURSOR_BLINK_RATE)
+ TOKEN_TABLE(CURSOR)
+ TOKEN_TABLE(FRAME_WIDTH)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(PARENT_NOTIFY)
+ TOKEN_TABLE(MAX_LENGTH)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE(EDIT)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd = 2;
+ CBParser parser(_gameRef);
+
+ if (complete) {
+ if (parser.getCommand((char **)&buffer, commands, (char **)&params) != TOKEN_EDIT) {
+ _gameRef->LOG(0, "'EDIT' keyword expected.");
+ return STATUS_FAILED;
+ }
+ buffer = params;
+ }
+
+ while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (DID_FAIL(loadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ setName((char *)params);
+ break;
+
+ case TOKEN_BACK:
+ delete _back;
+ _back = new CUITiledImage(_gameRef);
+ if (!_back || DID_FAIL(_back->loadFile((char *)params))) {
+ delete _back;
+ _back = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE:
+ delete _image;
+ _image = new CBSprite(_gameRef);
+ if (!_image || DID_FAIL(_image->loadFile((char *)params))) {
+ delete _image;
+ _image = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_FONT:
+ if (_font) _gameRef->_fontStorage->removeFont(_font);
+ _font = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_font) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_FONT_SELECTED:
+ if (_fontSelected) _gameRef->_fontStorage->removeFont(_fontSelected);
+ _fontSelected = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_fontSelected) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_TEXT:
+ setText((char *)params);
+ _gameRef->_stringTable->expand(&_text);
+ break;
+
+ case TOKEN_X:
+ parser.scanStr((char *)params, "%d", &_posX);
+ break;
+
+ case TOKEN_Y:
+ parser.scanStr((char *)params, "%d", &_posY);
+ break;
+
+ case TOKEN_WIDTH:
+ parser.scanStr((char *)params, "%d", &_width);
+ break;
+
+ case TOKEN_HEIGHT:
+ parser.scanStr((char *)params, "%d", &_height);
+ break;
+
+ case TOKEN_MAX_LENGTH:
+ parser.scanStr((char *)params, "%d", &_maxLength);
+ break;
+
+ case TOKEN_CAPTION:
+ setCaption((char *)params);
+ break;
+
+ case TOKEN_CURSOR:
+ delete _cursor;
+ _cursor = new CBSprite(_gameRef);
+ if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) {
+ delete _cursor;
+ _cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_CURSOR_BLINK_RATE:
+ parser.scanStr((char *)params, "%d", &_cursorBlinkRate);
+ break;
+
+ case TOKEN_FRAME_WIDTH:
+ parser.scanStr((char *)params, "%d", &_frameWidth);
+ break;
+
+ case TOKEN_SCRIPT:
+ addScript((char *)params);
+ break;
+
+ case TOKEN_PARENT_NOTIFY:
+ parser.scanStr((char *)params, "%b", &_parentNotify);
+ break;
+
+ case TOKEN_DISABLED:
+ parser.scanStr((char *)params, "%b", &_disable);
+ break;
+
+ case TOKEN_VISIBLE:
+ parser.scanStr((char *)params, "%b", &_visible);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ parseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ _gameRef->LOG(0, "Syntax error in EDIT definition");
+ return STATUS_FAILED;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ _gameRef->LOG(0, "Error loading EDIT definition");
+ return STATUS_FAILED;
+ }
+
+ correctSize();
+
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEdit::saveAsText(CBDynBuffer *buffer, int indent) {
+ buffer->putTextIndent(indent, "EDIT\n");
+ buffer->putTextIndent(indent, "{\n");
+
+ buffer->putTextIndent(indent + 2, "NAME=\"%s\"\n", _name);
+ buffer->putTextIndent(indent + 2, "CAPTION=\"%s\"\n", getCaption());
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ if (_back && _back->_filename)
+ buffer->putTextIndent(indent + 2, "BACK=\"%s\"\n", _back->_filename);
+
+ if (_image && _image->_filename)
+ buffer->putTextIndent(indent + 2, "IMAGE=\"%s\"\n", _image->_filename);
+
+ if (_font && _font->_filename)
+ buffer->putTextIndent(indent + 2, "FONT=\"%s\"\n", _font->_filename);
+ if (_fontSelected && _fontSelected->_filename)
+ buffer->putTextIndent(indent + 2, "FONT_SELECTED=\"%s\"\n", _fontSelected->_filename);
+
+ if (_cursor && _cursor->_filename)
+ buffer->putTextIndent(indent + 2, "CURSOR=\"%s\"\n", _cursor->_filename);
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ if (_text)
+ buffer->putTextIndent(indent + 2, "TEXT=\"%s\"\n", _text);
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ buffer->putTextIndent(indent + 2, "X=%d\n", _posX);
+ buffer->putTextIndent(indent + 2, "Y=%d\n", _posY);
+ buffer->putTextIndent(indent + 2, "WIDTH=%d\n", _width);
+ buffer->putTextIndent(indent + 2, "HEIGHT=%d\n", _height);
+ buffer->putTextIndent(indent + 2, "MAX_LENGTH=%d\n", _maxLength);
+ buffer->putTextIndent(indent + 2, "CURSOR_BLINK_RATE=%d\n", _cursorBlinkRate);
+ buffer->putTextIndent(indent + 2, "FRAME_WIDTH=%d\n", _frameWidth);
+
+ buffer->putTextIndent(indent + 2, "DISABLED=%s\n", _disable ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "VISIBLE=%s\n", _visible ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "PARENT_NOTIFY=%s\n", _parentNotify ? "TRUE" : "FALSE");
+
+ // scripts
+ for (int i = 0; i < _scripts.getSize(); i++) {
+ buffer->putTextIndent(indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
+ }
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ // editor properties
+ CBBase::saveAsText(buffer, indent + 2);
+
+ buffer->putTextIndent(indent, "}\n");
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+bool CUIEdit::scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name) {
+ //////////////////////////////////////////////////////////////////////////
+ // SetSelectedFont
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "SetSelectedFont") == 0) {
+ stack->correctParams(1);
+
+ if (_fontSelected) _gameRef->_fontStorage->removeFont(_fontSelected);
+ _fontSelected = _gameRef->_fontStorage->addFont(stack->pop()->getString());
+ stack->pushBool(_fontSelected != NULL);
+
+ return STATUS_OK;
+ }
+
+ else return CUIObject::scCallMethod(script, stack, thisStack, name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CUIEdit::scGetProperty(const char *name) {
+ _scValue->setNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "Type") == 0) {
+ _scValue->setString("editor");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SelStart
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SelStart") == 0) {
+ _scValue->setInt(_selStart);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SelEnd
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SelEnd") == 0) {
+ _scValue->setInt(_selEnd);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CursorBlinkRate
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "CursorBlinkRate") == 0) {
+ _scValue->setInt(_cursorBlinkRate);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CursorChar
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "CursorChar") == 0) {
+ _scValue->setString(_cursorChar);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // FrameWidth
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "FrameWidth") == 0) {
+ _scValue->setInt(_frameWidth);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MaxLength
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "MaxLength") == 0) {
+ _scValue->setInt(_maxLength);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Text
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Text") == 0) {
+ if (_gameRef->_textEncoding == TEXT_UTF8) {
+ WideString wstr = StringUtil::ansiToWide(_text);
+ _scValue->setString(StringUtil::wideToUtf8(wstr).c_str());
+ } else {
+ _scValue->setString(_text);
+ }
+ return _scValue;
+ }
+
+ else return CUIObject::scGetProperty(name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEdit::scSetProperty(const char *name, CScValue *value) {
+ //////////////////////////////////////////////////////////////////////////
+ // SelStart
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "SelStart") == 0) {
+ _selStart = value->getInt();
+ _selStart = MAX(_selStart, 0);
+ _selStart = MIN((size_t)_selStart, strlen(_text));
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SelEnd
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SelEnd") == 0) {
+ _selEnd = value->getInt();
+ _selEnd = MAX(_selEnd, 0);
+ _selEnd = MIN((size_t)_selEnd, strlen(_text));
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CursorBlinkRate
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "CursorBlinkRate") == 0) {
+ _cursorBlinkRate = value->getInt();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CursorChar
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "CursorChar") == 0) {
+ setCursorChar(value->getString());
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // FrameWidth
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "FrameWidth") == 0) {
+ _frameWidth = value->getInt();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // MaxLength
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "MaxLength") == 0) {
+ _maxLength = value->getInt();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Text
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Text") == 0) {
+ if (_gameRef->_textEncoding == TEXT_UTF8) {
+ WideString wstr = StringUtil::utf8ToWide(value->getString());
+ setText(StringUtil::wideToAnsi(wstr).c_str());
+ } else {
+ setText(value->getString());
+ }
+ return STATUS_OK;
+ }
+
+ else return CUIObject::scSetProperty(name, value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CUIEdit::scToString() {
+ return "[edit]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CUIEdit::setCursorChar(const char *character) {
+ if (!character) return;
+ delete[] _cursorChar;
+ _cursorChar = new char [strlen(character) + 1];
+ if (_cursorChar) strcpy(_cursorChar, character);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEdit::display(int offsetX, int offsetY) {
+ if (!_visible) return STATUS_OK;
+
+
+ // hack!
+ TTextEncoding OrigEncoding = _gameRef->_textEncoding;
+ _gameRef->_textEncoding = TEXT_ANSI;
+
+ if (_back) _back->display(offsetX + _posX, offsetY + _posY, _width, _height);
+ if (_image) _image->draw(offsetX + _posX, offsetY + _posY, NULL);
+
+ // prepare fonts
+ CBFont *font;
+ CBFont *sfont;
+
+ if (_font) font = _font;
+ else font = _gameRef->_systemFont;
+
+ if (_fontSelected) sfont = _fontSelected;
+ else sfont = font;
+
+ bool focused = isFocused();
+
+ _selStart = MAX(_selStart, 0);
+ _selEnd = MAX(_selEnd, 0);
+
+ _selStart = MIN((size_t)_selStart, strlen(_text));
+ _selEnd = MIN((size_t)_selEnd, strlen(_text));
+
+ //int CursorWidth = font->GetCharWidth(_cursorChar[0]);
+ int cursorWidth = font->getTextWidth((byte *)_cursorChar);
+
+ int s1, s2;
+ bool curFirst;
+ // modify scroll offset
+ if (_selStart >= _selEnd) {
+ while (font->getTextWidth((byte *)_text + _scrollOffset, MAX(0, _selEnd - _scrollOffset)) > _width - cursorWidth - 2 * _frameWidth) {
+ _scrollOffset++;
+ if (_scrollOffset >= (int)strlen(_text)) break;
+ }
+
+ _scrollOffset = MIN(_scrollOffset, _selEnd);
+
+ s1 = _selEnd;
+ s2 = _selStart;
+ curFirst = true;
+ } else {
+ while (font->getTextWidth((byte *)_text + _scrollOffset, MAX(0, _selStart - _scrollOffset)) +
+ sfont->getTextWidth((byte *)(_text + MAX(_scrollOffset, _selStart)), _selEnd - MAX(_scrollOffset, _selStart))
+
+ > _width - cursorWidth - 2 * _frameWidth) {
+ _scrollOffset++;
+ if (_scrollOffset >= (int)strlen(_text)) break;
+ }
+
+ _scrollOffset = MIN(_scrollOffset, _selEnd);
+
+ s1 = _selStart;
+ s2 = _selEnd;
+ curFirst = false;
+ }
+
+
+ int AlignOffset = 0;
+
+ for (int Count = 0; Count < 2; Count++) {
+ // draw text
+ int xxx, yyy, width, height;
+
+ xxx = _posX + _frameWidth + offsetX;
+ yyy = _posY + _frameWidth + offsetY;
+
+ width = _posX + _width + offsetX - _frameWidth;
+ height = MAX(font->getLetterHeight(), sfont->getLetterHeight());
+
+ if (_gameRef->_textRTL) xxx += AlignOffset;
+
+ TTextAlign Align = TAL_LEFT;
+
+
+ // unselected 1
+ if (s1 > _scrollOffset) {
+ if (Count) font->drawText((byte *)_text + _scrollOffset, xxx, yyy, width - xxx, Align, height, s1 - _scrollOffset);
+ xxx += font->getTextWidth((byte *)_text + _scrollOffset, s1 - _scrollOffset);
+ AlignOffset += font->getTextWidth((byte *)_text + _scrollOffset, s1 - _scrollOffset);
+ }
+
+ // cursor
+ if (focused && curFirst) {
+ if (Count) {
+ if (CBPlatform::getTime() - _lastBlinkTime >= _cursorBlinkRate) {
+ _lastBlinkTime = CBPlatform::getTime();
+ _cursorVisible = !_cursorVisible;
+ }
+ if (_cursorVisible)
+ font->drawText((byte *)_cursorChar, xxx, yyy, width - xxx, Align, height, 1);
+ }
+ xxx += cursorWidth;
+ AlignOffset += cursorWidth;
+ }
+
+ // selected
+ int s3 = MAX(s1, _scrollOffset);
+
+ if (s2 - s3 > 0) {
+ if (Count) sfont->drawText((byte *)_text + s3, xxx, yyy, width - xxx, Align, height, s2 - s3);
+ xxx += sfont->getTextWidth((byte *)_text + s3, s2 - s3);
+ AlignOffset += sfont->getTextWidth((byte *)_text + s3, s2 - s3);
+ }
+
+ // cursor
+ if (focused && !curFirst) {
+ if (Count) {
+ if (CBPlatform::getTime() - _lastBlinkTime >= _cursorBlinkRate) {
+ _lastBlinkTime = CBPlatform::getTime();
+ _cursorVisible = !_cursorVisible;
+ }
+ if (_cursorVisible)
+ font->drawText((byte *)_cursorChar, xxx, yyy, width - xxx, Align, height, 1);
+ }
+ xxx += cursorWidth;
+ AlignOffset += cursorWidth;
+ }
+
+ // unselected 2
+ if (Count) font->drawText((byte *)_text + s2, xxx, yyy, width - xxx, Align, height);
+ AlignOffset += font->getTextWidth((byte *)_text + s2);
+
+ AlignOffset = (_width - 2 * _frameWidth) - AlignOffset;
+ if (AlignOffset < 0) AlignOffset = 0;
+ }
+
+
+ _gameRef->_renderer->_rectList.add(new CBActiveRect(_gameRef, this, NULL, offsetX + _posX, offsetY + _posY, _width, _height, 100, 100, false));
+
+
+ _gameRef->_textEncoding = OrigEncoding;
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEdit::handleKeypress(Common::Event *event, bool printable) {
+ bool handled = false;
+
+ if (event->type == Common::EVENT_KEYDOWN && !printable) {
+ switch (event->kbd.keycode) {
+ case Common::KEYCODE_ESCAPE:
+ case Common::KEYCODE_TAB:
+ case Common::KEYCODE_RETURN:
+ return false;
+
+ // ctrl+A
+ case Common::KEYCODE_a:
+ if (CBKeyboardState::isControlDown()) {
+ _selStart = 0;
+ _selEnd = strlen(_text);
+ handled = true;
+ }
+ break;
+
+ case Common::KEYCODE_BACKSPACE:
+ if (_selStart == _selEnd) {
+ if (_gameRef->_textRTL) deleteChars(_selStart, _selStart + 1);
+ else deleteChars(_selStart - 1, _selStart);
+ } else deleteChars(_selStart, _selEnd);
+ if (_selEnd >= _selStart) _selEnd -= MAX(1, _selEnd - _selStart);
+ _selStart = _selEnd;
+
+ handled = true;
+ break;
+
+ case Common::KEYCODE_LEFT:
+ case Common::KEYCODE_UP:
+ _selEnd--;
+ if (!CBKeyboardState::isShiftDown()) _selStart = _selEnd;
+ handled = true;
+ break;
+
+ case Common::KEYCODE_RIGHT:
+ case Common::KEYCODE_DOWN:
+ _selEnd++;
+ if (!CBKeyboardState::isShiftDown()) _selStart = _selEnd;
+ handled = true;
+ break;
+
+ case Common::KEYCODE_HOME:
+ if (_gameRef->_textRTL) {
+ _selEnd = strlen(_text);
+ if (!CBKeyboardState::isShiftDown()) _selStart = _selEnd;
+ } else {
+ _selEnd = 0;
+ if (!CBKeyboardState::isShiftDown()) _selStart = _selEnd;
+ }
+ handled = true;
+ break;
+
+ case Common::KEYCODE_END:
+ if (_gameRef->_textRTL) {
+ _selEnd = 0;
+ if (!CBKeyboardState::isShiftDown()) _selStart = _selEnd;
+ } else {
+ _selEnd = strlen(_text);
+ if (!CBKeyboardState::isShiftDown()) _selStart = _selEnd;
+ }
+ handled = true;
+ break;
+
+ case Common::KEYCODE_DELETE:
+ if (_selStart == _selEnd) {
+ if (_gameRef->_textRTL) {
+ deleteChars(_selStart - 1, _selStart);
+ _selEnd--;
+ if (_selEnd < 0) _selEnd = 0;
+ } else deleteChars(_selStart, _selStart + 1);
+ } else deleteChars(_selStart, _selEnd);
+ if (_selEnd > _selStart) _selEnd -= (_selEnd - _selStart);
+
+ _selStart = _selEnd;
+ handled = true;
+ break;
+ default:
+ break;
+ }
+ return handled;
+ } else if (event->type == Common::EVENT_KEYDOWN && printable) {
+ if (_selStart != _selEnd) deleteChars(_selStart, _selEnd);
+
+ //WideString wstr = StringUtil::Utf8ToWide(event->kbd.ascii);
+ WideString wstr;
+ wstr += (char)event->kbd.ascii;
+ _selEnd += insertChars(_selEnd, (byte *)StringUtil::wideToAnsi(wstr).c_str(), 1);
+
+ if (_gameRef->_textRTL) _selEnd = _selStart;
+ else _selStart = _selEnd;
+
+ return true;
+ }
+
+ return false;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+int CUIEdit::deleteChars(int start, int end) {
+ if (start > end) CBUtils::swap(&start, &end);
+
+ start = MAX(start, (int)0);
+ end = MIN((size_t)end, strlen(_text));
+
+ char *str = new char[strlen(_text) - (end - start) + 1];
+ if (str) {
+ if (start > 0) memcpy(str, _text, start);
+ memcpy(str + MAX(0, start), _text + end, strlen(_text) - end + 1);
+
+ delete[] _text;
+ _text = str;
+ }
+ if (_parentNotify && _parent) _parent->applyEvent(_name);
+
+ return end - start;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+int CUIEdit::insertChars(int pos, byte *chars, int num) {
+ if ((int)strlen(_text) + num > _maxLength) {
+ num -= (strlen(_text) + num - _maxLength);
+ }
+
+ pos = MAX(pos, (int)0);
+ pos = MIN((size_t)pos, strlen(_text));
+
+ char *str = new char[strlen(_text) + num + 1];
+ if (str) {
+ if (pos > 0) memcpy(str, _text, pos);
+ memcpy(str + pos + num, _text + pos, strlen(_text) - pos + 1);
+
+ memcpy(str + pos, chars, num);
+
+ delete[] _text;
+ _text = str;
+ }
+ if (_parentNotify && _parent) _parent->applyEvent(_name);
+
+ return num;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEdit::persist(CBPersistMgr *persistMgr) {
+
+ CUIObject::persist(persistMgr);
+
+ persistMgr->transfer(TMEMBER(_cursorBlinkRate));
+ persistMgr->transfer(TMEMBER(_cursorChar));
+ persistMgr->transfer(TMEMBER(_fontSelected));
+ persistMgr->transfer(TMEMBER(_frameWidth));
+ persistMgr->transfer(TMEMBER(_maxLength));
+ persistMgr->transfer(TMEMBER(_scrollOffset));
+ persistMgr->transfer(TMEMBER(_selEnd));
+ persistMgr->transfer(TMEMBER(_selStart));
+
+ if (!persistMgr->_saving) {
+ _cursorVisible = false;
+ _lastBlinkTime = 0;
+ }
+
+ return STATUS_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/ui/UIEdit.h b/engines/wintermute/ui/UIEdit.h
new file mode 100644
index 0000000000..7249301592
--- /dev/null
+++ b/engines/wintermute/ui/UIEdit.h
@@ -0,0 +1,72 @@
+/* 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
+ */
+
+#ifndef WINTERMUTE_UIEDIT_H
+#define WINTERMUTE_UIEDIT_H
+
+#include "engines/wintermute/persistent.h"
+#include "UIObject.h"
+#include "common/events.h"
+
+namespace WinterMute {
+class CBFont;
+class CUIEdit : public CUIObject {
+public:
+ DECLARE_PERSISTENT(CUIEdit, CUIObject)
+ int _maxLength;
+ int insertChars(int pos, byte *chars, int num);
+ int deleteChars(int start, int end);
+ bool _cursorVisible;
+ uint32 _lastBlinkTime;
+ virtual bool display(int offsetX, int offsetY);
+ virtual bool handleKeypress(Common::Event *event, bool printable = false);
+ int _scrollOffset;
+ int _frameWidth;
+ uint32 _cursorBlinkRate;
+ void setCursorChar(const char *character);
+ char *_cursorChar;
+ int _selEnd;
+ int _selStart;
+ CBFont *_fontSelected;
+ CUIEdit(CBGame *inGame);
+ virtual ~CUIEdit();
+
+ bool loadFile(const char *filename);
+ bool loadBuffer(byte *buffer, bool complete = true);
+ virtual bool saveAsText(CBDynBuffer *buffer, int indent);
+
+ // scripting interface
+ virtual CScValue *scGetProperty(const char *name);
+ virtual bool scSetProperty(const char *name, CScValue *value);
+ virtual bool scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name);
+ virtual const char *scToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/ui/UIEntity.cpp b/engines/wintermute/ui/UIEntity.cpp
new file mode 100644
index 0000000000..7fbd2d13ff
--- /dev/null
+++ b/engines/wintermute/ui/UIEntity.cpp
@@ -0,0 +1,339 @@
+/* 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/ad/AdEntity.h"
+#include "engines/wintermute/base/BGame.h"
+#include "engines/wintermute/base/BFileManager.h"
+#include "engines/wintermute/ui/UIEntity.h"
+#include "engines/wintermute/base/BParser.h"
+#include "engines/wintermute/base/BDynBuffer.h"
+#include "engines/wintermute/base/scriptables/ScValue.h"
+#include "engines/wintermute/base/scriptables/ScScript.h"
+#include "engines/wintermute/base/scriptables/ScStack.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CUIEntity, false)
+
+//////////////////////////////////////////////////////////////////////////
+CUIEntity::CUIEntity(CBGame *inGame): CUIObject(inGame) {
+ _type = UI_CUSTOM;
+ _entity = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CUIEntity::~CUIEntity() {
+ if (_entity) _gameRef->unregisterObject(_entity);
+ _entity = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEntity::loadFile(const char *filename) {
+ byte *buffer = _gameRef->_fileManager->readWholeFile(filename);
+ if (buffer == NULL) {
+ _gameRef->LOG(0, "CUIEntity::LoadFile failed for file '%s'", filename);
+ return STATUS_FAILED;
+ }
+
+ bool ret;
+
+ _filename = new char [strlen(filename) + 1];
+ strcpy(_filename, filename);
+
+ if (DID_FAIL(ret = loadBuffer(buffer, true))) _gameRef->LOG(0, "Error parsing ENTITY container file '%s'", filename);
+
+
+ delete [] buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(ENTITY_CONTAINER)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(DISABLED)
+TOKEN_DEF(VISIBLE)
+TOKEN_DEF(X)
+TOKEN_DEF(Y)
+TOKEN_DEF(NAME)
+TOKEN_DEF(ENTITY)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+bool CUIEntity::loadBuffer(byte *buffer, bool complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(ENTITY_CONTAINER)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(DISABLED)
+ TOKEN_TABLE(VISIBLE)
+ TOKEN_TABLE(X)
+ TOKEN_TABLE(Y)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(ENTITY)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd = 2;
+ CBParser parser(_gameRef);
+
+ if (complete) {
+ if (parser.getCommand((char **)&buffer, commands, (char **)&params) != TOKEN_ENTITY_CONTAINER) {
+ _gameRef->LOG(0, "'ENTITY_CONTAINER' keyword expected.");
+ return STATUS_FAILED;
+ }
+ buffer = params;
+ }
+
+ while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (DID_FAIL(loadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ setName((char *)params);
+ break;
+
+ case TOKEN_X:
+ parser.scanStr((char *)params, "%d", &_posX);
+ break;
+
+ case TOKEN_Y:
+ parser.scanStr((char *)params, "%d", &_posY);
+ break;
+
+ case TOKEN_DISABLED:
+ parser.scanStr((char *)params, "%b", &_disable);
+ break;
+
+ case TOKEN_VISIBLE:
+ parser.scanStr((char *)params, "%b", &_visible);
+ break;
+
+ case TOKEN_ENTITY:
+ if (DID_FAIL(setEntity((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_SCRIPT:
+ addScript((char *)params);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ parseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ _gameRef->LOG(0, "Syntax error in ENTITY_CONTAINER definition");
+ return STATUS_FAILED;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ _gameRef->LOG(0, "Error loading ENTITY_CONTAINER definition");
+ return STATUS_FAILED;
+ }
+
+ correctSize();
+
+ if (_gameRef->_editorMode) {
+ _width = 50;
+ _height = 50;
+ }
+
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEntity::saveAsText(CBDynBuffer *buffer, int indent) {
+ buffer->putTextIndent(indent, "ENTITY_CONTAINER\n");
+ buffer->putTextIndent(indent, "{\n");
+
+ buffer->putTextIndent(indent + 2, "NAME=\"%s\"\n", _name);
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ buffer->putTextIndent(indent + 2, "X=%d\n", _posX);
+ buffer->putTextIndent(indent + 2, "Y=%d\n", _posY);
+
+ buffer->putTextIndent(indent + 2, "DISABLED=%s\n", _disable ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "VISIBLE=%s\n", _visible ? "TRUE" : "FALSE");
+
+ if (_entity && _entity->_filename)
+ buffer->putTextIndent(indent + 2, "ENTITY=\"%s\"\n", _entity->_filename);
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ // scripts
+ for (int i = 0; i < _scripts.getSize(); i++) {
+ buffer->putTextIndent(indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
+ }
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ // editor properties
+ CBBase::saveAsText(buffer, indent + 2);
+
+ buffer->putTextIndent(indent, "}\n");
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEntity::setEntity(const char *filename) {
+ if (_entity) _gameRef->unregisterObject(_entity);
+ _entity = new CAdEntity(_gameRef);
+ if (!_entity || DID_FAIL(_entity->loadFile(filename))) {
+ delete _entity;
+ _entity = NULL;
+ return STATUS_FAILED;
+ } else {
+ _entity->_nonIntMouseEvents = true;
+ _entity->_sceneIndependent = true;
+ _entity->makeFreezable(false);
+ _gameRef->registerObject(_entity);
+ }
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEntity::display(int offsetX, int offsetY) {
+ if (!_visible) return STATUS_OK;
+
+ if (_entity) {
+ _entity->_posX = offsetX + _posX;
+ _entity->_posY = offsetY + _posY;
+ if (_entity->_scale < 0) _entity->_zoomable = false;
+ _entity->_shadowable = false;
+
+ _entity->update();
+
+ bool origReg = _entity->_registrable;
+
+ if (_entity->_registrable && _disable) _entity->_registrable = false;
+
+ _entity->display();
+ _entity->_registrable = origReg;
+ }
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+bool CUIEntity::scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name) {
+ //////////////////////////////////////////////////////////////////////////
+ // GetEntity
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "GetEntity") == 0) {
+ stack->correctParams(0);
+
+ if (_entity) stack->pushNative(_entity, true);
+ else stack->pushNULL();
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetEntity
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetEntity") == 0) {
+ stack->correctParams(1);
+
+ const char *filename = stack->pop()->getString();
+
+ if (DID_SUCCEED(setEntity(filename)))
+ stack->pushBool(true);
+ else
+ stack->pushBool(false);
+
+ return STATUS_OK;
+ }
+
+ else return CUIObject::scCallMethod(script, stack, thisStack, name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CUIEntity::scGetProperty(const char *name) {
+ _scValue->setNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "Type") == 0) {
+ _scValue->setString("entity container");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Freezable
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Freezable") == 0) {
+ if (_entity) _scValue->setBool(_entity->_freezable);
+ else _scValue->setBool(false);
+ return _scValue;
+ }
+
+ else return CUIObject::scGetProperty(name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEntity::scSetProperty(const char *name, CScValue *value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Freezable
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "Freezable") == 0) {
+ if (_entity) _entity->makeFreezable(value->getBool());
+ return STATUS_OK;
+ } else return CUIObject::scSetProperty(name, value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CUIEntity::scToString() {
+ return "[entity container]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIEntity::persist(CBPersistMgr *persistMgr) {
+
+ CUIObject::persist(persistMgr);
+
+ persistMgr->transfer(TMEMBER(_entity));
+ return STATUS_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/ui/UIEntity.h b/engines/wintermute/ui/UIEntity.h
new file mode 100644
index 0000000000..b0711838a5
--- /dev/null
+++ b/engines/wintermute/ui/UIEntity.h
@@ -0,0 +1,58 @@
+/* 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
+ */
+
+#ifndef WINTERMUTE_UIENTITY_H
+#define WINTERMUTE_UIENTITY_H
+
+#include "UIObject.h"
+
+namespace WinterMute {
+class CAdEntity;
+class CUIEntity : public CUIObject {
+public:
+ DECLARE_PERSISTENT(CUIEntity, CUIObject)
+ CUIEntity(CBGame *inGame);
+ virtual ~CUIEntity();
+ bool loadFile(const char *filename);
+ bool loadBuffer(byte *buffer, bool complete);
+ virtual bool saveAsText(CBDynBuffer *buffer, int indent);
+
+ virtual bool display(int offsetX = 0, int offsetY = 0);
+ CAdEntity *_entity;
+ bool setEntity(const char *filename);
+
+ // scripting interface
+ virtual CScValue *scGetProperty(const char *name);
+ virtual bool scSetProperty(const char *name, CScValue *value);
+ virtual bool scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name);
+ virtual const char *scToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/ui/UIObject.cpp b/engines/wintermute/ui/UIObject.cpp
new file mode 100644
index 0000000000..1032faeb2c
--- /dev/null
+++ b/engines/wintermute/ui/UIObject.cpp
@@ -0,0 +1,589 @@
+/* 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/BGame.h"
+#include "engines/wintermute/base/BSprite.h"
+#include "engines/wintermute/ui/UIObject.h"
+#include "engines/wintermute/ui/UITiledImage.h"
+#include "engines/wintermute/ui/UIWindow.h"
+#include "engines/wintermute/PlatformSDL.h"
+#include "engines/wintermute/base/scriptables/ScValue.h"
+#include "engines/wintermute/base/scriptables/ScStack.h"
+#include "engines/wintermute/base/font/BFontStorage.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CUIObject, false)
+
+//////////////////////////////////////////////////////////////////////////
+CUIObject::CUIObject(CBGame *inGame): CBObject(inGame) {
+ _back = NULL;
+ _image = NULL;
+ _font = NULL;
+ _text = NULL;
+ _sharedFonts = _sharedImages = false;
+
+ _width = _height = 0;
+
+ _listenerObject = NULL;
+ _listenerParamObject = NULL;
+ _listenerParamDWORD = 0;
+
+ _disable = false;
+ _visible = true;
+
+ _type = UI_UNKNOWN;
+ _parent = NULL;
+
+ _parentNotify = false;
+
+ _focusedWidget = NULL;
+
+ _canFocus = false;
+ _nonIntMouseEvents = true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CUIObject::~CUIObject() {
+ if (!_gameRef->_loadInProgress) CSysClassRegistry::getInstance()->enumInstances(CBGame::invalidateValues, "CScValue", (void *)this);
+
+ if (_back) delete _back;
+ if (_font && !_sharedFonts) _gameRef->_fontStorage->removeFont(_font);
+
+ if (_image && !_sharedImages) delete _image;
+
+ if (_text) delete [] _text;
+
+ _focusedWidget = NULL; // ref only
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CUIObject::setText(const char *text) {
+ if (_text) delete [] _text;
+ _text = new char [strlen(text) + 1];
+ if (_text) {
+ strcpy(_text, text);
+ for (int i = 0; i < strlen(_text); i++) {
+ if (_text[i] == '|') _text[i] = '\n';
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIObject::display(int offsetX, int offsetY) {
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CUIObject::setListener(CBScriptHolder *object, CBScriptHolder *listenerObject, uint32 listenerParam) {
+ _listenerObject = object;
+ _listenerParamObject = listenerObject;
+ _listenerParamDWORD = listenerParam;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CUIObject::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 CUIObject::scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name) {
+ //////////////////////////////////////////////////////////////////////////
+ // SetFont
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "SetFont") == 0) {
+ stack->correctParams(1);
+ CScValue *Val = stack->pop();
+
+ if (_font) _gameRef->_fontStorage->removeFont(_font);
+ if (Val->isNULL()) {
+ _font = NULL;
+ stack->pushBool(true);
+ } else {
+ _font = _gameRef->_fontStorage->addFont(Val->getString());
+ stack->pushBool(_font != NULL);
+ }
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetImage") == 0) {
+ stack->correctParams(1);
+ CScValue *val = stack->pop();
+
+ /* const char *filename = */ val->getString();
+
+ delete _image;
+ _image = NULL;
+ if (val->isNULL()) {
+ stack->pushBool(true);
+ return STATUS_OK;
+ }
+
+ _image = new CBSprite(_gameRef);
+ if (!_image || DID_FAIL(_image->loadFile(val->getString()))) {
+ delete _image;
+ _image = NULL;
+ stack->pushBool(false);
+ } else stack->pushBool(true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetImage") == 0) {
+ stack->correctParams(0);
+ if (!_image || !_image->_filename) stack->pushNULL();
+ else stack->pushString(_image->_filename);
+
+ 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) {
+ CUIWindow *win = (CUIWindow *)_parent;
+
+ int i;
+ bool found = false;
+ CScValue *val = stack->pop();
+ // find directly
+ if (val->isNative()) {
+ CUIObject *widget = (CUIObject *)val->getNative();
+ for (i = 0; i < win->_widgets.getSize(); i++) {
+ if (win->_widgets[i] == widget) {
+ found = true;
+ break;
+ }
+ }
+ }
+ // find by name
+ else {
+ const char *findName = val->getString();
+ for (i = 0; i < win->_widgets.getSize(); i++) {
+ if (scumm_stricmp(win->_widgets[i]->_name, findName) == 0) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ bool done = false;
+ for (int j = 0; j < win->_widgets.getSize(); j++) {
+ if (win->_widgets[j] == this) {
+ if (strcmp(name, "MoveAfter") == 0) i++;
+ if (j >= i) j++;
+
+ win->_widgets.insertAt(i, this);
+ win->_widgets.removeAt(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) {
+ CUIWindow *win = (CUIWindow *)_parent;
+ for (int i = 0; i < win->_widgets.getSize(); i++) {
+ if (win->_widgets[i] == this) {
+ win->_widgets.removeAt(i);
+ win->_widgets.insertAt(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) {
+ CUIWindow *win = (CUIWindow *)_parent;
+ for (int i = 0; i < win->_widgets.getSize(); i++) {
+ if (win->_widgets[i] == this) {
+ win->_widgets.removeAt(i);
+ win->_widgets.add(this);
+ break;
+ }
+ }
+ stack->pushBool(true);
+ } else stack->pushBool(false);
+
+ return STATUS_OK;
+ }
+
+ else return CBObject::scCallMethod(script, stack, thisStack, name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CUIObject::scGetProperty(const char *name) {
+ _scValue->setNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "Type") == 0) {
+ _scValue->setString("ui_object");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Name") == 0) {
+ _scValue->setString(_name);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Parent (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Parent") == 0) {
+ _scValue->setNative(_parent, true);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ParentNotify
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "ParentNotify") == 0) {
+ _scValue->setBool(_parentNotify);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Width
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Width") == 0) {
+ _scValue->setInt(_width);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Height
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Height") == 0) {
+ _scValue->setInt(_height);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Visible
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Visible") == 0) {
+ _scValue->setBool(_visible);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Disabled
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Disabled") == 0) {
+ _scValue->setBool(_disable);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Text
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Text") == 0) {
+ _scValue->setString(_text);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NextSibling (RO) / PrevSibling (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "NextSibling") == 0 || strcmp(name, "PrevSibling") == 0) {
+ _scValue->setNULL();
+ if (_parent && _parent->_type == UI_WINDOW) {
+ CUIWindow *win = (CUIWindow *)_parent;
+ for (int i = 0; i < win->_widgets.getSize(); i++) {
+ if (win->_widgets[i] == this) {
+ if (strcmp(name, "NextSibling") == 0) {
+ if (i < win->_widgets.getSize() - 1) _scValue->setNative(win->_widgets[i + 1], true);
+ } else {
+ if (i > 0) _scValue->setNative(win->_widgets[i - 1], true);
+ }
+ break;
+ }
+ }
+ }
+ return _scValue;
+ }
+
+ else return CBObject::scGetProperty(name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIObject::scSetProperty(const char *name, CScValue *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 CBObject::scSetProperty(name, value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CUIObject::scToString() {
+ return "[ui_object]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIObject::isFocused() {
+ if (!_gameRef->_focusedWindow) return false;
+ if (_gameRef->_focusedWindow == this) return true;
+
+ CUIObject *obj = _gameRef->_focusedWindow;
+ while (obj) {
+ if (obj == this) return true;
+ else obj = obj->_focusedWidget;
+ }
+ return false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIObject::handleMouse(TMouseEvent event, TMouseButton button) {
+ // handle focus change
+ if (event == MOUSE_CLICK && button == MOUSE_BUTTON_LEFT) {
+ focus();
+ }
+ return CBObject::handleMouse(event, button);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIObject::focus() {
+ CUIObject *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((CUIWindow *)obj);
+ }
+
+ obj = obj->_parent;
+ }
+ }
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIObject::getTotalOffset(int *offsetX, int *offsetY) {
+ int offX = 0, offY = 0;
+
+ CUIObject *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 CUIObject::persist(CBPersistMgr *persistMgr) {
+
+ CBObject::persist(persistMgr);
+
+ persistMgr->transfer(TMEMBER(_back));
+ persistMgr->transfer(TMEMBER(_canFocus));
+ persistMgr->transfer(TMEMBER(_disable));
+ persistMgr->transfer(TMEMBER(_focusedWidget));
+ persistMgr->transfer(TMEMBER(_font));
+ persistMgr->transfer(TMEMBER(_height));
+ persistMgr->transfer(TMEMBER(_image));
+ persistMgr->transfer(TMEMBER(_listenerObject));
+ persistMgr->transfer(TMEMBER(_listenerParamObject));
+ persistMgr->transfer(TMEMBER(_listenerParamDWORD));
+ persistMgr->transfer(TMEMBER(_parent));
+ persistMgr->transfer(TMEMBER(_parentNotify));
+ persistMgr->transfer(TMEMBER(_sharedFonts));
+ persistMgr->transfer(TMEMBER(_sharedImages));
+ persistMgr->transfer(TMEMBER(_text));
+ persistMgr->transfer(TMEMBER_INT(_type));
+ persistMgr->transfer(TMEMBER(_visible));
+ persistMgr->transfer(TMEMBER(_width));
+
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIObject::saveAsText(CBDynBuffer *buffer, int indent) {
+ return STATUS_FAILED;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/ui/UIObject.h b/engines/wintermute/ui/UIObject.h
new file mode 100644
index 0000000000..26eecefe89
--- /dev/null
+++ b/engines/wintermute/ui/UIObject.h
@@ -0,0 +1,83 @@
+/* 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
+ */
+
+#ifndef WINTERMUTE_UIOBJECT_H
+#define WINTERMUTE_UIOBJECT_H
+
+
+#include "engines/wintermute/base/BObject.h"
+#include "engines/wintermute/dctypes.h" // Added by ClassView
+
+namespace WinterMute {
+
+class CUITiledImage;
+class CBFont;
+class CUIObject : public CBObject {
+public:
+
+ bool getTotalOffset(int *offsetX, int *offsetY);
+ bool _canFocus;
+ bool focus();
+ virtual bool handleMouse(TMouseEvent event, TMouseButton button);
+ bool isFocused();
+ bool _parentNotify;
+ DECLARE_PERSISTENT(CUIObject, CBObject)
+ CUIObject *_parent;
+ virtual bool display(int offsetX = 0, int offsetY = 0);
+ virtual void correctSize();
+ bool _sharedFonts;
+ bool _sharedImages;
+ void setText(const char *text);
+ char *_text;
+ CBFont *_font;
+ bool _visible;
+ CUITiledImage *_back;
+ bool _disable;
+ CUIObject(CBGame *inGame = NULL);
+ virtual ~CUIObject();
+ int _width;
+ int _height;
+ TUIObjectType _type;
+ CBSprite *_image;
+ void setListener(CBScriptHolder *object, CBScriptHolder *listenerObject, uint32 listenerParam);
+ CBScriptHolder *_listenerParamObject;
+ uint32 _listenerParamDWORD;
+ CBScriptHolder *_listenerObject;
+ CUIObject *_focusedWidget;
+ virtual bool saveAsText(CBDynBuffer *buffer, int indent);
+
+ // scripting interface
+ virtual CScValue *scGetProperty(const char *name);
+ virtual bool scSetProperty(const char *name, CScValue *value);
+ virtual bool scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name);
+ virtual const char *scToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/ui/UIText.cpp b/engines/wintermute/ui/UIText.cpp
new file mode 100644
index 0000000000..0b7df9bf19
--- /dev/null
+++ b/engines/wintermute/ui/UIText.cpp
@@ -0,0 +1,489 @@
+/* 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/dcgf.h"
+#include "engines/wintermute/base/BDynBuffer.h"
+#include "engines/wintermute/ui/UIText.h"
+#include "engines/wintermute/ui/UITiledImage.h"
+#include "engines/wintermute/base/BGame.h"
+#include "engines/wintermute/base/BParser.h"
+#include "engines/wintermute/base/scriptables/ScValue.h"
+#include "engines/wintermute/base/font/BFont.h"
+#include "engines/wintermute/base/font/BFontStorage.h"
+#include "engines/wintermute/base/BStringTable.h"
+#include "engines/wintermute/base/scriptables/ScScript.h"
+#include "engines/wintermute/base/scriptables/ScStack.h"
+#include "engines/wintermute/base/BSprite.h"
+#include "engines/wintermute/base/BFileManager.h"
+#include "engines/wintermute/PlatformSDL.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CUIText, false)
+
+//////////////////////////////////////////////////////////////////////////
+CUIText::CUIText(CBGame *inGame): CUIObject(inGame) {
+ _textAlign = TAL_LEFT;
+ _verticalAlign = VAL_CENTER;
+ _type = UI_STATIC;
+ _canFocus = false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CUIText::~CUIText() {
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIText::display(int offsetX, int offsetY) {
+ if (!_visible) return STATUS_OK;
+
+
+ CBFont *font = _font;
+ if (!font) font = _gameRef->_systemFont;
+
+ if (_back) _back->display(offsetX + _posX, offsetY + _posY, _width, _height);
+ if (_image) _image->draw(offsetX + _posX, offsetY + _posY, NULL);
+
+ if (font && _text) {
+ int textOffset;
+ switch (_verticalAlign) {
+ case VAL_TOP:
+ textOffset = 0;
+ break;
+ case VAL_BOTTOM:
+ textOffset = _height - font->getTextHeight((byte *)_text, _width);
+ break;
+ default:
+ textOffset = (_height - font->getTextHeight((byte *)_text, _width)) / 2;
+ }
+ font->drawText((byte *)_text, offsetX + _posX, offsetY + _posY + textOffset, _width, _textAlign, _height);
+ }
+
+ //_gameRef->_renderer->_rectList.add(new CBActiveRect(_gameRef, this, NULL, OffsetX + _posX, OffsetY + _posY, _width, _height, 100, 100, false));
+
+ return STATUS_OK;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIText::loadFile(const char *filename) {
+ byte *buffer = _gameRef->_fileManager->readWholeFile(filename);
+ if (buffer == NULL) {
+ _gameRef->LOG(0, "CUIText::LoadFile failed for file '%s'", filename);
+ return STATUS_FAILED;
+ }
+
+ bool ret;
+
+ _filename = new char [strlen(filename) + 1];
+ strcpy(_filename, filename);
+
+ if (DID_FAIL(ret = loadBuffer(buffer, true))) _gameRef->LOG(0, "Error parsing STATIC file '%s'", filename);
+
+ delete [] buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(STATIC)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(DISABLED)
+TOKEN_DEF(VISIBLE)
+TOKEN_DEF(BACK)
+TOKEN_DEF(IMAGE)
+TOKEN_DEF(FONT)
+TOKEN_DEF(TEXT_ALIGN)
+TOKEN_DEF(VERTICAL_ALIGN)
+TOKEN_DEF(TEXT)
+TOKEN_DEF(X)
+TOKEN_DEF(Y)
+TOKEN_DEF(WIDTH)
+TOKEN_DEF(HEIGHT)
+TOKEN_DEF(CURSOR)
+TOKEN_DEF(NAME)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(PARENT_NOTIFY)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+bool CUIText::loadBuffer(byte *buffer, bool complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(STATIC)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(DISABLED)
+ TOKEN_TABLE(VISIBLE)
+ TOKEN_TABLE(BACK)
+ TOKEN_TABLE(IMAGE)
+ TOKEN_TABLE(FONT)
+ TOKEN_TABLE(TEXT_ALIGN)
+ TOKEN_TABLE(VERTICAL_ALIGN)
+ TOKEN_TABLE(TEXT)
+ TOKEN_TABLE(X)
+ TOKEN_TABLE(Y)
+ TOKEN_TABLE(WIDTH)
+ TOKEN_TABLE(HEIGHT)
+ TOKEN_TABLE(CURSOR)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(PARENT_NOTIFY)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd = 2;
+ CBParser parser(_gameRef);
+
+ if (complete) {
+ if (parser.getCommand((char **)&buffer, commands, (char **)&params) != TOKEN_STATIC) {
+ _gameRef->LOG(0, "'STATIC' keyword expected.");
+ return STATUS_FAILED;
+ }
+ buffer = params;
+ }
+
+ while (cmd > 0 && (cmd = parser.getCommand((char **)&buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (DID_FAIL(loadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ setName((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ setCaption((char *)params);
+ break;
+
+ case TOKEN_BACK:
+ delete _back;
+ _back = new CUITiledImage(_gameRef);
+ if (!_back || DID_FAIL(_back->loadFile((char *)params))) {
+ delete _back;
+ _back = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE:
+ delete _image;
+ _image = new CBSprite(_gameRef);
+ if (!_image || DID_FAIL(_image->loadFile((char *)params))) {
+ delete _image;
+ _image = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_FONT:
+ if (_font) _gameRef->_fontStorage->removeFont(_font);
+ _font = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_font) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_TEXT:
+ setText((char *)params);
+ _gameRef->_stringTable->expand(&_text);
+ break;
+
+ case TOKEN_TEXT_ALIGN:
+ if (scumm_stricmp((char *)params, "left") == 0) _textAlign = TAL_LEFT;
+ else if (scumm_stricmp((char *)params, "right") == 0) _textAlign = TAL_RIGHT;
+ else _textAlign = TAL_CENTER;
+ break;
+
+ case TOKEN_VERTICAL_ALIGN:
+ if (scumm_stricmp((char *)params, "top") == 0) _verticalAlign = VAL_TOP;
+ else if (scumm_stricmp((char *)params, "bottom") == 0) _verticalAlign = VAL_BOTTOM;
+ else _verticalAlign = VAL_CENTER;
+ break;
+
+ case TOKEN_X:
+ parser.scanStr((char *)params, "%d", &_posX);
+ break;
+
+ case TOKEN_Y:
+ parser.scanStr((char *)params, "%d", &_posY);
+ break;
+
+ case TOKEN_WIDTH:
+ parser.scanStr((char *)params, "%d", &_width);
+ break;
+
+ case TOKEN_HEIGHT:
+ parser.scanStr((char *)params, "%d", &_height);
+ break;
+
+ case TOKEN_CURSOR:
+ delete _cursor;
+ _cursor = new CBSprite(_gameRef);
+ if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) {
+ delete _cursor;
+ _cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_SCRIPT:
+ addScript((char *)params);
+ break;
+
+ case TOKEN_PARENT_NOTIFY:
+ parser.scanStr((char *)params, "%b", &_parentNotify);
+ break;
+
+ case TOKEN_DISABLED:
+ parser.scanStr((char *)params, "%b", &_disable);
+ break;
+
+ case TOKEN_VISIBLE:
+ parser.scanStr((char *)params, "%b", &_visible);
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ parseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ _gameRef->LOG(0, "Syntax error in STATIC definition");
+ return STATUS_FAILED;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ _gameRef->LOG(0, "Error loading STATIC definition");
+ return STATUS_FAILED;
+ }
+
+ correctSize();
+
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIText::saveAsText(CBDynBuffer *buffer, int indent) {
+ buffer->putTextIndent(indent, "STATIC\n");
+ buffer->putTextIndent(indent, "{\n");
+
+ buffer->putTextIndent(indent + 2, "NAME=\"%s\"\n", _name);
+ buffer->putTextIndent(indent + 2, "CAPTION=\"%s\"\n", getCaption());
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ if (_back && _back->_filename)
+ buffer->putTextIndent(indent + 2, "BACK=\"%s\"\n", _back->_filename);
+
+ if (_image && _image->_filename)
+ buffer->putTextIndent(indent + 2, "IMAGE=\"%s\"\n", _image->_filename);
+
+ if (_font && _font->_filename)
+ buffer->putTextIndent(indent + 2, "FONT=\"%s\"\n", _font->_filename);
+
+ if (_cursor && _cursor->_filename)
+ buffer->putTextIndent(indent + 2, "CURSOR=\"%s\"\n", _cursor->_filename);
+
+ if (_text)
+ buffer->putTextIndent(indent + 2, "TEXT=\"%s\"\n", _text);
+
+ switch (_textAlign) {
+ case TAL_LEFT:
+ buffer->putTextIndent(indent + 2, "TEXT_ALIGN=\"%s\"\n", "left");
+ break;
+ case TAL_RIGHT:
+ buffer->putTextIndent(indent + 2, "TEXT_ALIGN=\"%s\"\n", "right");
+ break;
+ case TAL_CENTER:
+ buffer->putTextIndent(indent + 2, "TEXT_ALIGN=\"%s\"\n", "center");
+ break;
+ default:
+ error("CUIText::SaveAsText - Unhandled enum");
+ break;
+ }
+
+ switch (_verticalAlign) {
+ case VAL_TOP:
+ buffer->putTextIndent(indent + 2, "VERTICAL_ALIGN=\"%s\"\n", "top");
+ break;
+ case VAL_BOTTOM:
+ buffer->putTextIndent(indent + 2, "VERTICAL_ALIGN=\"%s\"\n", "bottom");
+ break;
+ case VAL_CENTER:
+ buffer->putTextIndent(indent + 2, "VERTICAL_ALIGN=\"%s\"\n", "center");
+ break;
+ default:
+ error("UIText::SaveAsText - Unhandled enum value: NUM_VERTICAL_ALIGN");
+ }
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ buffer->putTextIndent(indent + 2, "X=%d\n", _posX);
+ buffer->putTextIndent(indent + 2, "Y=%d\n", _posY);
+ buffer->putTextIndent(indent + 2, "WIDTH=%d\n", _width);
+ buffer->putTextIndent(indent + 2, "HEIGHT=%d\n", _height);
+
+ buffer->putTextIndent(indent + 2, "DISABLED=%s\n", _disable ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "VISIBLE=%s\n", _visible ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "PARENT_NOTIFY=%s\n", _parentNotify ? "TRUE" : "FALSE");
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ // scripts
+ for (int i = 0; i < _scripts.getSize(); i++) {
+ buffer->putTextIndent(indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
+ }
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ // editor properties
+ CBBase::saveAsText(buffer, indent + 2);
+
+ buffer->putTextIndent(indent, "}\n");
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+bool CUIText::scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name) {
+ //////////////////////////////////////////////////////////////////////////
+ // SizeToFit
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "SizeToFit") == 0) {
+ stack->correctParams(0);
+ sizeToFit();
+ stack->pushNULL();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // HeightToFit
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "HeightToFit") == 0) {
+ stack->correctParams(0);
+ if (_font && _text) _height = _font->getTextHeight((byte *)_text, _width);
+ stack->pushNULL();
+ return STATUS_OK;
+ }
+
+ else return CUIObject::scCallMethod(script, stack, thisStack, name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CUIText::scGetProperty(const char *name) {
+ _scValue->setNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "Type") == 0) {
+ _scValue->setString("static");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // TextAlign
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "TextAlign") == 0) {
+ _scValue->setInt(_textAlign);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // VerticalAlign
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "VerticalAlign") == 0) {
+ _scValue->setInt(_verticalAlign);
+ return _scValue;
+ }
+
+ else return CUIObject::scGetProperty(name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIText::scSetProperty(const char *name, CScValue *value) {
+ //////////////////////////////////////////////////////////////////////////
+ // TextAlign
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "TextAlign") == 0) {
+ int i = value->getInt();
+ if (i < 0 || i >= NUM_TEXT_ALIGN) i = 0;
+ _textAlign = (TTextAlign)i;
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // VerticalAlign
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "VerticalAlign") == 0) {
+ int i = value->getInt();
+ if (i < 0 || i >= NUM_VERTICAL_ALIGN) i = 0;
+ _verticalAlign = (TVerticalAlign)i;
+ return STATUS_OK;
+ }
+
+ else return CUIObject::scSetProperty(name, value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CUIText::scToString() {
+ return "[static]";
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIText::persist(CBPersistMgr *persistMgr) {
+
+ CUIObject::persist(persistMgr);
+ persistMgr->transfer(TMEMBER_INT(_textAlign));
+ persistMgr->transfer(TMEMBER_INT(_verticalAlign));
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIText::sizeToFit() {
+ if (_font && _text) {
+ _width = _font->getTextWidth((byte *)_text);
+ _height = _font->getTextHeight((byte *)_text, _width);
+ }
+ return STATUS_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/ui/UIText.h b/engines/wintermute/ui/UIText.h
new file mode 100644
index 0000000000..62fbf00b0a
--- /dev/null
+++ b/engines/wintermute/ui/UIText.h
@@ -0,0 +1,60 @@
+/* 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
+ */
+
+#ifndef WINTERMUTE_UITEXT_H
+#define WINTERMUTE_UITEXT_H
+
+
+#include "UIObject.h"
+
+namespace WinterMute {
+
+class CUIText : public CUIObject {
+private:
+ bool sizeToFit();
+public:
+ virtual bool display(int offsetX, int offsetY);
+ DECLARE_PERSISTENT(CUIText, CUIObject)
+ CUIText(CBGame *inGame = NULL);
+ virtual ~CUIText();
+ TTextAlign _textAlign;
+ TVerticalAlign _verticalAlign;
+ bool loadFile(const char *filename);
+ bool loadBuffer(byte *buffer, bool complete = true);
+ virtual bool saveAsText(CBDynBuffer *buffer, int indent);
+
+ // scripting interface
+ virtual CScValue *scGetProperty(const char *name);
+ virtual bool scSetProperty(const char *name, CScValue *value);
+ virtual bool scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name);
+ virtual const char *scToString();
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/ui/UITiledImage.cpp b/engines/wintermute/ui/UITiledImage.cpp
new file mode 100644
index 0000000000..b80ae76978
--- /dev/null
+++ b/engines/wintermute/ui/UITiledImage.cpp
@@ -0,0 +1,370 @@
+/* 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/dcgf.h"
+#include "engines/wintermute/ui/UITiledImage.h"
+#include "engines/wintermute/base/gfx/base_surface.h"
+#include "engines/wintermute/base/BDynBuffer.h"
+#include "engines/wintermute/base/BParser.h"
+#include "engines/wintermute/base/BGame.h"
+#include "engines/wintermute/base/BSubFrame.h"
+#include "engines/wintermute/base/BFileManager.h"
+#include "engines/wintermute/PlatformSDL.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CUITiledImage, false)
+
+//////////////////////////////////////////////////////////////////////////
+CUITiledImage::CUITiledImage(CBGame *inGame): CBObject(inGame) {
+ _image = NULL;
+
+ CBPlatform::setRectEmpty(&_upLeft);
+ CBPlatform::setRectEmpty(&_upMiddle);
+ CBPlatform::setRectEmpty(&_upRight);
+ CBPlatform::setRectEmpty(&_middleLeft);
+ CBPlatform::setRectEmpty(&_middleMiddle);
+ CBPlatform::setRectEmpty(&_middleRight);
+ CBPlatform::setRectEmpty(&_downLeft);
+ CBPlatform::setRectEmpty(&_downMiddle);
+ CBPlatform::setRectEmpty(&_downRight);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CUITiledImage::~CUITiledImage() {
+ delete _image;
+ _image = NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUITiledImage::display(int x, int y, int width, int height) {
+ if (!_image) return STATUS_FAILED;
+
+ int tileWidth = _middleMiddle.right - _middleMiddle.left;
+ int tileHeight = _middleMiddle.bottom - _middleMiddle.top;
+
+ int nuColumns = (width - (_middleLeft.right - _middleLeft.left) - (_middleRight.right - _middleRight.left)) / tileWidth;
+ int nuRows = (height - (_upMiddle.bottom - _upMiddle.top) - (_downMiddle.bottom - _downMiddle.top)) / tileHeight;
+
+ int col, row;
+
+ _gameRef->_renderer->startSpriteBatch();
+
+ // top left/right
+ _image->_surface->displayTrans(x, y, _upLeft);
+ _image->_surface->displayTrans(x + (_upLeft.right - _upLeft.left) + nuColumns * tileWidth, y, _upRight);
+
+ // bottom left/right
+ _image->_surface->displayTrans(x, y + (_upMiddle.bottom - _upMiddle.top) + nuRows * tileHeight, _downLeft);
+ _image->_surface->displayTrans(x + (_upLeft.right - _upLeft.left) + nuColumns * tileWidth, y + (_upMiddle.bottom - _upMiddle.top) + nuRows * tileHeight, _downRight);
+
+ // left/right
+ int yyy = y + (_upMiddle.bottom - _upMiddle.top);
+ for (row = 0; row < nuRows; row++) {
+ _image->_surface->displayTrans(x, yyy, _middleLeft);
+ _image->_surface->displayTrans(x + (_middleLeft.right - _middleLeft.left) + nuColumns * tileWidth, yyy, _middleRight);
+ yyy += tileWidth;
+ }
+
+ // top/bottom
+ int xxx = x + (_upLeft.right - _upLeft.left);
+ for (col = 0; col < nuColumns; col++) {
+ _image->_surface->displayTrans(xxx, y, _upMiddle);
+ _image->_surface->displayTrans(xxx, y + (_upMiddle.bottom - _upMiddle.top) + nuRows * tileHeight, _downMiddle);
+ xxx += tileWidth;
+ }
+
+ // tiles
+ yyy = y + (_upMiddle.bottom - _upMiddle.top);
+ for (row = 0; row < nuRows; row++) {
+ xxx = x + (_upLeft.right - _upLeft.left);
+ for (col = 0; col < nuColumns; col++) {
+ _image->_surface->displayTrans(xxx, yyy, _middleMiddle);
+ xxx += tileWidth;
+ }
+ yyy += tileWidth;
+ }
+
+ _gameRef->_renderer->endSpriteBatch();
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUITiledImage::loadFile(const char *filename) {
+ byte *buffer = _gameRef->_fileManager->readWholeFile(filename);
+ if (buffer == NULL) {
+ _gameRef->LOG(0, "CUITiledImage::LoadFile failed for file '%s'", filename);
+ return STATUS_FAILED;
+ }
+
+ bool ret;
+
+ _filename = new char [strlen(filename) + 1];
+ strcpy(_filename, filename);
+
+ if (DID_FAIL(ret = loadBuffer(buffer, true))) _gameRef->LOG(0, "Error parsing TILED_IMAGE file '%s'", filename);
+
+
+ delete [] buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(TILED_IMAGE)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(IMAGE)
+TOKEN_DEF(UP_LEFT)
+TOKEN_DEF(UP_RIGHT)
+TOKEN_DEF(UP_MIDDLE)
+TOKEN_DEF(DOWN_LEFT)
+TOKEN_DEF(DOWN_RIGHT)
+TOKEN_DEF(DOWN_MIDDLE)
+TOKEN_DEF(MIDDLE_LEFT)
+TOKEN_DEF(MIDDLE_RIGHT)
+TOKEN_DEF(MIDDLE_MIDDLE)
+TOKEN_DEF(VERTICAL_TILES)
+TOKEN_DEF(HORIZONTAL_TILES)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+bool CUITiledImage::loadBuffer(byte *buffer, bool complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(TILED_IMAGE)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(IMAGE)
+ TOKEN_TABLE(UP_LEFT)
+ TOKEN_TABLE(UP_RIGHT)
+ TOKEN_TABLE(UP_MIDDLE)
+ TOKEN_TABLE(DOWN_LEFT)
+ TOKEN_TABLE(DOWN_RIGHT)
+ TOKEN_TABLE(DOWN_MIDDLE)
+ TOKEN_TABLE(MIDDLE_LEFT)
+ TOKEN_TABLE(MIDDLE_RIGHT)
+ TOKEN_TABLE(MIDDLE_MIDDLE)
+ TOKEN_TABLE(VERTICAL_TILES)
+ TOKEN_TABLE(HORIZONTAL_TILES)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd;
+ CBParser parser(_gameRef);
+ bool hTiles = false, vTiles = false;
+ int h1 = 0, h2 = 0, h3 = 0;
+ int v1 = 0, v2 = 0, v3 = 0;
+
+ if (complete) {
+ if (parser.getCommand((char **)&buffer, commands, (char **)&params) != TOKEN_TILED_IMAGE) {
+ _gameRef->LOG(0, "'TILED_IMAGE' keyword expected.");
+ return STATUS_FAILED;
+ }
+ buffer = params;
+ }
+
+ while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)&params)) > 0) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (DID_FAIL(loadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_IMAGE:
+ delete _image;
+ _image = new CBSubFrame(_gameRef);
+ if (!_image || DID_FAIL(_image->setSurface((char *)params))) {
+ delete _image;
+ _image = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_UP_LEFT:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_upLeft.left, &_upLeft.top, &_upLeft.right, &_upLeft.bottom);
+ break;
+
+ case TOKEN_UP_RIGHT:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_upRight.left, &_upRight.top, &_upRight.right, &_upRight.bottom);
+ break;
+
+ case TOKEN_UP_MIDDLE:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_upMiddle.left, &_upMiddle.top, &_upMiddle.right, &_upMiddle.bottom);
+ break;
+
+ case TOKEN_DOWN_LEFT:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_downLeft.left, &_downLeft.top, &_downLeft.right, &_downLeft.bottom);
+ break;
+
+ case TOKEN_DOWN_RIGHT:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_downRight.left, &_downRight.top, &_downRight.right, &_downRight.bottom);
+ break;
+
+ case TOKEN_DOWN_MIDDLE:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_downMiddle.left, &_downMiddle.top, &_downMiddle.right, &_downMiddle.bottom);
+ break;
+
+ case TOKEN_MIDDLE_LEFT:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_middleLeft.left, &_middleLeft.top, &_middleLeft.right, &_middleLeft.bottom);
+ break;
+
+ case TOKEN_MIDDLE_RIGHT:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_middleRight.left, &_middleRight.top, &_middleRight.right, &_middleRight.bottom);
+ break;
+
+ case TOKEN_MIDDLE_MIDDLE:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_middleMiddle.left, &_middleMiddle.top, &_middleMiddle.right, &_middleMiddle.bottom);
+ break;
+
+ case TOKEN_HORIZONTAL_TILES:
+ parser.scanStr((char *)params, "%d,%d,%d", &h1, &h2, &h3);
+ hTiles = true;
+ break;
+
+ case TOKEN_VERTICAL_TILES:
+ parser.scanStr((char *)params, "%d,%d,%d", &v1, &v2, &v3);
+ vTiles = true;
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ parseEditorProperty(params, false);
+ break;
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ _gameRef->LOG(0, "Syntax error in TILED_IMAGE definition");
+ return STATUS_FAILED;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ _gameRef->LOG(0, "Error loading TILED_IMAGE definition");
+ return STATUS_FAILED;
+ }
+
+ if (vTiles && hTiles) {
+ // up row
+ CBPlatform::setRect(&_upLeft, 0, 0, h1, v1);
+ CBPlatform::setRect(&_upMiddle, h1, 0, h1 + h2, v1);
+ CBPlatform::setRect(&_upRight, h1 + h2, 0, h1 + h2 + h3, v1);
+
+ // middle row
+ CBPlatform::setRect(&_middleLeft, 0, v1, h1, v1 + v2);
+ CBPlatform::setRect(&_middleMiddle, h1, v1, h1 + h2, v1 + v2);
+ CBPlatform::setRect(&_middleRight, h1 + h2, v1, h1 + h2 + h3, v1 + v2);
+
+ // down row
+ CBPlatform::setRect(&_downLeft, 0, v1 + v2, h1, v1 + v2 + v3);
+ CBPlatform::setRect(&_downMiddle, h1, v1 + v2, h1 + h2, v1 + v2 + v3);
+ CBPlatform::setRect(&_downRight, h1 + h2, v1 + v2, h1 + h2 + h3, v1 + v2 + v3);
+ }
+
+ // default
+ if (_image && _image->_surface) {
+ int width = _image->_surface->getWidth() / 3;
+ int height = _image->_surface->getHeight() / 3;
+
+ if (CBPlatform::isRectEmpty(&_upLeft)) CBPlatform::setRect(&_upLeft, 0, 0, width, height);
+ if (CBPlatform::isRectEmpty(&_upMiddle)) CBPlatform::setRect(&_upMiddle, width, 0, 2 * width, height);
+ if (CBPlatform::isRectEmpty(&_upRight)) CBPlatform::setRect(&_upRight, 2 * width, 0, 3 * width, height);
+
+ if (CBPlatform::isRectEmpty(&_middleLeft)) CBPlatform::setRect(&_middleLeft, 0, height, width, 2 * height);
+ if (CBPlatform::isRectEmpty(&_middleMiddle)) CBPlatform::setRect(&_middleMiddle, width, height, 2 * width, 2 * height);
+ if (CBPlatform::isRectEmpty(&_middleRight)) CBPlatform::setRect(&_middleRight, 2 * width, height, 3 * width, 2 * height);
+
+ if (CBPlatform::isRectEmpty(&_downLeft)) CBPlatform::setRect(&_downLeft, 0, 2 * height, width, 3 * height);
+ if (CBPlatform::isRectEmpty(&_downMiddle)) CBPlatform::setRect(&_downMiddle, width, 2 * height, 2 * width, 3 * height);
+ if (CBPlatform::isRectEmpty(&_downRight)) CBPlatform::setRect(&_downRight, 2 * width, 2 * height, 3 * width, 3 * height);
+ }
+
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUITiledImage::saveAsText(CBDynBuffer *buffer, int indent) {
+ buffer->putTextIndent(indent, "TILED_IMAGE\n");
+ buffer->putTextIndent(indent, "{\n");
+
+ if (_image && _image->_surfaceFilename)
+ buffer->putTextIndent(indent + 2, "IMAGE=\"%s\"\n", _image->_surfaceFilename);
+
+ int h1, h2, h3;
+ int v1, v2, v3;
+
+ h1 = _upLeft.right;
+ h2 = _upMiddle.right - _upMiddle.left;
+ h3 = _upRight.right - _upRight.left;
+
+ v1 = _upLeft.bottom;
+ v2 = _middleLeft.bottom - _middleLeft.top;
+ v3 = _downLeft.bottom - _downLeft.top;
+
+
+ buffer->putTextIndent(indent + 2, "VERTICAL_TILES { %d, %d, %d }\n", v1, v2, v3);
+ buffer->putTextIndent(indent + 2, "HORIZONTAL_TILES { %d, %d, %d }\n", h1, h2, h3);
+
+ // editor properties
+ CBBase::saveAsText(buffer, indent + 2);
+
+ buffer->putTextIndent(indent, "}\n");
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+void CUITiledImage::correctSize(int *width, int *height) {
+ int tileWidth = _middleMiddle.right - _middleMiddle.left;
+ int tileHeight = _middleMiddle.bottom - _middleMiddle.top;
+
+ int nuColumns = (*width - (_middleLeft.right - _middleLeft.left) - (_middleRight.right - _middleRight.left)) / tileWidth;
+ int nuRows = (*height - (_upMiddle.bottom - _upMiddle.top) - (_downMiddle.bottom - _downMiddle.top)) / tileHeight;
+
+ *width = (_middleLeft.right - _middleLeft.left) + (_middleRight.right - _middleRight.left) + nuColumns * tileWidth;
+ *height = (_upMiddle.bottom - _upMiddle.top) + (_downMiddle.bottom - _downMiddle.top) + nuRows * tileHeight;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUITiledImage::persist(CBPersistMgr *persistMgr) {
+ CBObject::persist(persistMgr);
+
+ persistMgr->transfer(TMEMBER(_downLeft));
+ persistMgr->transfer(TMEMBER(_downMiddle));
+ persistMgr->transfer(TMEMBER(_downRight));
+ persistMgr->transfer(TMEMBER(_image));
+ persistMgr->transfer(TMEMBER(_middleLeft));
+ persistMgr->transfer(TMEMBER(_middleMiddle));
+ persistMgr->transfer(TMEMBER(_middleRight));
+ persistMgr->transfer(TMEMBER(_upLeft));
+ persistMgr->transfer(TMEMBER(_upMiddle));
+ persistMgr->transfer(TMEMBER(_upRight));
+
+ return STATUS_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/ui/UITiledImage.h b/engines/wintermute/ui/UITiledImage.h
new file mode 100644
index 0000000000..379af85e81
--- /dev/null
+++ b/engines/wintermute/ui/UITiledImage.h
@@ -0,0 +1,63 @@
+/* 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
+ */
+
+#ifndef WINTERMUTE_UITILEDIMAGE_H
+#define WINTERMUTE_UITILEDIMAGE_H
+
+
+#include "UIObject.h"
+#include "common/rect.h"
+
+namespace WinterMute {
+class CBSubFrame;
+class CUITiledImage : public CBObject {
+public:
+ DECLARE_PERSISTENT(CUITiledImage, CBObject)
+ void correctSize(int *width, int *height);
+ bool loadFile(const char *filename);
+ bool loadBuffer(byte *buffer, bool complete = true);
+ virtual bool saveAsText(CBDynBuffer *buffer, int indent);
+
+ bool display(int x, int y, int width, int height);
+ CUITiledImage(CBGame *inGame = NULL);
+ virtual ~CUITiledImage();
+ CBSubFrame *_image;
+ Rect32 _upLeft;
+ Rect32 _upMiddle;
+ Rect32 _upRight;
+ Rect32 _middleLeft;
+ Rect32 _middleMiddle;
+ Rect32 _middleRight;
+ Rect32 _downLeft;
+ Rect32 _downMiddle;
+ Rect32 _downRight;
+};
+
+} // end of namespace WinterMute
+
+#endif
diff --git a/engines/wintermute/ui/UIWindow.cpp b/engines/wintermute/ui/UIWindow.cpp
new file mode 100644
index 0000000000..1c6931b4a6
--- /dev/null
+++ b/engines/wintermute/ui/UIWindow.cpp
@@ -0,0 +1,1327 @@
+/* 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/dcgf.h"
+#include "engines/wintermute/ui/UIWindow.h"
+#include "engines/wintermute/base/BGame.h"
+#include "engines/wintermute/base/BParser.h"
+#include "engines/wintermute/base/BActiveRect.h"
+#include "engines/wintermute/base/BDynBuffer.h"
+#include "engines/wintermute/base/BKeyboardState.h"
+#include "engines/wintermute/base/scriptables/ScValue.h"
+#include "engines/wintermute/ui/UIButton.h"
+#include "engines/wintermute/ui/UIEdit.h"
+#include "engines/wintermute/ui/UIText.h"
+#include "engines/wintermute/ui/UITiledImage.h"
+#include "engines/wintermute/base/BViewport.h"
+#include "engines/wintermute/base/font/BFontStorage.h"
+#include "engines/wintermute/base/font/BFont.h"
+#include "engines/wintermute/base/BStringTable.h"
+#include "engines/wintermute/base/scriptables/ScScript.h"
+#include "engines/wintermute/base/scriptables/ScStack.h"
+#include "engines/wintermute/base/BSprite.h"
+#include "engines/wintermute/base/BFileManager.h"
+#include "engines/wintermute/PlatformSDL.h"
+
+namespace WinterMute {
+
+IMPLEMENT_PERSISTENT(CUIWindow, false)
+
+//////////////////////////////////////////////////////////////////////////
+CUIWindow::CUIWindow(CBGame *inGame): CUIObject(inGame) {
+ CBPlatform::setRectEmpty(&_titleRect);
+ CBPlatform::setRectEmpty(&_dragRect);
+ _titleAlign = TAL_LEFT;
+ _transparent = false;
+
+ _backInactive = NULL;
+ _fontInactive = NULL;
+ _imageInactive = NULL;
+
+ _type = UI_WINDOW;
+ _canFocus = true;
+
+ _dragging = false;
+ _dragFrom.x = _dragFrom.y = 0;
+
+ _mode = WINDOW_NORMAL;
+ _shieldWindow = NULL;
+ _shieldButton = NULL;
+
+ _fadeColor = 0x00000000;
+ _fadeBackground = false;
+
+ _ready = true;
+ _isMenu = false;
+ _inGame = false;
+
+ _clipContents = false;
+ _viewport = NULL;
+
+ _pauseMusic = true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CUIWindow::~CUIWindow() {
+ close();
+ cleanup();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CUIWindow::cleanup() {
+ delete _shieldWindow;
+ delete _shieldButton;
+ delete _viewport;
+ _shieldWindow = NULL;
+ _shieldButton = NULL;
+ _viewport = NULL;
+
+ delete _backInactive;
+ if (!_sharedFonts && _fontInactive) _gameRef->_fontStorage->removeFont(_fontInactive);
+ if (!_sharedImages && _imageInactive) delete _imageInactive;
+
+ for (int i = 0; i < _widgets.getSize(); i++) delete _widgets[i];
+ _widgets.removeAll();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::display(int offsetX, int offsetY) {
+ // go exclusive
+ if (_mode == WINDOW_EXCLUSIVE || _mode == WINDOW_SYSTEM_EXCLUSIVE) {
+ if (!_shieldWindow) _shieldWindow = new CUIWindow(_gameRef);
+ if (_shieldWindow) {
+ _shieldWindow->_posX = _shieldWindow->_posY = 0;
+ _shieldWindow->_width = _gameRef->_renderer->_width;
+ _shieldWindow->_height = _gameRef->_renderer->_height;
+
+ _shieldWindow->display();
+ }
+ } else if (_isMenu) {
+ if (!_shieldButton) {
+ _shieldButton = new CUIButton(_gameRef);
+ _shieldButton->setName("close");
+ _shieldButton->setListener(this, _shieldButton, 0);
+ _shieldButton->_parent = this;
+ }
+ if (_shieldButton) {
+ _shieldButton->_posX = _shieldButton->_posY = 0;
+ _shieldButton->_width = _gameRef->_renderer->_width;
+ _shieldButton->_height = _gameRef->_renderer->_height;
+
+ _shieldButton->display();
+ }
+ }
+
+ if (!_visible)
+ return STATUS_OK;
+
+ if (_fadeBackground) _gameRef->_renderer->fadeToColor(_fadeColor);
+
+ if (_dragging) {
+ _posX += (_gameRef->_mousePos.x - _dragFrom.x);
+ _posY += (_gameRef->_mousePos.y - _dragFrom.y);
+
+ _dragFrom.x = _gameRef->_mousePos.x;
+ _dragFrom.y = _gameRef->_mousePos.y;
+ }
+
+ if (!_focusedWidget || (!_focusedWidget->_canFocus || _focusedWidget->_disable || !_focusedWidget->_visible)) {
+ moveFocus();
+ }
+
+ bool popViewport = false;
+ if (_clipContents) {
+ if (!_viewport) _viewport = new CBViewport(_gameRef);
+ if (_viewport) {
+ _viewport->setRect(_posX + offsetX, _posY + offsetY, _posX + _width + offsetX, _posY + _height + offsetY);
+ _gameRef->pushViewport(_viewport);
+ popViewport = true;
+ }
+ }
+
+
+ CUITiledImage *back = _back;
+ CBSprite *image = _image;
+ CBFont *font = _font;
+
+ if (!isFocused()) {
+ if (_backInactive) back = _backInactive;
+ if (_imageInactive) image = _imageInactive;
+ if (_fontInactive) font = _fontInactive;
+ }
+
+ if (_alphaColor != 0)
+ _gameRef->_renderer->_forceAlphaColor = _alphaColor;
+ if (back)
+ back->display(_posX + offsetX, _posY + offsetY, _width, _height);
+ if (image)
+ image->draw(_posX + offsetX, _posY + offsetY, _transparent ? NULL : this);
+
+ if (!CBPlatform::isRectEmpty(&_titleRect) && font && _text) {
+ font->drawText((byte *)_text, _posX + offsetX + _titleRect.left, _posY + offsetY + _titleRect.top, _titleRect.right - _titleRect.left, _titleAlign, _titleRect.bottom - _titleRect.top);
+ }
+
+ if (!_transparent && !image)
+ _gameRef->_renderer->_rectList.add(new CBActiveRect(_gameRef, this, NULL, _posX + offsetX, _posY + offsetY, _width, _height, 100, 100, false));
+
+ for (int i = 0; i < _widgets.getSize(); i++) {
+ _widgets[i]->display(_posX + offsetX, _posY + offsetY);
+ }
+
+ if (_alphaColor != 0)
+ _gameRef->_renderer->_forceAlphaColor = 0;
+
+ if (popViewport)
+ _gameRef->popViewport();
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::loadFile(const char *filename) {
+ byte *buffer = _gameRef->_fileManager->readWholeFile(filename);
+ if (buffer == NULL) {
+ _gameRef->LOG(0, "CUIWindow::LoadFile failed for file '%s'", filename);
+ return STATUS_FAILED;
+ }
+
+ bool ret;
+
+ _filename = new char [strlen(filename) + 1];
+ strcpy(_filename, filename);
+
+ if (DID_FAIL(ret = loadBuffer(buffer, true))) _gameRef->LOG(0, "Error parsing WINDOW file '%s'", filename);
+
+ delete [] buffer;
+
+ return ret;
+}
+
+
+TOKEN_DEF_START
+TOKEN_DEF(WINDOW)
+TOKEN_DEF(ALPHA_COLOR)
+TOKEN_DEF(ALPHA)
+TOKEN_DEF(TEMPLATE)
+TOKEN_DEF(DISABLED)
+TOKEN_DEF(VISIBLE)
+TOKEN_DEF(BACK_INACTIVE)
+TOKEN_DEF(BACK)
+TOKEN_DEF(IMAGE_INACTIVE)
+TOKEN_DEF(IMAGE)
+TOKEN_DEF(FONT_INACTIVE)
+TOKEN_DEF(FONT)
+TOKEN_DEF(TITLE_ALIGN)
+TOKEN_DEF(TITLE_RECT)
+TOKEN_DEF(TITLE)
+TOKEN_DEF(DRAG_RECT)
+TOKEN_DEF(X)
+TOKEN_DEF(Y)
+TOKEN_DEF(WIDTH)
+TOKEN_DEF(HEIGHT)
+TOKEN_DEF(FADE_ALPHA)
+TOKEN_DEF(FADE_COLOR)
+TOKEN_DEF(CURSOR)
+TOKEN_DEF(NAME)
+TOKEN_DEF(BUTTON)
+TOKEN_DEF(STATIC)
+TOKEN_DEF(TRANSPARENT)
+TOKEN_DEF(SCRIPT)
+TOKEN_DEF(CAPTION)
+TOKEN_DEF(PARENT_NOTIFY)
+TOKEN_DEF(MENU)
+TOKEN_DEF(IN_GAME)
+TOKEN_DEF(CLIP_CONTENTS)
+TOKEN_DEF(PAUSE_MUSIC)
+TOKEN_DEF(EDITOR_PROPERTY)
+TOKEN_DEF(EDIT)
+TOKEN_DEF_END
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::loadBuffer(byte *buffer, bool complete) {
+ TOKEN_TABLE_START(commands)
+ TOKEN_TABLE(WINDOW)
+ TOKEN_TABLE(ALPHA_COLOR)
+ TOKEN_TABLE(ALPHA)
+ TOKEN_TABLE(TEMPLATE)
+ TOKEN_TABLE(DISABLED)
+ TOKEN_TABLE(VISIBLE)
+ TOKEN_TABLE(BACK_INACTIVE)
+ TOKEN_TABLE(BACK)
+ TOKEN_TABLE(IMAGE_INACTIVE)
+ TOKEN_TABLE(IMAGE)
+ TOKEN_TABLE(FONT_INACTIVE)
+ TOKEN_TABLE(FONT)
+ TOKEN_TABLE(TITLE_ALIGN)
+ TOKEN_TABLE(TITLE_RECT)
+ TOKEN_TABLE(TITLE)
+ TOKEN_TABLE(DRAG_RECT)
+ TOKEN_TABLE(X)
+ TOKEN_TABLE(Y)
+ TOKEN_TABLE(WIDTH)
+ TOKEN_TABLE(HEIGHT)
+ TOKEN_TABLE(FADE_ALPHA)
+ TOKEN_TABLE(FADE_COLOR)
+ TOKEN_TABLE(CURSOR)
+ TOKEN_TABLE(NAME)
+ TOKEN_TABLE(BUTTON)
+ TOKEN_TABLE(STATIC)
+ TOKEN_TABLE(TRANSPARENT)
+ TOKEN_TABLE(SCRIPT)
+ TOKEN_TABLE(CAPTION)
+ TOKEN_TABLE(PARENT_NOTIFY)
+ TOKEN_TABLE(MENU)
+ TOKEN_TABLE(IN_GAME)
+ TOKEN_TABLE(CLIP_CONTENTS)
+ TOKEN_TABLE(PAUSE_MUSIC)
+ TOKEN_TABLE(EDITOR_PROPERTY)
+ TOKEN_TABLE(EDIT)
+ TOKEN_TABLE_END
+
+ byte *params;
+ int cmd = 2;
+ CBParser parser(_gameRef);
+
+ int fadeR = 0, fadeG = 0, fadeB = 0, fadeA = 0;
+ int ar = 0, ag = 0, ab = 0, alpha = 0;
+
+ if (complete) {
+ if (parser.getCommand((char **)&buffer, commands, (char **)&params) != TOKEN_WINDOW) {
+ _gameRef->LOG(0, "'WINDOW' keyword expected.");
+ return STATUS_FAILED;
+ }
+ buffer = params;
+ }
+
+ while (cmd >= PARSERR_TOKENNOTFOUND && (cmd = parser.getCommand((char **)&buffer, commands, (char **)&params)) >= PARSERR_TOKENNOTFOUND) {
+ switch (cmd) {
+ case TOKEN_TEMPLATE:
+ if (DID_FAIL(loadFile((char *)params))) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_NAME:
+ setName((char *)params);
+ break;
+
+ case TOKEN_CAPTION:
+ setCaption((char *)params);
+ break;
+
+ case TOKEN_BACK:
+ delete _back;
+ _back = new CUITiledImage(_gameRef);
+ if (!_back || DID_FAIL(_back->loadFile((char *)params))) {
+ delete _back;
+ _back = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_BACK_INACTIVE:
+ delete _backInactive;
+ _backInactive = new CUITiledImage(_gameRef);
+ if (!_backInactive || DID_FAIL(_backInactive->loadFile((char *)params))) {
+ delete _backInactive;
+ _backInactive = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE:
+ delete _image;
+ _image = new CBSprite(_gameRef);
+ if (!_image || DID_FAIL(_image->loadFile((char *)params))) {
+ delete _image;
+ _image = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_IMAGE_INACTIVE:
+ delete _imageInactive,
+ _imageInactive = new CBSprite(_gameRef);
+ if (!_imageInactive || DID_FAIL(_imageInactive->loadFile((char *)params))) {
+ delete _imageInactive;
+ _imageInactive = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_FONT:
+ if (_font) _gameRef->_fontStorage->removeFont(_font);
+ _font = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_font) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_FONT_INACTIVE:
+ if (_fontInactive) _gameRef->_fontStorage->removeFont(_fontInactive);
+ _fontInactive = _gameRef->_fontStorage->addFont((char *)params);
+ if (!_fontInactive) cmd = PARSERR_GENERIC;
+ break;
+
+ case TOKEN_TITLE:
+ setText((char *)params);
+ _gameRef->_stringTable->expand(&_text);
+ break;
+
+ case TOKEN_TITLE_ALIGN:
+ if (scumm_stricmp((char *)params, "left") == 0) _titleAlign = TAL_LEFT;
+ else if (scumm_stricmp((char *)params, "right") == 0) _titleAlign = TAL_RIGHT;
+ else _titleAlign = TAL_CENTER;
+ break;
+
+ case TOKEN_TITLE_RECT:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_titleRect.left, &_titleRect.top, &_titleRect.right, &_titleRect.bottom);
+ break;
+
+ case TOKEN_DRAG_RECT:
+ parser.scanStr((char *)params, "%d,%d,%d,%d", &_dragRect.left, &_dragRect.top, &_dragRect.right, &_dragRect.bottom);
+ break;
+
+ case TOKEN_X:
+ parser.scanStr((char *)params, "%d", &_posX);
+ break;
+
+ case TOKEN_Y:
+ parser.scanStr((char *)params, "%d", &_posY);
+ break;
+
+ case TOKEN_WIDTH:
+ parser.scanStr((char *)params, "%d", &_width);
+ break;
+
+ case TOKEN_HEIGHT:
+ parser.scanStr((char *)params, "%d", &_height);
+ break;
+
+ case TOKEN_CURSOR:
+ delete _cursor;
+ _cursor = new CBSprite(_gameRef);
+ if (!_cursor || DID_FAIL(_cursor->loadFile((char *)params))) {
+ delete _cursor;
+ _cursor = NULL;
+ cmd = PARSERR_GENERIC;
+ }
+ break;
+
+ case TOKEN_BUTTON: {
+ CUIButton *btn = new CUIButton(_gameRef);
+ if (!btn || DID_FAIL(btn->loadBuffer(params, false))) {
+ delete btn;
+ btn = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ btn->_parent = this;
+ _widgets.add(btn);
+ }
+ }
+ break;
+
+ case TOKEN_STATIC: {
+ CUIText *text = new CUIText(_gameRef);
+ if (!text || DID_FAIL(text->loadBuffer(params, false))) {
+ delete text;
+ text = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ text->_parent = this;
+ _widgets.add(text);
+ }
+ }
+ break;
+
+ case TOKEN_EDIT: {
+ CUIEdit *edit = new CUIEdit(_gameRef);
+ if (!edit || DID_FAIL(edit->loadBuffer(params, false))) {
+ delete edit;
+ edit = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ edit->_parent = this;
+ _widgets.add(edit);
+ }
+ }
+ break;
+
+ case TOKEN_WINDOW: {
+ CUIWindow *win = new CUIWindow(_gameRef);
+ if (!win || DID_FAIL(win->loadBuffer(params, false))) {
+ delete win;
+ win = NULL;
+ cmd = PARSERR_GENERIC;
+ } else {
+ win->_parent = this;
+ _widgets.add(win);
+ }
+ }
+ break;
+
+
+ case TOKEN_TRANSPARENT:
+ parser.scanStr((char *)params, "%b", &_transparent);
+ break;
+
+ case TOKEN_SCRIPT:
+ addScript((char *)params);
+ break;
+
+ case TOKEN_PARENT_NOTIFY:
+ parser.scanStr((char *)params, "%b", &_parentNotify);
+ break;
+
+ case TOKEN_PAUSE_MUSIC:
+ parser.scanStr((char *)params, "%b", &_pauseMusic);
+ break;
+
+ case TOKEN_DISABLED:
+ parser.scanStr((char *)params, "%b", &_disable);
+ break;
+
+ case TOKEN_VISIBLE:
+ parser.scanStr((char *)params, "%b", &_visible);
+ break;
+
+ case TOKEN_MENU:
+ parser.scanStr((char *)params, "%b", &_isMenu);
+ break;
+
+ case TOKEN_IN_GAME:
+ parser.scanStr((char *)params, "%b", &_inGame);
+ break;
+
+ case TOKEN_CLIP_CONTENTS:
+ parser.scanStr((char *)params, "%b", &_clipContents);
+ break;
+
+ case TOKEN_FADE_COLOR:
+ parser.scanStr((char *)params, "%d,%d,%d", &fadeR, &fadeG, &fadeB);
+ _fadeBackground = true;
+ break;
+
+ case TOKEN_FADE_ALPHA:
+ parser.scanStr((char *)params, "%d", &fadeA);
+ _fadeBackground = true;
+ break;
+
+ case TOKEN_EDITOR_PROPERTY:
+ parseEditorProperty(params, false);
+ break;
+
+ case TOKEN_ALPHA_COLOR:
+ parser.scanStr((char *)params, "%d,%d,%d", &ar, &ag, &ab);
+ break;
+
+ case TOKEN_ALPHA:
+ parser.scanStr((char *)params, "%d", &alpha);
+ break;
+
+
+ default:
+ if (DID_FAIL(_gameRef->windowLoadHook(this, (char **)&buffer, (char **)params))) {
+ cmd = PARSERR_GENERIC;
+ }
+ }
+ }
+ if (cmd == PARSERR_TOKENNOTFOUND) {
+ _gameRef->LOG(0, "Syntax error in WINDOW definition");
+ return STATUS_FAILED;
+ }
+ if (cmd == PARSERR_GENERIC) {
+ _gameRef->LOG(0, "Error loading WINDOW definition");
+ return STATUS_FAILED;
+ }
+
+ correctSize();
+
+ if (alpha != 0 && ar == 0 && ag == 0 && ab == 0) {
+ ar = ag = ab = 255;
+ }
+ _alphaColor = BYTETORGBA(ar, ag, ab, alpha);
+
+ if (_fadeBackground)
+ _fadeColor = BYTETORGBA(fadeR, fadeG, fadeB, fadeA);
+
+ _focusedWidget = NULL;
+
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::saveAsText(CBDynBuffer *buffer, int indent) {
+ buffer->putTextIndent(indent, "WINDOW\n");
+ buffer->putTextIndent(indent, "{\n");
+
+ buffer->putTextIndent(indent + 2, "NAME=\"%s\"\n", _name);
+ buffer->putTextIndent(indent + 2, "CAPTION=\"%s\"\n", getCaption());
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ if (_back && _back->_filename)
+ buffer->putTextIndent(indent + 2, "BACK=\"%s\"\n", _back->_filename);
+ if (_backInactive && _backInactive->_filename)
+ buffer->putTextIndent(indent + 2, "BACK_INACTIVE=\"%s\"\n", _backInactive->_filename);
+
+ if (_image && _image->_filename)
+ buffer->putTextIndent(indent + 2, "IMAGE=\"%s\"\n", _image->_filename);
+ if (_imageInactive && _imageInactive->_filename)
+ buffer->putTextIndent(indent + 2, "IMAGE_INACTIVE=\"%s\"\n", _imageInactive->_filename);
+
+ if (_font && _font->_filename)
+ buffer->putTextIndent(indent + 2, "FONT=\"%s\"\n", _font->_filename);
+ if (_fontInactive && _fontInactive->_filename)
+ buffer->putTextIndent(indent + 2, "FONT_INACTIVE=\"%s\"\n", _fontInactive->_filename);
+
+ if (_cursor && _cursor->_filename)
+ buffer->putTextIndent(indent + 2, "CURSOR=\"%s\"\n", _cursor->_filename);
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ if (_text)
+ buffer->putTextIndent(indent + 2, "TITLE=\"%s\"\n", _text);
+
+ switch (_titleAlign) {
+ case TAL_LEFT:
+ buffer->putTextIndent(indent + 2, "TITLE_ALIGN=\"%s\"\n", "left");
+ break;
+ case TAL_RIGHT:
+ buffer->putTextIndent(indent + 2, "TITLE_ALIGN=\"%s\"\n", "right");
+ break;
+ case TAL_CENTER:
+ buffer->putTextIndent(indent + 2, "TITLE_ALIGN=\"%s\"\n", "center");
+ break;
+ default:
+ error("UIWindow::SaveAsText - Unhandled enum-value NUM_TEXT_ALIGN");
+ }
+
+ if (!CBPlatform::isRectEmpty(&_titleRect)) {
+ buffer->putTextIndent(indent + 2, "TITLE_RECT { %d, %d, %d, %d }\n", _titleRect.left, _titleRect.top, _titleRect.right, _titleRect.bottom);
+ }
+
+ if (!CBPlatform::isRectEmpty(&_dragRect)) {
+ buffer->putTextIndent(indent + 2, "DRAG_RECT { %d, %d, %d, %d }\n", _dragRect.left, _dragRect.top, _dragRect.right, _dragRect.bottom);
+ }
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ buffer->putTextIndent(indent + 2, "X=%d\n", _posX);
+ buffer->putTextIndent(indent + 2, "Y=%d\n", _posY);
+ buffer->putTextIndent(indent + 2, "WIDTH=%d\n", _width);
+ buffer->putTextIndent(indent + 2, "HEIGHT=%d\n", _height);
+
+ buffer->putTextIndent(indent + 2, "DISABLED=%s\n", _disable ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "VISIBLE=%s\n", _visible ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "PARENT_NOTIFY=%s\n", _parentNotify ? "TRUE" : "FALSE");
+
+ buffer->putTextIndent(indent + 2, "TRANSPARENT=%s\n", _transparent ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "PAUSE_MUSIC=%s\n", _pauseMusic ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "MENU=%s\n", _isMenu ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "IN_GAME=%s\n", _inGame ? "TRUE" : "FALSE");
+ buffer->putTextIndent(indent + 2, "CLIP_CONTENTS=%s\n", _clipContents ? "TRUE" : "FALSE");
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ if (_fadeBackground) {
+ buffer->putTextIndent(indent + 2, "FADE_COLOR { %d, %d, %d }\n", RGBCOLGetR(_fadeColor), RGBCOLGetG(_fadeColor), RGBCOLGetB(_fadeColor));
+ buffer->putTextIndent(indent + 2, "FADE_ALPHA=%d\n", RGBCOLGetA(_fadeColor));
+ }
+
+ buffer->putTextIndent(indent + 2, "ALPHA_COLOR { %d, %d, %d }\n", RGBCOLGetR(_alphaColor), RGBCOLGetG(_alphaColor), RGBCOLGetB(_alphaColor));
+ buffer->putTextIndent(indent + 2, "ALPHA=%d\n", RGBCOLGetA(_alphaColor));
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ // scripts
+ for (int i = 0; i < _scripts.getSize(); i++) {
+ buffer->putTextIndent(indent + 2, "SCRIPT=\"%s\"\n", _scripts[i]->_filename);
+ }
+
+ buffer->putTextIndent(indent + 2, "\n");
+
+ // editor properties
+ CBBase::saveAsText(buffer, indent + 2);
+
+ // controls
+ for (int i = 0; i < _widgets.getSize(); i++)
+ _widgets[i]->saveAsText(buffer, indent + 2);
+
+
+ buffer->putTextIndent(indent, "}\n");
+ return STATUS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::enableWidget(const char *name, bool Enable) {
+ for (int i = 0; i < _widgets.getSize(); i++) {
+ if (scumm_stricmp(_widgets[i]->_name, name) == 0) _widgets[i]->_disable = !Enable;
+ }
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::showWidget(const char *name, bool Visible) {
+ for (int i = 0; i < _widgets.getSize(); i++) {
+ if (scumm_stricmp(_widgets[i]->_name, name) == 0) _widgets[i]->_visible = Visible;
+ }
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// high level scripting interface
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name) {
+ //////////////////////////////////////////////////////////////////////////
+ // GetWidget / GetControl
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "GetWidget") == 0 || strcmp(name, "GetControl") == 0) {
+ stack->correctParams(1);
+ CScValue *val = stack->pop();
+ if (val->getType() == VAL_INT) {
+ int widget = val->getInt();
+ if (widget < 0 || widget >= _widgets.getSize()) stack->pushNULL();
+ else stack->pushNative(_widgets[widget], true);
+ } else {
+ for (int i = 0; i < _widgets.getSize(); i++) {
+ if (scumm_stricmp(_widgets[i]->_name, val->getString()) == 0) {
+ stack->pushNative(_widgets[i], true);
+ return STATUS_OK;
+ }
+ }
+ stack->pushNULL();
+ }
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetInactiveFont
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetInactiveFont") == 0) {
+ stack->correctParams(1);
+
+ if (_fontInactive) _gameRef->_fontStorage->removeFont(_fontInactive);
+ _fontInactive = _gameRef->_fontStorage->addFont(stack->pop()->getString());
+ stack->pushBool(_fontInactive != NULL);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SetInactiveImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SetInactiveImage") == 0) {
+ stack->correctParams(1);
+
+ delete _imageInactive;
+ _imageInactive = new CBSprite(_gameRef);
+ const char *filename = stack->pop()->getString();
+ if (!_imageInactive || DID_FAIL(_imageInactive->loadFile(filename))) {
+ delete _imageInactive;
+ _imageInactive = NULL;
+ stack->pushBool(false);
+ } else stack->pushBool(true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetInactiveImage
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetInactiveImage") == 0) {
+ stack->correctParams(0);
+ if (!_imageInactive || !_imageInactive->_filename) stack->pushNULL();
+ else stack->pushString(_imageInactive->_filename);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GetInactiveImageObject
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GetInactiveImageObject") == 0) {
+ stack->correctParams(0);
+ if (!_imageInactive) stack->pushNULL();
+ else stack->pushNative(_imageInactive, true);
+
+ return STATUS_OK;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////
+ // Close
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Close") == 0) {
+ stack->correctParams(0);
+ stack->pushBool(DID_SUCCEED(close()));
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GoExclusive
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GoExclusive") == 0) {
+ stack->correctParams(0);
+ goExclusive();
+ script->waitFor(this);
+ stack->pushNULL();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // GoSystemExclusive
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "GoSystemExclusive") == 0) {
+ stack->correctParams(0);
+ goSystemExclusive();
+ script->waitFor(this);
+ stack->pushNULL();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Center
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Center") == 0) {
+ stack->correctParams(0);
+ _posX = (_gameRef->_renderer->_width - _width) / 2;
+ _posY = (_gameRef->_renderer->_height - _height) / 2;
+ stack->pushNULL();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // LoadFromFile
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "LoadFromFile") == 0) {
+ stack->correctParams(1);
+
+ CScValue *val = stack->pop();
+ cleanup();
+ if (!val->isNULL()) {
+ stack->pushBool(DID_SUCCEED(loadFile(val->getString())));
+ } else stack->pushBool(true);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CreateButton
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "CreateButton") == 0) {
+ stack->correctParams(1);
+ CScValue *val = stack->pop();
+
+ CUIButton *btn = new CUIButton(_gameRef);
+ if (!val->isNULL()) btn->setName(val->getString());
+ stack->pushNative(btn, true);
+
+ btn->_parent = this;
+ _widgets.add(btn);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CreateStatic
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "CreateStatic") == 0) {
+ stack->correctParams(1);
+ CScValue *val = stack->pop();
+
+ CUIText *sta = new CUIText(_gameRef);
+ if (!val->isNULL()) sta->setName(val->getString());
+ stack->pushNative(sta, true);
+
+ sta->_parent = this;
+ _widgets.add(sta);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CreateEditor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "CreateEditor") == 0) {
+ stack->correctParams(1);
+ CScValue *val = stack->pop();
+
+ CUIEdit *edi = new CUIEdit(_gameRef);
+ if (!val->isNULL()) edi->setName(val->getString());
+ stack->pushNative(edi, true);
+
+ edi->_parent = this;
+ _widgets.add(edi);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // CreateWindow
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "CreateWindow") == 0) {
+ stack->correctParams(1);
+ CScValue *val = stack->pop();
+
+ CUIWindow *win = new CUIWindow(_gameRef);
+ if (!val->isNULL()) win->setName(val->getString());
+ stack->pushNative(win, true);
+
+ win->_parent = this;
+ _widgets.add(win);
+
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // DeleteControl / DeleteButton / DeleteStatic / DeleteEditor / DeleteWindow
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "DeleteControl") == 0 || strcmp(name, "DeleteButton") == 0 || strcmp(name, "DeleteStatic") == 0 || strcmp(name, "DeleteEditor") == 0 || strcmp(name, "DeleteWindow") == 0) {
+ stack->correctParams(1);
+ CScValue *val = stack->pop();
+ CUIObject *obj = (CUIObject *)val->getNative();
+
+ for (int i = 0; i < _widgets.getSize(); i++) {
+ if (_widgets[i] == obj) {
+ delete _widgets[i];
+ _widgets.removeAt(i);
+ if (val->getType() == VAL_VARIABLE_REF) val->setNULL();
+ }
+ }
+ stack->pushNULL();
+ return STATUS_OK;
+ } else if DID_SUCCEED(_gameRef->windowScriptMethodHook(this, script, stack, name)) return STATUS_OK;
+
+ else return CUIObject::scCallMethod(script, stack, thisStack, name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+CScValue *CUIWindow::scGetProperty(const char *name) {
+ _scValue->setNULL();
+
+ //////////////////////////////////////////////////////////////////////////
+ // Type
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "Type") == 0) {
+ _scValue->setString("window");
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // NumWidgets / NumControls (RO)
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "NumWidgets") == 0 || strcmp(name, "NumControls") == 0) {
+ _scValue->setInt(_widgets.getSize());
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Exclusive
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Exclusive") == 0) {
+ _scValue->setBool(_mode == WINDOW_EXCLUSIVE);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SystemExclusive
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SystemExclusive") == 0) {
+ _scValue->setBool(_mode == WINDOW_SYSTEM_EXCLUSIVE);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Menu
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Menu") == 0) {
+ _scValue->setBool(_isMenu);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InGame
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "InGame") == 0) {
+ _scValue->setBool(_inGame);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PauseMusic
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "PauseMusic") == 0) {
+ _scValue->setBool(_pauseMusic);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ClipContents
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "ClipContents") == 0) {
+ _scValue->setBool(_clipContents);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Transparent
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Transparent") == 0) {
+ _scValue->setBool(_transparent);
+ return _scValue;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // FadeColor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "FadeColor") == 0) {
+ _scValue->setInt((int)_fadeColor);
+ return _scValue;
+ }
+
+ else return CUIObject::scGetProperty(name);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::scSetProperty(const char *name, CScValue *value) {
+ //////////////////////////////////////////////////////////////////////////
+ // Name
+ //////////////////////////////////////////////////////////////////////////
+ if (strcmp(name, "Name") == 0) {
+ setName(value->getString());
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Menu
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Menu") == 0) {
+ _isMenu = value->getBool();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // InGame
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "InGame") == 0) {
+ _inGame = value->getBool();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // PauseMusic
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "PauseMusic") == 0) {
+ _pauseMusic = value->getBool();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // ClipContents
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "ClipContents") == 0) {
+ _clipContents = value->getBool();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Transparent
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Transparent") == 0) {
+ _transparent = value->getBool();
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // FadeColor
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "FadeColor") == 0) {
+ _fadeColor = (uint32)value->getInt();
+ _fadeBackground = (_fadeColor != 0);
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // Exclusive
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "Exclusive") == 0) {
+ if (value->getBool())
+ goExclusive();
+ else {
+ close();
+ _visible = true;
+ }
+ return STATUS_OK;
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+ // SystemExclusive
+ //////////////////////////////////////////////////////////////////////////
+ else if (strcmp(name, "SystemExclusive") == 0) {
+ if (value->getBool())
+ goSystemExclusive();
+ else {
+ close();
+ _visible = true;
+ }
+ return STATUS_OK;
+ }
+
+ else return CUIObject::scSetProperty(name, value);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+const char *CUIWindow::scToString() {
+ return "[window]";
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::handleKeypress(Common::Event *event, bool printable) {
+//TODO
+ if (event->type == Common::EVENT_KEYDOWN && event->kbd.keycode == Common::KEYCODE_TAB) {
+ return DID_SUCCEED(moveFocus(!CBKeyboardState::isShiftDown()));
+ } else {
+ if (_focusedWidget) return _focusedWidget->handleKeypress(event, printable);
+ else return false;
+ }
+ return false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::handleMouseWheel(int Delta) {
+ if (_focusedWidget) return _focusedWidget->handleMouseWheel(Delta);
+ else return false;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::handleMouse(TMouseEvent event, TMouseButton button) {
+ bool res = CUIObject::handleMouse(event, button);
+
+ // handle window dragging
+ if (!CBPlatform::isRectEmpty(&_dragRect)) {
+ // start drag
+ if (event == MOUSE_CLICK && button == MOUSE_BUTTON_LEFT) {
+ Rect32 dragRect = _dragRect;
+ int offsetX, offsetY;
+ getTotalOffset(&offsetX, &offsetY);
+ CBPlatform::offsetRect(&dragRect, _posX + offsetX, _posY + offsetY);
+
+ if (CBPlatform::ptInRect(&dragRect, _gameRef->_mousePos)) {
+ _dragFrom.x = _gameRef->_mousePos.x;
+ _dragFrom.y = _gameRef->_mousePos.y;
+ _dragging = true;
+ }
+ }
+ // end drag
+ else if (_dragging && event == MOUSE_RELEASE && button == MOUSE_BUTTON_LEFT) {
+ _dragging = false;
+ }
+ }
+
+ return res;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::persist(CBPersistMgr *persistMgr) {
+
+ CUIObject::persist(persistMgr);
+
+ persistMgr->transfer(TMEMBER(_backInactive));
+ persistMgr->transfer(TMEMBER(_clipContents));
+ persistMgr->transfer(TMEMBER(_dragFrom));
+ persistMgr->transfer(TMEMBER(_dragging));
+ persistMgr->transfer(TMEMBER(_dragRect));
+ persistMgr->transfer(TMEMBER(_fadeBackground));
+ persistMgr->transfer(TMEMBER(_fadeColor));
+ persistMgr->transfer(TMEMBER(_fontInactive));
+ persistMgr->transfer(TMEMBER(_imageInactive));
+ persistMgr->transfer(TMEMBER(_inGame));
+ persistMgr->transfer(TMEMBER(_isMenu));
+ persistMgr->transfer(TMEMBER_INT(_mode));
+ persistMgr->transfer(TMEMBER(_shieldButton));
+ persistMgr->transfer(TMEMBER(_shieldWindow));
+ persistMgr->transfer(TMEMBER_INT(_titleAlign));
+ persistMgr->transfer(TMEMBER(_titleRect));
+ persistMgr->transfer(TMEMBER(_transparent));
+ persistMgr->transfer(TMEMBER(_viewport));
+ persistMgr->transfer(TMEMBER(_pauseMusic));
+
+ _widgets.persist(persistMgr);
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::moveFocus(bool forward) {
+ int i;
+ bool found = false;
+ for (i = 0; i < _widgets.getSize(); i++) {
+ if (_widgets[i] == _focusedWidget) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) _focusedWidget = NULL;
+
+ if (!_focusedWidget) {
+ if (_widgets.getSize() > 0) i = 0;
+ else return STATUS_OK;
+ }
+
+ int numTries = 0;
+ bool done = false;
+
+ while (numTries <= _widgets.getSize()) {
+ if (_widgets[i] != _focusedWidget && _widgets[i]->_canFocus && _widgets[i]->_visible && !_widgets[i]->_disable) {
+ _focusedWidget = _widgets[i];
+ done = true;
+ break;
+ }
+
+ if (forward) {
+ i++;
+ if (i >= _widgets.getSize()) i = 0;
+ } else {
+ i--;
+ if (i < 0) i = _widgets.getSize() - 1;
+ }
+ numTries++;
+ }
+
+ return done ? STATUS_OK : STATUS_FAILED;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::goExclusive() {
+ if (_mode == WINDOW_EXCLUSIVE) return STATUS_OK;
+
+ if (_mode == WINDOW_NORMAL) {
+ _ready = false;
+ _mode = WINDOW_EXCLUSIVE;
+ _visible = true;
+ _disable = false;
+ _gameRef->focusWindow(this);
+ return STATUS_OK;
+ } else return STATUS_FAILED;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::goSystemExclusive() {
+ if (_mode == WINDOW_SYSTEM_EXCLUSIVE) return STATUS_OK;
+
+ makeFreezable(false);
+
+ _mode = WINDOW_SYSTEM_EXCLUSIVE;
+ _ready = false;
+ _visible = true;
+ _disable = false;
+ _gameRef->focusWindow(this);
+
+ _gameRef->freeze(_pauseMusic);
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::close() {
+ if (_mode == WINDOW_SYSTEM_EXCLUSIVE) {
+ _gameRef->unfreeze();
+ }
+
+ _mode = WINDOW_NORMAL;
+ _visible = false;
+ _ready = true;
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::listen(CBScriptHolder *param1, uint32 param2) {
+ CUIObject *obj = (CUIObject *)param1;
+
+ switch (obj->_type) {
+ case UI_BUTTON:
+ if (scumm_stricmp(obj->_name, "close") == 0) close();
+ else return CBObject::listen(param1, param2);
+ break;
+ default:
+ return CBObject::listen(param1, param2);
+ }
+
+ return STATUS_OK;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+void CUIWindow::makeFreezable(bool freezable) {
+ for (int i = 0; i < _widgets.getSize(); i++)
+ _widgets[i]->makeFreezable(freezable);
+
+ CBObject::makeFreezable(freezable);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+bool CUIWindow::getWindowObjects(CBArray<CUIObject *, CUIObject *> &objects, bool interactiveOnly) {
+ for (int i = 0; i < _widgets.getSize(); i++) {
+ CUIObject *control = _widgets[i];
+ if (control->_disable && interactiveOnly) continue;
+
+ switch (control->_type) {
+ case UI_WINDOW:
+ ((CUIWindow *)control)->getWindowObjects(objects, interactiveOnly);
+ break;
+
+ case UI_BUTTON:
+ case UI_EDIT:
+ objects.add(control);
+ break;
+
+ default:
+ if (!interactiveOnly) objects.add(control);
+ }
+ }
+ return STATUS_OK;
+}
+
+} // end of namespace WinterMute
diff --git a/engines/wintermute/ui/UIWindow.h b/engines/wintermute/ui/UIWindow.h
new file mode 100644
index 0000000000..f1d46711ff
--- /dev/null
+++ b/engines/wintermute/ui/UIWindow.h
@@ -0,0 +1,93 @@
+/* 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
+ */
+
+#ifndef WINTERMUTE_UIWINDOW_H
+#define WINTERMUTE_UIWINDOW_H
+
+
+#include "UIObject.h"
+#include "common/events.h"
+
+namespace WinterMute {
+
+class CUIButton;
+class CBViewport;
+class CUIWindow : public CUIObject {
+public:
+ bool getWindowObjects(CBArray<CUIObject *, CUIObject *> &Objects, bool InteractiveOnly);
+
+ bool _pauseMusic;
+ void cleanup();
+ virtual void makeFreezable(bool freezable);
+ CBViewport *_viewport;
+ bool _clipContents;
+ bool _inGame;
+ bool _isMenu;
+ bool _fadeBackground;
+ uint32 _fadeColor;
+ virtual bool handleMouseWheel(int delta);
+ CUIWindow *_shieldWindow;
+ CUIButton *_shieldButton;
+ bool close();
+ bool goSystemExclusive();
+ bool goExclusive();
+ TWindowMode _mode;
+ bool moveFocus(bool forward = true);
+ virtual bool handleMouse(TMouseEvent Event, TMouseButton Button);
+ Point32 _dragFrom;
+ bool _dragging;
+ DECLARE_PERSISTENT(CUIWindow, CUIObject)
+ bool _transparent;
+ bool showWidget(const char *name, bool visible = true);
+ bool enableWidget(const char *name, bool enable = true);
+ Rect32 _titleRect;
+ Rect32 _dragRect;
+ virtual bool display(int offsetX = 0, int offsetY = 0);
+ CUIWindow(CBGame *inGame);
+ virtual ~CUIWindow();
+ virtual bool handleKeypress(Common::Event *event, bool printable = false);
+ CBArray<CUIObject *, CUIObject *> _widgets;
+ TTextAlign _titleAlign;
+ bool loadFile(const char *filename);
+ bool loadBuffer(byte *buffer, bool complete = true);
+ CUITiledImage *_backInactive;
+ CBFont *_fontInactive;
+ CBSprite *_imageInactive;
+ virtual bool listen(CBScriptHolder *param1, uint32 param2);
+ virtual bool saveAsText(CBDynBuffer *buffer, int indent);
+
+ // scripting interface
+ virtual CScValue *scGetProperty(const char *name);
+ virtual bool scSetProperty(const char *name, CScValue *value);
+ virtual bool scCallMethod(CScScript *script, CScStack *stack, CScStack *thisStack, const char *name);
+ virtual const char *scToString();
+};
+
+} // end of namespace WinterMute
+
+#endif