Files
2026-05-10 01:30:36 -07:00

591 lines
16 KiB
C++

/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef __WINDOW_H__
#define __WINDOW_H__
#include "RegExp.h"
#include "Winvar.h"
#include "GuiScript.h"
#include "SimpleWindow.h"
const int WIN_CHILD = 0x00000001;
const int WIN_CAPTION = 0x00000002;
const int WIN_BORDER = 0x00000004;
const int WIN_SIZABLE = 0x00000008;
const int WIN_MOVABLE = 0x00000010;
const int WIN_FOCUS = 0x00000020;
const int WIN_CAPTURE = 0x00000040;
const int WIN_HCENTER = 0x00000080;
const int WIN_VCENTER = 0x00000100;
const int WIN_MODAL = 0x00000200;
const int WIN_INTRANSITION = 0x00000400;
const int WIN_CANFOCUS = 0x00000800;
const int WIN_SELECTED = 0x00001000;
const int WIN_TRANSFORM = 0x00002000;
const int WIN_HOLDCAPTURE = 0x00004000;
const int WIN_NOWRAP = 0x00008000;
const int WIN_NOCLIP = 0x00010000;
const int WIN_INVERTRECT = 0x00020000;
const int WIN_NATURALMAT = 0x00040000;
const int WIN_NOCURSOR = 0x00080000;
const int WIN_MENUGUI = 0x00100000;
const int WIN_ACTIVE = 0x00200000;
const int WIN_SHOWCOORDS = 0x00400000;
const int WIN_SHOWTIME = 0x00800000;
const int WIN_WANTENTER = 0x01000000;
#ifdef QUAKE4
const int WIN_ALWAYSTHINK = 0x08000000;
#endif
const int WIN_DESKTOP = 0x10000000;
#ifdef QUAKE4
const int WIN_CHATWINDOW = 0x20000000;
#endif
const char CAPTION_HEIGHT[] = "16.0";
const char SCROLLER_SIZE[] = "16.0";
const int SCROLLBAR_SIZE = 16;
const int MAX_WINDOW_NAME = 32;
const int MAX_LIST_ITEMS = 1024;
const char DEFAULT_BACKCOLOR[] = "1 1 1 1";
const char DEFAULT_FORECOLOR[] = "0 0 0 1";
const char DEFAULT_BORDERCOLOR[] = "0 0 0 1";
const char DEFAULT_TEXTSCALE[] = "0.4";
typedef enum {
WOP_TYPE_ADD,
WOP_TYPE_SUBTRACT,
WOP_TYPE_MULTIPLY,
WOP_TYPE_DIVIDE,
WOP_TYPE_MOD,
WOP_TYPE_TABLE,
WOP_TYPE_GT,
WOP_TYPE_GE,
WOP_TYPE_LT,
WOP_TYPE_LE,
WOP_TYPE_EQ,
WOP_TYPE_NE,
WOP_TYPE_AND,
WOP_TYPE_OR,
WOP_TYPE_VAR,
WOP_TYPE_VARS,
WOP_TYPE_VARF,
WOP_TYPE_VARI,
WOP_TYPE_VARB,
WOP_TYPE_COND
#ifdef QUAKE4
, WOP_TYPE_VARFM
#endif
} wexpOpType_t;
typedef enum {
WEXP_REG_TIME,
WEXP_REG_NUM_PREDEFINED
} wexpRegister_t;
typedef struct {
wexpOpType_t opType;
intptr_t a, b, c, d;
} wexpOp_t;
struct idRegEntry {
const char* name;
idRegister::REGTYPE type;
int index;
};
class rvGEWindowWrapper;
class idWindow;
struct idTimeLineEvent {
idTimeLineEvent() {
event = new idGuiScriptList;
}
~idTimeLineEvent() {
delete event;
}
int time;
idGuiScriptList* event;
bool pending;
size_t Size() {
return sizeof(*this) + event->Size();
}
};
class rvNamedEvent
{
public:
rvNamedEvent(const char* name)
{
mEvent = new idGuiScriptList;
mName = name;
}
~rvNamedEvent(void)
{
delete mEvent;
}
size_t Size()
{
return sizeof(*this) + mEvent->Size();
}
idStr mName;
idGuiScriptList* mEvent;
};
struct idTransitionData {
idWinVar* data;
int offset;
idInterpolateAccelDecelLinear<idVec4> interp;
};
class idUserInterfaceLocal;
class idWindow {
public:
idWindow(idUserInterfaceLocal* gui);
idWindow(idDeviceContext* d, idUserInterfaceLocal* gui);
virtual ~idWindow();
enum {
ON_MOUSEENTER = 0,
ON_MOUSEEXIT,
ON_ACTION,
#ifdef QUAKE4
ON_ACTIONRIGHT, // Q4 secondary / mouse2 action slot
#endif
ON_ACTIVATE,
ON_DEACTIVATE,
ON_ESC,
ON_FRAME,
ON_TRIGGER,
ON_ACTIONRELEASE,
ON_ENTER,
ON_ENTERRELEASE,
#ifdef QUAKE4
ON_ESCRELEASE, // reserved Q4 slot
ON_GAINFOCUS,
ON_LOSEFOCUS,
ON_RESERVED15, // reserved Q4 slot
ON_INIT,
ON_JOYBUTTON3,
ON_JOYACTION,
ON_JOYBACK,
ON_JOYLSHOULDER,
ON_JOYRSHOULDER,
ON_JOYLEFT,
ON_JOYRIGHT,
ON_JOYDOWN,
ON_JOYUP,
ON_JOYBUTTON1,
ON_JOYBUTTON2,
#endif
SCRIPT_COUNT
};
enum {
ADJUST_MOVE = 0,
ADJUST_TOP,
ADJUST_RIGHT,
ADJUST_BOTTOM,
ADJUST_LEFT,
ADJUST_TOPLEFT,
ADJUST_BOTTOMRIGHT,
ADJUST_TOPRIGHT,
ADJUST_BOTTOMLEFT
};
static const char* ScriptNames[SCRIPT_COUNT];
static const idRegEntry RegisterVars[];
static const int NumRegisterVars;
void SetDC(idDeviceContext* d);
idDeviceContext* GetDC(void) { return dc; }
idWindow* SetFocus(idWindow* w, bool scripts = true);
idWindow* SetCapture(idWindow* w);
void SetParent(idWindow* w);
void SetFlag(unsigned int f);
void ClearFlag(unsigned int f);
unsigned GetFlags() { return flags; };
void Move(float x, float y);
void BringToTop(idWindow* w);
void Adjust(float xd, float yd);
void SetAdjustMode(idWindow* child);
void Size(float x, float y, float w, float h);
void SetupFromState();
void SetupBackground();
drawWin_t* FindChildByName(const char* name);
idSimpleWindow* FindSimpleWinByName(const char* _name);
idWindow* GetParent() { return parent; }
idUserInterfaceLocal* GetGui() { return gui; };
bool Contains(float x, float y);
size_t Size();
virtual size_t Allocated();
idStr* GetStrPtrByName(const char* _name);
virtual idWinVar* GetWinVarByName(const char* _name, bool winLookup = false, drawWin_t** owner = NULL);
intptr_t GetWinVarOffset(idWinVar* wv, drawWin_t* dw);
float GetMaxCharHeight();
float GetMaxCharWidth();
void SetFont();
void SetInitialState(const char* _name);
void AddChild(idWindow* win);
void DebugDraw(int time, float x, float y);
void CalcClientRect(float xofs, float yofs);
void CommonInit();
void CleanUp();
void DrawBorderAndCaption(const idRectangle& drawRect);
void DrawCaption(int time, float x, float y);
void SetupTransforms(float x, float y);
bool Contains(const idRectangle& sr, float x, float y);
const char* GetName() { return name; };
virtual bool Parse(idParser* src, bool rebuild = true);
virtual const char* HandleEvent(const sysEvent_t* event, bool* updateVisuals);
void CalcRects(float x, float y);
virtual void Redraw(float x, float y);
virtual void ArchiveToDictionary(idDict* dict, bool useNames = true);
virtual void InitFromDictionary(idDict* dict, bool byName = true);
virtual void PostParse();
virtual void Activate(bool activate, idStr& act);
virtual void Trigger();
#ifdef QUAKE4
virtual void Init();
virtual bool RunControllerScript(int script, const sysEvent_t* event, bool* updateVisuals);
virtual bool RouteJoystickChange(int xd, int yd);
#endif
virtual void GainFocus();
virtual void LoseFocus();
virtual void GainCapture();
virtual void LoseCapture();
virtual void Sized();
virtual void Moved();
virtual void Draw(int time, float x, float y);
virtual void MouseExit();
virtual void MouseEnter();
virtual void DrawBackground(const idRectangle& drawRect);
virtual const char* RouteMouseCoords(float xd, float yd);
virtual void SetBuddy(idWindow* buddy) {};
virtual void HandleBuddyUpdate(idWindow* buddy) {};
virtual void StateChanged(bool redraw);
virtual void ReadFromDemoFile(class idDemoFile* f, bool rebuild = true);
virtual void WriteToDemoFile(class idDemoFile* f);
// SaveGame support
void WriteSaveGameString(const char* string, idFile* savefile);
void WriteSaveGameTransition(idTransitionData& trans, idFile* savefile);
virtual void WriteToSaveGame(idFile* savefile);
void ReadSaveGameString(idStr& string, idFile* savefile);
void ReadSaveGameTransition(idTransitionData& trans, idFile* savefile);
virtual void ReadFromSaveGame(idFile* savefile);
void FixupTransitions();
virtual void HasAction() {};
virtual void HasScripts() {};
void FixupParms();
void GetScriptString(const char* name, idStr& out);
void SetScriptParams();
bool HasOps() { return (ops.Num() > 0); };
float EvalRegs(int test = -1, bool force = false);
void StartTransition();
void AddTransition(idWinVar* dest, idVec4 from, idVec4 to, int time, float accelTime, float decelTime);
#ifdef QUAKE4
void ClearTransitions();
#endif
void ResetTime(int time);
void ResetCinematics();
#ifdef QUAKE4
bool IsVisible() const;
void SetWrapper(int wrapper);
#endif
int NumTransitions();
bool ParseScript(idParser* src, idGuiScriptList& list, int* timeParm = NULL, bool allowIf = false);
bool RunScript(int n);
bool RunScriptList(idGuiScriptList* src);
void SetRegs(const char* key, const char* val);
intptr_t ParseExpression(idParser* src, idWinVar* var = NULL, intptr_t component = 0);
int ExpressionConstant(float f);
idRegisterList* RegList() { return &regList; }
void AddCommand(const char* cmd);
void AddUpdateVar(idWinVar* var);
bool Interactive();
bool ContainsStateVars();
void SetChildWinVarVal(const char* name, const char* var, const char* val);
idWindow* GetFocusedChild();
idWindow* GetCaptureChild();
const char* GetComment() { return comment; }
void SetComment(const char* p) { comment = p; }
idStr cmd;
virtual void RunNamedEvent(const char* eventName);
void AddDefinedVar(idWinVar* var);
idWindow* FindChildByPoint(float x, float y, idWindow* below = NULL);
int GetChildIndex(idWindow* window);
int GetChildCount(void);
idWindow* GetChild(int index);
void RemoveChild(idWindow* win);
bool InsertChild(idWindow* win, idWindow* before);
void ScreenToClient(idRectangle* rect);
void ClientToScreen(idRectangle* rect);
bool UpdateFromDictionary(idDict& dict);
protected:
friend class rvGEWindowWrapper;
idWindow* FindChildByPoint(float x, float y, idWindow** below);
#ifdef QUAKE4
void FindBestChild_r(int xd, int yd, int& startX, int& startY, int& bestX, int& bestY, idWindow* current, idWindow*& best);
#endif
void SetDefaults(void);
friend class idSimpleWindow;
friend class idUserInterfaceLocal;
bool IsSimple();
void UpdateWinVars();
void DisableRegister(const char* _name);
void Transition();
void Time();
bool RunTimeEvents(int time);
void Dump();
int ExpressionTemporary();
wexpOp_t* ExpressionOp();
intptr_t EmitOp(intptr_t a, intptr_t b, wexpOpType_t opType, wexpOp_t** opp = NULL);
intptr_t ParseEmitOp(idParser* src, intptr_t a, wexpOpType_t opType, int priority, wexpOp_t** opp = NULL);
intptr_t ParseTerm(idParser* src, idWinVar* var = NULL, intptr_t component = 0);
intptr_t ParseExpressionPriority(idParser* src, int priority, idWinVar* var = NULL, intptr_t component = 0);
void EvaluateRegisters(float* registers);
void SaveExpressionParseState();
void RestoreExpressionParseState();
void ParseBracedExpression(idParser* src);
bool ParseScriptEntry(const char* name, idParser* src);
bool ParseRegEntry(const char* name, idParser* src);
virtual bool ParseInternalVar(const char* name, idParser* src);
void ParseString(idParser* src, idStr& out);
void ParseVec4(idParser* src, idVec4& out);
void ConvertRegEntry(const char* name, idParser* src, idStr& out, int tabs);
float actualX; // physical coords
float actualY; // ''
int childID; // this childs id
unsigned int flags; // visible, focus, mouseover, cursor, border, etc..
int lastTimeRun; //
idRectangle drawRect; // overall rect
idRectangle clientRect; // client area
idVec2 origin;
int timeLine; // time stamp used for various fx
float xOffset;
float yOffset;
float forceAspectWidth;
float forceAspectHeight;
float matScalex;
float matScaley;
float borderSize;
float textAlignx;
float textAligny;
idStr name;
idStr comment;
idVec2 shear;
signed char textShadow;
#ifdef QUAKE4
signed char textStyle;
#endif
unsigned char fontNum;
unsigned char cursor; //
signed char textAlign;
#ifdef QUAKE4
float textSpacing;
#endif
idWinBool noTime; //
idWinBool visible; //
idWinBool noEvents;
idWinRectangle rect; // overall rect
idWinVec4 backColor;
idWinVec4 matColor;
idWinVec4 foreColor;
idWinVec4 hoverColor;
idWinVec4 borderColor;
idWinFloat textScale;
idWinFloat rotate;
idWinStr text;
idWinBackground backGroundName; //
idList<idWinVar*> definedVars;
idList<idWinVar*> updateVars;
idRectangle textRect; // text extented rect
const idMaterial* background; // background asset
idWindow* parent; // parent window
idList<idWindow*> children; // child windows
idList<drawWin_t> drawWindows;
#ifdef QUAKE4
int startChildSearch; // Q4 child-lookup optimization
idWindow* currentChild; // controller navigation helper
#endif
idWindow* focusedChild; // if a child window has the focus
idWindow* captureChild; // if a child window has mouse capture
idWindow* overChild; // if a child window has mouse capture
bool hover;
idDeviceContext* dc;
idUserInterfaceLocal* gui;
static idCVar gui_debug;
static idCVar gui_edit;
idGuiScriptList* scripts[SCRIPT_COUNT];
bool* saveTemps;
idList<idTimeLineEvent*> timeLineEvents;
idList<idTransitionData> transitions;
#ifdef QUAKE4
idList<intptr_t> transitionSubs;
#endif
static bool registerIsTemporary[MAX_EXPRESSION_REGISTERS]; // statics to assist during parsing
idList<wexpOp_t> ops; // evaluate to make expressionRegisters
idList<float> expressionRegisters;
idList<wexpOp_t>* saveOps; // evaluate to make expressionRegisters
idList<rvNamedEvent*> namedEvents; // added named events
idList<float>* saveRegs;
idRegisterList regList;
idWinBool hideCursor;
};
ID_INLINE void idWindow::AddDefinedVar(idWinVar* var) {
definedVars.AddUnique(var);
}
#ifdef QUAKE4
// Quake 4 added synthetic float-member window vars so expressions / transitions
// can address rect_x, rect_y, forecolor_w, etc. Doom 3 does not ship one, so
// we keep the helper local to Window.cpp.
class idWinFloatMember : public idWinVar {
public:
idWinFloatMember() : owner(NULL), component(0) {}
idWinFloatMember(idWinVar* base, int index) : owner(base), component(index) {}
virtual void Init(const char* name, idWindow* win) {
idWinVar::Init(name, win);
}
virtual void Update() {
if (owner) {
owner->Update();
}
}
virtual void Set(const char* value) {
if (!owner) {
return;
}
float f = static_cast<float>(atof(value));
if (idWinVec4* v4 = dynamic_cast<idWinVec4*>(owner)) {
(*v4)[component] = f;
}
else if (idWinRectangle* r = dynamic_cast<idWinRectangle*>(owner)) {
switch (component) {
case 0: r->data.x = f; break;
case 1: r->data.y = f; break;
case 2: r->data.w = f; break;
case 3: r->data.h = f; break;
}
}
}
virtual const char* c_str() const {
return va("%g", x());
}
virtual float x() const {
if (!owner) {
return 0.0f;
}
if (const idWinVec4* v4 = dynamic_cast<const idWinVec4*>(owner)) {
return (*v4)[component];
}
if (const idWinRectangle* r = dynamic_cast<const idWinRectangle*>(owner)) {
switch (component) {
case 0: return r->data.x;
case 1: return r->data.y;
case 2: return r->data.w;
case 3: return r->data.h;
}
}
return 0.0f;
}
virtual void WriteToSaveGame(idFile* savefile) {
idWinFloat temp;
temp = x();
temp.WriteToSaveGame(savefile);
}
virtual void ReadFromSaveGame(idFile* savefile) {
idWinFloat temp;
temp.ReadFromSaveGame(savefile);
Set(va("%g", temp.data));
}
virtual size_t Size() {
return sizeof(*this);
}
idWinVar* GetOwner() const { return owner; }
int GetComponent() const { return component; }
private:
idWinVar* owner;
int component;
};
#endif // QUAKE4
#endif /* !__WINDOW_H__ */