From 221490a93df13fb6b17589c48c536c73ef6576b5 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Sat, 2 Jun 2012 02:21:01 +0200 Subject: WINTERMUTE: Add subfolders for math, UI, tinyxml and Sys --- engines/wintermute/UI/UIButton.cpp | 1043 +++++++++++++++++++++++++ engines/wintermute/UI/UIButton.h | 79 ++ engines/wintermute/UI/UIEdit.cpp | 860 +++++++++++++++++++++ engines/wintermute/UI/UIEdit.h | 72 ++ engines/wintermute/UI/UIEntity.cpp | 339 ++++++++ engines/wintermute/UI/UIEntity.h | 58 ++ engines/wintermute/UI/UIObject.cpp | 589 ++++++++++++++ engines/wintermute/UI/UIObject.h | 83 ++ engines/wintermute/UI/UIText.cpp | 489 ++++++++++++ engines/wintermute/UI/UIText.h | 59 ++ engines/wintermute/UI/UITiledImage.cpp | 370 +++++++++ engines/wintermute/UI/UITiledImage.h | 62 ++ engines/wintermute/UI/UIWindow.cpp | 1321 ++++++++++++++++++++++++++++++++ engines/wintermute/UI/UIWindow.h | 92 +++ 14 files changed, 5516 insertions(+) create mode 100644 engines/wintermute/UI/UIButton.cpp create mode 100644 engines/wintermute/UI/UIButton.h create mode 100644 engines/wintermute/UI/UIEdit.cpp create mode 100644 engines/wintermute/UI/UIEdit.h create mode 100644 engines/wintermute/UI/UIEntity.cpp create mode 100644 engines/wintermute/UI/UIEntity.h create mode 100644 engines/wintermute/UI/UIObject.cpp create mode 100644 engines/wintermute/UI/UIObject.h create mode 100644 engines/wintermute/UI/UIText.cpp create mode 100644 engines/wintermute/UI/UIText.h create mode 100644 engines/wintermute/UI/UITiledImage.cpp create mode 100644 engines/wintermute/UI/UITiledImage.h create mode 100644 engines/wintermute/UI/UIWindow.cpp create mode 100644 engines/wintermute/UI/UIWindow.h (limited to 'engines/wintermute/UI') diff --git a/engines/wintermute/UI/UIButton.cpp b/engines/wintermute/UI/UIButton.cpp new file mode 100644 index 0000000000..75cc3d5689 --- /dev/null +++ b/engines/wintermute/UI/UIButton.cpp @@ -0,0 +1,1043 @@ +/* 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/BFontStorage.h" +#include "engines/wintermute/Base/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() { + if (_backPress) delete _backPress; + if (_backHover) delete _backHover; + if (_backDisable) delete _backDisable; + if (_backFocus) delete _backFocus; + + if (!_sharedFonts) { + if (_fontHover) Game->_fontStorage->RemoveFont(_fontHover); + if (_fontPress) Game->_fontStorage->RemoveFont(_fontPress); + if (_fontDisable) Game->_fontStorage->RemoveFont(_fontDisable); + if (_fontFocus) Game->_fontStorage->RemoveFont(_fontFocus); + } + + if (!_sharedImages) { + if (_imageHover) delete _imageHover; + if (_imagePress) delete _imagePress; + if (_imageDisable) delete _imageDisable; + if (_imageFocus) delete _imageFocus; + } +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIButton::LoadFile(const char *Filename) { + byte *Buffer = Game->_fileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIButton::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + _filename = new char [strlen(Filename) + 1]; + strcpy(_filename, Filename); + + if (FAILED(ret = LoadBuffer(Buffer, true))) Game->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 +////////////////////////////////////////////////////////////////////////// +HRESULT 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(Game); + + if (Complete) { + if (parser.GetCommand((char **)&Buffer, commands, (char **)¶ms) != TOKEN_BUTTON) { + Game->LOG(0, "'BUTTON' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while (cmd > 0 && (cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 0) { + switch (cmd) { + case TOKEN_TEMPLATE: + if (FAILED(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(Game); + if (!_back || FAILED(_back->LoadFile((char *)params))) { + delete _back; + _back = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_HOVER: + delete _backHover; + _backHover = new CUITiledImage(Game); + if (!_backHover || FAILED(_backHover->LoadFile((char *)params))) { + delete _backHover; + _backHover = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_PRESS: + delete _backPress; + _backPress = new CUITiledImage(Game); + if (!_backPress || FAILED(_backPress->LoadFile((char *)params))) { + delete _backPress; + _backPress = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_DISABLE: + delete _backDisable; + _backDisable = new CUITiledImage(Game); + if (!_backDisable || FAILED(_backDisable->LoadFile((char *)params))) { + delete _backDisable; + _backDisable = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_FOCUS: + delete _backFocus; + _backFocus = new CUITiledImage(Game); + if (!_backFocus || FAILED(_backFocus->LoadFile((char *)params))) { + delete _backFocus; + _backFocus = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE: + delete _image; + _image = new CBSprite(Game); + if (!_image || FAILED(_image->LoadFile((char *)params))) { + delete _image; + _image = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_HOVER: + delete _imageHover; + _imageHover = new CBSprite(Game); + if (!_imageHover || FAILED(_imageHover->LoadFile((char *)params))) { + delete _imageHover; + _imageHover = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_PRESS: + delete _imagePress; + _imagePress = new CBSprite(Game); + if (!_imagePress || FAILED(_imagePress->LoadFile((char *)params))) { + delete _imagePress; + _imagePress = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_DISABLE: + delete _imageDisable; + _imageDisable = new CBSprite(Game); + if (!_imageDisable || FAILED(_imageDisable->LoadFile((char *)params))) { + delete _imageDisable; + _imageDisable = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_FOCUS: + delete _imageFocus; + _imageFocus = new CBSprite(Game); + if (!_imageFocus || FAILED(_imageFocus->LoadFile((char *)params))) { + delete _imageFocus; + _imageFocus = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_FONT: + if (_font) Game->_fontStorage->RemoveFont(_font); + _font = Game->_fontStorage->AddFont((char *)params); + if (!_font) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_HOVER: + if (_fontHover) Game->_fontStorage->RemoveFont(_fontHover); + _fontHover = Game->_fontStorage->AddFont((char *)params); + if (!_fontHover) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_PRESS: + if (_fontPress) Game->_fontStorage->RemoveFont(_fontPress); + _fontPress = Game->_fontStorage->AddFont((char *)params); + if (!_fontPress) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_DISABLE: + if (_fontDisable) Game->_fontStorage->RemoveFont(_fontDisable); + _fontDisable = Game->_fontStorage->AddFont((char *)params); + if (!_fontDisable) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_FOCUS: + if (_fontFocus) Game->_fontStorage->RemoveFont(_fontFocus); + _fontFocus = Game->_fontStorage->AddFont((char *)params); + if (!_fontFocus) cmd = PARSERR_GENERIC; + break; + + case TOKEN_TEXT: + SetText((char *)params); + Game->_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(Game); + if (!_cursor || FAILED(_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) { + Game->LOG(0, "Syntax error in BUTTON definition"); + return E_FAIL; + } + if (cmd == PARSERR_GENERIC) { + Game->LOG(0, "Error loading BUTTON definition"); + return E_FAIL; + } + + CorrectSize(); + + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT 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; + } + + 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 S_OK; +} + +////////////////////////////////////////////////////////////////////////// +void CUIButton::CorrectSize() { + RECT 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 = Game->_systemFont->GetTextHeight((byte *)_text, _width); + + if (text_height > _height) _height = text_height; + } + + if (_height <= 0) _height = 100; + + if (_back) _back->CorrectSize(&_width, &_height); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIButton::Display(int OffsetX, int OffsetY) { + if (!_visible) return S_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, Game->_mousePos)!=FALSE); + _hover = (!_disable && Game->_activeObject == this && (Game->_interactive || Game->_state == GAME_SEMI_FROZEN)); + + if ((_press && _hover && !Game->_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 = Game->_systemFont; + } + + int ImageX = OffsetX + _posX; + int ImageY = OffsetY + _posY; + + if (image && _centerImage) { + RECT 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) Game->_renderer->_rectList.Add(new CBActiveRect(Game, 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 && Game->_mouseLeftDown && Game->_capturedObject == this; + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +void CUIButton::Press() { + ApplyEvent("Press"); + if (_listenerObject) _listenerObject->Listen(_listenerParamObject, _listenerParamDWORD); + if (_parentNotify && _parent) _parent->ApplyEvent(_name); + + _oneTimePress = false; +} + + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +HRESULT 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) Game->_fontStorage->RemoveFont(_fontDisable); + if (Val->IsNULL()) { + _fontDisable = NULL; + Stack->PushBool(true); + } else { + _fontDisable = Game->_fontStorage->AddFont(Val->GetString()); + Stack->PushBool(_fontDisable != NULL); + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetHoverFont + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetHoverFont") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + if (_fontHover) Game->_fontStorage->RemoveFont(_fontHover); + if (Val->IsNULL()) { + _fontHover = NULL; + Stack->PushBool(true); + } else { + _fontHover = Game->_fontStorage->AddFont(Val->GetString()); + Stack->PushBool(_fontHover != NULL); + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetPressedFont + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetPressedFont") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + if (_fontPress) Game->_fontStorage->RemoveFont(_fontPress); + if (Val->IsNULL()) { + _fontPress = NULL; + Stack->PushBool(true); + } else { + _fontPress = Game->_fontStorage->AddFont(Val->GetString()); + Stack->PushBool(_fontPress != NULL); + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetFocusedFont + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetFocusedFont") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + if (_fontFocus) Game->_fontStorage->RemoveFont(_fontFocus); + if (Val->IsNULL()) { + _fontFocus = NULL; + Stack->PushBool(true); + } else { + _fontFocus = Game->_fontStorage->AddFont(Val->GetString()); + Stack->PushBool(_fontFocus != NULL); + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetDisabledImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetDisabledImage") == 0) { + Stack->CorrectParams(1); + + delete _imageDisable; + _imageDisable = new CBSprite(Game); + const char *Filename = Stack->Pop()->GetString(); + if (!_imageDisable || FAILED(_imageDisable->LoadFile(Filename))) { + delete _imageDisable; + _imageDisable = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetDisabledImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetDisabledImage") == 0) { + Stack->CorrectParams(0); + if (!_imageDisable || !_imageDisable->_filename) Stack->PushNULL(); + else Stack->PushString(_imageDisable->_filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetDisabledImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetDisabledImageObject") == 0) { + Stack->CorrectParams(0); + if (!_imageDisable) Stack->PushNULL(); + else Stack->PushNative(_imageDisable, true); + + return S_OK; + } + + + ////////////////////////////////////////////////////////////////////////// + // SetHoverImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetHoverImage") == 0) { + Stack->CorrectParams(1); + + delete _imageHover; + _imageHover = new CBSprite(Game); + const char *Filename = Stack->Pop()->GetString(); + if (!_imageHover || FAILED(_imageHover->LoadFile(Filename))) { + delete _imageHover; + _imageHover = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetHoverImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetHoverImage") == 0) { + Stack->CorrectParams(0); + if (!_imageHover || !_imageHover->_filename) Stack->PushNULL(); + else Stack->PushString(_imageHover->_filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetHoverImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetHoverImageObject") == 0) { + Stack->CorrectParams(0); + if (!_imageHover) Stack->PushNULL(); + else Stack->PushNative(_imageHover, true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetPressedImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetPressedImage") == 0) { + Stack->CorrectParams(1); + + delete _imagePress; + _imagePress = new CBSprite(Game); + const char *Filename = Stack->Pop()->GetString(); + if (!_imagePress || FAILED(_imagePress->LoadFile(Filename))) { + delete _imagePress; + _imagePress = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetPressedImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetPressedImage") == 0) { + Stack->CorrectParams(0); + if (!_imagePress || !_imagePress->_filename) Stack->PushNULL(); + else Stack->PushString(_imagePress->_filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetPressedImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetPressedImageObject") == 0) { + Stack->CorrectParams(0); + if (!_imagePress) Stack->PushNULL(); + else Stack->PushNative(_imagePress, true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetFocusedImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetFocusedImage") == 0) { + Stack->CorrectParams(1); + + delete _imageFocus; + _imageFocus = new CBSprite(Game); + const char *Filename = Stack->Pop()->GetString(); + if (!_imageFocus || FAILED(_imageFocus->LoadFile(Filename))) { + delete _imageFocus; + _imageFocus = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetFocusedImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetFocusedImage") == 0) { + Stack->CorrectParams(0); + if (!_imageFocus || !_imageFocus->_filename) Stack->PushNULL(); + else Stack->PushString(_imageFocus->_filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetFocusedImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetFocusedImageObject") == 0) { + Stack->CorrectParams(0); + if (!_imageFocus) Stack->PushNULL(); + else Stack->PushNative(_imageFocus, true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Press + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Press") == 0) { + Stack->CorrectParams(0); + + if (_visible && !_disable) { + _oneTimePress = true; + _oneTimePressTime = CBPlatform::GetTime(); + } + Stack->PushNULL(); + + return S_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); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Focusable + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Focusable") == 0) { + _canFocus = Value->GetBool(); + return S_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Pressed + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Pressed") == 0) { + _stayPressed = Value->GetBool(); + return S_OK; + } + ////////////////////////////////////////////////////////////////////////// + // PixelPerfect + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "PixelPerfect") == 0) { + _pixelPerfect = Value->GetBool(); + return S_OK; + } + + else return CUIObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +const char *CUIButton::ScToString() { + return "[button]"; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_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..75133e2c0a --- /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 HRESULT 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(); + HRESULT LoadFile(const char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(const char *Name); + virtual HRESULT ScSetProperty(const char *Name, CScValue *Value); + virtual HRESULT 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..3f2bc71996 --- /dev/null +++ b/engines/wintermute/UI/UIEdit.cpp @@ -0,0 +1,860 @@ +/* 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/StringUtil.h" +#include "engines/wintermute/Base/BActiveRect.h" +#include "engines/wintermute/Base/BFileManager.h" +#include "engines/wintermute/Base/BFont.h" +#include "engines/wintermute/Base/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.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("|"); + +#ifdef __WIN32__ + _cursorBlinkRate = GetCaretBlinkTime(); +#else + _cursorBlinkRate = 600; +#endif + _frameWidth = 0; + + SetText(""); + + _lastBlinkTime = 0; + _cursorVisible = true; + + _maxLength = -1; + + _canFocus = true; +} + + +////////////////////////////////////////////////////////////////////////// +CUIEdit::~CUIEdit() { + if (!_sharedFonts) { + if (_fontSelected) Game->_fontStorage->RemoveFont(_fontSelected); + } + + delete[] _cursorChar; + _cursorChar = NULL; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEdit::LoadFile(const char *Filename) { + byte *Buffer = Game->_fileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIEdit::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + _filename = new char [strlen(Filename) + 1]; + strcpy(_filename, Filename); + + if (FAILED(ret = LoadBuffer(Buffer, true))) Game->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 +////////////////////////////////////////////////////////////////////////// +HRESULT 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(Game); + + if (Complete) { + if (parser.GetCommand((char **)&Buffer, commands, (char **)¶ms) != TOKEN_EDIT) { + Game->LOG(0, "'EDIT' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while (cmd > 0 && (cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 0) { + switch (cmd) { + case TOKEN_TEMPLATE: + if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC; + break; + + case TOKEN_NAME: + SetName((char *)params); + break; + + case TOKEN_BACK: + delete _back; + _back = new CUITiledImage(Game); + if (!_back || FAILED(_back->LoadFile((char *)params))) { + delete _back; + _back = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE: + delete _image; + _image = new CBSprite(Game); + if (!_image || FAILED(_image->LoadFile((char *)params))) { + delete _image; + _image = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_FONT: + if (_font) Game->_fontStorage->RemoveFont(_font); + _font = Game->_fontStorage->AddFont((char *)params); + if (!_font) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_SELECTED: + if (_fontSelected) Game->_fontStorage->RemoveFont(_fontSelected); + _fontSelected = Game->_fontStorage->AddFont((char *)params); + if (!_fontSelected) cmd = PARSERR_GENERIC; + break; + + case TOKEN_TEXT: + SetText((char *)params); + Game->_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(Game); + if (!_cursor || FAILED(_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) { + Game->LOG(0, "Syntax error in EDIT definition"); + return E_FAIL; + } + if (cmd == PARSERR_GENERIC) { + Game->LOG(0, "Error loading EDIT definition"); + return E_FAIL; + } + + CorrectSize(); + + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEdit::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name) { + ////////////////////////////////////////////////////////////////////////// + // SetSelectedFont + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "SetSelectedFont") == 0) { + Stack->CorrectParams(1); + + if (_fontSelected) Game->_fontStorage->RemoveFont(_fontSelected); + _fontSelected = Game->_fontStorage->AddFont(Stack->Pop()->GetString()); + Stack->PushBool(_fontSelected != NULL); + + return S_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 (Game->_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); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SelEnd + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SelEnd") == 0) { + _selEnd = Value->GetInt(); + _selEnd = MAX(_selEnd, 0); + _selEnd = MIN((size_t)_selEnd, strlen(_text)); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // CursorBlinkRate + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "CursorBlinkRate") == 0) { + _cursorBlinkRate = Value->GetInt(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // CursorChar + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "CursorChar") == 0) { + SetCursorChar(Value->GetString()); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // FrameWidth + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "FrameWidth") == 0) { + _frameWidth = Value->GetInt(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // MaxLength + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "MaxLength") == 0) { + _maxLength = Value->GetInt(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Text + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Text") == 0) { + if (Game->_textEncoding == TEXT_UTF8) { + WideString wstr = StringUtil::Utf8ToWide(Value->GetString()); + SetText(StringUtil::WideToAnsi(wstr).c_str()); + } else { + SetText(Value->GetString()); + } + return S_OK; + } + + else return CUIObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +const char *CUIEdit::ScToString() { + return "[edit]"; +} + + +////////////////////////////////////////////////////////////////////////// +void CUIEdit::SetCursorChar(const char *Char) { + if (!Char) return; + delete[] _cursorChar; + _cursorChar = new char [strlen(Char) + 1]; + if (_cursorChar) strcpy(_cursorChar, Char); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEdit::Display(int OffsetX, int OffsetY) { + if (!_visible) return S_OK; + + + // hack! + TTextEncoding OrigEncoding = Game->_textEncoding; + Game->_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 = Game->_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 >= 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 >= 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 (Game->_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; + } + + + Game->_renderer->_rectList.Add(new CBActiveRect(Game, this, NULL, OffsetX + _posX, OffsetY + _posY, _width, _height, 100, 100, false)); + + + Game->_textEncoding = OrigEncoding; + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +bool CUIEdit::HandleKeypress(Common::Event *event) { + bool Handled = false; + + if (event->type == Common::EVENT_KEYDOWN) { + 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 (Game->_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 (Game->_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 (Game->_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 (Game->_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; + } +#if 0 + else if (event->type == SDL_TEXTINPUT) { + if (_selStart != _selEnd) DeleteChars(_selStart, _selEnd); + + WideString wstr = StringUtil::Utf8ToWide(event->text.text); + _selEnd += InsertChars(_selEnd, (byte *)StringUtil::WideToAnsi(wstr).c_str(), 1); + + if (Game->_textRTL) _selEnd = _selStart; + else _selStart = _selEnd; + + return true; + } +#endif + 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 (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; +} + + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_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..3b8698d55d --- /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 HRESULT Display(int OffsetX, int OffsetY); + virtual bool HandleKeypress(Common::Event *event); + int _scrollOffset; + int _frameWidth; + uint32 _cursorBlinkRate; + void SetCursorChar(const char *Char); + char *_cursorChar; + int _selEnd; + int _selStart; + CBFont *_fontSelected; + CUIEdit(CBGame *inGame); + virtual ~CUIEdit(); + + HRESULT LoadFile(const char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(const char *Name); + virtual HRESULT ScSetProperty(const char *Name, CScValue *Value); + virtual HRESULT 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..97565603f3 --- /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) Game->UnregisterObject(_entity); + _entity = NULL; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::LoadFile(const char *Filename) { + byte *Buffer = Game->_fileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIEntity::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + _filename = new char [strlen(Filename) + 1]; + strcpy(_filename, Filename); + + if (FAILED(ret = LoadBuffer(Buffer, true))) Game->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 +////////////////////////////////////////////////////////////////////////// +HRESULT 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(Game); + + if (Complete) { + if (parser.GetCommand((char **)&Buffer, commands, (char **)¶ms) != TOKEN_ENTITY_CONTAINER) { + Game->LOG(0, "'ENTITY_CONTAINER' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while (cmd > 0 && (cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 0) { + switch (cmd) { + case TOKEN_TEMPLATE: + if (FAILED(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 (FAILED(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) { + Game->LOG(0, "Syntax error in ENTITY_CONTAINER definition"); + return E_FAIL; + } + if (cmd == PARSERR_GENERIC) { + Game->LOG(0, "Error loading ENTITY_CONTAINER definition"); + return E_FAIL; + } + + CorrectSize(); + + if (Game->_editorMode) { + _width = 50; + _height = 50; + } + + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::SetEntity(const char *Filename) { + if (_entity) Game->UnregisterObject(_entity); + _entity = new CAdEntity(Game); + if (!_entity || FAILED(_entity->LoadFile(Filename))) { + delete _entity; + _entity = NULL; + return E_FAIL; + } else { + _entity->_nonIntMouseEvents = true; + _entity->_sceneIndependent = true; + _entity->MakeFreezable(false); + Game->RegisterObject(_entity); + } + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::Display(int OffsetX, int OffsetY) { + if (!_visible) return S_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 S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetEntity + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetEntity") == 0) { + Stack->CorrectParams(1); + + const char *Filename = Stack->Pop()->GetString(); + + if (SUCCEEDED(SetEntity(Filename))) + Stack->PushBool(true); + else + Stack->PushBool(false); + + return S_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); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::ScSetProperty(const char *Name, CScValue *Value) { + ////////////////////////////////////////////////////////////////////////// + // Freezable + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Freezable") == 0) { + if (_entity) _entity->MakeFreezable(Value->GetBool()); + return S_OK; + } else return CUIObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +const char *CUIEntity::ScToString() { + return "[entity container]"; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::Persist(CBPersistMgr *PersistMgr) { + + CUIObject::Persist(PersistMgr); + + PersistMgr->Transfer(TMEMBER(_entity)); + return S_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..c18fd952dc --- /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(); + HRESULT LoadFile(const char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + virtual HRESULT Display(int OffsetX = 0, int OffsetY = 0); + CAdEntity *_entity; + HRESULT SetEntity(const char *Filename); + + // scripting interface + virtual CScValue *ScGetProperty(const char *Name); + virtual HRESULT ScSetProperty(const char *Name, CScValue *Value); + virtual HRESULT 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..20a89c5897 --- /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/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 (!Game->_loadInProgress) CSysClassRegistry::GetInstance()->EnumInstances(CBGame::InvalidateValues, "CScValue", (void *)this); + + if (_back) delete _back; + if (_font && !_sharedFonts) Game->_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'; + } + } +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::Display(int OffsetX, int OffsetY) { + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +void CUIObject::SetListener(CBScriptHolder *Object, CBScriptHolder *ListenerObject, uint32 ListenerParam) { + _listenerObject = Object; + _listenerParamObject = ListenerObject; + _listenerParamDWORD = ListenerParam; +} + + +////////////////////////////////////////////////////////////////////////// +void CUIObject::CorrectSize() { + RECT 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 +////////////////////////////////////////////////////////////////////////// +HRESULT 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) Game->_fontStorage->RemoveFont(_font); + if (Val->IsNULL()) { + _font = NULL; + Stack->PushBool(true); + } else { + _font = Game->_fontStorage->AddFont(Val->GetString()); + Stack->PushBool(_font != NULL); + } + return S_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 S_OK; + } + + _image = new CBSprite(Game); + if (!_image || FAILED(_image->LoadFile(Val->GetString()))) { + delete _image; + _image = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetImage") == 0) { + Stack->CorrectParams(0); + if (!_image || !_image->_filename) Stack->PushNULL(); + else Stack->PushString(_image->_filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetImageObject") == 0) { + Stack->CorrectParams(0); + if (!_image) Stack->PushNULL(); + else Stack->PushNative(_image, true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Focus + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Focus") == 0) { + Stack->CorrectParams(0); + Focus(); + Stack->PushNULL(); + return S_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 *name = val->GetString(); + for (i = 0; i < win->_widgets.GetSize(); i++) { + if (scumm_stricmp(win->_widgets[i]->_name, name) == 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 S_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 S_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 S_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); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::ScSetProperty(const char *Name, CScValue *Value) { + ////////////////////////////////////////////////////////////////////////// + // Name + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Name") == 0) { + SetName(Value->GetString()); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // ParentNotify + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "ParentNotify") == 0) { + _parentNotify = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Width + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Width") == 0) { + _width = Value->GetInt(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Height + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Height") == 0) { + _height = Value->GetInt(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Visible + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Visible") == 0) { + _visible = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Disabled + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Disabled") == 0) { + _disable = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Text + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Text") == 0) { + SetText(Value->GetString()); + return S_OK; + } + + else return CBObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +const char *CUIObject::ScToString() { + return "[ui_object]"; +} + + +////////////////////////////////////////////////////////////////////////// +bool CUIObject::IsFocused() { + if (!Game->_focusedWindow) return false; + if (Game->_focusedWindow == this) return true; + + CUIObject *obj = Game->_focusedWindow; + while (obj) { + if (obj == this) return true; + else obj = obj->_focusedWidget; + } + return false; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::HandleMouse(TMouseEvent Event, TMouseButton Button) { + // handle focus change + if (Event == MOUSE_CLICK && Button == MOUSE_BUTTON_LEFT) { + Focus(); + } + return CBObject::HandleMouse(Event, Button); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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) Game->FocusWindow((CUIWindow *)obj); + } + + obj = obj->_parent; + } + } + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::SaveAsText(CBDynBuffer *Buffer, int Indent) { + return E_FAIL; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/UI/UIObject.h b/engines/wintermute/UI/UIObject.h new file mode 100644 index 0000000000..7d6dfb41f5 --- /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: + + HRESULT GetTotalOffset(int *OffsetX, int *OffsetY); + bool _canFocus; + HRESULT Focus(); + virtual HRESULT HandleMouse(TMouseEvent Event, TMouseButton Button); + bool IsFocused(); + bool _parentNotify; + DECLARE_PERSISTENT(CUIObject, CBObject) + CUIObject *_parent; + virtual HRESULT 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 HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(const char *Name); + virtual HRESULT ScSetProperty(const char *Name, CScValue *Value); + virtual HRESULT 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..c2888e7393 --- /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/BFont.h" +#include "engines/wintermute/Base/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() { + +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::Display(int OffsetX, int OffsetY) { + if (!_visible) return S_OK; + + + CBFont *font = _font; + if (!font) font = Game->_systemFont; + + if (_back) _back->Display(OffsetX + _posX, OffsetY + _posY, _width, _height); + if (_image) _image->Draw(OffsetX + _posX, OffsetY + _posY, NULL); + + if (font && _text) { + int text_offset; + switch (_verticalAlign) { + case VAL_TOP: + text_offset = 0; + break; + case VAL_BOTTOM: + text_offset = _height - font->GetTextHeight((byte *)_text, _width); + break; + default: + text_offset = (_height - font->GetTextHeight((byte *)_text, _width)) / 2; + } + font->DrawText((byte *)_text, OffsetX + _posX, OffsetY + _posY + text_offset, _width, _textAlign, _height); + } + + //Game->_renderer->_rectList.Add(new CBActiveRect(Game, this, NULL, OffsetX + _posX, OffsetY + _posY, _width, _height, 100, 100, false)); + + return S_OK; +} + + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::LoadFile(const char *Filename) { + byte *Buffer = Game->_fileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIText::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + _filename = new char [strlen(Filename) + 1]; + strcpy(_filename, Filename); + + if (FAILED(ret = LoadBuffer(Buffer, true))) Game->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 +////////////////////////////////////////////////////////////////////////// +HRESULT 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(Game); + + if (Complete) { + if (parser.GetCommand((char **)&Buffer, commands, (char **)¶ms) != TOKEN_STATIC) { + Game->LOG(0, "'STATIC' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while (cmd > 0 && (cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 0) { + switch (cmd) { + case TOKEN_TEMPLATE: + if (FAILED(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(Game); + if (!_back || FAILED(_back->LoadFile((char *)params))) { + delete _back; + _back = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE: + delete _image; + _image = new CBSprite(Game); + if (!_image || FAILED(_image->LoadFile((char *)params))) { + delete _image; + _image = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_FONT: + if (_font) Game->_fontStorage->RemoveFont(_font); + _font = Game->_fontStorage->AddFont((char *)params); + if (!_font) cmd = PARSERR_GENERIC; + break; + + case TOKEN_TEXT: + SetText((char *)params); + Game->_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(Game); + if (!_cursor || FAILED(_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) { + Game->LOG(0, "Syntax error in STATIC definition"); + return E_FAIL; + } + if (cmd == PARSERR_GENERIC) { + Game->LOG(0, "Error loading STATIC definition"); + return E_FAIL; + } + + CorrectSize(); + + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name) { + ////////////////////////////////////////////////////////////////////////// + // SizeToFit + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "SizeToFit") == 0) { + Stack->CorrectParams(0); + SizeToFit(); + Stack->PushNULL(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // HeightToFit + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "HeightToFit") == 0) { + Stack->CorrectParams(0); + if (_font && _text) _height = _font->GetTextHeight((byte *)_text, _width); + Stack->PushNULL(); + return S_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); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_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 S_OK; + } + + else return CUIObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +const char *CUIText::ScToString() { + return "[static]"; +} + + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::Persist(CBPersistMgr *PersistMgr) { + + CUIObject::Persist(PersistMgr); + PersistMgr->Transfer(TMEMBER_INT(_textAlign)); + PersistMgr->Transfer(TMEMBER_INT(_verticalAlign)); + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::SizeToFit() { + if (_font && _text) { + _width = _font->GetTextWidth((byte *)_text); + _height = _font->GetTextHeight((byte *)_text, _width); + } + return S_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..756834fd5c --- /dev/null +++ b/engines/wintermute/UI/UIText.h @@ -0,0 +1,59 @@ +/* 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 { +public: + HRESULT SizeToFit(); + virtual HRESULT Display(int OffsetX, int OffsetY); + DECLARE_PERSISTENT(CUIText, CUIObject) + CUIText(CBGame *inGame = NULL); + virtual ~CUIText(); + TTextAlign _textAlign; + TVerticalAlign _verticalAlign; + HRESULT LoadFile(const char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(const char *Name); + virtual HRESULT ScSetProperty(const char *Name, CScValue *Value); + virtual HRESULT 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..9965ed5128 --- /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/BSurface.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; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUITiledImage::Display(int X, int Y, int Width, int Height) { + if (!_image) return E_FAIL; + + int tile_width = _middleMiddle.right - _middleMiddle.left; + int tile_height = _middleMiddle.bottom - _middleMiddle.top; + + int nu_columns = (Width - (_middleLeft.right - _middleLeft.left) - (_middleRight.right - _middleRight.left)) / tile_width; + int nu_rows = (Height - (_upMiddle.bottom - _upMiddle.top) - (_downMiddle.bottom - _downMiddle.top)) / tile_height; + + int col, row; + + Game->_renderer->StartSpriteBatch(); + + // top left/right + _image->_surface->DisplayTrans(X, Y, _upLeft); + _image->_surface->DisplayTrans(X + (_upLeft.right - _upLeft.left) + nu_columns * tile_width, Y, _upRight); + + // bottom left/right + _image->_surface->DisplayTrans(X, Y + (_upMiddle.bottom - _upMiddle.top) + nu_rows * tile_height, _downLeft); + _image->_surface->DisplayTrans(X + (_upLeft.right - _upLeft.left) + nu_columns * tile_width, Y + (_upMiddle.bottom - _upMiddle.top) + nu_rows * tile_height, _downRight); + + // left/right + int yyy = Y + (_upMiddle.bottom - _upMiddle.top); + for (row = 0; row < nu_rows; row++) { + _image->_surface->DisplayTrans(X, yyy, _middleLeft); + _image->_surface->DisplayTrans(X + (_middleLeft.right - _middleLeft.left) + nu_columns * tile_width, yyy, _middleRight); + yyy += tile_width; + } + + // top/bottom + int xxx = X + (_upLeft.right - _upLeft.left); + for (col = 0; col < nu_columns; col++) { + _image->_surface->DisplayTrans(xxx, Y, _upMiddle); + _image->_surface->DisplayTrans(xxx, Y + (_upMiddle.bottom - _upMiddle.top) + nu_rows * tile_height, _downMiddle); + xxx += tile_width; + } + + // tiles + yyy = Y + (_upMiddle.bottom - _upMiddle.top); + for (row = 0; row < nu_rows; row++) { + xxx = X + (_upLeft.right - _upLeft.left); + for (col = 0; col < nu_columns; col++) { + _image->_surface->DisplayTrans(xxx, yyy, _middleMiddle); + xxx += tile_width; + } + yyy += tile_width; + } + + Game->_renderer->EndSpriteBatch(); + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUITiledImage::LoadFile(const char *Filename) { + byte *Buffer = Game->_fileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUITiledImage::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + _filename = new char [strlen(Filename) + 1]; + strcpy(_filename, Filename); + + if (FAILED(ret = LoadBuffer(Buffer, true))) Game->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 +////////////////////////////////////////////////////////////////////////// +HRESULT 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(Game); + 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 **)¶ms) != TOKEN_TILED_IMAGE) { + Game->LOG(0, "'TILED_IMAGE' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while ((cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) > 0) { + switch (cmd) { + case TOKEN_TEMPLATE: + if (FAILED(LoadFile((char *)params))) cmd = PARSERR_GENERIC; + break; + + case TOKEN_IMAGE: + delete _image; + _image = new CBSubFrame(Game); + if (!_image || FAILED(_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) { + Game->LOG(0, "Syntax error in TILED_IMAGE definition"); + return E_FAIL; + } + if (cmd == PARSERR_GENERIC) { + Game->LOG(0, "Error loading TILED_IMAGE definition"); + return E_FAIL; + } + + 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 S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + +////////////////////////////////////////////////////////////////////////// +void CUITiledImage::CorrectSize(int *Width, int *Height) { + int tile_width = _middleMiddle.right - _middleMiddle.left; + int tile_height = _middleMiddle.bottom - _middleMiddle.top; + + int nu_columns = (*Width - (_middleLeft.right - _middleLeft.left) - (_middleRight.right - _middleRight.left)) / tile_width; + int nu_rows = (*Height - (_upMiddle.bottom - _upMiddle.top) - (_downMiddle.bottom - _downMiddle.top)) / tile_height; + + *Width = (_middleLeft.right - _middleLeft.left) + (_middleRight.right - _middleRight.left) + nu_columns * tile_width; + *Height = (_upMiddle.bottom - _upMiddle.top) + (_downMiddle.bottom - _downMiddle.top) + nu_rows * tile_height; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_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..03d15a0daa --- /dev/null +++ b/engines/wintermute/UI/UITiledImage.h @@ -0,0 +1,62 @@ +/* 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" + +namespace WinterMute { +class CBSubFrame; +class CUITiledImage : public CBObject { +public: + DECLARE_PERSISTENT(CUITiledImage, CBObject) + void CorrectSize(int *Width, int *Height); + HRESULT LoadFile(const char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + HRESULT Display(int X, int Y, int Width, int Height); + CUITiledImage(CBGame *inGame = NULL); + virtual ~CUITiledImage(); + CBSubFrame *_image; + RECT _upLeft; + RECT _upMiddle; + RECT _upRight; + RECT _middleLeft; + RECT _middleMiddle; + RECT _middleRight; + RECT _downLeft; + RECT _downMiddle; + RECT _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..d364b27740 --- /dev/null +++ b/engines/wintermute/UI/UIWindow.cpp @@ -0,0 +1,1321 @@ +/* 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/BFontStorage.h" +#include "engines/wintermute/Base/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; + + if (_backInactive) delete _backInactive; + if (!_sharedFonts && _fontInactive) Game->_fontStorage->RemoveFont(_fontInactive); + if (!_sharedImages && _imageInactive) delete _imageInactive; + + for (int i = 0; i < _widgets.GetSize(); i++) delete _widgets[i]; + _widgets.RemoveAll(); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::Display(int OffsetX, int OffsetY) { + // go exclusive + if (_mode == WINDOW_EXCLUSIVE || _mode == WINDOW_SYSTEM_EXCLUSIVE) { + if (!_shieldWindow) _shieldWindow = new CUIWindow(Game); + if (_shieldWindow) { + _shieldWindow->_posX = _shieldWindow->_posY = 0; + _shieldWindow->_width = Game->_renderer->_width; + _shieldWindow->_height = Game->_renderer->_height; + + _shieldWindow->Display(); + } + } else if (_isMenu) { + if (!_shieldButton) { + _shieldButton = new CUIButton(Game); + _shieldButton->SetName("close"); + _shieldButton->SetListener(this, _shieldButton, 0); + _shieldButton->_parent = this; + } + if (_shieldButton) { + _shieldButton->_posX = _shieldButton->_posY = 0; + _shieldButton->_width = Game->_renderer->_width; + _shieldButton->_height = Game->_renderer->_height; + + _shieldButton->Display(); + } + } + + if (!_visible) return S_OK; + + if (_fadeBackground) Game->_renderer->FadeToColor(_fadeColor); + + if (_dragging) { + _posX += (Game->_mousePos.x - _dragFrom.x); + _posY += (Game->_mousePos.y - _dragFrom.y); + + _dragFrom.x = Game->_mousePos.x; + _dragFrom.y = Game->_mousePos.y; + } + + if (!_focusedWidget || (!_focusedWidget->_canFocus || _focusedWidget->_disable || !_focusedWidget->_visible)) { + MoveFocus(); + } + + bool PopViewport = false; + if (_clipContents) { + if (!_viewport) _viewport = new CBViewport(Game); + if (_viewport) { + _viewport->SetRect(_posX + OffsetX, _posY + OffsetY, _posX + _width + OffsetX, _posY + _height + OffsetY); + Game->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) Game->_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) Game->_renderer->_rectList.Add(new CBActiveRect(Game, 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) Game->_renderer->_forceAlphaColor = 0; + + if (PopViewport) Game->PopViewport(); + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::LoadFile(const char *Filename) { + byte *Buffer = Game->_fileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIWindow::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + _filename = new char [strlen(Filename) + 1]; + strcpy(_filename, Filename); + + if (FAILED(ret = LoadBuffer(Buffer, true))) Game->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 +////////////////////////////////////////////////////////////////////////// +HRESULT 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(Game); + + 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 **)¶ms) != TOKEN_WINDOW) { + Game->LOG(0, "'WINDOW' keyword expected."); + return E_FAIL; + } + Buffer = params; + } + + while (cmd >= PARSERR_TOKENNOTFOUND && (cmd = parser.GetCommand((char **)&Buffer, commands, (char **)¶ms)) >= PARSERR_TOKENNOTFOUND) { + switch (cmd) { + case TOKEN_TEMPLATE: + if (FAILED(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(Game); + if (!_back || FAILED(_back->LoadFile((char *)params))) { + delete _back; + _back = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_INACTIVE: + delete _backInactive; + _backInactive = new CUITiledImage(Game); + if (!_backInactive || FAILED(_backInactive->LoadFile((char *)params))) { + delete _backInactive; + _backInactive = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE: + delete _image; + _image = new CBSprite(Game); + if (!_image || FAILED(_image->LoadFile((char *)params))) { + delete _image; + _image = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_INACTIVE: + delete _imageInactive, + _imageInactive = new CBSprite(Game); + if (!_imageInactive || FAILED(_imageInactive->LoadFile((char *)params))) { + delete _imageInactive; + _imageInactive = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_FONT: + if (_font) Game->_fontStorage->RemoveFont(_font); + _font = Game->_fontStorage->AddFont((char *)params); + if (!_font) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_INACTIVE: + if (_fontInactive) Game->_fontStorage->RemoveFont(_fontInactive); + _fontInactive = Game->_fontStorage->AddFont((char *)params); + if (!_fontInactive) cmd = PARSERR_GENERIC; + break; + + case TOKEN_TITLE: + SetText((char *)params); + Game->_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(Game); + if (!_cursor || FAILED(_cursor->LoadFile((char *)params))) { + delete _cursor; + _cursor = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BUTTON: { + CUIButton *btn = new CUIButton(Game); + if (!btn || FAILED(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(Game); + if (!text || FAILED(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(Game); + if (!edit || FAILED(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(Game); + if (!win || FAILED(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 (FAILED(Game->WindowLoadHook(this, (char **)&Buffer, (char **)params))) { + cmd = PARSERR_GENERIC; + } + } + } + if (cmd == PARSERR_TOKENNOTFOUND) { + Game->LOG(0, "Syntax error in WINDOW definition"); + return E_FAIL; + } + if (cmd == PARSERR_GENERIC) { + Game->LOG(0, "Error loading WINDOW definition"); + return E_FAIL; + } + + CorrectSize(); + + if (alpha != 0 && ar == 0 && ag == 0 && ab == 0) { + ar = ag = ab = 255; + } + _alphaColor = DRGBA(ar, ag, ab, alpha); + + if (_fadeBackground) _fadeColor = DRGBA(FadeR, FadeG, FadeB, FadeA); + + _focusedWidget = NULL; + + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT 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", D3DCOLGetR(_fadeColor), D3DCOLGetG(_fadeColor), D3DCOLGetB(_fadeColor)); + Buffer->PutTextIndent(Indent + 2, "FADE_ALPHA=%d\n", D3DCOLGetA(_fadeColor)); + } + + Buffer->PutTextIndent(Indent + 2, "ALPHA_COLOR { %d, %d, %d }\n", D3DCOLGetR(_alphaColor), D3DCOLGetG(_alphaColor), D3DCOLGetB(_alphaColor)); + Buffer->PutTextIndent(Indent + 2, "ALPHA=%d\n", D3DCOLGetA(_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 S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; + } + } + Stack->PushNULL(); + } + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetInactiveFont + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetInactiveFont") == 0) { + Stack->CorrectParams(1); + + if (_fontInactive) Game->_fontStorage->RemoveFont(_fontInactive); + _fontInactive = Game->_fontStorage->AddFont(Stack->Pop()->GetString()); + Stack->PushBool(_fontInactive != NULL); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetInactiveImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetInactiveImage") == 0) { + Stack->CorrectParams(1); + + delete _imageInactive; + _imageInactive = new CBSprite(Game); + const char *Filename = Stack->Pop()->GetString(); + if (!_imageInactive || FAILED(_imageInactive->LoadFile(Filename))) { + delete _imageInactive; + _imageInactive = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetInactiveImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetInactiveImage") == 0) { + Stack->CorrectParams(0); + if (!_imageInactive || !_imageInactive->_filename) Stack->PushNULL(); + else Stack->PushString(_imageInactive->_filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetInactiveImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetInactiveImageObject") == 0) { + Stack->CorrectParams(0); + if (!_imageInactive) Stack->PushNULL(); + else Stack->PushNative(_imageInactive, true); + + return S_OK; + } + + + ////////////////////////////////////////////////////////////////////////// + // Close + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Close") == 0) { + Stack->CorrectParams(0); + Stack->PushBool(SUCCEEDED(Close())); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GoExclusive + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GoExclusive") == 0) { + Stack->CorrectParams(0); + GoExclusive(); + Script->WaitFor(this); + Stack->PushNULL(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GoSystemExclusive + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GoSystemExclusive") == 0) { + Stack->CorrectParams(0); + GoSystemExclusive(); + Script->WaitFor(this); + Stack->PushNULL(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Center + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Center") == 0) { + Stack->CorrectParams(0); + _posX = (Game->_renderer->_width - _width) / 2; + _posY = (Game->_renderer->_height - _height) / 2; + Stack->PushNULL(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // LoadFromFile + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "LoadFromFile") == 0) { + Stack->CorrectParams(1); + + CScValue *Val = Stack->Pop(); + Cleanup(); + if (!Val->IsNULL()) { + Stack->PushBool(SUCCEEDED(LoadFile(Val->GetString()))); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // CreateButton + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "CreateButton") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + CUIButton *Btn = new CUIButton(Game); + if (!Val->IsNULL()) Btn->SetName(Val->GetString()); + Stack->PushNative(Btn, true); + + Btn->_parent = this; + _widgets.Add(Btn); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // CreateStatic + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "CreateStatic") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + CUIText *Sta = new CUIText(Game); + if (!Val->IsNULL()) Sta->SetName(Val->GetString()); + Stack->PushNative(Sta, true); + + Sta->_parent = this; + _widgets.Add(Sta); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // CreateEditor + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "CreateEditor") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + CUIEdit *Edi = new CUIEdit(Game); + if (!Val->IsNULL()) Edi->SetName(Val->GetString()); + Stack->PushNative(Edi, true); + + Edi->_parent = this; + _widgets.Add(Edi); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // CreateWindow + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "CreateWindow") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + CUIWindow *Win = new CUIWindow(Game); + if (!Val->IsNULL()) Win->SetName(Val->GetString()); + Stack->PushNative(Win, true); + + Win->_parent = this; + _widgets.Add(Win); + + return S_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 S_OK; + } else if SUCCEEDED(Game->WindowScriptMethodHook(this, Script, Stack, Name)) return S_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); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::ScSetProperty(const char *Name, CScValue *Value) { + ////////////////////////////////////////////////////////////////////////// + // Name + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Name") == 0) { + SetName(Value->GetString()); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Menu + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Menu") == 0) { + _isMenu = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // InGame + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "InGame") == 0) { + _inGame = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // PauseMusic + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "PauseMusic") == 0) { + _pauseMusic = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // ClipContents + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "ClipContents") == 0) { + _clipContents = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Transparent + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Transparent") == 0) { + _transparent = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // FadeColor + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "FadeColor") == 0) { + _fadeColor = (uint32)Value->GetInt(); + _fadeBackground = (_fadeColor != 0); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Exclusive + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Exclusive") == 0) { + if (Value->GetBool()) + GoExclusive(); + else { + Close(); + _visible = true; + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SystemExclusive + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SystemExclusive") == 0) { + if (Value->GetBool()) + GoSystemExclusive(); + else { + Close(); + _visible = true; + } + return S_OK; + } + + else return CUIObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +const char *CUIWindow::ScToString() { + return "[window]"; +} + + +////////////////////////////////////////////////////////////////////////// +bool CUIWindow::HandleKeypress(SDL_Event *event) { +//TODO +#if 0 + if (event->type == SDL_KEYDOWN && event->key.keysym.scancode == SDL_SCANCODE_TAB) { + return SUCCEEDED(MoveFocus(!CBKeyboardState::IsShiftDown())); + } else { + if (_focusedWidget) return _focusedWidget->HandleKeypress(event); + else return false; + } +#endif + return false; +} + + +////////////////////////////////////////////////////////////////////////// +bool CUIWindow::HandleMouseWheel(int Delta) { + if (_focusedWidget) return _focusedWidget->HandleMouseWheel(Delta); + else return false; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::HandleMouse(TMouseEvent Event, TMouseButton Button) { + HRESULT res = CUIObject::HandleMouse(Event, Button); + + // handle window dragging + if (!CBPlatform::IsRectEmpty(&_dragRect)) { + // start drag + if (Event == MOUSE_CLICK && Button == MOUSE_BUTTON_LEFT) { + RECT DragRect = _dragRect; + int OffsetX, OffsetY; + GetTotalOffset(&OffsetX, &OffsetY); + CBPlatform::OffsetRect(&DragRect, _posX + OffsetX, _posY + OffsetY); + + if (CBPlatform::PtInRect(&DragRect, Game->_mousePos)) { + _dragFrom.x = Game->_mousePos.x; + _dragFrom.y = Game->_mousePos.y; + _dragging = true; + } + } + // end drag + else if (_dragging && Event == MOUSE_RELEASE && Button == MOUSE_BUTTON_LEFT) { + _dragging = false; + } + } + + return res; +} + + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_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 ? S_OK : E_FAIL; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::GoExclusive() { + if (_mode == WINDOW_EXCLUSIVE) return S_OK; + + if (_mode == WINDOW_NORMAL) { + _ready = false; + _mode = WINDOW_EXCLUSIVE; + _visible = true; + _disable = false; + Game->FocusWindow(this); + return S_OK; + } else return E_FAIL; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::GoSystemExclusive() { + if (_mode == WINDOW_SYSTEM_EXCLUSIVE) return S_OK; + + MakeFreezable(false); + + _mode = WINDOW_SYSTEM_EXCLUSIVE; + _ready = false; + _visible = true; + _disable = false; + Game->FocusWindow(this); + + Game->Freeze(_pauseMusic); + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::Close() { + if (_mode == WINDOW_SYSTEM_EXCLUSIVE) { + Game->Unfreeze(); + } + + _mode = WINDOW_NORMAL; + _visible = false; + _ready = true; + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT 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 S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +void CUIWindow::MakeFreezable(bool Freezable) { + for (int i = 0; i < _widgets.GetSize(); i++) + _widgets[i]->MakeFreezable(Freezable); + + CBObject::MakeFreezable(Freezable); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::GetWindowObjects(CBArray &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 S_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..510fc076b4 --- /dev/null +++ b/engines/wintermute/UI/UIWindow.h @@ -0,0 +1,92 @@ +/* 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" + +namespace WinterMute { + +class CUIButton; +class CBViewport; +class CUIWindow : public CUIObject { +public: + HRESULT GetWindowObjects(CBArray &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; + HRESULT Close(); + HRESULT GoSystemExclusive(); + HRESULT GoExclusive(); + TWindowMode _mode; + HRESULT MoveFocus(bool Forward = true); + virtual HRESULT HandleMouse(TMouseEvent Event, TMouseButton Button); + POINT _dragFrom; + bool _dragging; + DECLARE_PERSISTENT(CUIWindow, CUIObject) + bool _transparent; + HRESULT ShowWidget(const char *Name, bool Visible = true); + HRESULT EnableWidget(const char *Name, bool Enable = true); + RECT _titleRect; + RECT _dragRect; + virtual HRESULT Display(int OffsetX = 0, int OffsetY = 0); + CUIWindow(CBGame *inGame); + virtual ~CUIWindow(); + virtual bool HandleKeypress(SDL_Event *event); + CBArray _widgets; + TTextAlign _titleAlign; + HRESULT LoadFile(const char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + CUITiledImage *_backInactive; + CBFont *_fontInactive; + CBSprite *_imageInactive; + virtual HRESULT Listen(CBScriptHolder *param1, uint32 param2); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(const char *Name); + virtual HRESULT ScSetProperty(const char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, const char *Name); + virtual const char *ScToString(); +}; + +} // end of namespace WinterMute + +#endif -- cgit v1.2.3