From 5a2cf6f36ff5f8a75b1e34b00bd5444619eb4615 Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Tue, 6 Mar 2012 04:26:55 +0100 Subject: WINTERMUTE: Add the UI-classes. --- engines/wintermute/AdEntity.h | 67 ++ engines/wintermute/AdObject.h | 123 ++++ engines/wintermute/AdTalkHolder.h | 57 ++ engines/wintermute/AdTypes.h | 93 +++ engines/wintermute/BGame.h | 10 +- engines/wintermute/BScriptHolder.h | 2 - engines/wintermute/PartEmitter.h | 136 ++++ engines/wintermute/PartForce.h | 54 ++ engines/wintermute/PartParticle.h | 86 +++ engines/wintermute/UIButton.cpp | 1043 ++++++++++++++++++++++++++++ engines/wintermute/UIButton.h | 79 +++ engines/wintermute/UIEdit.cpp | 856 +++++++++++++++++++++++ engines/wintermute/UIEdit.h | 71 ++ engines/wintermute/UIEntity.cpp | 339 +++++++++ engines/wintermute/UIEntity.h | 58 ++ engines/wintermute/UIObject.cpp | 589 ++++++++++++++++ engines/wintermute/UIObject.h | 83 +++ engines/wintermute/UIText.cpp | 484 +++++++++++++ engines/wintermute/UIText.h | 59 ++ engines/wintermute/UITiledImage.cpp | 368 ++++++++++ engines/wintermute/UITiledImage.h | 62 ++ engines/wintermute/UIWindow.cpp | 1309 +++++++++++++++++++++++++++++++++++ engines/wintermute/UIWindow.h | 92 +++ engines/wintermute/module.mk | 4 + 24 files changed, 6118 insertions(+), 6 deletions(-) create mode 100644 engines/wintermute/AdEntity.h create mode 100644 engines/wintermute/AdObject.h create mode 100644 engines/wintermute/AdTalkHolder.h create mode 100644 engines/wintermute/AdTypes.h create mode 100644 engines/wintermute/PartEmitter.h create mode 100644 engines/wintermute/PartForce.h create mode 100644 engines/wintermute/PartParticle.h create mode 100644 engines/wintermute/UIButton.cpp create mode 100644 engines/wintermute/UIButton.h create mode 100644 engines/wintermute/UIEdit.cpp create mode 100644 engines/wintermute/UIEdit.h create mode 100644 engines/wintermute/UIEntity.cpp create mode 100644 engines/wintermute/UIEntity.h create mode 100644 engines/wintermute/UIObject.cpp create mode 100644 engines/wintermute/UIObject.h create mode 100644 engines/wintermute/UIText.cpp create mode 100644 engines/wintermute/UIText.h create mode 100644 engines/wintermute/UITiledImage.cpp create mode 100644 engines/wintermute/UITiledImage.h create mode 100644 engines/wintermute/UIWindow.cpp create mode 100644 engines/wintermute/UIWindow.h diff --git a/engines/wintermute/AdEntity.h b/engines/wintermute/AdEntity.h new file mode 100644 index 0000000000..b85cc123c6 --- /dev/null +++ b/engines/wintermute/AdEntity.h @@ -0,0 +1,67 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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_ADENTITY_H +#define WINTERMUTE_ADENTITY_H + +#include "AdTalkHolder.h" + +namespace WinterMute { + +class CAdEntity : public CAdTalkHolder { +public: + HRESULT SetSprite(char *Filename); + int m_WalkToX; + int m_WalkToY; + TDirection m_WalkToDir; + void SetItem(char *ItemName); + char *m_Item; + DECLARE_PERSISTENT(CAdEntity, CAdTalkHolder) + void UpdatePosition(); + virtual int GetHeight(); + CBRegion *m_Region; + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + virtual HRESULT Update(); + virtual HRESULT Display(); + CAdEntity(CBGame *inGame); + virtual ~CAdEntity(); + HRESULT LoadFile(char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + TEntityType m_Subtype; + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); + +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/AdObject.h b/engines/wintermute/AdObject.h new file mode 100644 index 0000000000..e5cb39e6b4 --- /dev/null +++ b/engines/wintermute/AdObject.h @@ -0,0 +1,123 @@ +/* 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_ADOBJECT_H +#define WINTERMUTE_ADOBJECT_H + +#include "AdTypes.h" +#include "PartEmitter.h" + +namespace WinterMute { + +class CAdWaypointGroup; +class CAdRegion; +class CAdSentence; +class CBFont; +class CBRegion; +class CAdInventory; + +#define MAX_NUM_REGIONS 10 + +class CAdObject : public CBObject { +public: + CPartEmitter *m_PartEmitter; + virtual CPartEmitter *CreateParticleEmitter(bool FollowParent = false, int OffsetX = 0, int OffsetY = 0); + virtual HRESULT UpdatePartEmitter(); + bool m_PartFollowParent; + int m_PartOffsetX; + int m_PartOffsetY; + + HRESULT InvalidateCurrRegions(); + bool m_SubtitlesModRelative; + bool m_SubtitlesModXCenter; + int m_SubtitlesModX; + int m_SubtitlesModY; + int m_SubtitlesWidth; + CAdRegion *m_StickRegion; + bool m_SceneIndependent; + bool m_IgnoreItems; + HRESULT UpdateBlockRegion(); + bool m_ForcedTalkAnimUsed; + char *m_ForcedTalkAnimName; + virtual bool GetExtendedFlag(char *FlagName); + virtual HRESULT ResetSoundPan(); + virtual HRESULT UpdateSounds(); + HRESULT Reset(); + DECLARE_PERSISTENT(CAdObject, CBObject) + virtual void Talk(char *Text, char *Sound = NULL, uint32 Duration = 0, char *Stances = NULL, TTextAlign Align = TAL_CENTER); + virtual int GetHeight(); + CAdSentence *m_Sentence; + HRESULT SetFont(char *Filename); + virtual HRESULT Update(); + virtual HRESULT Display(); + bool m_Drawn; + bool m_Active; + virtual HRESULT PlayAnim(char *Filename); + CBSprite *m_AnimSprite; + CBSprite *m_CurrentSprite; + TObjectState m_State; + TObjectState m_NextState; + TObjectType m_Type; + CAdObject(CBGame *inGame); + virtual ~CAdObject(); + CBFont *m_Font; + CBSprite *m_TempSprite2; + CBRegion *m_BlockRegion; + CAdWaypointGroup *m_WptGroup; + CBRegion *m_CurrentBlockRegion; + CAdWaypointGroup *m_CurrentWptGroup; + CAdInventory *GetInventory(); + + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + virtual HRESULT AfterMove(); + CAdRegion *m_CurrentRegions[MAX_NUM_REGIONS]; + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); + + CBArray m_AttachmentsPre; + CBArray m_AttachmentsPost; + + HRESULT UpdateSpriteAttachments(); + HRESULT DisplaySpriteAttachments(bool PreDisplay); + CAdObject *m_RegisterAlias; +private: + HRESULT DisplaySpriteAttachment(CAdObject *Attachment); + CAdInventory *m_Inventory; + +protected: + HRESULT GetScale(float *ScaleX, float *ScaleY); +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/AdTalkHolder.h b/engines/wintermute/AdTalkHolder.h new file mode 100644 index 0000000000..7eb07a8f66 --- /dev/null +++ b/engines/wintermute/AdTalkHolder.h @@ -0,0 +1,57 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 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_ADTALKHOLDER_H +#define WINTERMUTE_ADTALKHOLDER_H + +#include "AdObject.h" + +namespace WinterMute { + +class CAdTalkHolder : public CAdObject { +public: + DECLARE_PERSISTENT(CAdTalkHolder, CAdObject) + virtual CBSprite *GetTalkStance(char *Stance); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + CBSprite *m_Sprite; + CBArray m_TalkSprites; + CBArray m_TalkSpritesEx; + CAdTalkHolder(CBGame *inGame); + virtual ~CAdTalkHolder(); + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); + +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/AdTypes.h b/engines/wintermute/AdTypes.h new file mode 100644 index 0000000000..8e77f289bc --- /dev/null +++ b/engines/wintermute/AdTypes.h @@ -0,0 +1,93 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* + * This file is based on WME Lite. + * http://dead-code.org/redir.php?target=wmelite + * Copyright (c) 2011 Jan Nedoma + */ + +#ifndef WINTERMUTE_ADTYPES_H +#define WINTERMUTE_ADTYPES_H + +namespace WinterMute { + +typedef enum { + GAME_NORMAL, GAME_WAITING_RESPONSE +} TGameStateEx; + + +typedef enum { + OBJECT_ENTITY, OBJECT_REGION, OBJECT_ACTOR, OBJECT_NONE +} TObjectType; + + +typedef enum { + ENTITY_NORMAL, ENTITY_SOUND +} TEntityType; + + +typedef enum { + STATE_NONE, + STATE_IDLE, + STATE_PLAYING_ANIM, + STATE_READY, + STATE_FOLLOWING_PATH, + STATE_SEARCHING_PATH, + STATE_WAITING_PATH, + STATE_TURNING_LEFT, + STATE_TURNING_RIGHT, + STATE_TURNING, + STATE_TALKING, + STATE_DIRECT_CONTROL, + STATE_PLAYING_ANIM_SET +} TObjectState; + +typedef enum { + DIRECT_WALK_NONE, DIRECT_WALK_FW, DIRECT_WALK_BK +} TDirectWalkMode; + +typedef enum { + DIRECT_TURN_NONE, DIRECT_TURN_CW, DIRECT_TURN_CCW +} TDirectTurnMode; + +typedef enum { + RESPONSE_TEXT, RESPONSE_ICON +} TResponseStyle; + +typedef enum { + RESPONSE_ALWAYS, RESPONSE_ONCE, RESPONSE_ONCE_GAME +} TResponseType; + + +typedef enum { + TALK_SKIP_LEFT = 0, TALK_SKIP_RIGHT = 1, TALK_SKIP_BOTH = 2, TALK_SKIP_NONE = 3 +} TTalkSkipButton; + + +typedef enum { + GEOM_WAYPOINT, GEOM_WALKPLANE, GEOM_BLOCKED, GEOM_GENERIC +} TGeomNodeType; + +} // end of namespace WinterMute + +#endif // __WmeAdTypes_H__ diff --git a/engines/wintermute/BGame.h b/engines/wintermute/BGame.h index 2af7d834b1..a13144d325 100644 --- a/engines/wintermute/BGame.h +++ b/engines/wintermute/BGame.h @@ -170,10 +170,8 @@ public: #endif uint32 m_CurrentTime; uint32 m_DeltaTime; -#if 0 CBFont *m_SystemFont; CBFont *m_VideoFont; -#endif HRESULT Initialize1(); HRESULT Initialize2(); HRESULT Initialize3(); @@ -265,10 +263,12 @@ public: virtual HRESULT GetVersion(byte *VerMajor, byte *VerMinor, byte *ExtMajor, byte *ExtMinor); #if 0 virtual bool HandleKeypress(SDL_Event *event); +#endif int m_FreezeLevel; HRESULT Unfreeze(); HRESULT Freeze(bool IncludingMusic = true); HRESULT FocusWindow(CUIWindow *Window); + bool m_LoadInProgress; CUIWindow *m_FocusedWindow; bool m_EditorForceScripts; @@ -278,6 +278,7 @@ public: static void AfterLoadFont(void *Font, void *Data); static void AfterLoadScript(void *script, void *data); static void InvalidateValues(void *Value, void *Data); +#if 0 HRESULT LoadSettings(char *Filename); HRESULT ResumeMusic(int Channel); HRESULT SetMusicStartTime(int Channel, uint32 Time); @@ -315,13 +316,14 @@ public: uint32 m_LiveTimer; uint32 m_LiveTimerDelta; uint32 m_LiveTimerLast; -#if 0 + CBObject *m_CapturedObject; +#if 0 POINT m_MousePos; +#endif bool ValidObject(CBObject *Object); HRESULT UnregisterObject(CBObject *Object); HRESULT RegisterObject(CBObject *Object); -#endif void QuickMessage(char *Text); #if 0 void QuickMessageForm(LPSTR fmt, ...); diff --git a/engines/wintermute/BScriptHolder.h b/engines/wintermute/BScriptHolder.h index cece043b88..84a1e73c46 100644 --- a/engines/wintermute/BScriptHolder.h +++ b/engines/wintermute/BScriptHolder.h @@ -41,12 +41,10 @@ public: CBScriptHolder(CBGame *inGame); virtual ~CBScriptHolder(); -#if 0 virtual CScScript *InvokeMethodThread(char *MethodName); virtual void MakeFreezable(bool Freezable); bool CanHandleEvent(char *EventName); virtual bool CanHandleMethod(char *EventMethod); -#endif HRESULT Cleanup(); HRESULT RemoveScript(CScScript *Script); HRESULT AddScript(char *Filename); diff --git a/engines/wintermute/PartEmitter.h b/engines/wintermute/PartEmitter.h new file mode 100644 index 0000000000..d23b4db488 --- /dev/null +++ b/engines/wintermute/PartEmitter.h @@ -0,0 +1,136 @@ +/* +This file is part of WME Lite. +http://dead-code.org/redir.php?target=wmelite + +Copyright (c) 2011 Jan Nedoma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef __WmePartEmitter_H__ +#define __WmePartEmitter_H__ + + +#include "BObject.h" +#include "PartParticle.h" +#include "PartForce.h" + +namespace WinterMute { +class CBRegion; + +class CPartEmitter : public CBObject { +public: + DECLARE_PERSISTENT(CPartEmitter, CBObject) + + CPartEmitter(CBGame *inGame, CBScriptHolder *Owner); + virtual ~CPartEmitter(void); + + int m_Width; + int m_Height; + + int m_Angle1; + int m_Angle2; + + float m_Rotation1; + float m_Rotation2; + + float m_AngVelocity1; + float m_AngVelocity2; + + float m_GrowthRate1; + float m_GrowthRate2; + bool m_ExponentialGrowth; + + float m_Velocity1; + float m_Velocity2; + bool m_VelocityZBased; + + float m_Scale1; + float m_Scale2; + bool m_ScaleZBased; + + int m_MaxParticles; + + int m_LifeTime1; + int m_LifeTime2; + bool m_LifeTimeZBased; + + int m_GenInterval; + int m_GenAmount; + + bool m_Running; + int m_OverheadTime; + + int m_MaxBatches; + int m_BatchesGenerated; + + RECT m_Border; + int m_BorderThicknessLeft; + int m_BorderThicknessRight; + int m_BorderThicknessTop; + int m_BorderThicknessBottom; + + int m_FadeInTime; + int m_FadeOutTime; + + int m_Alpha1; + int m_Alpha2; + bool m_AlphaTimeBased; + + bool m_UseRegion; + + char *m_EmitEvent; + CBScriptHolder *m_Owner; + + HRESULT Start(); + + HRESULT Update(); + HRESULT Display(CBRegion *Region = NULL); + + HRESULT SortParticlesByZ(); + HRESULT AddSprite(char *Filename); + HRESULT RemoveSprite(char *Filename); + HRESULT SetBorder(int X, int Y, int Width, int Height); + HRESULT SetBorderThickness(int ThicknessLeft, int ThicknessRight, int ThicknessTop, int ThicknessBottom); + + HRESULT AddForce(char *Name, CPartForce::TForceType Type, int PosX, int PosY, float Angle, float Strength); + HRESULT RemoveForce(char *Name); + + CBArray m_Forces; + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); + + +private: + CPartForce *AddForceByName(char *Name); + int static CompareZ(const void *Obj1, const void *Obj2); + HRESULT InitParticle(CPartParticle *Particle, uint32 CurrentTime, uint32 TimerDelta); + HRESULT UpdateInternal(uint32 CurrentTime, uint32 TimerDelta); + uint32 m_LastGenTime; + CBArray m_Particles; + CBArray m_Sprites; +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/PartForce.h b/engines/wintermute/PartForce.h new file mode 100644 index 0000000000..140174eb4f --- /dev/null +++ b/engines/wintermute/PartForce.h @@ -0,0 +1,54 @@ +/* +This file is part of WME Lite. +http://dead-code.org/redir.php?target=wmelite + +Copyright (c) 2011 Jan Nedoma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef __WmePartForce_H__ +#define __WmePartForce_H__ + + +#include "BBase.h" +#include "BNamedObject.h" +#include "Vector2.h" + +namespace WinterMute { + +class CPartForce : public CBNamedObject { +public: + enum TForceType { + FORCE_POINT, FORCE_GLOBAL + }; + + CPartForce(CBGame *inGame); + virtual ~CPartForce(void); + + Vector2 m_Pos; + Vector2 m_Direction; + TForceType m_Type; + + HRESULT Persist(CBPersistMgr *PersistMgr); +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/PartParticle.h b/engines/wintermute/PartParticle.h new file mode 100644 index 0000000000..eec3862b72 --- /dev/null +++ b/engines/wintermute/PartParticle.h @@ -0,0 +1,86 @@ +/* +This file is part of WME Lite. +http://dead-code.org/redir.php?target=wmelite + +Copyright (c) 2011 Jan Nedoma + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef __WmePartParticle_H__ +#define __WmePartParticle_H__ + + +#include "BBase.h" +#include "Vector2.h" + +namespace WinterMute { + +class CPartEmitter; +class CBSprite; +class CBPersistMgr; + +class CPartParticle : public CBBase { +public: + enum TParticleState { + PARTICLE_NORMAL, PARTICLE_FADEIN, PARTICLE_FADEOUT + }; + + CPartParticle(CBGame *inGame); + virtual ~CPartParticle(void); + + float m_GrowthRate; + bool m_ExponentialGrowth; + + float m_Rotation; + float m_AngVelocity; + + int m_Alpha1; + int m_Alpha2; + + RECT m_Border; + Vector2 m_Pos; + float m_PosZ; + Vector2 m_Velocity; + float m_Scale; + CBSprite *m_Sprite; + uint32 m_CreationTime; + int m_LifeTime; + bool m_IsDead; + TParticleState m_State; + + HRESULT Update(CPartEmitter *Emitter, uint32 CurrentTime, uint32 TimerDelta); + HRESULT Display(CPartEmitter *Emitter); + + HRESULT SetSprite(char *Filename); + + HRESULT FadeIn(uint32 CurrentTime, int FadeTime); + HRESULT FadeOut(uint32 CurrentTime, int FadeTime); + + HRESULT Persist(CBPersistMgr *PersistMgr); +private: + uint32 m_FadeStart; + int m_FadeTime; + int m_CurrentAlpha; + int m_FadeStartAlpha; +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/UIButton.cpp b/engines/wintermute/UIButton.cpp new file mode 100644 index 0000000000..1053cec166 --- /dev/null +++ b/engines/wintermute/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/BDynBuffer.h" +#include "engines/wintermute/BGame.h" +#include "engines/wintermute/UIButton.h" +#include "engines/wintermute/UITiledImage.h" +#include "engines/wintermute/BParser.h" +#include "engines/wintermute/BActiveRect.h" +#include "engines/wintermute/BFontStorage.h" +#include "engines/wintermute/BFont.h" +#include "engines/wintermute/BStringTable.h" +#include "engines/wintermute/BSprite.h" +#include "engines/wintermute/BFileManager.h" +#include "engines/wintermute/PlatformSDL.h" +#include "engines/wintermute/scriptables/ScValue.h" +#include "engines/wintermute/scriptables/ScScript.h" +#include "engines/wintermute/scriptables/ScStack.h" + +namespace WinterMute { + +IMPLEMENT_PERSISTENT(CUIButton, false) + +////////////////////////////////////////////////////////////////////////// +CUIButton::CUIButton(CBGame *inGame): CUIObject(inGame) { + m_BackPress = m_BackHover = m_BackDisable = m_BackFocus = NULL; + + m_FontHover = m_FontPress = m_FontDisable = m_FontFocus = NULL; + + m_ImageDisable = m_ImagePress = m_ImageHover = m_ImageFocus = NULL; + + m_Align = TAL_CENTER; + + m_Hover = m_Press = false; + + m_Type = UI_BUTTON; + + m_CanFocus = false; + m_StayPressed = false; + + m_OneTimePress = false; + m_CenterImage = false; + + m_PixelPerfect = false; +} + + +////////////////////////////////////////////////////////////////////////// +CUIButton::~CUIButton() { + if (m_BackPress) delete m_BackPress; + if (m_BackHover) delete m_BackHover; + if (m_BackDisable) delete m_BackDisable; + if (m_BackFocus) delete m_BackFocus; + + if (!m_SharedFonts) { + if (m_FontHover) Game->m_FontStorage->RemoveFont(m_FontHover); + if (m_FontPress) Game->m_FontStorage->RemoveFont(m_FontPress); + if (m_FontDisable) Game->m_FontStorage->RemoveFont(m_FontDisable); + if (m_FontFocus) Game->m_FontStorage->RemoveFont(m_FontFocus); + } + + if (!m_SharedImages) { + if (m_ImageHover) delete m_ImageHover; + if (m_ImagePress) delete m_ImagePress; + if (m_ImageDisable) delete m_ImageDisable; + if (m_ImageFocus) delete m_ImageFocus; + } +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIButton::LoadFile(char *Filename) { + byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIButton::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + m_Filename = new char [strlen(Filename) + 1]; + strcpy(m_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 m_Back; + m_Back = new CUITiledImage(Game); + if (!m_Back || FAILED(m_Back->LoadFile((char *)params))) { + delete m_Back; + m_Back = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_HOVER: + delete m_BackHover; + m_BackHover = new CUITiledImage(Game); + if (!m_BackHover || FAILED(m_BackHover->LoadFile((char *)params))) { + delete m_BackHover; + m_BackHover = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_PRESS: + delete m_BackPress; + m_BackPress = new CUITiledImage(Game); + if (!m_BackPress || FAILED(m_BackPress->LoadFile((char *)params))) { + delete m_BackPress; + m_BackPress = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_DISABLE: + delete m_BackDisable; + m_BackDisable = new CUITiledImage(Game); + if (!m_BackDisable || FAILED(m_BackDisable->LoadFile((char *)params))) { + delete m_BackDisable; + m_BackDisable = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_FOCUS: + delete m_BackFocus; + m_BackFocus = new CUITiledImage(Game); + if (!m_BackFocus || FAILED(m_BackFocus->LoadFile((char *)params))) { + delete m_BackFocus; + m_BackFocus = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE: + delete m_Image; + m_Image = new CBSprite(Game); + if (!m_Image || FAILED(m_Image->LoadFile((char *)params))) { + delete m_Image; + m_Image = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_HOVER: + delete m_ImageHover; + m_ImageHover = new CBSprite(Game); + if (!m_ImageHover || FAILED(m_ImageHover->LoadFile((char *)params))) { + delete m_ImageHover; + m_ImageHover = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_PRESS: + delete m_ImagePress; + m_ImagePress = new CBSprite(Game); + if (!m_ImagePress || FAILED(m_ImagePress->LoadFile((char *)params))) { + delete m_ImagePress; + m_ImagePress = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_DISABLE: + delete m_ImageDisable; + m_ImageDisable = new CBSprite(Game); + if (!m_ImageDisable || FAILED(m_ImageDisable->LoadFile((char *)params))) { + delete m_ImageDisable; + m_ImageDisable = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_FOCUS: + delete m_ImageFocus; + m_ImageFocus = new CBSprite(Game); + if (!m_ImageFocus || FAILED(m_ImageFocus->LoadFile((char *)params))) { + delete m_ImageFocus; + m_ImageFocus = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_FONT: + if (m_Font) Game->m_FontStorage->RemoveFont(m_Font); + m_Font = Game->m_FontStorage->AddFont((char *)params); + if (!m_Font) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_HOVER: + if (m_FontHover) Game->m_FontStorage->RemoveFont(m_FontHover); + m_FontHover = Game->m_FontStorage->AddFont((char *)params); + if (!m_FontHover) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_PRESS: + if (m_FontPress) Game->m_FontStorage->RemoveFont(m_FontPress); + m_FontPress = Game->m_FontStorage->AddFont((char *)params); + if (!m_FontPress) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_DISABLE: + if (m_FontDisable) Game->m_FontStorage->RemoveFont(m_FontDisable); + m_FontDisable = Game->m_FontStorage->AddFont((char *)params); + if (!m_FontDisable) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_FOCUS: + if (m_FontFocus) Game->m_FontStorage->RemoveFont(m_FontFocus); + m_FontFocus = Game->m_FontStorage->AddFont((char *)params); + if (!m_FontFocus) cmd = PARSERR_GENERIC; + break; + + case TOKEN_TEXT: + SetText((char *)params); + Game->m_StringTable->Expand(&m_Text); + break; + + case TOKEN_TEXT_ALIGN: + if (scumm_stricmp((char *)params, "left") == 0) m_Align = TAL_LEFT; + else if (scumm_stricmp((char *)params, "right") == 0) m_Align = TAL_RIGHT; + else m_Align = TAL_CENTER; + break; + + case TOKEN_X: + parser.ScanStr((char *)params, "%d", &m_PosX); + break; + + case TOKEN_Y: + parser.ScanStr((char *)params, "%d", &m_PosY); + break; + + case TOKEN_WIDTH: + parser.ScanStr((char *)params, "%d", &m_Width); + break; + + case TOKEN_HEIGHT: + parser.ScanStr((char *)params, "%d", &m_Height); + break; + + case TOKEN_CURSOR: + delete m_Cursor; + m_Cursor = new CBSprite(Game); + if (!m_Cursor || FAILED(m_Cursor->LoadFile((char *)params))) { + delete m_Cursor; + m_Cursor = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_SCRIPT: + AddScript((char *)params); + break; + + case TOKEN_PARENT_NOTIFY: + parser.ScanStr((char *)params, "%b", &m_ParentNotify); + break; + + case TOKEN_DISABLED: + parser.ScanStr((char *)params, "%b", &m_Disable); + break; + + case TOKEN_VISIBLE: + parser.ScanStr((char *)params, "%b", &m_Visible); + break; + + case TOKEN_FOCUSABLE: + parser.ScanStr((char *)params, "%b", &m_CanFocus); + break; + + case TOKEN_CENTER_IMAGE: + parser.ScanStr((char *)params, "%b", &m_CenterImage); + break; + + case TOKEN_PRESSED: + parser.ScanStr((char *)params, "%b", &m_StayPressed); + break; + + case TOKEN_PIXEL_PERFECT: + parser.ScanStr((char *)params, "%b", &m_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", m_Name); + Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption()); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + if (m_Back && m_Back->m_Filename) + Buffer->PutTextIndent(Indent + 2, "BACK=\"%s\"\n", m_Back->m_Filename); + if (m_BackHover && m_BackHover->m_Filename) + Buffer->PutTextIndent(Indent + 2, "BACK_HOVER=\"%s\"\n", m_BackHover->m_Filename); + if (m_BackPress && m_BackPress->m_Filename) + Buffer->PutTextIndent(Indent + 2, "BACK_PRESS=\"%s\"\n", m_BackPress->m_Filename); + if (m_BackDisable && m_BackDisable->m_Filename) + Buffer->PutTextIndent(Indent + 2, "BACK_DISABLE=\"%s\"\n", m_BackDisable->m_Filename); + if (m_BackFocus && m_BackFocus->m_Filename) + Buffer->PutTextIndent(Indent + 2, "BACK_FOCUS=\"%s\"\n", m_BackFocus->m_Filename); + + if (m_Image && m_Image->m_Filename) + Buffer->PutTextIndent(Indent + 2, "IMAGE=\"%s\"\n", m_Image->m_Filename); + if (m_ImageHover && m_ImageHover->m_Filename) + Buffer->PutTextIndent(Indent + 2, "IMAGE_HOVER=\"%s\"\n", m_ImageHover->m_Filename); + if (m_ImagePress && m_ImagePress->m_Filename) + Buffer->PutTextIndent(Indent + 2, "IMAGE_PRESS=\"%s\"\n", m_ImagePress->m_Filename); + if (m_ImageDisable && m_ImageDisable->m_Filename) + Buffer->PutTextIndent(Indent + 2, "IMAGE_DISABLE=\"%s\"\n", m_ImageDisable->m_Filename); + if (m_ImageFocus && m_ImageFocus->m_Filename) + Buffer->PutTextIndent(Indent + 2, "IMAGE_FOCUS=\"%s\"\n", m_ImageFocus->m_Filename); + + if (m_Font && m_Font->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT=\"%s\"\n", m_Font->m_Filename); + if (m_FontHover && m_FontHover->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT_HOVER=\"%s\"\n", m_FontHover->m_Filename); + if (m_FontPress && m_FontPress->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT_PRESS=\"%s\"\n", m_FontPress->m_Filename); + if (m_FontDisable && m_FontDisable->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT_DISABLE=\"%s\"\n", m_FontDisable->m_Filename); + if (m_FontFocus && m_FontFocus->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT_FOCUS=\"%s\"\n", m_FontFocus->m_Filename); + + if (m_Cursor && m_Cursor->m_Filename) + Buffer->PutTextIndent(Indent + 2, "CURSOR=\"%s\"\n", m_Cursor->m_Filename); + + + Buffer->PutTextIndent(Indent + 2, "\n"); + + if (m_Text) + Buffer->PutTextIndent(Indent + 2, "TEXT=\"%s\"\n", m_Text); + + switch (m_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", m_PosX); + Buffer->PutTextIndent(Indent + 2, "Y=%d\n", m_PosY); + Buffer->PutTextIndent(Indent + 2, "WIDTH=%d\n", m_Width); + Buffer->PutTextIndent(Indent + 2, "HEIGHT=%d\n", m_Height); + + + Buffer->PutTextIndent(Indent + 2, "DISABLED=%s\n", m_Disable ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "VISIBLE=%s\n", m_Visible ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "PARENT_NOTIFY=%s\n", m_ParentNotify ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "FOCUSABLE=%s\n", m_CanFocus ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "CENTER_IMAGE=%s\n", m_CenterImage ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "PRESSED=%s\n", m_StayPressed ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "PIXEL_PERFECT=%s\n", m_PixelPerfect ? "TRUE" : "FALSE"); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + // scripts + for (int i = 0; i < m_Scripts.GetSize(); i++) { + Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", m_Scripts[i]->m_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 (m_Image) img = m_Image; + else if (m_ImageDisable) img = m_ImageDisable; + else if (m_ImageHover) img = m_ImageHover; + else if (m_ImagePress) img = m_ImagePress; + else if (m_ImageFocus) img = m_ImageFocus; + + if (m_Width <= 0) { + if (img) { + img->GetBoundingRect(&rect, 0, 0); + m_Width = rect.right - rect.left; + } else m_Width = 100; + } + + if (m_Height <= 0) { + if (img) { + img->GetBoundingRect(&rect, 0, 0); + m_Height = rect.bottom - rect.top; + } + } + + if (m_Text) { + int text_height; + if (m_Font) text_height = m_Font->GetTextHeight((byte *)m_Text, m_Width); + else text_height = Game->m_SystemFont->GetTextHeight((byte *)m_Text, m_Width); + + if (text_height > m_Height) m_Height = text_height; + } + + if (m_Height <= 0) m_Height = 100; + + if (m_Back) m_Back->CorrectSize(&m_Width, &m_Height); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIButton::Display(int OffsetX, int OffsetY) { + if (!m_Visible) return S_OK; + + CUITiledImage *back = NULL; + CBSprite *image = NULL; + CBFont *font = 0; + + //RECT rect; + //CBPlatform::SetRect(&rect, OffsetX + m_PosX, OffsetY + m_PosY, OffsetX+m_PosX+m_Width, OffsetY+m_PosY+m_Height); + //m_Hover = (!m_Disable && CBPlatform::PtInRect(&rect, Game->m_MousePos)!=FALSE); + m_Hover = (!m_Disable && Game->m_ActiveObject == this && (Game->m_Interactive || Game->m_State == GAME_SEMI_FROZEN)); + + if ((m_Press && m_Hover && !Game->m_MouseLeftDown) || + m_OneTimePress && CBPlatform::GetTime() - m_OneTimePressTime >= 100) Press(); + + + if (m_Disable) { + if (m_BackDisable) back = m_BackDisable; + if (m_ImageDisable) image = m_ImageDisable; + if (m_Text && m_FontDisable) font = m_FontDisable; + } else if (m_Press || m_OneTimePress || m_StayPressed) { + if (m_BackPress) back = m_BackPress; + if (m_ImagePress) image = m_ImagePress; + if (m_Text && m_FontPress) font = m_FontPress; + } else if (m_Hover) { + if (m_BackHover) back = m_BackHover; + if (m_ImageHover) image = m_ImageHover; + if (m_Text && m_FontHover) font = m_FontHover; + } else if (m_CanFocus && IsFocused()) { + if (m_BackFocus) back = m_BackFocus; + if (m_ImageFocus) image = m_ImageFocus; + if (m_Text && m_FontFocus) font = m_FontFocus; + } + + if (!back && m_Back) back = m_Back; + if (!image && m_Image) image = m_Image; + if (m_Text && !font) { + if (m_Font) font = m_Font; + else font = Game->m_SystemFont; + } + + int ImageX = OffsetX + m_PosX; + int ImageY = OffsetY + m_PosY; + + if (image && m_CenterImage) { + RECT rc; + image->GetBoundingRect(&rc, 0, 0); + ImageX += (m_Width - (rc.right - rc.left)) / 2; + ImageY += (m_Height - (rc.bottom - rc.top)) / 2; + } + + if (back) back->Display(OffsetX + m_PosX, OffsetY + m_PosY, m_Width, m_Height); + //if(image) image->Draw(ImageX +((m_Press||m_OneTimePress)&&back?1:0), ImageY +((m_Press||m_OneTimePress)&&back?1:0), NULL); + if (image) image->Draw(ImageX + ((m_Press || m_OneTimePress) && back ? 1 : 0), ImageY + ((m_Press || m_OneTimePress) && back ? 1 : 0), m_PixelPerfect ? this : NULL); + + if (font && m_Text) { + int text_offset = (m_Height - font->GetTextHeight((byte *)m_Text, m_Width)) / 2; + font->DrawText((byte *)m_Text, OffsetX + m_PosX + ((m_Press || m_OneTimePress) ? 1 : 0), OffsetY + m_PosY + text_offset + ((m_Press || m_OneTimePress) ? 1 : 0), m_Width, m_Align); + } + + if (!m_PixelPerfect || !m_Image) Game->m_Renderer->m_RectList.Add(new CBActiveRect(Game, this, NULL, OffsetX + m_PosX, OffsetY + m_PosY, m_Width, m_Height, 100, 100, false)); + + // reset unused sprites + if (m_Image && m_Image != image) m_Image->Reset(); + if (m_ImageDisable && m_ImageDisable != image) m_ImageDisable->Reset(); + if (m_ImageFocus && m_ImageFocus != image) m_ImageFocus->Reset(); + if (m_ImagePress && m_ImagePress != image) m_ImagePress->Reset(); + if (m_ImageHover && m_ImageHover != image) m_ImageHover->Reset(); + + m_Press = m_Hover && Game->m_MouseLeftDown && Game->m_CapturedObject == this; + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +void CUIButton::Press() { + ApplyEvent("Press"); + if (m_ListenerObject) m_ListenerObject->Listen(m_ListenerParamObject, m_ListenerParamDWORD); + if (m_ParentNotify && m_Parent) m_Parent->ApplyEvent(m_Name); + + m_OneTimePress = false; +} + + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +HRESULT CUIButton::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) { + ////////////////////////////////////////////////////////////////////////// + // SetDisabledFont + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "SetDisabledFont") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + if (m_FontDisable) Game->m_FontStorage->RemoveFont(m_FontDisable); + if (Val->IsNULL()) { + m_FontDisable = NULL; + Stack->PushBool(true); + } else { + m_FontDisable = Game->m_FontStorage->AddFont(Val->GetString()); + Stack->PushBool(m_FontDisable != NULL); + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetHoverFont + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetHoverFont") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + if (m_FontHover) Game->m_FontStorage->RemoveFont(m_FontHover); + if (Val->IsNULL()) { + m_FontHover = NULL; + Stack->PushBool(true); + } else { + m_FontHover = Game->m_FontStorage->AddFont(Val->GetString()); + Stack->PushBool(m_FontHover != NULL); + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetPressedFont + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetPressedFont") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + if (m_FontPress) Game->m_FontStorage->RemoveFont(m_FontPress); + if (Val->IsNULL()) { + m_FontPress = NULL; + Stack->PushBool(true); + } else { + m_FontPress = Game->m_FontStorage->AddFont(Val->GetString()); + Stack->PushBool(m_FontPress != NULL); + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetFocusedFont + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetFocusedFont") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + if (m_FontFocus) Game->m_FontStorage->RemoveFont(m_FontFocus); + if (Val->IsNULL()) { + m_FontFocus = NULL; + Stack->PushBool(true); + } else { + m_FontFocus = Game->m_FontStorage->AddFont(Val->GetString()); + Stack->PushBool(m_FontFocus != NULL); + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetDisabledImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetDisabledImage") == 0) { + Stack->CorrectParams(1); + + delete m_ImageDisable; + m_ImageDisable = new CBSprite(Game); + char *Filename = Stack->Pop()->GetString(); + if (!m_ImageDisable || FAILED(m_ImageDisable->LoadFile(Filename))) { + delete m_ImageDisable; + m_ImageDisable = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetDisabledImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetDisabledImage") == 0) { + Stack->CorrectParams(0); + if (!m_ImageDisable || !m_ImageDisable->m_Filename) Stack->PushNULL(); + else Stack->PushString(m_ImageDisable->m_Filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetDisabledImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetDisabledImageObject") == 0) { + Stack->CorrectParams(0); + if (!m_ImageDisable) Stack->PushNULL(); + else Stack->PushNative(m_ImageDisable, true); + + return S_OK; + } + + + ////////////////////////////////////////////////////////////////////////// + // SetHoverImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetHoverImage") == 0) { + Stack->CorrectParams(1); + + delete m_ImageHover; + m_ImageHover = new CBSprite(Game); + char *Filename = Stack->Pop()->GetString(); + if (!m_ImageHover || FAILED(m_ImageHover->LoadFile(Filename))) { + delete m_ImageHover; + m_ImageHover = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetHoverImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetHoverImage") == 0) { + Stack->CorrectParams(0); + if (!m_ImageHover || !m_ImageHover->m_Filename) Stack->PushNULL(); + else Stack->PushString(m_ImageHover->m_Filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetHoverImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetHoverImageObject") == 0) { + Stack->CorrectParams(0); + if (!m_ImageHover) Stack->PushNULL(); + else Stack->PushNative(m_ImageHover, true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetPressedImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetPressedImage") == 0) { + Stack->CorrectParams(1); + + delete m_ImagePress; + m_ImagePress = new CBSprite(Game); + char *Filename = Stack->Pop()->GetString(); + if (!m_ImagePress || FAILED(m_ImagePress->LoadFile(Filename))) { + delete m_ImagePress; + m_ImagePress = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetPressedImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetPressedImage") == 0) { + Stack->CorrectParams(0); + if (!m_ImagePress || !m_ImagePress->m_Filename) Stack->PushNULL(); + else Stack->PushString(m_ImagePress->m_Filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetPressedImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetPressedImageObject") == 0) { + Stack->CorrectParams(0); + if (!m_ImagePress) Stack->PushNULL(); + else Stack->PushNative(m_ImagePress, true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetFocusedImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetFocusedImage") == 0) { + Stack->CorrectParams(1); + + delete m_ImageFocus; + m_ImageFocus = new CBSprite(Game); + char *Filename = Stack->Pop()->GetString(); + if (!m_ImageFocus || FAILED(m_ImageFocus->LoadFile(Filename))) { + delete m_ImageFocus; + m_ImageFocus = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetFocusedImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetFocusedImage") == 0) { + Stack->CorrectParams(0); + if (!m_ImageFocus || !m_ImageFocus->m_Filename) Stack->PushNULL(); + else Stack->PushString(m_ImageFocus->m_Filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetFocusedImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetFocusedImageObject") == 0) { + Stack->CorrectParams(0); + if (!m_ImageFocus) Stack->PushNULL(); + else Stack->PushNative(m_ImageFocus, true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Press + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Press") == 0) { + Stack->CorrectParams(0); + + if (m_Visible && !m_Disable) { + m_OneTimePress = true; + m_OneTimePressTime = CBPlatform::GetTime(); + } + Stack->PushNULL(); + + return S_OK; + } + + + else return CUIObject::ScCallMethod(Script, Stack, ThisStack, Name); +} + + +////////////////////////////////////////////////////////////////////////// +CScValue *CUIButton::ScGetProperty(char *Name) { + m_ScValue->SetNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Type") == 0) { + m_ScValue->SetString("button"); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // TextAlign + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "TextAlign") == 0) { + m_ScValue->SetInt(m_Align); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Focusable + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Focusable") == 0) { + m_ScValue->SetBool(m_CanFocus); + return m_ScValue; + } + ////////////////////////////////////////////////////////////////////////// + // Pressed + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Pressed") == 0) { + m_ScValue->SetBool(m_StayPressed); + return m_ScValue; + } + ////////////////////////////////////////////////////////////////////////// + // PixelPerfect + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "PixelPerfect") == 0) { + m_ScValue->SetBool(m_PixelPerfect); + return m_ScValue; + } + + else return CUIObject::ScGetProperty(Name); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIButton::ScSetProperty(char *Name, CScValue *Value) { + ////////////////////////////////////////////////////////////////////////// + // TextAlign + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "TextAlign") == 0) { + int i = Value->GetInt(); + if (i < 0 || i >= NUM_TEXT_ALIGN) i = 0; + m_Align = (TTextAlign)i; + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Focusable + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Focusable") == 0) { + m_CanFocus = Value->GetBool(); + return S_OK; + } + ////////////////////////////////////////////////////////////////////////// + // Pressed + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Pressed") == 0) { + m_StayPressed = Value->GetBool(); + return S_OK; + } + ////////////////////////////////////////////////////////////////////////// + // PixelPerfect + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "PixelPerfect") == 0) { + m_PixelPerfect = Value->GetBool(); + return S_OK; + } + + else return CUIObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +char *CUIButton::ScToString() { + return "[button]"; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIButton::Persist(CBPersistMgr *PersistMgr) { + + CUIObject::Persist(PersistMgr); + + PersistMgr->Transfer(TMEMBER_INT(m_Align)); + PersistMgr->Transfer(TMEMBER(m_BackDisable)); + PersistMgr->Transfer(TMEMBER(m_BackFocus)); + PersistMgr->Transfer(TMEMBER(m_BackHover)); + PersistMgr->Transfer(TMEMBER(m_BackPress)); + PersistMgr->Transfer(TMEMBER(m_CenterImage)); + PersistMgr->Transfer(TMEMBER(m_FontDisable)); + PersistMgr->Transfer(TMEMBER(m_FontFocus)); + PersistMgr->Transfer(TMEMBER(m_FontHover)); + PersistMgr->Transfer(TMEMBER(m_FontPress)); + PersistMgr->Transfer(TMEMBER(m_Hover)); + PersistMgr->Transfer(TMEMBER(m_Image)); + PersistMgr->Transfer(TMEMBER(m_ImageDisable)); + PersistMgr->Transfer(TMEMBER(m_ImageFocus)); + PersistMgr->Transfer(TMEMBER(m_ImageHover)); + PersistMgr->Transfer(TMEMBER(m_ImagePress)); + PersistMgr->Transfer(TMEMBER(m_PixelPerfect)); + PersistMgr->Transfer(TMEMBER(m_Press)); + PersistMgr->Transfer(TMEMBER(m_StayPressed)); + + if (!PersistMgr->m_Saving) { + m_OneTimePress = false; + m_OneTimePressTime = 0; + } + + return S_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/UIButton.h b/engines/wintermute/UIButton.h new file mode 100644 index 0000000000..aa4b7f8b78 --- /dev/null +++ b/engines/wintermute/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 "dctypes.h" // Added by ClassView + +namespace WinterMute { + +class CUIButton : public CUIObject { +public: + bool m_PixelPerfect; + bool m_StayPressed; + bool m_CenterImage; + bool m_OneTimePress; + uint32 m_OneTimePressTime; + DECLARE_PERSISTENT(CUIButton, CUIObject) + void Press(); + virtual HRESULT Display(int OffsetX = 0, int OffsetY = 0); + bool m_Press; + bool m_Hover; + void CorrectSize(); + TTextAlign m_Align; + CBSprite *m_ImageHover; + CBSprite *m_ImagePress; + CBSprite *m_ImageDisable; + CBSprite *m_ImageFocus; + CBFont *m_FontDisable; + CBFont *m_FontPress; + CBFont *m_FontHover; + CBFont *m_FontFocus; + CUITiledImage *m_BackPress; + CUITiledImage *m_BackHover; + CUITiledImage *m_BackDisable; + CUITiledImage *m_BackFocus; + CUIButton(CBGame *inGame = NULL); + virtual ~CUIButton(); + HRESULT LoadFile(char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/UIEdit.cpp b/engines/wintermute/UIEdit.cpp new file mode 100644 index 0000000000..af214c50dd --- /dev/null +++ b/engines/wintermute/UIEdit.cpp @@ -0,0 +1,856 @@ +/* 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/UIEdit.h" +#include "engines/wintermute/UIObject.h" +#include "engines/wintermute/UITiledImage.h" +#include "engines/wintermute/StringUtil.h" +#include "engines/wintermute/BActiveRect.h" +#include "engines/wintermute/BFileManager.h" +#include "engines/wintermute/BFont.h" +#include "engines/wintermute/BFontStorage.h" +#include "engines/wintermute/BKeyboardState.h" +#include "engines/wintermute/BDynBuffer.h" +#include "engines/wintermute/BParser.h" +#include "engines/wintermute/BSprite.h" +#include "engines/wintermute/BStringTable.h" +#include "engines/wintermute/BGame.h" +#include "engines/wintermute/PlatformSDL.h" +#include "engines/wintermute/scriptables/ScValue.h" +#include "engines/wintermute/scriptables/ScStack.h" +#include "engines/wintermute/scriptables/ScScript.h" +#include "engines/wintermute/utils.h" + +namespace WinterMute { + +IMPLEMENT_PERSISTENT(CUIEdit, false) + +////////////////////////////////////////////////////////////////////////// +CUIEdit::CUIEdit(CBGame *inGame): CUIObject(inGame) { + m_Type = UI_EDIT; + + m_FontSelected = NULL; + + m_SelStart = m_SelEnd = 10000; + m_ScrollOffset = 0; + + m_CursorChar = NULL; + SetCursorChar("|"); + +#ifdef __WIN32__ + m_CursorBlinkRate = GetCaretBlinkTime(); +#else + m_CursorBlinkRate = 600; +#endif + m_FrameWidth = 0; + + SetText(""); + + m_LastBlinkTime = 0; + m_CursorVisible = true; + + m_MaxLength = -1; + + m_CanFocus = true; +} + + +////////////////////////////////////////////////////////////////////////// +CUIEdit::~CUIEdit() { + if (!m_SharedFonts) { + if (m_FontSelected) Game->m_FontStorage->RemoveFont(m_FontSelected); + } + + delete[] m_CursorChar; + m_CursorChar = NULL; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEdit::LoadFile(char *Filename) { + byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIEdit::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + m_Filename = new char [strlen(Filename) + 1]; + strcpy(m_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 m_Back; + m_Back = new CUITiledImage(Game); + if (!m_Back || FAILED(m_Back->LoadFile((char *)params))) { + delete m_Back; + m_Back = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE: + delete m_Image; + m_Image = new CBSprite(Game); + if (!m_Image || FAILED(m_Image->LoadFile((char *)params))) { + delete m_Image; + m_Image = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_FONT: + if (m_Font) Game->m_FontStorage->RemoveFont(m_Font); + m_Font = Game->m_FontStorage->AddFont((char *)params); + if (!m_Font) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_SELECTED: + if (m_FontSelected) Game->m_FontStorage->RemoveFont(m_FontSelected); + m_FontSelected = Game->m_FontStorage->AddFont((char *)params); + if (!m_FontSelected) cmd = PARSERR_GENERIC; + break; + + case TOKEN_TEXT: + SetText((char *)params); + Game->m_StringTable->Expand(&m_Text); + break; + + case TOKEN_X: + parser.ScanStr((char *)params, "%d", &m_PosX); + break; + + case TOKEN_Y: + parser.ScanStr((char *)params, "%d", &m_PosY); + break; + + case TOKEN_WIDTH: + parser.ScanStr((char *)params, "%d", &m_Width); + break; + + case TOKEN_HEIGHT: + parser.ScanStr((char *)params, "%d", &m_Height); + break; + + case TOKEN_MAX_LENGTH: + parser.ScanStr((char *)params, "%d", &m_MaxLength); + break; + + case TOKEN_CAPTION: + SetCaption((char *)params); + break; + + case TOKEN_CURSOR: + delete m_Cursor; + m_Cursor = new CBSprite(Game); + if (!m_Cursor || FAILED(m_Cursor->LoadFile((char *)params))) { + delete m_Cursor; + m_Cursor = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_CURSOR_BLINK_RATE: + parser.ScanStr((char *)params, "%d", &m_CursorBlinkRate); + break; + + case TOKEN_FRAME_WIDTH: + parser.ScanStr((char *)params, "%d", &m_FrameWidth); + break; + + case TOKEN_SCRIPT: + AddScript((char *)params); + break; + + case TOKEN_PARENT_NOTIFY: + parser.ScanStr((char *)params, "%b", &m_ParentNotify); + break; + + case TOKEN_DISABLED: + parser.ScanStr((char *)params, "%b", &m_Disable); + break; + + case TOKEN_VISIBLE: + parser.ScanStr((char *)params, "%b", &m_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", m_Name); + Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption()); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + if (m_Back && m_Back->m_Filename) + Buffer->PutTextIndent(Indent + 2, "BACK=\"%s\"\n", m_Back->m_Filename); + + if (m_Image && m_Image->m_Filename) + Buffer->PutTextIndent(Indent + 2, "IMAGE=\"%s\"\n", m_Image->m_Filename); + + if (m_Font && m_Font->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT=\"%s\"\n", m_Font->m_Filename); + if (m_FontSelected && m_FontSelected->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT_SELECTED=\"%s\"\n", m_FontSelected->m_Filename); + + if (m_Cursor && m_Cursor->m_Filename) + Buffer->PutTextIndent(Indent + 2, "CURSOR=\"%s\"\n", m_Cursor->m_Filename); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + if (m_Text) + Buffer->PutTextIndent(Indent + 2, "TEXT=\"%s\"\n", m_Text); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + Buffer->PutTextIndent(Indent + 2, "X=%d\n", m_PosX); + Buffer->PutTextIndent(Indent + 2, "Y=%d\n", m_PosY); + Buffer->PutTextIndent(Indent + 2, "WIDTH=%d\n", m_Width); + Buffer->PutTextIndent(Indent + 2, "HEIGHT=%d\n", m_Height); + Buffer->PutTextIndent(Indent + 2, "MAX_LENGTH=%d\n", m_MaxLength); + Buffer->PutTextIndent(Indent + 2, "CURSOR_BLINK_RATE=%d\n", m_CursorBlinkRate); + Buffer->PutTextIndent(Indent + 2, "FRAME_WIDTH=%d\n", m_FrameWidth); + + Buffer->PutTextIndent(Indent + 2, "DISABLED=%s\n", m_Disable ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "VISIBLE=%s\n", m_Visible ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "PARENT_NOTIFY=%s\n", m_ParentNotify ? "TRUE" : "FALSE"); + + // scripts + for (int i = 0; i < m_Scripts.GetSize(); i++) { + Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", m_Scripts[i]->m_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, char *Name) { + ////////////////////////////////////////////////////////////////////////// + // SetSelectedFont + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "SetSelectedFont") == 0) { + Stack->CorrectParams(1); + + if (m_FontSelected) Game->m_FontStorage->RemoveFont(m_FontSelected); + m_FontSelected = Game->m_FontStorage->AddFont(Stack->Pop()->GetString()); + Stack->PushBool(m_FontSelected != NULL); + + return S_OK; + } + + else return CUIObject::ScCallMethod(Script, Stack, ThisStack, Name); +} + + +////////////////////////////////////////////////////////////////////////// +CScValue *CUIEdit::ScGetProperty(char *Name) { + m_ScValue->SetNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Type") == 0) { + m_ScValue->SetString("editor"); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // SelStart + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SelStart") == 0) { + m_ScValue->SetInt(m_SelStart); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // SelEnd + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SelEnd") == 0) { + m_ScValue->SetInt(m_SelEnd); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // CursorBlinkRate + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "CursorBlinkRate") == 0) { + m_ScValue->SetInt(m_CursorBlinkRate); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // CursorChar + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "CursorChar") == 0) { + m_ScValue->SetString(m_CursorChar); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // FrameWidth + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "FrameWidth") == 0) { + m_ScValue->SetInt(m_FrameWidth); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // MaxLength + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "MaxLength") == 0) { + m_ScValue->SetInt(m_MaxLength); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Text + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Text") == 0) { + if (Game->m_TextEncoding == TEXT_UTF8) { + WideString wstr = StringUtil::AnsiToWide(m_Text); + m_ScValue->SetString(StringUtil::WideToUtf8(wstr).c_str()); + } else { + m_ScValue->SetString(m_Text); + } + return m_ScValue; + } + + else return CUIObject::ScGetProperty(Name); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEdit::ScSetProperty(char *Name, CScValue *Value) { + ////////////////////////////////////////////////////////////////////////// + // SelStart + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "SelStart") == 0) { + m_SelStart = Value->GetInt(); + m_SelStart = MAX(m_SelStart, 0); + m_SelStart = MIN(m_SelStart, strlen(m_Text)); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SelEnd + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SelEnd") == 0) { + m_SelEnd = Value->GetInt(); + m_SelEnd = MAX(m_SelEnd, 0); + m_SelEnd = MIN(m_SelEnd, strlen(m_Text)); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // CursorBlinkRate + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "CursorBlinkRate") == 0) { + m_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) { + m_FrameWidth = Value->GetInt(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // MaxLength + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "MaxLength") == 0) { + m_MaxLength = Value->GetInt(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Text + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Text") == 0) { + if (Game->m_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); +} + + +////////////////////////////////////////////////////////////////////////// +char *CUIEdit::ScToString() { + return "[edit]"; +} + + +////////////////////////////////////////////////////////////////////////// +void CUIEdit::SetCursorChar(char *Char) { + if (!Char) return; + delete[] m_CursorChar; + m_CursorChar = new char [strlen(Char) + 1]; + if (m_CursorChar) strcpy(m_CursorChar, Char); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEdit::Display(int OffsetX, int OffsetY) { + if (!m_Visible) return S_OK; + + + // hack! + TTextEncoding OrigEncoding = Game->m_TextEncoding; + Game->m_TextEncoding = TEXT_ANSI; + + if (m_Back) m_Back->Display(OffsetX + m_PosX, OffsetY + m_PosY, m_Width, m_Height); + if (m_Image) m_Image->Draw(OffsetX + m_PosX, OffsetY + m_PosY, NULL); + + // prepare fonts + CBFont *font; + CBFont *sfont; + + if (m_Font) font = m_Font; + else font = Game->m_SystemFont; + + if (m_FontSelected) sfont = m_FontSelected; + else sfont = font; + + bool focused = IsFocused(); + + m_SelStart = MAX(m_SelStart, 0); + m_SelEnd = MAX(m_SelEnd, 0); + + m_SelStart = MIN(m_SelStart, strlen(m_Text)); + m_SelEnd = MIN(m_SelEnd, strlen(m_Text)); + + //int CursorWidth = font->GetCharWidth(m_CursorChar[0]); + int CursorWidth = font->GetTextWidth((byte *)m_CursorChar); + + int s1, s2; + bool CurFirst; + // modify scroll offset + if (m_SelStart >= m_SelEnd) { + while (font->GetTextWidth((byte *)m_Text + m_ScrollOffset, std::max(0, m_SelEnd - m_ScrollOffset)) > m_Width - CursorWidth - 2 * m_FrameWidth) { + m_ScrollOffset++; + if (m_ScrollOffset >= strlen(m_Text)) break; + } + + m_ScrollOffset = std::min(m_ScrollOffset, m_SelEnd); + + s1 = m_SelEnd; + s2 = m_SelStart; + CurFirst = true; + } else { + while (font->GetTextWidth((byte *)m_Text + m_ScrollOffset, std::max(0, m_SelStart - m_ScrollOffset)) + + sfont->GetTextWidth((byte *)(m_Text + std::max(m_ScrollOffset, m_SelStart)), m_SelEnd - std::max(m_ScrollOffset, m_SelStart)) + + > m_Width - CursorWidth - 2 * m_FrameWidth) { + m_ScrollOffset++; + if (m_ScrollOffset >= strlen(m_Text)) break; + } + + m_ScrollOffset = std::min(m_ScrollOffset, m_SelEnd); + + s1 = m_SelStart; + s2 = m_SelEnd; + CurFirst = false; + } + + + int AlignOffset = 0; + + for (int Count = 0; Count < 2; Count++) { + // draw text + int xxx, yyy, width, height; + + xxx = m_PosX + m_FrameWidth + OffsetX; + yyy = m_PosY + m_FrameWidth + OffsetY; + + width = m_PosX + m_Width + OffsetX - m_FrameWidth; + height = std::max(font->GetLetterHeight(), sfont->GetLetterHeight()); + + if (Game->m_TextRTL) xxx += AlignOffset; + + TTextAlign Align = TAL_LEFT; + + + // unselected 1 + if (s1 > m_ScrollOffset) { + if (Count) font->DrawText((byte *)m_Text + m_ScrollOffset, xxx, yyy, width - xxx, Align, height, s1 - m_ScrollOffset); + xxx += font->GetTextWidth((byte *)m_Text + m_ScrollOffset, s1 - m_ScrollOffset); + AlignOffset += font->GetTextWidth((byte *)m_Text + m_ScrollOffset, s1 - m_ScrollOffset); + } + + // cursor + if (focused && CurFirst) { + if (Count) { + if (CBPlatform::GetTime() - m_LastBlinkTime >= m_CursorBlinkRate) { + m_LastBlinkTime = CBPlatform::GetTime(); + m_CursorVisible = !m_CursorVisible; + } + if (m_CursorVisible) + font->DrawText((byte *)m_CursorChar, xxx, yyy, width - xxx, Align, height, 1); + } + xxx += CursorWidth; + AlignOffset += CursorWidth; + } + + // selected + int s3 = std::max(s1, m_ScrollOffset); + + if (s2 - s3 > 0) { + if (Count) sfont->DrawText((byte *)m_Text + s3, xxx, yyy, width - xxx, Align, height, s2 - s3); + xxx += sfont->GetTextWidth((byte *)m_Text + s3, s2 - s3); + AlignOffset += sfont->GetTextWidth((byte *)m_Text + s3, s2 - s3); + } + + // cursor + if (focused && !CurFirst) { + if (Count) { + if (CBPlatform::GetTime() - m_LastBlinkTime >= m_CursorBlinkRate) { + m_LastBlinkTime = CBPlatform::GetTime(); + m_CursorVisible = !m_CursorVisible; + } + if (m_CursorVisible) + font->DrawText((byte *)m_CursorChar, xxx, yyy, width - xxx, Align, height, 1); + } + xxx += CursorWidth; + AlignOffset += CursorWidth; + } + + // unselected 2 + if (Count) font->DrawText((byte *)m_Text + s2, xxx, yyy, width - xxx, Align, height); + AlignOffset += font->GetTextWidth((byte *)m_Text + s2); + + AlignOffset = (m_Width - 2 * m_FrameWidth) - AlignOffset; + if (AlignOffset < 0) AlignOffset = 0; + } + + + Game->m_Renderer->m_RectList.Add(new CBActiveRect(Game, this, NULL, OffsetX + m_PosX, OffsetY + m_PosY, m_Width, m_Height, 100, 100, false)); + + + Game->m_TextEncoding = OrigEncoding; + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +bool CUIEdit::HandleKeypress(SDL_Event *event) { + bool Handled = false; + + if (event->type == SDL_KEYDOWN) { + switch (event->key.keysym.sym) { + case SDLK_ESCAPE: + case SDLK_TAB: + case SDLK_RETURN: + return false; + + // ctrl+A + case SDLK_a: + if (CBKeyboardState::IsControlDown()) { + m_SelStart = 0; + m_SelEnd = strlen(m_Text); + Handled = true; + } + break; + + case SDLK_BACKSPACE: + if (m_SelStart == m_SelEnd) { + if (Game->m_TextRTL) DeleteChars(m_SelStart, m_SelStart + 1); + else DeleteChars(m_SelStart - 1, m_SelStart); + } else DeleteChars(m_SelStart, m_SelEnd); + if (m_SelEnd >= m_SelStart) m_SelEnd -= std::max(1, m_SelEnd - m_SelStart); + m_SelStart = m_SelEnd; + + Handled = true; + break; + + case SDLK_LEFT: + case SDLK_UP: + m_SelEnd--; + if (!CBKeyboardState::IsShiftDown()) m_SelStart = m_SelEnd; + Handled = true; + break; + + case SDLK_RIGHT: + case SDLK_DOWN: + m_SelEnd++; + if (!CBKeyboardState::IsShiftDown()) m_SelStart = m_SelEnd; + Handled = true; + break; + + case SDLK_HOME: + if (Game->m_TextRTL) { + m_SelEnd = strlen(m_Text); + if (!CBKeyboardState::IsShiftDown()) m_SelStart = m_SelEnd; + } else { + m_SelEnd = 0; + if (!CBKeyboardState::IsShiftDown()) m_SelStart = m_SelEnd; + } + Handled = true; + break; + + case SDLK_END: + if (Game->m_TextRTL) { + m_SelEnd = 0; + if (!CBKeyboardState::IsShiftDown()) m_SelStart = m_SelEnd; + } else { + m_SelEnd = strlen(m_Text); + if (!CBKeyboardState::IsShiftDown()) m_SelStart = m_SelEnd; + } + Handled = true; + break; + + case SDLK_DELETE: + if (m_SelStart == m_SelEnd) { + if (Game->m_TextRTL) { + DeleteChars(m_SelStart - 1, m_SelStart); + m_SelEnd--; + if (m_SelEnd < 0) m_SelEnd = 0; + } else DeleteChars(m_SelStart, m_SelStart + 1); + } else DeleteChars(m_SelStart, m_SelEnd); + if (m_SelEnd > m_SelStart) m_SelEnd -= (m_SelEnd - m_SelStart); + + m_SelStart = m_SelEnd; + Handled = true; + break; + } + return Handled; + } + + else if (event->type == SDL_TEXTINPUT) { + if (m_SelStart != m_SelEnd) DeleteChars(m_SelStart, m_SelEnd); + + WideString wstr = StringUtil::Utf8ToWide(event->text.text); + m_SelEnd += InsertChars(m_SelEnd, (byte *)StringUtil::WideToAnsi(wstr).c_str(), 1); + + if (Game->m_TextRTL) m_SelEnd = m_SelStart; + else m_SelStart = m_SelEnd; + + return true; + } + + return false; +} + + + +////////////////////////////////////////////////////////////////////////// +int CUIEdit::DeleteChars(int Start, int End) { + if (Start > End) CBUtils::Swap(&Start, &End); + + Start = MAX(Start, 0); + End = MIN(End, strlen(m_Text)); + + char *str = new char[strlen(m_Text) - (End - Start) + 1]; + if (str) { + if (Start > 0) memcpy(str, m_Text, Start); + memcpy(str + std::max(0, Start), m_Text + End, strlen(m_Text) - End + 1); + + delete[] m_Text; + m_Text = str; + } + if (m_ParentNotify && m_Parent) m_Parent->ApplyEvent(m_Name); + + return End - Start; +} + + +////////////////////////////////////////////////////////////////////////// +int CUIEdit::InsertChars(int Pos, byte *Chars, int Num) { + if (strlen(m_Text) + Num > m_MaxLength) { + Num -= (strlen(m_Text) + Num - m_MaxLength); + } + + Pos = MAX(Pos, 0); + Pos = MIN(Pos, strlen(m_Text)); + + char *str = new char[strlen(m_Text) + Num + 1]; + if (str) { + if (Pos > 0) memcpy(str, m_Text, Pos); + memcpy(str + Pos + Num, m_Text + Pos, strlen(m_Text) - Pos + 1); + + memcpy(str + Pos, Chars, Num); + + delete[] m_Text; + m_Text = str; + } + if (m_ParentNotify && m_Parent) m_Parent->ApplyEvent(m_Name); + + return Num; +} + + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEdit::Persist(CBPersistMgr *PersistMgr) { + + CUIObject::Persist(PersistMgr); + + PersistMgr->Transfer(TMEMBER(m_CursorBlinkRate)); + PersistMgr->Transfer(TMEMBER(m_CursorChar)); + PersistMgr->Transfer(TMEMBER(m_FontSelected)); + PersistMgr->Transfer(TMEMBER(m_FrameWidth)); + PersistMgr->Transfer(TMEMBER(m_MaxLength)); + PersistMgr->Transfer(TMEMBER(m_ScrollOffset)); + PersistMgr->Transfer(TMEMBER(m_SelEnd)); + PersistMgr->Transfer(TMEMBER(m_SelStart)); + + if (!PersistMgr->m_Saving) { + m_CursorVisible = false; + m_LastBlinkTime = 0; + } + + return S_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/UIEdit.h b/engines/wintermute/UIEdit.h new file mode 100644 index 0000000000..134218c877 --- /dev/null +++ b/engines/wintermute/UIEdit.h @@ -0,0 +1,71 @@ +/* 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 "persistent.h" +#include "UIObject.h" + +namespace WinterMute { +class CBFont; +class CUIEdit : public CUIObject { +public: + DECLARE_PERSISTENT(CUIEdit, CUIObject) + int m_MaxLength; + int InsertChars(int Pos, byte *Chars, int Num); + int DeleteChars(int Start, int End); + bool m_CursorVisible; + uint32 m_LastBlinkTime; + virtual HRESULT Display(int OffsetX, int OffsetY); + virtual bool HandleKeypress(SDL_Event *event); + int m_ScrollOffset; + int m_FrameWidth; + uint32 m_CursorBlinkRate; + void SetCursorChar(char *Char); + char *m_CursorChar; + int m_SelEnd; + int m_SelStart; + CBFont *m_FontSelected; + CUIEdit(CBGame *inGame); + virtual ~CUIEdit(); + + HRESULT LoadFile(char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/UIEntity.cpp b/engines/wintermute/UIEntity.cpp new file mode 100644 index 0000000000..2cf7a3096f --- /dev/null +++ b/engines/wintermute/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/AdEntity.h" +#include "engines/wintermute/BGame.h" +#include "engines/wintermute/BFileManager.h" +#include "engines/wintermute/UIEntity.h" +#include "engines/wintermute/BParser.h" +#include "engines/wintermute/BDynBuffer.h" +#include "engines/wintermute/scriptables/ScValue.h" +#include "engines/wintermute/scriptables/ScScript.h" +#include "engines/wintermute/scriptables/ScStack.h" + +namespace WinterMute { + +IMPLEMENT_PERSISTENT(CUIEntity, false) + +////////////////////////////////////////////////////////////////////////// +CUIEntity::CUIEntity(CBGame *inGame): CUIObject(inGame) { + m_Type = UI_CUSTOM; + m_Entity = NULL; +} + + +////////////////////////////////////////////////////////////////////////// +CUIEntity::~CUIEntity() { + if (m_Entity) Game->UnregisterObject(m_Entity); + m_Entity = NULL; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::LoadFile(char *Filename) { + byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIEntity::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + m_Filename = new char [strlen(Filename) + 1]; + strcpy(m_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", &m_PosX); + break; + + case TOKEN_Y: + parser.ScanStr((char *)params, "%d", &m_PosY); + break; + + case TOKEN_DISABLED: + parser.ScanStr((char *)params, "%b", &m_Disable); + break; + + case TOKEN_VISIBLE: + parser.ScanStr((char *)params, "%b", &m_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->m_EditorMode) { + m_Width = 50; + m_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", m_Name); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + Buffer->PutTextIndent(Indent + 2, "X=%d\n", m_PosX); + Buffer->PutTextIndent(Indent + 2, "Y=%d\n", m_PosY); + + Buffer->PutTextIndent(Indent + 2, "DISABLED=%s\n", m_Disable ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "VISIBLE=%s\n", m_Visible ? "TRUE" : "FALSE"); + + if (m_Entity && m_Entity->m_Filename) + Buffer->PutTextIndent(Indent + 2, "ENTITY=\"%s\"\n", m_Entity->m_Filename); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + // scripts + for (int i = 0; i < m_Scripts.GetSize(); i++) { + Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", m_Scripts[i]->m_Filename); + } + + Buffer->PutTextIndent(Indent + 2, "\n"); + + // editor properties + CBBase::SaveAsText(Buffer, Indent + 2); + + Buffer->PutTextIndent(Indent, "}\n"); + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::SetEntity(char *Filename) { + if (m_Entity) Game->UnregisterObject(m_Entity); + m_Entity = new CAdEntity(Game); + if (!m_Entity || FAILED(m_Entity->LoadFile(Filename))) { + delete m_Entity; + m_Entity = NULL; + return E_FAIL; + } else { + m_Entity->m_NonIntMouseEvents = true; + m_Entity->m_SceneIndependent = true; + m_Entity->MakeFreezable(false); + Game->RegisterObject(m_Entity); + } + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::Display(int OffsetX, int OffsetY) { + if (!m_Visible) return S_OK; + + if (m_Entity) { + m_Entity->m_PosX = OffsetX + m_PosX; + m_Entity->m_PosY = OffsetY + m_PosY; + if (m_Entity->m_Scale < 0) m_Entity->m_Zoomable = false; + m_Entity->m_Shadowable = false; + + m_Entity->Update(); + + bool OrigReg = m_Entity->m_Registrable; + + if (m_Entity->m_Registrable && m_Disable) m_Entity->m_Registrable = false; + + m_Entity->Display(); + m_Entity->m_Registrable = OrigReg; + } + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) { + ////////////////////////////////////////////////////////////////////////// + // GetEntity + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "GetEntity") == 0) { + Stack->CorrectParams(0); + + if (m_Entity) Stack->PushNative(m_Entity, true); + else Stack->PushNULL(); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetEntity + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetEntity") == 0) { + Stack->CorrectParams(1); + + 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(char *Name) { + m_ScValue->SetNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Type") == 0) { + m_ScValue->SetString("entity container"); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Freezable + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Freezable") == 0) { + if (m_Entity) m_ScValue->SetBool(m_Entity->m_Freezable); + else m_ScValue->SetBool(false); + return m_ScValue; + } + + else return CUIObject::ScGetProperty(Name); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::ScSetProperty(char *Name, CScValue *Value) { + ////////////////////////////////////////////////////////////////////////// + // Freezable + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Freezable") == 0) { + if (m_Entity) m_Entity->MakeFreezable(Value->GetBool()); + return S_OK; + } else return CUIObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +char *CUIEntity::ScToString() { + return "[entity container]"; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIEntity::Persist(CBPersistMgr *PersistMgr) { + + CUIObject::Persist(PersistMgr); + + PersistMgr->Transfer(TMEMBER(m_Entity)); + return S_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/UIEntity.h b/engines/wintermute/UIEntity.h new file mode 100644 index 0000000000..f3c9385b7b --- /dev/null +++ b/engines/wintermute/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(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 *m_Entity; + HRESULT SetEntity(char *Filename); + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/UIObject.cpp b/engines/wintermute/UIObject.cpp new file mode 100644 index 0000000000..4ff0952bd7 --- /dev/null +++ b/engines/wintermute/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/BGame.h" +#include "engines/wintermute/BSprite.h" +#include "engines/wintermute/UIObject.h" +#include "engines/wintermute/UITiledImage.h" +#include "engines/wintermute/UIWindow.h" +#include "engines/wintermute/PlatformSDL.h" +#include "engines/wintermute/scriptables/ScValue.h" +#include "engines/wintermute/scriptables/ScStack.h" +#include "engines/wintermute/BFontStorage.h" + +namespace WinterMute { + +IMPLEMENT_PERSISTENT(CUIObject, false) + +////////////////////////////////////////////////////////////////////////// +CUIObject::CUIObject(CBGame *inGame): CBObject(inGame) { + m_Back = NULL; + m_Image = NULL; + m_Font = NULL; + m_Text = NULL; + m_SharedFonts = m_SharedImages = false; + + m_Width = m_Height = 0; + + m_ListenerObject = NULL; + m_ListenerParamObject = NULL; + m_ListenerParamDWORD = 0; + + m_Disable = false; + m_Visible = true; + + m_Type = UI_UNKNOWN; + m_Parent = NULL; + + m_ParentNotify = false; + + m_FocusedWidget = NULL; + + m_CanFocus = false; + m_NonIntMouseEvents = true; +} + + +////////////////////////////////////////////////////////////////////////// +CUIObject::~CUIObject() { + if (!Game->m_LoadInProgress) CSysClassRegistry::GetInstance()->EnumInstances(CBGame::InvalidateValues, "CScValue", (void *)this); + + if (m_Back) delete m_Back; + if (m_Font && !m_SharedFonts) Game->m_FontStorage->RemoveFont(m_Font); + + if (m_Image && !m_SharedImages) delete m_Image; + + if (m_Text) delete [] m_Text; + + m_FocusedWidget = NULL; // ref only +} + + +////////////////////////////////////////////////////////////////////////// +void CUIObject::SetText(const char *Text) { + if (m_Text) delete [] m_Text; + m_Text = new char [strlen(Text) + 1]; + if (m_Text) { + strcpy(m_Text, Text); + for (int i = 0; i < strlen(m_Text); i++) { + if (m_Text[i] == '|') m_Text[i] = '\n'; + } + } +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::Display(int OffsetX, int OffsetY) { + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +void CUIObject::SetListener(CBScriptHolder *Object, CBScriptHolder *ListenerObject, uint32 ListenerParam) { + m_ListenerObject = Object; + m_ListenerParamObject = ListenerObject; + m_ListenerParamDWORD = ListenerParam; +} + + +////////////////////////////////////////////////////////////////////////// +void CUIObject::CorrectSize() { + RECT rect; + + if (m_Width <= 0) { + if (m_Image) { + m_Image->GetBoundingRect(&rect, 0, 0); + m_Width = rect.right - rect.left; + } else m_Width = 100; + } + + if (m_Height <= 0) { + if (m_Image) { + m_Image->GetBoundingRect(&rect, 0, 0); + m_Height = rect.bottom - rect.top; + } + } + + if (m_Back) m_Back->CorrectSize(&m_Width, &m_Height); +} + + + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name) { + ////////////////////////////////////////////////////////////////////////// + // SetFont + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "SetFont") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + if (m_Font) Game->m_FontStorage->RemoveFont(m_Font); + if (Val->IsNULL()) { + m_Font = NULL; + Stack->PushBool(true); + } else { + m_Font = Game->m_FontStorage->AddFont(Val->GetString()); + Stack->PushBool(m_Font != NULL); + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetImage") == 0) { + Stack->CorrectParams(1); + CScValue *Val = Stack->Pop(); + + char *Filename = Val->GetString(); + + delete m_Image; + m_Image = NULL; + if (Val->IsNULL()) { + Stack->PushBool(true); + return S_OK; + } + + m_Image = new CBSprite(Game); + if (!m_Image || FAILED(m_Image->LoadFile(Val->GetString()))) { + delete m_Image; + m_Image = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetImage") == 0) { + Stack->CorrectParams(0); + if (!m_Image || !m_Image->m_Filename) Stack->PushNULL(); + else Stack->PushString(m_Image->m_Filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetImageObject") == 0) { + Stack->CorrectParams(0); + if (!m_Image) Stack->PushNULL(); + else Stack->PushNative(m_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 (m_Parent && m_Parent->m_Type == UI_WINDOW) { + CUIWindow *win = (CUIWindow *)m_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->m_Widgets.GetSize(); i++) { + if (win->m_Widgets[i] == widget) { + found = true; + break; + } + } + } + // find by name + else { + char *name = val->GetString(); + for (i = 0; i < win->m_Widgets.GetSize(); i++) { + if (scumm_stricmp(win->m_Widgets[i]->m_Name, name) == 0) { + found = true; + break; + } + } + } + + if (found) { + bool done = false; + for (int j = 0; j < win->m_Widgets.GetSize(); j++) { + if (win->m_Widgets[j] == this) { + if (strcmp(Name, "MoveAfter") == 0) i++; + if (j >= i) j++; + + win->m_Widgets.InsertAt(i, this); + win->m_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 (m_Parent && m_Parent->m_Type == UI_WINDOW) { + CUIWindow *win = (CUIWindow *)m_Parent; + for (int i = 0; i < win->m_Widgets.GetSize(); i++) { + if (win->m_Widgets[i] == this) { + win->m_Widgets.RemoveAt(i); + win->m_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 (m_Parent && m_Parent->m_Type == UI_WINDOW) { + CUIWindow *win = (CUIWindow *)m_Parent; + for (int i = 0; i < win->m_Widgets.GetSize(); i++) { + if (win->m_Widgets[i] == this) { + win->m_Widgets.RemoveAt(i); + win->m_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(char *Name) { + m_ScValue->SetNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Type") == 0) { + m_ScValue->SetString("ui_object"); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Name + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Name") == 0) { + m_ScValue->SetString(m_Name); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Parent (RO) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Parent") == 0) { + m_ScValue->SetNative(m_Parent, true); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // ParentNotify + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "ParentNotify") == 0) { + m_ScValue->SetBool(m_ParentNotify); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Width + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Width") == 0) { + m_ScValue->SetInt(m_Width); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Height + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Height") == 0) { + m_ScValue->SetInt(m_Height); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Visible + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Visible") == 0) { + m_ScValue->SetBool(m_Visible); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Disabled + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Disabled") == 0) { + m_ScValue->SetBool(m_Disable); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Text + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Text") == 0) { + m_ScValue->SetString(m_Text); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // NextSibling (RO) / PrevSibling (RO) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "NextSibling") == 0 || strcmp(Name, "PrevSibling") == 0) { + m_ScValue->SetNULL(); + if (m_Parent && m_Parent->m_Type == UI_WINDOW) { + CUIWindow *win = (CUIWindow *)m_Parent; + for (int i = 0; i < win->m_Widgets.GetSize(); i++) { + if (win->m_Widgets[i] == this) { + if (strcmp(Name, "NextSibling") == 0) { + if (i < win->m_Widgets.GetSize() - 1) m_ScValue->SetNative(win->m_Widgets[i + 1], true); + } else { + if (i > 0) m_ScValue->SetNative(win->m_Widgets[i - 1], true); + } + break; + } + } + } + return m_ScValue; + } + + else return CBObject::ScGetProperty(Name); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::ScSetProperty(char *Name, CScValue *Value) { + ////////////////////////////////////////////////////////////////////////// + // Name + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Name") == 0) { + SetName(Value->GetString()); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // ParentNotify + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "ParentNotify") == 0) { + m_ParentNotify = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Width + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Width") == 0) { + m_Width = Value->GetInt(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Height + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Height") == 0) { + m_Height = Value->GetInt(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Visible + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Visible") == 0) { + m_Visible = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Disabled + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Disabled") == 0) { + m_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); +} + + +////////////////////////////////////////////////////////////////////////// +char *CUIObject::ScToString() { + return "[ui_object]"; +} + + +////////////////////////////////////////////////////////////////////////// +bool CUIObject::IsFocused() { + if (!Game->m_FocusedWindow) return false; + if (Game->m_FocusedWindow == this) return true; + + CUIObject *obj = Game->m_FocusedWindow; + while (obj) { + if (obj == this) return true; + else obj = obj->m_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->m_Disable && obj->m_Type == UI_WINDOW) { + disabled = true; + break; + } + obj = obj->m_Parent; + } + if (!disabled) { + obj = this; + while (obj) { + if (obj->m_Parent) { + if (!obj->m_Disable && obj->m_CanFocus) obj->m_Parent->m_FocusedWidget = obj; + } else { + if (obj->m_Type == UI_WINDOW) Game->FocusWindow((CUIWindow *)obj); + } + + obj = obj->m_Parent; + } + } + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::GetTotalOffset(int *OffsetX, int *OffsetY) { + int OffX = 0, OffY = 0; + + CUIObject *obj = m_Parent; + while (obj) { + OffX += obj->m_PosX; + OffY += obj->m_PosY; + + obj = obj->m_Parent; + } + if (OffsetX) *OffsetX = OffX; + if (OffsetY) *OffsetY = OffY; + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::Persist(CBPersistMgr *PersistMgr) { + + CBObject::Persist(PersistMgr); + + PersistMgr->Transfer(TMEMBER(m_Back)); + PersistMgr->Transfer(TMEMBER(m_CanFocus)); + PersistMgr->Transfer(TMEMBER(m_Disable)); + PersistMgr->Transfer(TMEMBER(m_FocusedWidget)); + PersistMgr->Transfer(TMEMBER(m_Font)); + PersistMgr->Transfer(TMEMBER(m_Height)); + PersistMgr->Transfer(TMEMBER(m_Image)); + PersistMgr->Transfer(TMEMBER(m_ListenerObject)); + PersistMgr->Transfer(TMEMBER(m_ListenerParamObject)); + PersistMgr->Transfer(TMEMBER(m_ListenerParamDWORD)); + PersistMgr->Transfer(TMEMBER(m_Parent)); + PersistMgr->Transfer(TMEMBER(m_ParentNotify)); + PersistMgr->Transfer(TMEMBER(m_SharedFonts)); + PersistMgr->Transfer(TMEMBER(m_SharedImages)); + PersistMgr->Transfer(TMEMBER(m_Text)); + PersistMgr->Transfer(TMEMBER_INT(m_Type)); + PersistMgr->Transfer(TMEMBER(m_Visible)); + PersistMgr->Transfer(TMEMBER(m_Width)); + + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIObject::SaveAsText(CBDynBuffer *Buffer, int Indent) { + return E_FAIL; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/UIObject.h b/engines/wintermute/UIObject.h new file mode 100644 index 0000000000..9742307504 --- /dev/null +++ b/engines/wintermute/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 "BObject.h" +#include "dctypes.h" // Added by ClassView + +namespace WinterMute { + +class CUITiledImage; +class CBFont; +class CUIObject : public CBObject { +public: + + HRESULT GetTotalOffset(int *OffsetX, int *OffsetY); + bool m_CanFocus; + HRESULT Focus(); + virtual HRESULT HandleMouse(TMouseEvent Event, TMouseButton Button); + bool IsFocused(); + bool m_ParentNotify; + DECLARE_PERSISTENT(CUIObject, CBObject) + CUIObject *m_Parent; + virtual HRESULT Display(int OffsetX = 0, int OffsetY = 0); + virtual void CorrectSize(); + bool m_SharedFonts; + bool m_SharedImages; + void SetText(const char *Text); + char *m_Text; + CBFont *m_Font; + bool m_Visible; + CUITiledImage *m_Back; + bool m_Disable; + CUIObject(CBGame *inGame = NULL); + virtual ~CUIObject(); + int m_Width; + int m_Height; + TUIObjectType m_Type; + CBSprite *m_Image; + void SetListener(CBScriptHolder *Object, CBScriptHolder *ListenerObject, uint32 ListenerParam); + CBScriptHolder *m_ListenerParamObject; + uint32 m_ListenerParamDWORD; + CBScriptHolder *m_ListenerObject; + CUIObject *m_FocusedWidget; + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/UIText.cpp b/engines/wintermute/UIText.cpp new file mode 100644 index 0000000000..7a0b206cec --- /dev/null +++ b/engines/wintermute/UIText.cpp @@ -0,0 +1,484 @@ +/* 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 "dcgf.h" +#include "BDynBuffer.h" +#include "UIText.h" +#include "UITiledImage.h" +#include "BGame.h" +#include "BParser.h" +#include "ScValue.h" +#include "BFont.h" +#include "BFontStorage.h" +#include "BStringTable.h" +#include "ScScript.h" +#include "ScStack.h" +#include "BSprite.h" +#include "BFileManager.h" +#include "PlatformSDL.h" + +namespace WinterMute { + +IMPLEMENT_PERSISTENT(CUIText, false) + +////////////////////////////////////////////////////////////////////////// +CUIText::CUIText(CBGame *inGame): CUIObject(inGame) { + m_TextAlign = TAL_LEFT; + m_VerticalAlign = VAL_CENTER; + m_Type = UI_STATIC; + m_CanFocus = false; +} + + +////////////////////////////////////////////////////////////////////////// +CUIText::~CUIText() { + +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::Display(int OffsetX, int OffsetY) { + if (!m_Visible) return S_OK; + + + CBFont *font = m_Font; + if (!font) font = Game->m_SystemFont; + + if (m_Back) m_Back->Display(OffsetX + m_PosX, OffsetY + m_PosY, m_Width, m_Height); + if (m_Image) m_Image->Draw(OffsetX + m_PosX, OffsetY + m_PosY, NULL); + + if (font && m_Text) { + int text_offset; + switch (m_VerticalAlign) { + case VAL_TOP: + text_offset = 0; + break; + case VAL_BOTTOM: + text_offset = m_Height - font->GetTextHeight((byte *)m_Text, m_Width); + break; + default: + text_offset = (m_Height - font->GetTextHeight((byte *)m_Text, m_Width)) / 2; + } + font->DrawText((byte *)m_Text, OffsetX + m_PosX, OffsetY + m_PosY + text_offset, m_Width, m_TextAlign, m_Height); + } + + //Game->m_Renderer->m_RectList.Add(new CBActiveRect(Game, this, NULL, OffsetX + m_PosX, OffsetY + m_PosY, m_Width, m_Height, 100, 100, false)); + + return S_OK; +} + + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::LoadFile(char *Filename) { + byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIText::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + m_Filename = new char [strlen(Filename) + 1]; + strcpy(m_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 m_Back; + m_Back = new CUITiledImage(Game); + if (!m_Back || FAILED(m_Back->LoadFile((char *)params))) { + delete m_Back; + m_Back = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE: + delete m_Image; + m_Image = new CBSprite(Game); + if (!m_Image || FAILED(m_Image->LoadFile((char *)params))) { + delete m_Image; + m_Image = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_FONT: + if (m_Font) Game->m_FontStorage->RemoveFont(m_Font); + m_Font = Game->m_FontStorage->AddFont((char *)params); + if (!m_Font) cmd = PARSERR_GENERIC; + break; + + case TOKEN_TEXT: + SetText((char *)params); + Game->m_StringTable->Expand(&m_Text); + break; + + case TOKEN_TEXT_ALIGN: + if (scumm_stricmp((char *)params, "left") == 0) m_TextAlign = TAL_LEFT; + else if (scumm_stricmp((char *)params, "right") == 0) m_TextAlign = TAL_RIGHT; + else m_TextAlign = TAL_CENTER; + break; + + case TOKEN_VERTICAL_ALIGN: + if (scumm_stricmp((char *)params, "top") == 0) m_VerticalAlign = VAL_TOP; + else if (scumm_stricmp((char *)params, "bottom") == 0) m_VerticalAlign = VAL_BOTTOM; + else m_VerticalAlign = VAL_CENTER; + break; + + case TOKEN_X: + parser.ScanStr((char *)params, "%d", &m_PosX); + break; + + case TOKEN_Y: + parser.ScanStr((char *)params, "%d", &m_PosY); + break; + + case TOKEN_WIDTH: + parser.ScanStr((char *)params, "%d", &m_Width); + break; + + case TOKEN_HEIGHT: + parser.ScanStr((char *)params, "%d", &m_Height); + break; + + case TOKEN_CURSOR: + delete m_Cursor; + m_Cursor = new CBSprite(Game); + if (!m_Cursor || FAILED(m_Cursor->LoadFile((char *)params))) { + delete m_Cursor; + m_Cursor = NULL; + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_SCRIPT: + AddScript((char *)params); + break; + + case TOKEN_PARENT_NOTIFY: + parser.ScanStr((char *)params, "%b", &m_ParentNotify); + break; + + case TOKEN_DISABLED: + parser.ScanStr((char *)params, "%b", &m_Disable); + break; + + case TOKEN_VISIBLE: + parser.ScanStr((char *)params, "%b", &m_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", m_Name); + Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption()); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + if (m_Back && m_Back->m_Filename) + Buffer->PutTextIndent(Indent + 2, "BACK=\"%s\"\n", m_Back->m_Filename); + + if (m_Image && m_Image->m_Filename) + Buffer->PutTextIndent(Indent + 2, "IMAGE=\"%s\"\n", m_Image->m_Filename); + + if (m_Font && m_Font->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT=\"%s\"\n", m_Font->m_Filename); + + if (m_Cursor && m_Cursor->m_Filename) + Buffer->PutTextIndent(Indent + 2, "CURSOR=\"%s\"\n", m_Cursor->m_Filename); + + if (m_Text) + Buffer->PutTextIndent(Indent + 2, "TEXT=\"%s\"\n", m_Text); + + switch (m_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; + } + + switch (m_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; + } + + Buffer->PutTextIndent(Indent + 2, "\n"); + + Buffer->PutTextIndent(Indent + 2, "X=%d\n", m_PosX); + Buffer->PutTextIndent(Indent + 2, "Y=%d\n", m_PosY); + Buffer->PutTextIndent(Indent + 2, "WIDTH=%d\n", m_Width); + Buffer->PutTextIndent(Indent + 2, "HEIGHT=%d\n", m_Height); + + Buffer->PutTextIndent(Indent + 2, "DISABLED=%s\n", m_Disable ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "VISIBLE=%s\n", m_Visible ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "PARENT_NOTIFY=%s\n", m_ParentNotify ? "TRUE" : "FALSE"); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + // scripts + for (int i = 0; i < m_Scripts.GetSize(); i++) { + Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", m_Scripts[i]->m_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, 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 (m_Font && m_Text) m_Height = m_Font->GetTextHeight((byte *)m_Text, m_Width); + Stack->PushNULL(); + return S_OK; + } + + else return CUIObject::ScCallMethod(Script, Stack, ThisStack, Name); +} + + +////////////////////////////////////////////////////////////////////////// +CScValue *CUIText::ScGetProperty(char *Name) { + m_ScValue->SetNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Type") == 0) { + m_ScValue->SetString("static"); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // TextAlign + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "TextAlign") == 0) { + m_ScValue->SetInt(m_TextAlign); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // VerticalAlign + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "VerticalAlign") == 0) { + m_ScValue->SetInt(m_VerticalAlign); + return m_ScValue; + } + + else return CUIObject::ScGetProperty(Name); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::ScSetProperty(char *Name, CScValue *Value) { + ////////////////////////////////////////////////////////////////////////// + // TextAlign + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "TextAlign") == 0) { + int i = Value->GetInt(); + if (i < 0 || i >= NUM_TEXT_ALIGN) i = 0; + m_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; + m_VerticalAlign = (TVerticalAlign)i; + return S_OK; + } + + else return CUIObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +char *CUIText::ScToString() { + return "[static]"; +} + + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::Persist(CBPersistMgr *PersistMgr) { + + CUIObject::Persist(PersistMgr); + PersistMgr->Transfer(TMEMBER_INT(m_TextAlign)); + PersistMgr->Transfer(TMEMBER_INT(m_VerticalAlign)); + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIText::SizeToFit() { + if (m_Font && m_Text) { + m_Width = m_Font->GetTextWidth((byte *)m_Text); + m_Height = m_Font->GetTextHeight((byte *)m_Text, m_Width); + } + return S_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/UIText.h b/engines/wintermute/UIText.h new file mode 100644 index 0000000000..74158cb636 --- /dev/null +++ b/engines/wintermute/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 m_TextAlign; + TVerticalAlign m_VerticalAlign; + HRESULT LoadFile(char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/UITiledImage.cpp b/engines/wintermute/UITiledImage.cpp new file mode 100644 index 0000000000..488c1bdd7b --- /dev/null +++ b/engines/wintermute/UITiledImage.cpp @@ -0,0 +1,368 @@ +/* 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/UITiledImage.h" +#include "engines/wintermute/BSurface.h" +#include "engines/wintermute/BDynBuffer.h" +#include "engines/wintermute/BParser.h" +#include "engines/wintermute/BGame.h" +#include "engines/wintermute/BSubFrame.h" +#include "engines/wintermute/BFileManager.h" +#include "engines/wintermute/PlatformSDL.h" + +namespace WinterMute { + +IMPLEMENT_PERSISTENT(CUITiledImage, false) + +////////////////////////////////////////////////////////////////////////// +CUITiledImage::CUITiledImage(CBGame *inGame): CBObject(inGame) { + m_Image = NULL; + + CBPlatform::SetRectEmpty(&m_UpLeft); + CBPlatform::SetRectEmpty(&m_UpMiddle); + CBPlatform::SetRectEmpty(&m_UpRight); + CBPlatform::SetRectEmpty(&m_MiddleLeft); + CBPlatform::SetRectEmpty(&m_MiddleMiddle); + CBPlatform::SetRectEmpty(&m_MiddleRight); + CBPlatform::SetRectEmpty(&m_DownLeft); + CBPlatform::SetRectEmpty(&m_DownMiddle); + CBPlatform::SetRectEmpty(&m_DownRight); +} + + +////////////////////////////////////////////////////////////////////////// +CUITiledImage::~CUITiledImage() { + SAFE_DELETE(m_Image); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUITiledImage::Display(int X, int Y, int Width, int Height) { + if (!m_Image) return E_FAIL; + + int tile_width = m_MiddleMiddle.right - m_MiddleMiddle.left; + int tile_height = m_MiddleMiddle.bottom - m_MiddleMiddle.top; + + int num_columns = (Width - (m_MiddleLeft.right - m_MiddleLeft.left) - (m_MiddleRight.right - m_MiddleRight.left)) / tile_width; + int num_rows = (Height - (m_UpMiddle.bottom - m_UpMiddle.top) - (m_DownMiddle.bottom - m_DownMiddle.top)) / tile_height; + + int col, row; + + Game->m_Renderer->StartSpriteBatch(); + + // top left/right + m_Image->m_Surface->DisplayTrans(X, Y, m_UpLeft); + m_Image->m_Surface->DisplayTrans(X + (m_UpLeft.right - m_UpLeft.left) + num_columns * tile_width, Y, m_UpRight); + + // bottom left/right + m_Image->m_Surface->DisplayTrans(X, Y + (m_UpMiddle.bottom - m_UpMiddle.top) + num_rows * tile_height, m_DownLeft); + m_Image->m_Surface->DisplayTrans(X + (m_UpLeft.right - m_UpLeft.left) + num_columns * tile_width, Y + (m_UpMiddle.bottom - m_UpMiddle.top) + num_rows * tile_height, m_DownRight); + + // left/right + int yyy = Y + (m_UpMiddle.bottom - m_UpMiddle.top); + for (row = 0; row < num_rows; row++) { + m_Image->m_Surface->DisplayTrans(X, yyy, m_MiddleLeft); + m_Image->m_Surface->DisplayTrans(X + (m_MiddleLeft.right - m_MiddleLeft.left) + num_columns * tile_width, yyy, m_MiddleRight); + yyy += tile_width; + } + + // top/bottom + int xxx = X + (m_UpLeft.right - m_UpLeft.left); + for (col = 0; col < num_columns; col++) { + m_Image->m_Surface->DisplayTrans(xxx, Y, m_UpMiddle); + m_Image->m_Surface->DisplayTrans(xxx, Y + (m_UpMiddle.bottom - m_UpMiddle.top) + num_rows * tile_height, m_DownMiddle); + xxx += tile_width; + } + + // tiles + yyy = Y + (m_UpMiddle.bottom - m_UpMiddle.top); + for (row = 0; row < num_rows; row++) { + xxx = X + (m_UpLeft.right - m_UpLeft.left); + for (col = 0; col < num_columns; col++) { + m_Image->m_Surface->DisplayTrans(xxx, yyy, m_MiddleMiddle); + xxx += tile_width; + } + yyy += tile_width; + } + + Game->m_Renderer->EndSpriteBatch(); + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUITiledImage::LoadFile(char *Filename) { + byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUITiledImage::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + m_Filename = new char [strlen(Filename) + 1]; + strcpy(m_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: + SAFE_DELETE(m_Image); + m_Image = new CBSubFrame(Game); + if (!m_Image || FAILED(m_Image->SetSurface((char *)params))) { + SAFE_DELETE(m_Image); + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_UP_LEFT: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_UpLeft.left, &m_UpLeft.top, &m_UpLeft.right, &m_UpLeft.bottom); + break; + + case TOKEN_UP_RIGHT: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_UpRight.left, &m_UpRight.top, &m_UpRight.right, &m_UpRight.bottom); + break; + + case TOKEN_UP_MIDDLE: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_UpMiddle.left, &m_UpMiddle.top, &m_UpMiddle.right, &m_UpMiddle.bottom); + break; + + case TOKEN_DOWN_LEFT: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_DownLeft.left, &m_DownLeft.top, &m_DownLeft.right, &m_DownLeft.bottom); + break; + + case TOKEN_DOWN_RIGHT: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_DownRight.left, &m_DownRight.top, &m_DownRight.right, &m_DownRight.bottom); + break; + + case TOKEN_DOWN_MIDDLE: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_DownMiddle.left, &m_DownMiddle.top, &m_DownMiddle.right, &m_DownMiddle.bottom); + break; + + case TOKEN_MIDDLE_LEFT: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_MiddleLeft.left, &m_MiddleLeft.top, &m_MiddleLeft.right, &m_MiddleLeft.bottom); + break; + + case TOKEN_MIDDLE_RIGHT: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_MiddleRight.left, &m_MiddleRight.top, &m_MiddleRight.right, &m_MiddleRight.bottom); + break; + + case TOKEN_MIDDLE_MIDDLE: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_MiddleMiddle.left, &m_MiddleMiddle.top, &m_MiddleMiddle.right, &m_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(&m_UpLeft, 0, 0, H1, V1); + CBPlatform::SetRect(&m_UpMiddle, H1, 0, H1 + H2, V1); + CBPlatform::SetRect(&m_UpRight, H1 + H2, 0, H1 + H2 + H3, V1); + + // middle row + CBPlatform::SetRect(&m_MiddleLeft, 0, V1, H1, V1 + V2); + CBPlatform::SetRect(&m_MiddleMiddle, H1, V1, H1 + H2, V1 + V2); + CBPlatform::SetRect(&m_MiddleRight, H1 + H2, V1, H1 + H2 + H3, V1 + V2); + + // down row + CBPlatform::SetRect(&m_DownLeft, 0, V1 + V2, H1, V1 + V2 + V3); + CBPlatform::SetRect(&m_DownMiddle, H1, V1 + V2, H1 + H2, V1 + V2 + V3); + CBPlatform::SetRect(&m_DownRight, H1 + H2, V1 + V2, H1 + H2 + H3, V1 + V2 + V3); + } + + // default + if (m_Image && m_Image->m_Surface) { + int Width = m_Image->m_Surface->GetWidth() / 3; + int Height = m_Image->m_Surface->GetHeight() / 3; + + if (CBPlatform::IsRectEmpty(&m_UpLeft)) CBPlatform::SetRect(&m_UpLeft, 0, 0, Width, Height); + if (CBPlatform::IsRectEmpty(&m_UpMiddle)) CBPlatform::SetRect(&m_UpMiddle, Width, 0, 2 * Width, Height); + if (CBPlatform::IsRectEmpty(&m_UpRight)) CBPlatform::SetRect(&m_UpRight, 2 * Width, 0, 3 * Width, Height); + + if (CBPlatform::IsRectEmpty(&m_MiddleLeft)) CBPlatform::SetRect(&m_MiddleLeft, 0, Height, Width, 2 * Height); + if (CBPlatform::IsRectEmpty(&m_MiddleMiddle)) CBPlatform::SetRect(&m_MiddleMiddle, Width, Height, 2 * Width, 2 * Height); + if (CBPlatform::IsRectEmpty(&m_MiddleRight)) CBPlatform::SetRect(&m_MiddleRight, 2 * Width, Height, 3 * Width, 2 * Height); + + if (CBPlatform::IsRectEmpty(&m_DownLeft)) CBPlatform::SetRect(&m_DownLeft, 0, 2 * Height, Width, 3 * Height); + if (CBPlatform::IsRectEmpty(&m_DownMiddle)) CBPlatform::SetRect(&m_DownMiddle, Width, 2 * Height, 2 * Width, 3 * Height); + if (CBPlatform::IsRectEmpty(&m_DownRight)) CBPlatform::SetRect(&m_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 (m_Image && m_Image->m_SurfaceFilename) + Buffer->PutTextIndent(Indent + 2, "IMAGE=\"%s\"\n", m_Image->m_SurfaceFilename); + + int H1, H2, H3; + int V1, V2, V3; + + H1 = m_UpLeft.right; + H2 = m_UpMiddle.right - m_UpMiddle.left; + H3 = m_UpRight.right - m_UpRight.left; + + V1 = m_UpLeft.bottom; + V2 = m_MiddleLeft.bottom - m_MiddleLeft.top; + V3 = m_DownLeft.bottom - m_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 = m_MiddleMiddle.right - m_MiddleMiddle.left; + int tile_height = m_MiddleMiddle.bottom - m_MiddleMiddle.top; + + int num_columns = (*Width - (m_MiddleLeft.right - m_MiddleLeft.left) - (m_MiddleRight.right - m_MiddleRight.left)) / tile_width; + int num_rows = (*Height - (m_UpMiddle.bottom - m_UpMiddle.top) - (m_DownMiddle.bottom - m_DownMiddle.top)) / tile_height; + + *Width = (m_MiddleLeft.right - m_MiddleLeft.left) + (m_MiddleRight.right - m_MiddleRight.left) + num_columns * tile_width; + *Height = (m_UpMiddle.bottom - m_UpMiddle.top) + (m_DownMiddle.bottom - m_DownMiddle.top) + num_rows * tile_height; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUITiledImage::Persist(CBPersistMgr *PersistMgr) { + CBObject::Persist(PersistMgr); + + PersistMgr->Transfer(TMEMBER(m_DownLeft)); + PersistMgr->Transfer(TMEMBER(m_DownMiddle)); + PersistMgr->Transfer(TMEMBER(m_DownRight)); + PersistMgr->Transfer(TMEMBER(m_Image)); + PersistMgr->Transfer(TMEMBER(m_MiddleLeft)); + PersistMgr->Transfer(TMEMBER(m_MiddleMiddle)); + PersistMgr->Transfer(TMEMBER(m_MiddleRight)); + PersistMgr->Transfer(TMEMBER(m_UpLeft)); + PersistMgr->Transfer(TMEMBER(m_UpMiddle)); + PersistMgr->Transfer(TMEMBER(m_UpRight)); + + return S_OK; +} + +} // end of namespace WinterMute diff --git a/engines/wintermute/UITiledImage.h b/engines/wintermute/UITiledImage.h new file mode 100644 index 0000000000..e97b27f59e --- /dev/null +++ b/engines/wintermute/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(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 *m_Image; + RECT m_UpLeft; + RECT m_UpMiddle; + RECT m_UpRight; + RECT m_MiddleLeft; + RECT m_MiddleMiddle; + RECT m_MiddleRight; + RECT m_DownLeft; + RECT m_DownMiddle; + RECT m_DownRight; +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/UIWindow.cpp b/engines/wintermute/UIWindow.cpp new file mode 100644 index 0000000000..b68f788fcc --- /dev/null +++ b/engines/wintermute/UIWindow.cpp @@ -0,0 +1,1309 @@ +/* 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 "dcgf.h" +#include "UIWindow.h" +#include "BGame.h" +#include "BParser.h" +#include "BActiveRect.h" +#include "BDynBuffer.h" +#include "BKeyboardState.h" +#include "ScValue.h" +#include "UIButton.h" +#include "UIEdit.h" +#include "UIText.h" +#include "UITiledImage.h" +#include "BViewport.h" +#include "BFontStorage.h" +#include "BFont.h" +#include "BStringTable.h" +#include "ScScript.h" +#include "ScStack.h" +#include "BSprite.h" +#include "BFileManager.h" +#include "PlatformSDL.h" + +namespace WinterMute { + +IMPLEMENT_PERSISTENT(CUIWindow, false) + +////////////////////////////////////////////////////////////////////////// +CUIWindow::CUIWindow(CBGame *inGame): CUIObject(inGame) { + CBPlatform::SetRectEmpty(&m_TitleRect); + CBPlatform::SetRectEmpty(&m_DragRect); + m_TitleAlign = TAL_LEFT; + m_Transparent = false; + + m_BackInactive = NULL; + m_FontInactive = NULL; + m_ImageInactive = NULL; + + m_Type = UI_WINDOW; + m_CanFocus = true; + + m_Dragging = false; + m_DragFrom.x = m_DragFrom.y = 0; + + m_Mode = WINDOW_NORMAL; + m_ShieldWindow = NULL; + m_ShieldButton = NULL; + + m_FadeColor = 0x00000000; + m_FadeBackground = false; + + m_Ready = true; + m_IsMenu = false; + m_InGame = false; + + m_ClipContents = false; + m_Viewport = NULL; + + m_PauseMusic = true; +} + + +////////////////////////////////////////////////////////////////////////// +CUIWindow::~CUIWindow() { + Close(); + Cleanup(); +} + + +////////////////////////////////////////////////////////////////////////// +void CUIWindow::Cleanup() { + delete m_ShieldWindow; + delete m_ShieldButton; + delete m_Viewport; + m_ShieldWindow = NULL; + m_ShieldButton = NULL; + m_Viewport = NULL; + + if (m_BackInactive) delete m_BackInactive; + if (!m_SharedFonts && m_FontInactive) Game->m_FontStorage->RemoveFont(m_FontInactive); + if (!m_SharedImages && m_ImageInactive) delete m_ImageInactive; + + for (int i = 0; i < m_Widgets.GetSize(); i++) delete m_Widgets[i]; + m_Widgets.RemoveAll(); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::Display(int OffsetX, int OffsetY) { + // go exclusive + if (m_Mode == WINDOW_EXCLUSIVE || m_Mode == WINDOW_SYSTEM_EXCLUSIVE) { + if (!m_ShieldWindow) m_ShieldWindow = new CUIWindow(Game); + if (m_ShieldWindow) { + m_ShieldWindow->m_PosX = m_ShieldWindow->m_PosY = 0; + m_ShieldWindow->m_Width = Game->m_Renderer->m_Width; + m_ShieldWindow->m_Height = Game->m_Renderer->m_Height; + + m_ShieldWindow->Display(); + } + } else if (m_IsMenu) { + if (!m_ShieldButton) { + m_ShieldButton = new CUIButton(Game); + m_ShieldButton->SetName("close"); + m_ShieldButton->SetListener(this, m_ShieldButton, 0); + m_ShieldButton->m_Parent = this; + } + if (m_ShieldButton) { + m_ShieldButton->m_PosX = m_ShieldButton->m_PosY = 0; + m_ShieldButton->m_Width = Game->m_Renderer->m_Width; + m_ShieldButton->m_Height = Game->m_Renderer->m_Height; + + m_ShieldButton->Display(); + } + } + + if (!m_Visible) return S_OK; + + if (m_FadeBackground) Game->m_Renderer->FadeToColor(m_FadeColor); + + if (m_Dragging) { + m_PosX += (Game->m_MousePos.x - m_DragFrom.x); + m_PosY += (Game->m_MousePos.y - m_DragFrom.y); + + m_DragFrom.x = Game->m_MousePos.x; + m_DragFrom.y = Game->m_MousePos.y; + } + + if (!m_FocusedWidget || (!m_FocusedWidget->m_CanFocus || m_FocusedWidget->m_Disable || !m_FocusedWidget->m_Visible)) { + MoveFocus(); + } + + bool PopViewport = false; + if (m_ClipContents) { + if (!m_Viewport) m_Viewport = new CBViewport(Game); + if (m_Viewport) { + m_Viewport->SetRect(m_PosX + OffsetX, m_PosY + OffsetY, m_PosX + m_Width + OffsetX, m_PosY + m_Height + OffsetY); + Game->PushViewport(m_Viewport); + PopViewport = true; + } + } + + + CUITiledImage *back = m_Back; + CBSprite *image = m_Image; + CBFont *font = m_Font; + + if (!IsFocused()) { + if (m_BackInactive) back = m_BackInactive; + if (m_ImageInactive) image = m_ImageInactive; + if (m_FontInactive) font = m_FontInactive; + } + + if (m_AlphaColor != 0) Game->m_Renderer->m_ForceAlphaColor = m_AlphaColor; + if (back) back->Display(m_PosX + OffsetX, m_PosY + OffsetY, m_Width, m_Height); + if (image) image->Draw(m_PosX + OffsetX, m_PosY + OffsetY, m_Transparent ? NULL : this); + + if (!CBPlatform::IsRectEmpty(&m_TitleRect) && font && m_Text) { + font->DrawText((byte *)m_Text, m_PosX + OffsetX + m_TitleRect.left, m_PosY + OffsetY + m_TitleRect.top, m_TitleRect.right - m_TitleRect.left, m_TitleAlign, m_TitleRect.bottom - m_TitleRect.top); + } + + if (!m_Transparent && !image) Game->m_Renderer->m_RectList.Add(new CBActiveRect(Game, this, NULL, m_PosX + OffsetX, m_PosY + OffsetY, m_Width, m_Height, 100, 100, false)); + + for (int i = 0; i < m_Widgets.GetSize(); i++) { + m_Widgets[i]->Display(m_PosX + OffsetX, m_PosY + OffsetY); + } + + if (m_AlphaColor != 0) Game->m_Renderer->m_ForceAlphaColor = 0; + + if (PopViewport) Game->PopViewport(); + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::LoadFile(char *Filename) { + byte *Buffer = Game->m_FileManager->ReadWholeFile(Filename); + if (Buffer == NULL) { + Game->LOG(0, "CUIWindow::LoadFile failed for file '%s'", Filename); + return E_FAIL; + } + + HRESULT ret; + + m_Filename = new char [strlen(Filename) + 1]; + strcpy(m_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: + SAFE_DELETE(m_Back); + m_Back = new CUITiledImage(Game); + if (!m_Back || FAILED(m_Back->LoadFile((char *)params))) { + SAFE_DELETE(m_Back); + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BACK_INACTIVE: + SAFE_DELETE(m_BackInactive); + m_BackInactive = new CUITiledImage(Game); + if (!m_BackInactive || FAILED(m_BackInactive->LoadFile((char *)params))) { + SAFE_DELETE(m_BackInactive); + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE: + SAFE_DELETE(m_Image); + m_Image = new CBSprite(Game); + if (!m_Image || FAILED(m_Image->LoadFile((char *)params))) { + SAFE_DELETE(m_Image); + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_IMAGE_INACTIVE: + SAFE_DELETE(m_ImageInactive), + m_ImageInactive = new CBSprite(Game); + if (!m_ImageInactive || FAILED(m_ImageInactive->LoadFile((char *)params))) { + SAFE_DELETE(m_ImageInactive); + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_FONT: + if (m_Font) Game->m_FontStorage->RemoveFont(m_Font); + m_Font = Game->m_FontStorage->AddFont((char *)params); + if (!m_Font) cmd = PARSERR_GENERIC; + break; + + case TOKEN_FONT_INACTIVE: + if (m_FontInactive) Game->m_FontStorage->RemoveFont(m_FontInactive); + m_FontInactive = Game->m_FontStorage->AddFont((char *)params); + if (!m_FontInactive) cmd = PARSERR_GENERIC; + break; + + case TOKEN_TITLE: + SetText((char *)params); + Game->m_StringTable->Expand(&m_Text); + break; + + case TOKEN_TITLE_ALIGN: + if (scumm_stricmp((char *)params, "left") == 0) m_TitleAlign = TAL_LEFT; + else if (scumm_stricmp((char *)params, "right") == 0) m_TitleAlign = TAL_RIGHT; + else m_TitleAlign = TAL_CENTER; + break; + + case TOKEN_TITLE_RECT: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_TitleRect.left, &m_TitleRect.top, &m_TitleRect.right, &m_TitleRect.bottom); + break; + + case TOKEN_DRAG_RECT: + parser.ScanStr((char *)params, "%d,%d,%d,%d", &m_DragRect.left, &m_DragRect.top, &m_DragRect.right, &m_DragRect.bottom); + break; + + case TOKEN_X: + parser.ScanStr((char *)params, "%d", &m_PosX); + break; + + case TOKEN_Y: + parser.ScanStr((char *)params, "%d", &m_PosY); + break; + + case TOKEN_WIDTH: + parser.ScanStr((char *)params, "%d", &m_Width); + break; + + case TOKEN_HEIGHT: + parser.ScanStr((char *)params, "%d", &m_Height); + break; + + case TOKEN_CURSOR: + SAFE_DELETE(m_Cursor); + m_Cursor = new CBSprite(Game); + if (!m_Cursor || FAILED(m_Cursor->LoadFile((char *)params))) { + SAFE_DELETE(m_Cursor); + cmd = PARSERR_GENERIC; + } + break; + + case TOKEN_BUTTON: { + CUIButton *btn = new CUIButton(Game); + if (!btn || FAILED(btn->LoadBuffer(params, false))) { + SAFE_DELETE(btn); + cmd = PARSERR_GENERIC; + } else { + btn->m_Parent = this; + m_Widgets.Add(btn); + } + } + break; + + case TOKEN_STATIC: { + CUIText *text = new CUIText(Game); + if (!text || FAILED(text->LoadBuffer(params, false))) { + SAFE_DELETE(text); + cmd = PARSERR_GENERIC; + } else { + text->m_Parent = this; + m_Widgets.Add(text); + } + } + break; + + case TOKEN_EDIT: { + CUIEdit *edit = new CUIEdit(Game); + if (!edit || FAILED(edit->LoadBuffer(params, false))) { + SAFE_DELETE(edit); + cmd = PARSERR_GENERIC; + } else { + edit->m_Parent = this; + m_Widgets.Add(edit); + } + } + break; + + case TOKEN_WINDOW: { + CUIWindow *win = new CUIWindow(Game); + if (!win || FAILED(win->LoadBuffer(params, false))) { + SAFE_DELETE(win); + cmd = PARSERR_GENERIC; + } else { + win->m_Parent = this; + m_Widgets.Add(win); + } + } + break; + + + case TOKEN_TRANSPARENT: + parser.ScanStr((char *)params, "%b", &m_Transparent); + break; + + case TOKEN_SCRIPT: + AddScript((char *)params); + break; + + case TOKEN_PARENT_NOTIFY: + parser.ScanStr((char *)params, "%b", &m_ParentNotify); + break; + + case TOKEN_PAUSE_MUSIC: + parser.ScanStr((char *)params, "%b", &m_PauseMusic); + break; + + case TOKEN_DISABLED: + parser.ScanStr((char *)params, "%b", &m_Disable); + break; + + case TOKEN_VISIBLE: + parser.ScanStr((char *)params, "%b", &m_Visible); + break; + + case TOKEN_MENU: + parser.ScanStr((char *)params, "%b", &m_IsMenu); + break; + + case TOKEN_IN_GAME: + parser.ScanStr((char *)params, "%b", &m_InGame); + break; + + case TOKEN_CLIP_CONTENTS: + parser.ScanStr((char *)params, "%b", &m_ClipContents); + break; + + case TOKEN_FADE_COLOR: + parser.ScanStr((char *)params, "%d,%d,%d", &FadeR, &FadeG, &FadeB); + m_FadeBackground = true; + break; + + case TOKEN_FADE_ALPHA: + parser.ScanStr((char *)params, "%d", &FadeA); + m_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; + } + m_AlphaColor = DRGBA(ar, ag, ab, alpha); + + if (m_FadeBackground) m_FadeColor = DRGBA(FadeR, FadeG, FadeB, FadeA); + + m_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", m_Name); + Buffer->PutTextIndent(Indent + 2, "CAPTION=\"%s\"\n", GetCaption()); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + if (m_Back && m_Back->m_Filename) + Buffer->PutTextIndent(Indent + 2, "BACK=\"%s\"\n", m_Back->m_Filename); + if (m_BackInactive && m_BackInactive->m_Filename) + Buffer->PutTextIndent(Indent + 2, "BACK_INACTIVE=\"%s\"\n", m_BackInactive->m_Filename); + + if (m_Image && m_Image->m_Filename) + Buffer->PutTextIndent(Indent + 2, "IMAGE=\"%s\"\n", m_Image->m_Filename); + if (m_ImageInactive && m_ImageInactive->m_Filename) + Buffer->PutTextIndent(Indent + 2, "IMAGE_INACTIVE=\"%s\"\n", m_ImageInactive->m_Filename); + + if (m_Font && m_Font->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT=\"%s\"\n", m_Font->m_Filename); + if (m_FontInactive && m_FontInactive->m_Filename) + Buffer->PutTextIndent(Indent + 2, "FONT_INACTIVE=\"%s\"\n", m_FontInactive->m_Filename); + + if (m_Cursor && m_Cursor->m_Filename) + Buffer->PutTextIndent(Indent + 2, "CURSOR=\"%s\"\n", m_Cursor->m_Filename); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + if (m_Text) + Buffer->PutTextIndent(Indent + 2, "TITLE=\"%s\"\n", m_Text); + + switch (m_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; + } + + if (!CBPlatform::IsRectEmpty(&m_TitleRect)) { + Buffer->PutTextIndent(Indent + 2, "TITLE_RECT { %d, %d, %d, %d }\n", m_TitleRect.left, m_TitleRect.top, m_TitleRect.right, m_TitleRect.bottom); + } + + if (!CBPlatform::IsRectEmpty(&m_DragRect)) { + Buffer->PutTextIndent(Indent + 2, "DRAG_RECT { %d, %d, %d, %d }\n", m_DragRect.left, m_DragRect.top, m_DragRect.right, m_DragRect.bottom); + } + + Buffer->PutTextIndent(Indent + 2, "\n"); + + Buffer->PutTextIndent(Indent + 2, "X=%d\n", m_PosX); + Buffer->PutTextIndent(Indent + 2, "Y=%d\n", m_PosY); + Buffer->PutTextIndent(Indent + 2, "WIDTH=%d\n", m_Width); + Buffer->PutTextIndent(Indent + 2, "HEIGHT=%d\n", m_Height); + + Buffer->PutTextIndent(Indent + 2, "DISABLED=%s\n", m_Disable ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "VISIBLE=%s\n", m_Visible ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "PARENT_NOTIFY=%s\n", m_ParentNotify ? "TRUE" : "FALSE"); + + Buffer->PutTextIndent(Indent + 2, "TRANSPARENT=%s\n", m_Transparent ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "PAUSE_MUSIC=%s\n", m_PauseMusic ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "MENU=%s\n", m_IsMenu ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "IN_GAME=%s\n", m_InGame ? "TRUE" : "FALSE"); + Buffer->PutTextIndent(Indent + 2, "CLIP_CONTENTS=%s\n", m_ClipContents ? "TRUE" : "FALSE"); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + if (m_FadeBackground) { + Buffer->PutTextIndent(Indent + 2, "FADE_COLOR { %d, %d, %d }\n", D3DCOLGetR(m_FadeColor), D3DCOLGetG(m_FadeColor), D3DCOLGetB(m_FadeColor)); + Buffer->PutTextIndent(Indent + 2, "FADE_ALPHA=%d\n", D3DCOLGetA(m_FadeColor)); + } + + Buffer->PutTextIndent(Indent + 2, "ALPHA_COLOR { %d, %d, %d }\n", D3DCOLGetR(m_AlphaColor), D3DCOLGetG(m_AlphaColor), D3DCOLGetB(m_AlphaColor)); + Buffer->PutTextIndent(Indent + 2, "ALPHA=%d\n", D3DCOLGetA(m_AlphaColor)); + + Buffer->PutTextIndent(Indent + 2, "\n"); + + // scripts + for (int i = 0; i < m_Scripts.GetSize(); i++) { + Buffer->PutTextIndent(Indent + 2, "SCRIPT=\"%s\"\n", m_Scripts[i]->m_Filename); + } + + Buffer->PutTextIndent(Indent + 2, "\n"); + + // editor properties + CBBase::SaveAsText(Buffer, Indent + 2); + + // controls + for (int i = 0; i < m_Widgets.GetSize(); i++) + m_Widgets[i]->SaveAsText(Buffer, Indent + 2); + + + Buffer->PutTextIndent(Indent, "}\n"); + return S_OK; +} + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::EnableWidget(char *Name, bool Enable) { + for (int i = 0; i < m_Widgets.GetSize(); i++) { + if (scumm_stricmp(m_Widgets[i]->m_Name, Name) == 0) m_Widgets[i]->m_Disable = !Enable; + } + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::ShowWidget(char *Name, bool Visible) { + for (int i = 0; i < m_Widgets.GetSize(); i++) { + if (scumm_stricmp(m_Widgets[i]->m_Name, Name) == 0) m_Widgets[i]->m_Visible = Visible; + } + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +// high level scripting interface +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, 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 >= m_Widgets.GetSize()) Stack->PushNULL(); + else Stack->PushNative(m_Widgets[widget], true); + } else { + for (int i = 0; i < m_Widgets.GetSize(); i++) { + if (scumm_stricmp(m_Widgets[i]->m_Name, val->GetString()) == 0) { + Stack->PushNative(m_Widgets[i], true); + return S_OK; + } + } + Stack->PushNULL(); + } + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetInactiveFont + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetInactiveFont") == 0) { + Stack->CorrectParams(1); + + if (m_FontInactive) Game->m_FontStorage->RemoveFont(m_FontInactive); + m_FontInactive = Game->m_FontStorage->AddFont(Stack->Pop()->GetString()); + Stack->PushBool(m_FontInactive != NULL); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SetInactiveImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SetInactiveImage") == 0) { + Stack->CorrectParams(1); + + delete m_ImageInactive; + m_ImageInactive = new CBSprite(Game); + char *Filename = Stack->Pop()->GetString(); + if (!m_ImageInactive || FAILED(m_ImageInactive->LoadFile(Filename))) { + delete m_ImageInactive; + m_ImageInactive = NULL; + Stack->PushBool(false); + } else Stack->PushBool(true); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetInactiveImage + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetInactiveImage") == 0) { + Stack->CorrectParams(0); + if (!m_ImageInactive || !m_ImageInactive->m_Filename) Stack->PushNULL(); + else Stack->PushString(m_ImageInactive->m_Filename); + + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // GetInactiveImageObject + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "GetInactiveImageObject") == 0) { + Stack->CorrectParams(0); + if (!m_ImageInactive) Stack->PushNULL(); + else Stack->PushNative(m_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); + m_PosX = (Game->m_Renderer->m_Width - m_Width) / 2; + m_PosY = (Game->m_Renderer->m_Height - m_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->m_Parent = this; + m_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->m_Parent = this; + m_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->m_Parent = this; + m_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->m_Parent = this; + m_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 < m_Widgets.GetSize(); i++) { + if (m_Widgets[i] == obj) { + delete m_Widgets[i]; + m_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(char *Name) { + m_ScValue->SetNULL(); + + ////////////////////////////////////////////////////////////////////////// + // Type + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Type") == 0) { + m_ScValue->SetString("window"); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // NumWidgets / NumControls (RO) + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "NumWidgets") == 0 || strcmp(Name, "NumControls") == 0) { + m_ScValue->SetInt(m_Widgets.GetSize()); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Exclusive + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Exclusive") == 0) { + m_ScValue->SetBool(m_Mode == WINDOW_EXCLUSIVE); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // SystemExclusive + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SystemExclusive") == 0) { + m_ScValue->SetBool(m_Mode == WINDOW_SYSTEM_EXCLUSIVE); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Menu + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Menu") == 0) { + m_ScValue->SetBool(m_IsMenu); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // InGame + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "InGame") == 0) { + m_ScValue->SetBool(m_InGame); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // PauseMusic + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "PauseMusic") == 0) { + m_ScValue->SetBool(m_PauseMusic); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // ClipContents + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "ClipContents") == 0) { + m_ScValue->SetBool(m_ClipContents); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // Transparent + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Transparent") == 0) { + m_ScValue->SetBool(m_Transparent); + return m_ScValue; + } + + ////////////////////////////////////////////////////////////////////////// + // FadeColor + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "FadeColor") == 0) { + m_ScValue->SetInt((int)m_FadeColor); + return m_ScValue; + } + + else return CUIObject::ScGetProperty(Name); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::ScSetProperty(char *Name, CScValue *Value) { + ////////////////////////////////////////////////////////////////////////// + // Name + ////////////////////////////////////////////////////////////////////////// + if (strcmp(Name, "Name") == 0) { + SetName(Value->GetString()); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Menu + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Menu") == 0) { + m_IsMenu = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // InGame + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "InGame") == 0) { + m_InGame = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // PauseMusic + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "PauseMusic") == 0) { + m_PauseMusic = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // ClipContents + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "ClipContents") == 0) { + m_ClipContents = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Transparent + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Transparent") == 0) { + m_Transparent = Value->GetBool(); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // FadeColor + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "FadeColor") == 0) { + m_FadeColor = (uint32)Value->GetInt(); + m_FadeBackground = (m_FadeColor != 0); + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // Exclusive + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "Exclusive") == 0) { + if (Value->GetBool()) + GoExclusive(); + else { + Close(); + m_Visible = true; + } + return S_OK; + } + + ////////////////////////////////////////////////////////////////////////// + // SystemExclusive + ////////////////////////////////////////////////////////////////////////// + else if (strcmp(Name, "SystemExclusive") == 0) { + if (Value->GetBool()) + GoSystemExclusive(); + else { + Close(); + m_Visible = true; + } + return S_OK; + } + + else return CUIObject::ScSetProperty(Name, Value); +} + + +////////////////////////////////////////////////////////////////////////// +char *CUIWindow::ScToString() { + return "[window]"; +} + + +////////////////////////////////////////////////////////////////////////// +bool CUIWindow::HandleKeypress(SDL_Event *event) { + + if (event->type == SDL_KEYDOWN && event->key.keysym.scancode == SDL_SCANCODE_TAB) { + return SUCCEEDED(MoveFocus(!CBKeyboardState::IsShiftDown())); + } else { + if (m_FocusedWidget) return m_FocusedWidget->HandleKeypress(event); + else return false; + } + + return false; +} + + +////////////////////////////////////////////////////////////////////////// +bool CUIWindow::HandleMouseWheel(int Delta) { + if (m_FocusedWidget) return m_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(&m_DragRect)) { + // start drag + if (Event == MOUSE_CLICK && Button == MOUSE_BUTTON_LEFT) { + RECT DragRect = m_DragRect; + int OffsetX, OffsetY; + GetTotalOffset(&OffsetX, &OffsetY); + CBPlatform::OffsetRect(&DragRect, m_PosX + OffsetX, m_PosY + OffsetY); + + if (CBPlatform::PtInRect(&DragRect, Game->m_MousePos)) { + m_DragFrom.x = Game->m_MousePos.x; + m_DragFrom.y = Game->m_MousePos.y; + m_Dragging = true; + } + } + // end drag + else if (m_Dragging && Event == MOUSE_RELEASE && Button == MOUSE_BUTTON_LEFT) { + m_Dragging = false; + } + } + + return res; +} + + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::Persist(CBPersistMgr *PersistMgr) { + + CUIObject::Persist(PersistMgr); + + PersistMgr->Transfer(TMEMBER(m_BackInactive)); + PersistMgr->Transfer(TMEMBER(m_ClipContents)); + PersistMgr->Transfer(TMEMBER(m_DragFrom)); + PersistMgr->Transfer(TMEMBER(m_Dragging)); + PersistMgr->Transfer(TMEMBER(m_DragRect)); + PersistMgr->Transfer(TMEMBER(m_FadeBackground)); + PersistMgr->Transfer(TMEMBER(m_FadeColor)); + PersistMgr->Transfer(TMEMBER(m_FontInactive)); + PersistMgr->Transfer(TMEMBER(m_ImageInactive)); + PersistMgr->Transfer(TMEMBER(m_InGame)); + PersistMgr->Transfer(TMEMBER(m_IsMenu)); + PersistMgr->Transfer(TMEMBER_INT(m_Mode)); + PersistMgr->Transfer(TMEMBER(m_ShieldButton)); + PersistMgr->Transfer(TMEMBER(m_ShieldWindow)); + PersistMgr->Transfer(TMEMBER_INT(m_TitleAlign)); + PersistMgr->Transfer(TMEMBER(m_TitleRect)); + PersistMgr->Transfer(TMEMBER(m_Transparent)); + PersistMgr->Transfer(TMEMBER(m_Viewport)); + PersistMgr->Transfer(TMEMBER(m_PauseMusic)); + + m_Widgets.Persist(PersistMgr); + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::MoveFocus(bool Forward) { + int i; + bool found = false; + for (i = 0; i < m_Widgets.GetSize(); i++) { + if (m_Widgets[i] == m_FocusedWidget) { + found = true; + break; + } + } + if (!found) m_FocusedWidget = NULL; + + if (!m_FocusedWidget) { + if (m_Widgets.GetSize() > 0) i = 0; + else return S_OK; + } + + int NumTries = 0; + bool done = false; + + while (NumTries <= m_Widgets.GetSize()) { + if (m_Widgets[i] != m_FocusedWidget && m_Widgets[i]->m_CanFocus && m_Widgets[i]->m_Visible && !m_Widgets[i]->m_Disable) { + m_FocusedWidget = m_Widgets[i]; + done = true; + break; + } + + if (Forward) { + i++; + if (i >= m_Widgets.GetSize()) i = 0; + } else { + i--; + if (i < 0) i = m_Widgets.GetSize() - 1; + } + NumTries++; + } + + return done ? S_OK : E_FAIL; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::GoExclusive() { + if (m_Mode == WINDOW_EXCLUSIVE) return S_OK; + + if (m_Mode == WINDOW_NORMAL) { + m_Ready = false; + m_Mode = WINDOW_EXCLUSIVE; + m_Visible = true; + m_Disable = false; + Game->FocusWindow(this); + return S_OK; + } else return E_FAIL; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::GoSystemExclusive() { + if (m_Mode == WINDOW_SYSTEM_EXCLUSIVE) return S_OK; + + MakeFreezable(false); + + m_Mode = WINDOW_SYSTEM_EXCLUSIVE; + m_Ready = false; + m_Visible = true; + m_Disable = false; + Game->FocusWindow(this); + + Game->Freeze(m_PauseMusic); + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::Close() { + if (m_Mode == WINDOW_SYSTEM_EXCLUSIVE) { + Game->Unfreeze(); + } + + m_Mode = WINDOW_NORMAL; + m_Visible = false; + m_Ready = true; + + return S_OK; +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::Listen(CBScriptHolder *param1, uint32 param2) { + CUIObject *obj = (CUIObject *)param1; + + switch (obj->m_Type) { + case UI_BUTTON: + if (scumm_stricmp(obj->m_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 < m_Widgets.GetSize(); i++) + m_Widgets[i]->MakeFreezable(Freezable); + + CBObject::MakeFreezable(Freezable); +} + + +////////////////////////////////////////////////////////////////////////// +HRESULT CUIWindow::GetWindowObjects(CBArray& Objects, bool InteractiveOnly) { + for (int i = 0; i < m_Widgets.GetSize(); i++) { + CUIObject *Control = m_Widgets[i]; + if (Control->m_Disable && InteractiveOnly) continue; + + switch (Control->m_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/UIWindow.h b/engines/wintermute/UIWindow.h new file mode 100644 index 0000000000..b8adc2f27f --- /dev/null +++ b/engines/wintermute/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 m_PauseMusic; + void Cleanup(); + virtual void MakeFreezable(bool Freezable); + CBViewport *m_Viewport; + bool m_ClipContents; + bool m_InGame; + bool m_IsMenu; + bool m_FadeBackground; + uint32 m_FadeColor; + virtual bool HandleMouseWheel(int Delta); + CUIWindow *m_ShieldWindow; + CUIButton *m_ShieldButton; + HRESULT Close(); + HRESULT GoSystemExclusive(); + HRESULT GoExclusive(); + TWindowMode m_Mode; + HRESULT MoveFocus(bool Forward = true); + virtual HRESULT HandleMouse(TMouseEvent Event, TMouseButton Button); + POINT m_DragFrom; + bool m_Dragging; + DECLARE_PERSISTENT(CUIWindow, CUIObject) + bool m_Transparent; + HRESULT ShowWidget(char *Name, bool Visible = true); + HRESULT EnableWidget(char *Name, bool Enable = true); + RECT m_TitleRect; + RECT m_DragRect; + virtual HRESULT Display(int OffsetX = 0, int OffsetY = 0); + CUIWindow(CBGame *inGame); + virtual ~CUIWindow(); + virtual bool HandleKeypress(SDL_Event *event); + CBArray m_Widgets; + TTextAlign m_TitleAlign; + HRESULT LoadFile(char *Filename); + HRESULT LoadBuffer(byte *Buffer, bool Complete = true); + CUITiledImage *m_BackInactive; + CBFont *m_FontInactive; + CBSprite *m_ImageInactive; + virtual HRESULT Listen(CBScriptHolder *param1, uint32 param2); + virtual HRESULT SaveAsText(CBDynBuffer *Buffer, int Indent); + + // scripting interface + virtual CScValue *ScGetProperty(char *Name); + virtual HRESULT ScSetProperty(char *Name, CScValue *Value); + virtual HRESULT ScCallMethod(CScScript *Script, CScStack *Stack, CScStack *ThisStack, char *Name); + virtual char *ScToString(); +}; + +} // end of namespace WinterMute + +#endif diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk index e6847eb585..a7bac98891 100644 --- a/engines/wintermute/module.mk +++ b/engines/wintermute/module.mk @@ -42,6 +42,10 @@ MODULE_OBJS := \ StringUtil.o \ SysClass.o \ SysInstance.o \ + UIButton.o \ + UIEntity.o \ + UIObject.o \ + UITiledImage.o \ utils.o \ wintermute.o -- cgit v1.2.3