dhewm3/neo/ui/Window.cpp
Daniel Gibson ae63021d00 Add absolute mouse mode and refactor mouse grabbing code
There were lots of places in the code that called Sys_GrabInput(),
some of them each frame.
Most of this is unified in events.cpp now, in handleMouseGrab() which
is called once per frame by Sys_GenerateEvents() - this makes reasoning
about when the mouse is grabbed and when not a lot easier.
Sys_GrabInput(false) still is called in a few places, before operations
that tend to take long (like loading a map or vid_restart), but
(hopefully) not regularly anymore.

The other big change is that the game now uses SDLs absolute mouse mode
for fullscreen menus (except the PDA which is an ugly hack), so the
ingame cursor is at the same position as the system cursor, which
especially helps when debugging with `in_nograb 1` and should also help
if someone wants to integrate an additional GUI toolkit like Dear ImGui.
2022-01-10 00:46:32 +01:00

4264 lines
97 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.
===========================================================================
*/
#include "sys/platform.h"
#include "idlib/containers/HashTable.h"
#include "framework/UsercmdGen.h"
#include "framework/KeyInput.h"
#include "ui/DeviceContext.h"
#include "ui/UserInterfaceLocal.h"
#include "ui/EditWindow.h"
#include "ui/ChoiceWindow.h"
#include "ui/SliderWindow.h"
#include "ui/BindWindow.h"
#include "ui/ListWindow.h"
#include "ui/RenderWindow.h"
#include "ui/MarkerWindow.h"
#include "ui/FieldWindow.h"
#include "ui/GameSSDWindow.h"
#include "ui/GameBearShootWindow.h"
#include "ui/GameBustOutWindow.h"
// gui editor is more integrated into the window now
#include "tools/guied/GEWindowWrapper.h"
#include "ui/Window.h"
bool idWindow::registerIsTemporary[MAX_EXPRESSION_REGISTERS]; // statics to assist during parsing
//float idWindow::shaderRegisters[MAX_EXPRESSION_REGISTERS];
//wexpOp_t idWindow::shaderOps[MAX_EXPRESSION_OPS];
idCVar idWindow::gui_debug( "gui_debug", "0", CVAR_GUI | CVAR_BOOL, "" );
idCVar idWindow::gui_edit( "gui_edit", "0", CVAR_GUI | CVAR_BOOL, "" );
extern idCVar r_skipGuiShaders; // 1 = don't render any gui elements on surfaces
extern idCVar r_scaleMenusTo43;
// made RegisterVars a member of idWindow
const idRegEntry idWindow::RegisterVars[] = {
{ "forecolor", idRegister::VEC4 },
{ "hovercolor", idRegister::VEC4 },
{ "backcolor", idRegister::VEC4 },
{ "bordercolor", idRegister::VEC4 },
{ "rect", idRegister::RECTANGLE },
{ "matcolor", idRegister::VEC4 },
{ "scale", idRegister::VEC2 },
{ "translate", idRegister::VEC2 },
{ "rotate", idRegister::FLOAT },
{ "textscale", idRegister::FLOAT },
{ "visible", idRegister::BOOL },
{ "noevents", idRegister::BOOL },
{ "text", idRegister::STRING },
{ "background", idRegister::STRING },
{ "runscript", idRegister::STRING },
{ "varbackground", idRegister::STRING },
{ "cvar", idRegister::STRING },
{ "choices", idRegister::STRING },
{ "choiceVar", idRegister::STRING },
{ "bind", idRegister::STRING },
{ "modelRotate", idRegister::VEC4 },
{ "modelOrigin", idRegister::VEC4 },
{ "lightOrigin", idRegister::VEC4 },
{ "lightColor", idRegister::VEC4 },
{ "viewOffset", idRegister::VEC4 },
{ "hideCursor", idRegister::BOOL}
};
const int idWindow::NumRegisterVars = sizeof(RegisterVars) / sizeof(idRegEntry);
const char *idWindow::ScriptNames[] = {
"onMouseEnter",
"onMouseExit",
"onAction",
"onActivate",
"onDeactivate",
"onESC",
"onEvent",
"onTrigger",
"onActionRelease",
"onEnter",
"onEnterRelease"
};
/*
================
idWindow::CommonInit
================
*/
void idWindow::CommonInit() {
childID = 0;
flags = 0;
lastTimeRun = 0;
origin.Zero();
fontNum = 0;
timeLine = -1;
xOffset = yOffset = 0.0;
cursor = 0;
forceAspectWidth = 640;
forceAspectHeight = 480;
matScalex = 1;
matScaley = 1;
borderSize = 0;
noTime = false;
visible = true;
textAlign = 0;
textAlignx = 0;
textAligny = 0;
noEvents = false;
rotate = 0;
shear.Zero();
textScale = 0.35f;
backColor.Zero();
foreColor = idVec4(1, 1, 1, 1);
hoverColor = idVec4(1, 1, 1, 1);
matColor = idVec4(1, 1, 1, 1);
borderColor.Zero();
background = NULL;
backGroundName = "";
focusedChild = NULL;
captureChild = NULL;
overChild = NULL;
parent = NULL;
saveOps = NULL;
saveRegs = NULL;
timeLine = -1;
textShadow = 0;
hover = false;
for (int i = 0; i < SCRIPT_COUNT; i++) {
scripts[i] = NULL;
}
hideCursor = false;
}
/*
================
idWindow::Size
================
*/
size_t idWindow::Size() {
int c = children.Num();
int sz = 0;
for (int i = 0; i < c; i++) {
sz += children[i]->Size();
}
sz += sizeof(*this) + Allocated();
return sz;
}
/*
================
idWindow::Allocated
================
*/
size_t idWindow::Allocated() {
int i, c;
int sz = name.Allocated();
sz += text.Size();
sz += backGroundName.Size();
c = definedVars.Num();
for (i = 0; i < c; i++) {
sz += definedVars[i]->Size();
}
for (i = 0; i < SCRIPT_COUNT; i++) {
if (scripts[i]) {
sz += scripts[i]->Size();
}
}
c = timeLineEvents.Num();
for (i = 0; i < c; i++) {
sz += timeLineEvents[i]->Size();
}
c = namedEvents.Num();
for (i = 0; i < c; i++) {
sz += namedEvents[i]->Size();
}
c = drawWindows.Num();
for (i = 0; i < c; i++) {
if (drawWindows[i].simp) {
sz += drawWindows[i].simp->Size();
}
}
return sz;
}
/*
================
idWindow::idWindow
================
*/
idWindow::idWindow(idUserInterfaceLocal *ui) {
dc = NULL;
gui = ui;
CommonInit();
}
/*
================
idWindow::idWindow
================
*/
idWindow::idWindow(idDeviceContext *d, idUserInterfaceLocal *ui) {
dc = d;
gui = ui;
CommonInit();
}
/*
================
idWindow::CleanUp
================
*/
void idWindow::CleanUp() {
int i, c = drawWindows.Num();
for (i = 0; i < c; i++) {
delete drawWindows[i].simp;
}
// ensure the register list gets cleaned up
regList.Reset ( );
// Cleanup the named events
namedEvents.DeleteContents(true);
// Cleanup the operations and update vars
// (if it is not fixed, orphane register references are possible)
ops.Clear();
updateVars.Clear();
drawWindows.Clear();
children.DeleteContents(true);
definedVars.DeleteContents(true);
timeLineEvents.DeleteContents(true);
for (i = 0; i < SCRIPT_COUNT; i++) {
delete scripts[i];
}
CommonInit();
}
/*
================
idWindow::~idWindow
================
*/
idWindow::~idWindow() {
CleanUp();
}
/*
================
idWindow::Move
================
*/
void idWindow::Move(float x, float y) {
idRectangle rct = rect;
rct.x = x;
rct.y = y;
idRegister *reg = RegList()->FindReg("rect");
if (reg) {
reg->Enable(false);
}
rect = rct;
}
/*
================
idWindow::SetFont
================
*/
void idWindow::SetFont() {
dc->SetFont(fontNum);
}
/*
================
idWindow::GetMaxCharHeight
================
*/
float idWindow::GetMaxCharHeight() {
SetFont();
return dc->MaxCharHeight(textScale);
}
/*
================
idWindow::GetMaxCharWidth
================
*/
float idWindow::GetMaxCharWidth() {
SetFont();
return dc->MaxCharWidth(textScale);
}
/*
================
idWindow::Draw
================
*/
void idWindow::Draw( int time, float x, float y ) {
if ( text.Length() == 0 ) {
return;
}
if ( textShadow ) {
idStr shadowText = text;
idRectangle shadowRect = textRect;
shadowText.RemoveColors();
shadowRect.x += textShadow;
shadowRect.y += textShadow;
dc->DrawText( shadowText, textScale, textAlign, colorBlack, shadowRect, !( flags & WIN_NOWRAP ), -1 );
}
dc->DrawText( text, textScale, textAlign, foreColor, textRect, !( flags & WIN_NOWRAP ), -1 );
if ( gui_edit.GetBool() ) {
dc->EnableClipping( false );
dc->DrawText( va( "x: %i y: %i", ( int )rect.x(), ( int )rect.y() ), 0.25, 0, dc->colorWhite, idRectangle( rect.x(), rect.y() - 15, 100, 20 ), false );
dc->DrawText( va( "w: %i h: %i", ( int )rect.w(), ( int )rect.h() ), 0.25, 0, dc->colorWhite, idRectangle( rect.x() + rect.w(), rect.w() + rect.h() + 5, 100, 20 ), false );
dc->EnableClipping( true );
}
}
/*
================
idWindow::BringToTop
================
*/
void idWindow::BringToTop(idWindow *w) {
if (w && !(w->flags & WIN_MODAL)) {
return;
}
int c = children.Num();
for (int i = 0; i < c; i++) {
if (children[i] == w) {
// this is it move from i - 1 to 0 to i to 1 then shove this one into 0
for (int j = i+1; j < c; j++) {
children[j-1] = children[j];
}
children[c-1] = w;
break;
}
}
}
/*
================
idWindow::Size
================
*/
void idWindow::Size(float x, float y, float w, float h) {
idRectangle rct = rect;
rct.x = x;
rct.y = y;
rct.w = w;
rct.h = h;
rect = rct;
CalcClientRect(0,0);
}
/*
================
idWindow::MouseEnter
================
*/
void idWindow::MouseEnter() {
if (noEvents) {
return;
}
RunScript(ON_MOUSEENTER);
}
/*
================
idWindow::MouseExit
================
*/
void idWindow::MouseExit() {
if (noEvents) {
return;
}
RunScript(ON_MOUSEEXIT);
}
/*
================
idWindow::RouteMouseCoords
================
*/
const char *idWindow::RouteMouseCoords(float xd, float yd) {
idStr str;
if (GetCaptureChild()) {
//FIXME: unkludge this whole mechanism
return GetCaptureChild()->RouteMouseCoords(xd, yd);
}
if (xd == -2000 || yd == -2000) {
return "";
}
int c = children.Num();
while (c > 0) {
idWindow *child = children[--c];
if (child->visible && !child->noEvents && child->Contains(child->drawRect, gui->CursorX(), gui->CursorY())) {
dc->SetCursor(child->cursor);
child->hover = true;
if (overChild != child) {
if (overChild) {
overChild->MouseExit();
str = overChild->cmd;
if (str.Length()) {
gui->GetDesktop()->AddCommand(str);
overChild->cmd = "";
}
}
overChild = child;
overChild->MouseEnter();
str = overChild->cmd;
if (str.Length()) {
gui->GetDesktop()->AddCommand(str);
overChild->cmd = "";
}
} else {
if (!(child->flags & WIN_HOLDCAPTURE)) {
child->RouteMouseCoords(xd, yd);
}
}
return "";
}
}
if (overChild) {
overChild->MouseExit();
str = overChild->cmd;
if (str.Length()) {
gui->GetDesktop()->AddCommand(str);
overChild->cmd = "";
}
overChild = NULL;
}
return "";
}
/*
================
idWindow::Activate
================
*/
void idWindow::Activate( bool activate, idStr &act ) {
int n = (activate) ? ON_ACTIVATE : ON_DEACTIVATE;
// make sure win vars are updated before activation
UpdateWinVars ( );
RunScript(n);
int c = children.Num();
for (int i = 0; i < c; i++) {
children[i]->Activate( activate, act );
}
if ( act.Length() ) {
act += " ; ";
}
}
/*
================
idWindow::Trigger
================
*/
void idWindow::Trigger() {
RunScript( ON_TRIGGER );
int c = children.Num();
for ( int i = 0; i < c; i++ ) {
children[i]->Trigger();
}
StateChanged( true );
}
/*
================
idWindow::StateChanged
================
*/
void idWindow::StateChanged( bool redraw ) {
UpdateWinVars();
if (expressionRegisters.Num() && ops.Num()) {
EvalRegs();
}
int c = drawWindows.Num();
for ( int i = 0; i < c; i++ ) {
if ( drawWindows[i].win ) {
drawWindows[i].win->StateChanged( redraw );
} else {
drawWindows[i].simp->StateChanged( redraw );
}
}
if ( redraw ) {
if ( flags & WIN_DESKTOP ) {
Redraw( 0.0f, 0.0f );
}
if ( background && background->CinematicLength() ) {
background->UpdateCinematic( gui->GetTime() );
}
}
}
/*
================
idWindow::SetCapture
================
*/
idWindow *idWindow::SetCapture(idWindow *w) {
// only one child can have the focus
idWindow *last = NULL;
int c = children.Num();
for (int i = 0; i < c; i++) {
if ( children[i]->flags & WIN_CAPTURE ) {
last = children[i];
//last->flags &= ~WIN_CAPTURE;
last->LoseCapture();
break;
}
}
w->flags |= WIN_CAPTURE;
w->GainCapture();
gui->GetDesktop()->captureChild = w;
return last;
}
/*
================
idWindow::AddUpdateVar
================
*/
void idWindow::AddUpdateVar(idWinVar *var) {
updateVars.AddUnique(var);
}
/*
================
idWindow::UpdateWinVars
================
*/
void idWindow::UpdateWinVars() {
int c = updateVars.Num();
for (int i = 0; i < c; i++) {
updateVars[i]->Update();
}
}
/*
================
idWindow::RunTimeEvents
================
*/
bool idWindow::RunTimeEvents(int time) {
if ( time - lastTimeRun < USERCMD_MSEC ) {
//common->Printf("Skipping gui time events at %i\n", time);
return false;
}
lastTimeRun = time;
UpdateWinVars();
if (expressionRegisters.Num() && ops.Num()) {
EvalRegs();
}
if ( flags & WIN_INTRANSITION ) {
Transition();
}
Time();
// renamed ON_EVENT to ON_FRAME
RunScript(ON_FRAME);
int c = children.Num();
for (int i = 0; i < c; i++) {
children[i]->RunTimeEvents(time);
}
return true;
}
/*
================
idWindow::RunNamedEvent
================
*/
void idWindow::RunNamedEvent ( const char* eventName )
{
int i;
int c;
// Find and run the event
c = namedEvents.Num( );
for ( i = 0; i < c; i ++ ) {
if ( namedEvents[i]->mName.Icmp( eventName ) ) {
continue;
}
UpdateWinVars();
// Make sure we got all the current values for stuff
if (expressionRegisters.Num() && ops.Num()) {
EvalRegs(-1, true);
}
RunScriptList( namedEvents[i]->mEvent );
break;
}
// Run the event in all the children as well
c = children.Num();
for ( i = 0; i < c; i++ ) {
children[i]->RunNamedEvent ( eventName );
}
}
/*
================
idWindow::Contains
================
*/
bool idWindow::Contains(const idRectangle &sr, float x, float y) {
idRectangle r = sr;
r.x += actualX - drawRect.x;
r.y += actualY - drawRect.y;
return r.Contains(x, y);
}
/*
================
idWindow::Contains
================
*/
bool idWindow::Contains(float x, float y) {
idRectangle r = drawRect;
r.x = actualX;
r.y = actualY;
return r.Contains(x, y);
}
/*
================
idWindow::AddCommand
================
*/
void idWindow::AddCommand(const char *_cmd) {
idStr str = cmd;
if (str.Length()) {
str += " ; ";
str += _cmd;
} else {
str = _cmd;
}
cmd = str;
}
/*
================
idWindow::HandleEvent
================
*/
const char *idWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) {
static bool actionDownRun;
static bool actionUpRun;
cmd = "";
if ( flags & WIN_DESKTOP ) {
actionDownRun = false;
actionUpRun = false;
if (expressionRegisters.Num() && ops.Num()) {
EvalRegs();
}
RunTimeEvents(gui->GetTime());
CalcRects(0,0);
dc->SetCursor( idDeviceContext::CURSOR_ARROW );
}
if (visible && !noEvents) {
if (event->evType == SE_KEY) {
EvalRegs(-1, true);
if (updateVisuals) {
*updateVisuals = true;
}
if (event->evValue == K_MOUSE1) {
if (!event->evValue2 && GetCaptureChild()) {
GetCaptureChild()->LoseCapture();
gui->GetDesktop()->captureChild = NULL;
return "";
}
int c = children.Num();
while (--c >= 0) {
if (children[c]->visible && children[c]->Contains(children[c]->drawRect, gui->CursorX(), gui->CursorY()) && !(children[c]->noEvents)) {
idWindow *child = children[c];
if (event->evValue2) {
BringToTop(child);
SetFocus(child);
if (child->flags & WIN_HOLDCAPTURE) {
SetCapture(child);
}
}
if (child->Contains(child->clientRect, gui->CursorX(), gui->CursorY())) {
//if ((gui_edit.GetBool() && (child->flags & WIN_SELECTED)) || (!gui_edit.GetBool() && (child->flags & WIN_MOVABLE))) {
// SetCapture(child);
//}
SetFocus(child);
const char *childRet = child->HandleEvent(event, updateVisuals);
if (childRet && *childRet) {
return childRet;
}
if (child->flags & WIN_MODAL) {
return "";
}
} else {
if (event->evValue2) {
SetFocus(child);
bool capture = true;
if (capture && ((child->flags & WIN_MOVABLE) || gui_edit.GetBool())) {
SetCapture(child);
}
return "";
} else {
}
}
}
}
if (event->evValue2 && !actionDownRun) {
actionDownRun = RunScript( ON_ACTION );
} else if (!actionUpRun) {
actionUpRun = RunScript( ON_ACTIONRELEASE );
}
} else if (event->evValue == K_MOUSE2) {
if (!event->evValue2 && GetCaptureChild()) {
GetCaptureChild()->LoseCapture();
gui->GetDesktop()->captureChild = NULL;
return "";
}
int c = children.Num();
while (--c >= 0) {
if (children[c]->visible && children[c]->Contains(children[c]->drawRect, gui->CursorX(), gui->CursorY()) && !(children[c]->noEvents)) {
idWindow *child = children[c];
if (event->evValue2) {
BringToTop(child);
SetFocus(child);
}
if (child->Contains(child->clientRect,gui->CursorX(), gui->CursorY()) || GetCaptureChild() == child) {
if ((gui_edit.GetBool() && (child->flags & WIN_SELECTED)) || (!gui_edit.GetBool() && (child->flags & WIN_MOVABLE))) {
SetCapture(child);
}
const char *childRet = child->HandleEvent(event, updateVisuals);
if (childRet && *childRet) {
return childRet;
}
if (child->flags & WIN_MODAL) {
return "";
}
}
}
}
} else if (event->evValue == K_MOUSE3) {
if (gui_edit.GetBool()) {
int c = children.Num();
for (int i = 0; i < c; i++) {
if (children[i]->drawRect.Contains(gui->CursorX(), gui->CursorY())) {
if (event->evValue2) {
children[i]->flags ^= WIN_SELECTED;
if (children[i]->flags & WIN_SELECTED) {
flags &= ~WIN_SELECTED;
return "childsel";
}
}
}
}
}
} else if (event->evValue == K_TAB && event->evValue2) {
if (GetFocusedChild()) {
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
if (childRet && *childRet) {
return childRet;
}
// If the window didn't handle the tab, then move the focus to the next window
// or the previous window if shift is held down
int direction = 1;
if ( idKeyInput::IsDown( K_SHIFT ) ) {
direction = -1;
}
idWindow *currentFocus = GetFocusedChild();
idWindow *child = GetFocusedChild();
idWindow *parent = child->GetParent();
while ( parent ) {
bool foundFocus = false;
bool recurse = false;
int index = 0;
if ( child ) {
index = parent->GetChildIndex( child ) + direction;
} else if ( direction < 0 ) {
index = parent->GetChildCount() - 1;
}
while ( index < parent->GetChildCount() && index >= 0) {
idWindow *testWindow = parent->GetChild( index );
if ( testWindow == currentFocus ) {
// we managed to wrap around and get back to our starting window
foundFocus = true;
break;
}
if ( testWindow && !testWindow->noEvents && testWindow->visible ) {
if ( testWindow->flags & WIN_CANFOCUS ) {
SetFocus( testWindow );
foundFocus = true;
break;
} else if ( testWindow->GetChildCount() > 0 ) {
parent = testWindow;
child = NULL;
recurse = true;
break;
}
}
index += direction;
}
if ( foundFocus ) {
// We found a child to focus on
break;
} else if ( recurse ) {
// We found a child with children
continue;
} else {
// We didn't find anything, so go back up to our parent
child = parent;
parent = child->GetParent();
if ( parent == gui->GetDesktop() ) {
// We got back to the desktop, so wrap around but don't actually go to the desktop
parent = NULL;
child = NULL;
}
}
}
}
} else if (event->evValue == K_ESCAPE && event->evValue2) {
if (GetFocusedChild()) {
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
if (childRet && *childRet) {
return childRet;
}
}
RunScript( ON_ESC );
} else if (event->evValue == K_ENTER ) {
if (GetFocusedChild()) {
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
if (childRet && *childRet) {
return childRet;
}
}
if ( flags & WIN_WANTENTER ) {
if ( event->evValue2 ) {
RunScript( ON_ACTION );
} else {
RunScript( ON_ACTIONRELEASE );
}
}
} else {
if (GetFocusedChild()) {
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
if (childRet && *childRet) {
return childRet;
}
}
}
} else if (event->evType == SE_MOUSE || event->evType == SE_MOUSE_ABS) {
if (updateVisuals) {
*updateVisuals = true;
}
const char *mouseRet = RouteMouseCoords(event->evValue, event->evValue2);
if (mouseRet && *mouseRet) {
return mouseRet;
}
} else if (event->evType == SE_NONE) {
} else if (event->evType == SE_CHAR) {
if (GetFocusedChild()) {
const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
if (childRet && *childRet) {
return childRet;
}
}
}
}
gui->GetReturnCmd() = cmd;
if ( gui->GetPendingCmd().Length() ) {
gui->GetReturnCmd() += " ; ";
gui->GetReturnCmd() += gui->GetPendingCmd();
gui->GetPendingCmd().Clear();
}
cmd = "";
return gui->GetReturnCmd();
}
/*
================
idWindow::DebugDraw
================
*/
void idWindow::DebugDraw(int time, float x, float y) {
static char buff[16384];
if (dc) {
dc->EnableClipping(false);
if (gui_debug.GetInteger() == 1) {
dc->DrawRect(drawRect.x, drawRect.y, drawRect.w, drawRect.h, 1, idDeviceContext::colorRed);
} else if (gui_debug.GetInteger() == 2) {
char out[1024];
idStr str;
str = text.c_str();
if (str.Length()) {
sprintf(buff, "%s\n", str.c_str());
}
sprintf(out, "Rect: %0.1f, %0.1f, %0.1f, %0.1f\n", rect.x(), rect.y(), rect.w(), rect.h());
strcat(buff, out);
sprintf(out, "Draw Rect: %0.1f, %0.1f, %0.1f, %0.1f\n", drawRect.x, drawRect.y, drawRect.w, drawRect.h);
strcat(buff, out);
sprintf(out, "Client Rect: %0.1f, %0.1f, %0.1f, %0.1f\n", clientRect.x, clientRect.y, clientRect.w, clientRect.h);
strcat(buff, out);
sprintf(out, "Cursor: %0.1f : %0.1f\n", gui->CursorX(), gui->CursorY());
strcat(buff, out);
//idRectangle tempRect = textRect;
//tempRect.x += offsetX;
//drawRect.y += offsetY;
dc->DrawText(buff, textScale, textAlign, foreColor, textRect, true);
}
dc->EnableClipping(true);
}
}
/*
================
idWindow::Transition
================
*/
void idWindow::Transition() {
int i, c = transitions.Num();
bool clear = true;
for ( i = 0; i < c; i++ ) {
idTransitionData *data = &transitions[i];
idWinRectangle *r = NULL;
idWinVec4 *v4 = dynamic_cast<idWinVec4*>(data->data);
idWinFloat* val = NULL;
if (v4 == NULL) {
r = dynamic_cast<idWinRectangle*>(data->data);
if ( !r ) {
val = dynamic_cast<idWinFloat*>(data->data);
}
}
if ( data->interp.IsDone( gui->GetTime() ) && data->data) {
if (v4) {
*v4 = data->interp.GetEndValue();
} else if ( val ) {
*val = data->interp.GetEndValue()[0];
} else {
*r = data->interp.GetEndValue();
}
} else {
clear = false;
if (data->data) {
if (v4) {
*v4 = data->interp.GetCurrentValue( gui->GetTime() );
} else if ( val ) {
*val = data->interp.GetCurrentValue( gui->GetTime() )[0];
} else {
*r = data->interp.GetCurrentValue( gui->GetTime() );
}
} else {
common->Warning("Invalid transitional data for window %s in gui %s", GetName(), gui->GetSourceFile());
}
}
}
if ( clear ) {
transitions.SetNum( 0, false );
flags &= ~WIN_INTRANSITION;
}
}
/*
================
idWindow::Time
================
*/
void idWindow::Time() {
if ( noTime ) {
return;
}
if ( timeLine == -1 ) {
timeLine = gui->GetTime();
}
cmd = "";
int c = timeLineEvents.Num();
if ( c > 0 ) {
for (int i = 0; i < c; i++) {
if ( timeLineEvents[i]->pending && gui->GetTime() - timeLine >= timeLineEvents[i]->time ) {
timeLineEvents[i]->pending = false;
RunScriptList( timeLineEvents[i]->event );
}
}
}
if ( gui->Active() ) {
gui->GetPendingCmd() += cmd;
}
}
/*
================
idWindow::EvalRegs
================
*/
float idWindow::EvalRegs(int test, bool force) {
static float regs[MAX_EXPRESSION_REGISTERS];
static idWindow *lastEval = NULL;
if (!force && test >= 0 && test < MAX_EXPRESSION_REGISTERS && lastEval == this) {
return regs[test];
}
lastEval = this;
if (expressionRegisters.Num()) {
regList.SetToRegs(regs);
EvaluateRegisters(regs);
regList.GetFromRegs(regs);
}
if (test >= 0 && test < MAX_EXPRESSION_REGISTERS) {
return regs[test];
}
return 0.0;
}
/*
================
idWindow::DrawBackground
================
*/
void idWindow::DrawBackground(const idRectangle &drawRect) {
if ( backColor.w() ) {
dc->DrawFilledRect(drawRect.x, drawRect.y, drawRect.w, drawRect.h, backColor);
}
if ( background && matColor.w() ) {
float scalex, scaley;
if ( flags & WIN_NATURALMAT ) {
scalex = drawRect.w / background->GetImageWidth();
scaley = drawRect.h / background->GetImageHeight();
} else {
scalex = matScalex;
scaley = matScaley;
}
dc->DrawMaterial(drawRect.x, drawRect.y, drawRect.w, drawRect.h, background, matColor, scalex, scaley);
}
}
/*
================
idWindow::DrawBorderAndCaption
================
*/
void idWindow::DrawBorderAndCaption(const idRectangle &drawRect) {
if ( flags & WIN_BORDER && borderSize && borderColor.w() ) {
dc->DrawRect(drawRect.x, drawRect.y, drawRect.w, drawRect.h, borderSize, borderColor);
}
}
/*
================
idWindow::SetupTransforms
================
*/
void idWindow::SetupTransforms(float x, float y) {
static idMat3 trans;
static idVec3 org;
trans.Identity();
org.Set( origin.x + x, origin.y + y, 0 );
if ( rotate ) {
static idRotation rot;
static idVec3 vec(0, 0, 1);
rot.Set( org, vec, rotate );
trans = rot.ToMat3();
}
if ( shear.x || shear.y ) {
static idMat3 smat;
smat.Identity();
smat[0][1] = shear.x;
smat[1][0] = shear.y;
trans *= smat;
}
if ( !trans.IsIdentity() ) {
dc->SetTransformInfo( org, trans );
}
}
/*
================
idWindow::CalcRects
================
*/
void idWindow::CalcRects(float x, float y) {
CalcClientRect(0, 0);
drawRect.Offset(x, y);
clientRect.Offset(x, y);
actualX = drawRect.x;
actualY = drawRect.y;
int c = drawWindows.Num();
for (int i = 0; i < c; i++) {
if (drawWindows[i].win) {
drawWindows[i].win->CalcRects(clientRect.x + xOffset, clientRect.y + yOffset);
}
}
drawRect.Offset(-x, -y);
clientRect.Offset(-x, -y);
}
/*
================
idWindow::Redraw
================
*/
void idWindow::Redraw(float x, float y) {
idStr str;
if (r_skipGuiShaders.GetInteger() == 1 || dc == NULL ) {
return;
}
int time = gui->GetTime();
if ( flags & WIN_DESKTOP && r_skipGuiShaders.GetInteger() != 3 ) {
RunTimeEvents( time );
}
if ( r_skipGuiShaders.GetInteger() == 2 ) {
return;
}
// DG: allow scaling menus to 4:3
bool fixupFor43 = false;
if ( flags & WIN_DESKTOP ) {
// only scale desktop windows (will automatically scale its sub-windows)
// that EITHER have the scaleto43 flag set OR are fullscreen menus and r_scaleMenusTo43 is 1
if( (flags & WIN_SCALETO43) ||
((flags & WIN_MENUGUI) && r_scaleMenusTo43.GetBool()) )
{
fixupFor43 = true;
dc->SetMenuScaleFix(true);
}
}
if ( flags & WIN_SHOWTIME ) {
dc->DrawText(va(" %0.1f seconds\n%s", (float)(time - timeLine) / 1000, gui->State().GetString("name")), 0.35f, 0, dc->colorWhite, idRectangle(100, 0, 80, 80), false);
}
if ( flags & WIN_SHOWCOORDS ) {
dc->EnableClipping(false);
sprintf(str, "x: %i y: %i cursorx: %i cursory: %i", (int)rect.x(), (int)rect.y(), (int)gui->CursorX(), (int)gui->CursorY());
dc->DrawText(str, 0.25f, 0, dc->colorWhite, idRectangle(0, 0, 100, 20), false);
dc->EnableClipping(true);
}
if (!visible) {
if (fixupFor43) { // DG: gotta reset that before returning this function
dc->SetMenuScaleFix(false);
}
return;
}
CalcClientRect(0, 0);
SetFont();
//if (flags & WIN_DESKTOP) {
// see if this window forces a new aspect ratio
dc->SetSize(forceAspectWidth, forceAspectHeight);
//}
//FIXME: go to screen coord tracking
drawRect.Offset(x, y);
clientRect.Offset(x, y);
textRect.Offset(x, y);
actualX = drawRect.x;
actualY = drawRect.y;
idVec3 oldOrg;
idMat3 oldTrans;
dc->GetTransformInfo( oldOrg, oldTrans );
SetupTransforms(x, y);
DrawBackground(drawRect);
DrawBorderAndCaption(drawRect);
if ( !( flags & WIN_NOCLIP) ) {
dc->PushClipRect(clientRect);
}
if ( r_skipGuiShaders.GetInteger() < 5 ) {
Draw(time, x, y);
}
if ( gui_debug.GetInteger() ) {
DebugDraw(time, x, y);
}
int c = drawWindows.Num();
for ( int i = 0; i < c; i++ ) {
if ( drawWindows[i].win ) {
drawWindows[i].win->Redraw( clientRect.x + xOffset, clientRect.y + yOffset );
} else {
drawWindows[i].simp->Redraw( clientRect.x + xOffset, clientRect.y + yOffset );
}
}
// Put transforms back to what they were before the children were processed
dc->SetTransformInfo(oldOrg, oldTrans);
if ( ! ( flags & WIN_NOCLIP ) ) {
dc->PopClipRect();
}
if (gui_edit.GetBool() || (flags & WIN_DESKTOP && !( flags & WIN_NOCURSOR ) && !hideCursor && (gui->Active() || ( flags & WIN_MENUGUI ) ))) {
dc->SetTransformInfo(vec3_origin, mat3_identity);
gui->DrawCursor();
}
if (gui_debug.GetInteger() && flags & WIN_DESKTOP) {
dc->EnableClipping(false);
sprintf(str, "x: %1.f y: %1.f", gui->CursorX(), gui->CursorY());
dc->DrawText(str, 0.25, 0, dc->colorWhite, idRectangle(0, 0, 100, 20), false);
dc->DrawText(gui->GetSourceFile(), 0.25, 0, dc->colorWhite, idRectangle(0, 20, 300, 20), false);
dc->EnableClipping(true);
}
if (fixupFor43) { // DG: gotta reset that before returning this function
dc->SetMenuScaleFix(false);
}
drawRect.Offset(-x, -y);
clientRect.Offset(-x, -y);
textRect.Offset(-x, -y);
}
/*
================
idWindow::SetDC
================
*/
void idWindow::SetDC(idDeviceContext *d) {
dc = d;
//if (flags & WIN_DESKTOP) {
dc->SetSize(forceAspectWidth, forceAspectHeight);
//}
int c = children.Num();
for (int i = 0; i < c; i++) {
children[i]->SetDC(d);
}
}
/*
================
idWindow::ArchiveToDictionary
================
*/
void idWindow::ArchiveToDictionary(idDict *dict, bool useNames) {
//FIXME: rewrite without state
int c = children.Num();
for (int i = 0; i < c; i++) {
children[i]->ArchiveToDictionary(dict);
}
}
/*
================
idWindow::InitFromDictionary
================
*/
void idWindow::InitFromDictionary(idDict *dict, bool byName) {
//FIXME: rewrite without state
int c = children.Num();
for (int i = 0; i < c; i++) {
children[i]->InitFromDictionary(dict);
}
}
/*
================
idWindow::CalcClientRect
================
*/
void idWindow::CalcClientRect(float xofs, float yofs) {
drawRect = rect;
if ( flags & WIN_INVERTRECT ) {
drawRect.x = rect.x() - rect.w();
drawRect.y = rect.y() - rect.h();
}
if (flags & (WIN_HCENTER | WIN_VCENTER) && parent) {
// in this case treat xofs and yofs as absolute top left coords
// and ignore the original positioning
if (flags & WIN_HCENTER) {
drawRect.x = (parent->rect.w() - rect.w()) / 2;
} else {
drawRect.y = (parent->rect.h() - rect.h()) / 2;
}
}
drawRect.x += xofs;
drawRect.y += yofs;
clientRect = drawRect;
if (rect.h() > 0.0 && rect.w() > 0.0) {
if (flags & WIN_BORDER && borderSize != 0.0) {
clientRect.x += borderSize;
clientRect.y += borderSize;
clientRect.w -= borderSize;
clientRect.h -= borderSize;
}
textRect = clientRect;
textRect.x += 2.0;
textRect.w -= 2.0;
textRect.y += 2.0;
textRect.h -= 2.0;
textRect.x += textAlignx;
textRect.y += textAligny;
}
origin.Set( rect.x() + (rect.w() / 2 ), rect.y() + ( rect.h() / 2 ) );
}
/*
================
idWindow::SetupBackground
================
*/
void idWindow::SetupBackground() {
if (backGroundName.Length()) {
background = declManager->FindMaterial(backGroundName);
background->SetImageClassifications( 1 ); // just for resource tracking
if ( background && !background->TestMaterialFlag( MF_DEFAULTED ) ) {
background->SetSort(SS_GUI );
}
}
backGroundName.SetMaterialPtr(&background);
}
/*
================
idWindow::SetupFromState
================
*/
void idWindow::SetupFromState() {
idStr str;
background = NULL;
SetupBackground();
if (borderSize) {
flags |= WIN_BORDER;
}
if (regList.FindReg("rotate") || regList.FindReg("shear")) {
flags |= WIN_TRANSFORM;
}
CalcClientRect(0,0);
if ( scripts[ ON_ACTION ] ) {
cursor = idDeviceContext::CURSOR_HAND;
flags |= WIN_CANFOCUS;
}
}
/*
================
idWindow::Moved
================
*/
void idWindow::Moved() {
}
/*
================
idWindow::Sized
================
*/
void idWindow::Sized() {
}
/*
================
idWindow::GainFocus
================
*/
void idWindow::GainFocus() {
}
/*
================
idWindow::LoseFocus
================
*/
void idWindow::LoseFocus() {
}
/*
================
idWindow::GainCapture
================
*/
void idWindow::GainCapture() {
}
/*
================
idWindow::LoseCapture
================
*/
void idWindow::LoseCapture() {
flags &= ~WIN_CAPTURE;
}
/*
================
idWindow::SetFlag
================
*/
void idWindow::SetFlag(unsigned int f) {
flags |= f;
}
/*
================
idWindow::ClearFlag
================
*/
void idWindow::ClearFlag(unsigned int f) {
flags &= ~f;
}
/*
================
idWindow::SetParent
================
*/
void idWindow::SetParent(idWindow *w) {
parent = w;
}
/*
================
idWindow::GetCaptureChild
================
*/
idWindow *idWindow::GetCaptureChild() {
if (flags & WIN_DESKTOP) {
return gui->GetDesktop()->captureChild;
}
return NULL;
}
/*
================
idWindow::GetFocusedChild
================
*/
idWindow *idWindow::GetFocusedChild() {
if (flags & WIN_DESKTOP) {
return gui->GetDesktop()->focusedChild;
}
return NULL;
}
/*
================
idWindow::SetFocus
================
*/
idWindow *idWindow::SetFocus(idWindow *w, bool scripts) {
// only one child can have the focus
idWindow *lastFocus = NULL;
if (w->flags & WIN_CANFOCUS) {
lastFocus = gui->GetDesktop()->focusedChild;
if ( lastFocus ) {
lastFocus->flags &= ~WIN_FOCUS;
lastFocus->LoseFocus();
}
// call on lose focus
if ( scripts && lastFocus ) {
// calling this broke all sorts of guis
// lastFocus->RunScript(ON_MOUSEEXIT);
}
// call on gain focus
if ( scripts && w ) {
// calling this broke all sorts of guis
// w->RunScript(ON_MOUSEENTER);
}
w->flags |= WIN_FOCUS;
w->GainFocus();
gui->GetDesktop()->focusedChild = w;
}
return lastFocus;
}
/*
================
idWindow::ParseScript
================
*/
bool idWindow::ParseScript(idParser *src, idGuiScriptList &list, int *timeParm, bool elseBlock ) {
bool ifElseBlock = false;
idToken token;
// scripts start with { ( unless parm is true ) and have ; separated command lists.. commands are command,
// arg.. basically we want everything between the { } as it will be interpreted at
// run time
if ( elseBlock ) {
src->ReadToken ( &token );
if ( !token.Icmp ( "if" ) ) {
ifElseBlock = true;
}
src->UnreadToken ( &token );
if ( !ifElseBlock && !src->ExpectTokenString( "{" ) ) {
return false;
}
}
else if ( !src->ExpectTokenString( "{" ) ) {
return false;
}
int nest = 0;
while (1) {
if ( !src->ReadToken(&token) ) {
src->Error( "Unexpected end of file" );
return false;
}
if ( token == "{" ) {
nest++;
}
if ( token == "}" ) {
if (nest-- <= 0) {
return true;
}
}
idGuiScript *gs = new idGuiScript();
if (token.Icmp("if") == 0) {
gs->conditionReg = ParseExpression(src);
gs->ifList = new idGuiScriptList();
ParseScript(src, *gs->ifList, NULL);
if (src->ReadToken(&token)) {
if (token == "else") {
gs->elseList = new idGuiScriptList();
// pass true to indicate we are parsing an else condition
ParseScript(src, *gs->elseList, NULL, true );
} else {
src->UnreadToken(&token);
}
}
list.Append(gs);
// if we are parsing an else if then return out so
// the initial "if" parser can handle the rest of the tokens
if ( ifElseBlock ) {
return true;
}
continue;
} else {
src->UnreadToken(&token);
}
// empty { } is not allowed
if ( token == "{" ) {
src->Error ( "Unexpected {" );
delete gs;
return false;
}
gs->Parse(src);
list.Append(gs);
}
}
/*
================
idWindow::SaveExpressionParseState
================
*/
void idWindow::SaveExpressionParseState() {
saveTemps = (bool*)Mem_Alloc(MAX_EXPRESSION_REGISTERS * sizeof(bool));
memcpy(saveTemps, registerIsTemporary, MAX_EXPRESSION_REGISTERS * sizeof(bool));
}
/*
================
idWindow::RestoreExpressionParseState
================
*/
void idWindow::RestoreExpressionParseState() {
memcpy(registerIsTemporary, saveTemps, MAX_EXPRESSION_REGISTERS * sizeof(bool));
Mem_Free(saveTemps);
}
/*
================
idWindow::ParseScriptEntry
================
*/
bool idWindow::ParseScriptEntry(const char *name, idParser *src) {
for (int i = 0; i < SCRIPT_COUNT; i++) {
if (idStr::Icmp(name, ScriptNames[i]) == 0) {
delete scripts[i];
scripts[i] = new idGuiScriptList;
return ParseScript(src, *scripts[i]);
}
}
return false;
}
/*
================
idWindow::DisableRegister
================
*/
void idWindow::DisableRegister(const char *_name) {
idRegister *reg = RegList()->FindReg(_name);
if (reg) {
reg->Enable(false);
}
}
/*
================
idWindow::PostParse
================
*/
void idWindow::PostParse() {
}
/*
================
idWindow::GetWinVarOffset
================
*/
intptr_t idWindow::GetWinVarOffset( idWinVar *wv, drawWin_t* owner) {
intptr_t ret = -1;
if ( wv == &rect ) {
ret = (ptrdiff_t)&this->rect - (ptrdiff_t)this;
}
if ( wv == &backColor ) {
ret = (ptrdiff_t)&this->backColor - (ptrdiff_t)this;
}
if ( wv == &matColor ) {
ret = (ptrdiff_t)&this->matColor - (ptrdiff_t)this;
}
if ( wv == &foreColor ) {
ret = (ptrdiff_t)&this->foreColor - (ptrdiff_t)this;
}
if ( wv == &hoverColor ) {
ret = (ptrdiff_t)&this->hoverColor - (ptrdiff_t)this;
}
if ( wv == &borderColor ) {
ret = (ptrdiff_t)&this->borderColor - (ptrdiff_t)this;
}
if ( wv == &textScale ) {
ret = (ptrdiff_t)&this->textScale - (ptrdiff_t)this;
}
if ( wv == &rotate ) {
ret = (ptrdiff_t)&this->rotate - (ptrdiff_t)this;
}
if ( ret != -1 ) {
owner->win = this;
return ret;
}
for ( int i = 0; i < drawWindows.Num(); i++ ) {
if ( drawWindows[i].win ) {
ret = drawWindows[i].win->GetWinVarOffset( wv, owner );
} else {
ret = drawWindows[i].simp->GetWinVarOffset( wv, owner );
}
if ( ret != -1 ) {
break;
}
}
return ret;
}
/*
================
idWindow::GetWinVarByName
================
*/
idWinVar *idWindow::GetWinVarByName(const char *_name, bool fixup, drawWin_t** owner) {
idWinVar *retVar = NULL;
if ( owner ) {
*owner = NULL;
}
if (idStr::Icmp(_name, "notime") == 0) {
retVar = &noTime;
}
if (idStr::Icmp(_name, "background") == 0) {
retVar = &backGroundName;
}
if (idStr::Icmp(_name, "visible") == 0) {
retVar = &visible;
}
if (idStr::Icmp(_name, "rect") == 0) {
retVar = &rect;
}
if (idStr::Icmp(_name, "backColor") == 0) {
retVar = &backColor;
}
if (idStr::Icmp(_name, "matColor") == 0) {
retVar = &matColor;
}
if (idStr::Icmp(_name, "foreColor") == 0) {
retVar = &foreColor;
}
if (idStr::Icmp(_name, "hoverColor") == 0) {
retVar = &hoverColor;
}
if (idStr::Icmp(_name, "borderColor") == 0) {
retVar = &borderColor;
}
if (idStr::Icmp(_name, "textScale") == 0) {
retVar = &textScale;
}
if (idStr::Icmp(_name, "rotate") == 0) {
retVar = &rotate;
}
if (idStr::Icmp(_name, "noEvents") == 0) {
retVar = &noEvents;
}
if (idStr::Icmp(_name, "text") == 0) {
retVar = &text;
}
if (idStr::Icmp(_name, "backGroundName") == 0) {
retVar = &backGroundName;
}
if (idStr::Icmp(_name, "hidecursor") == 0) {
retVar = &hideCursor;
}
idStr key = _name;
bool guiVar = (key.Find(VAR_GUIPREFIX) >= 0);
int c = definedVars.Num();
for (int i = 0; i < c; i++) {
if (idStr::Icmp(_name, (guiVar) ? va("%s",definedVars[i]->GetName()) : definedVars[i]->GetName()) == 0) {
retVar = definedVars[i];
break;
}
}
if (retVar) {
if (fixup && *_name != '$') {
DisableRegister(_name);
}
if ( owner && parent ) {
*owner = parent->FindChildByName ( name );
}
return retVar;
}
int len = key.Length();
if ( len > 5 && guiVar ) {
idWinVar *var = new idWinStr;
var->Init(_name, this);
definedVars.Append(var);
return var;
} else if (fixup) {
int n = key.Find("::");
if (n > 0) {
idStr winName = key.Left(n);
idStr var = key.Right(key.Length() - n - 2);
drawWin_t *win = GetGui()->GetDesktop()->FindChildByName(winName);
if (win) {
if (win->win) {
return win->win->GetWinVarByName(var, false, owner);
} else {
if ( owner ) {
*owner = win;
}
return win->simp->GetWinVarByName(var);
}
}
}
}
return NULL;
}
/*
================
idWindow::ParseString
================
*/
void idWindow::ParseString(idParser *src, idStr &out) {
idToken tok;
if (src->ReadToken(&tok)) {
out = tok;
}
}
/*
================
idWindow::ParseVec4
================
*/
void idWindow::ParseVec4(idParser *src, idVec4 &out) {
idToken tok;
src->ReadToken(&tok);
out.x = atof(tok);
src->ExpectTokenString(",");
src->ReadToken(&tok);
out.y = atof(tok);
src->ExpectTokenString(",");
src->ReadToken(&tok);
out.z = atof(tok);
src->ExpectTokenString(",");
src->ReadToken(&tok);
out.w = atof(tok);
}
/*
================
idWindow::ParseInternalVar
================
*/
bool idWindow::ParseInternalVar(const char *_name, idParser *src) {
if (idStr::Icmp(_name, "showtime") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_SHOWTIME;
}
return true;
}
if (idStr::Icmp(_name, "showcoords") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_SHOWCOORDS;
}
return true;
}
// DG: added this window flag for Windows that should be scaled to 4:3
// (with "empty" bars left/right or above/below)
if (idStr::Icmp(_name, "scaleto43") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_SCALETO43;
}
return true;
}
// DG end
if (idStr::Icmp(_name, "forceaspectwidth") == 0) {
forceAspectWidth = src->ParseFloat();
return true;
}
if (idStr::Icmp(_name, "forceaspectheight") == 0) {
forceAspectHeight = src->ParseFloat();
return true;
}
if (idStr::Icmp(_name, "matscalex") == 0) {
matScalex = src->ParseFloat();
return true;
}
if (idStr::Icmp(_name, "matscaley") == 0) {
matScaley = src->ParseFloat();
return true;
}
if (idStr::Icmp(_name, "bordersize") == 0) {
borderSize = src->ParseFloat();
return true;
}
if (idStr::Icmp(_name, "nowrap") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_NOWRAP;
}
return true;
}
if (idStr::Icmp(_name, "shadow") == 0) {
textShadow = src->ParseInt();
return true;
}
if (idStr::Icmp(_name, "textalign") == 0) {
textAlign = src->ParseInt();
return true;
}
if (idStr::Icmp(_name, "textalignx") == 0) {
textAlignx = src->ParseFloat();
return true;
}
if (idStr::Icmp(_name, "textaligny") == 0) {
textAligny = src->ParseFloat();
return true;
}
if (idStr::Icmp(_name, "shear") == 0) {
shear.x = src->ParseFloat();
idToken tok;
src->ReadToken( &tok );
if ( tok.Icmp( "," ) ) {
src->Error( "Expected comma in shear definiation" );
return false;
}
shear.y = src->ParseFloat();
return true;
}
if (idStr::Icmp(_name, "wantenter") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_WANTENTER;
}
return true;
}
if (idStr::Icmp(_name, "naturalmatscale") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_NATURALMAT;
}
return true;
}
if (idStr::Icmp(_name, "noclip") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_NOCLIP;
}
return true;
}
if (idStr::Icmp(_name, "nocursor") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_NOCURSOR;
}
return true;
}
if (idStr::Icmp(_name, "menugui") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_MENUGUI;
}
return true;
}
if (idStr::Icmp(_name, "modal") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_MODAL;
}
return true;
}
if (idStr::Icmp(_name, "invertrect") == 0) {
if ( src->ParseBool() ) {
flags |= WIN_INVERTRECT;
}
return true;
}
if (idStr::Icmp(_name, "name") == 0) {
ParseString(src, name);
return true;
}
if (idStr::Icmp(_name, "play") == 0) {
common->Warning( "play encountered during gui parse.. see Robert\n" );
idStr playStr;
ParseString(src, playStr);
return true;
}
if (idStr::Icmp(_name, "comment") == 0) {
ParseString(src, comment);
return true;
}
if ( idStr::Icmp( _name, "font" ) == 0 ) {
idStr fontStr;
ParseString( src, fontStr );
fontNum = dc->FindFont( fontStr );
return true;
}
return false;
}
/*
================
idWindow::ParseRegEntry
================
*/
bool idWindow::ParseRegEntry(const char *name, idParser *src) {
idStr work;
work = name;
work.ToLower();
idWinVar *var = GetWinVarByName(work, false);
if ( var ) {
for (int i = 0; i < NumRegisterVars; i++) {
if (idStr::Icmp(work, RegisterVars[i].name) == 0) {
regList.AddReg(work, RegisterVars[i].type, src, this, var);
return true;
}
}
}
// not predefined so just read the next token and add it to the state
idToken tok;
idVec4 v;
idWinInt *vari;
idWinFloat *varf;
idWinStr *vars;
if (src->ReadToken(&tok)) {
if (var) {
var->Set(tok);
return true;
}
switch (tok.type) {
case TT_NUMBER :
if (tok.subtype & TT_INTEGER) {
vari = new idWinInt();
*vari = atoi(tok);
vari->SetName(work);
definedVars.Append(vari);
} else if (tok.subtype & TT_FLOAT) {
varf = new idWinFloat();
*varf = atof(tok);
varf->SetName(work);
definedVars.Append(varf);
} else {
vars = new idWinStr();
*vars = tok;
vars->SetName(work);
definedVars.Append(vars);
}
break;
default :
vars = new idWinStr();
*vars = tok;
vars->SetName(work);
definedVars.Append(vars);
break;
}
}
return true;
}
/*
================
idWindow::SetInitialState
================
*/
void idWindow::SetInitialState(const char *_name) {
name = _name;
matScalex = 1.0;
matScaley = 1.0;
forceAspectWidth = 640.0;
forceAspectHeight = 480.0;
noTime = false;
visible = true;
flags = 0;
}
/*
================
idWindow::Parse
================
*/
bool idWindow::Parse( idParser *src, bool rebuild) {
idToken token, token2, token3, token4, token5, token6, token7;
idStr work;
if (rebuild) {
CleanUp();
}
drawWin_t dwt;
timeLineEvents.Clear();
transitions.Clear();
namedEvents.DeleteContents( true );
src->ExpectTokenType( TT_NAME, 0, &token );
SetInitialState(token);
src->ExpectTokenString( "{" );
src->ExpectAnyToken( &token );
bool ret = true;
// attach a window wrapper to the window if the gui editor is running
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
new rvGEWindowWrapper ( this, rvGEWindowWrapper::WT_NORMAL );
}
#endif
while( token != "}" ) {
// track what was parsed so we can maintain it for the guieditor
src->SetMarker ( );
if ( token == "windowDef" || token == "animationDef" ) {
if (token == "animationDef") {
visible = false;
rect = idRectangle(0,0,0,0);
}
src->ExpectTokenType( TT_NAME, 0, &token );
token2 = token;
src->UnreadToken(&token);
drawWin_t *dw = FindChildByName(token2.c_str());
if (dw && dw->win) {
SaveExpressionParseState();
dw->win->Parse(src, rebuild);
RestoreExpressionParseState();
} else {
idWindow *win = new idWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
win->SetParent(this);
dwt.simp = NULL;
dwt.win = NULL;
if (win->IsSimple()) {
idSimpleWindow *simple = new idSimpleWindow(win);
dwt.simp = simple;
drawWindows.Append(dwt);
delete win;
} else {
AddChild(win);
SetFocus(win,false);
dwt.win = win;
drawWindows.Append(dwt);
}
}
}
else if ( token == "editDef" ) {
idEditWindow *win = new idEditWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "choiceDef" ) {
idChoiceWindow *win = new idChoiceWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "sliderDef" ) {
idSliderWindow *win = new idSliderWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "markerDef" ) {
idMarkerWindow *win = new idMarkerWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "bindDef" ) {
idBindWindow *win = new idBindWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "listDef" ) {
idListWindow *win = new idListWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "fieldDef" ) {
idFieldWindow *win = new idFieldWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "renderDef" ) {
idRenderWindow *win = new idRenderWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "gameSSDDef" ) {
idGameSSDWindow *win = new idGameSSDWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "gameBearShootDef" ) {
idGameBearShootWindow *win = new idGameBearShootWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
else if ( token == "gameBustOutDef" ) {
idGameBustOutWindow *win = new idGameBustOutWindow(dc, gui);
SaveExpressionParseState();
win->Parse(src, rebuild);
RestoreExpressionParseState();
AddChild(win);
win->SetParent(this);
dwt.simp = NULL;
dwt.win = win;
drawWindows.Append(dwt);
}
//
// added new onEvent
else if ( token == "onNamedEvent" ) {
// Read the event name
if ( !src->ReadToken(&token) ) {
src->Error( "Expected event name" );
return false;
}
rvNamedEvent* ev = new rvNamedEvent ( token );
src->SetMarker ( );
if ( !ParseScript ( src, *ev->mEvent ) ) {
ret = false;
break;
}
// If we are in the gui editor then add the internal var to the
// the wrapper
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
idStr str;
idStr out;
// Grab the string from the last marker
src->GetStringFromMarker ( str, false );
// Parse it one more time to knock unwanted tabs out
idLexer src2( str, str.Length(), "", src->GetFlags() );
src2.ParseBracedSectionExact ( out, 1);
// Save the script
rvGEWindowWrapper::GetWrapper ( this )->GetScriptDict().Set ( va("onEvent %s", token.c_str()), out );
}
#endif
namedEvents.Append(ev);
}
else if ( token == "onTime" ) {
idTimeLineEvent *ev = new idTimeLineEvent;
if ( !src->ReadToken(&token) ) {
src->Error( "Unexpected end of file" );
return false;
}
ev->time = atoi(token.c_str());
// reset the mark since we dont want it to include the time
src->SetMarker ( );
if (!ParseScript(src, *ev->event, &ev->time)) {
ret = false;
break;
}
// add the script to the wrappers script list
// If we are in the gui editor then add the internal var to the
// the wrapper
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
idStr str;
idStr out;
// Grab the string from the last marker
src->GetStringFromMarker ( str, false );
// Parse it one more time to knock unwanted tabs out
idLexer src2( str, str.Length(), "", src->GetFlags() );
src2.ParseBracedSectionExact ( out, 1);
// Save the script
rvGEWindowWrapper::GetWrapper ( this )->GetScriptDict().Set ( va("onTime %d", ev->time), out );
}
#endif
// this is a timeline event
ev->pending = true;
timeLineEvents.Append(ev);
}
else if ( token == "definefloat" ) {
src->ReadToken(&token);
work = token;
work.ToLower();
idWinFloat *varf = new idWinFloat();
varf->SetName(work);
definedVars.Append(varf);
// add the float to the editors wrapper dict
// Set the marker after the float name
src->SetMarker ( );
// Read in the float
regList.AddReg(work, idRegister::FLOAT, src, this, varf);
// If we are in the gui editor then add the float to the defines
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
idStr str;
// Grab the string from the last marker and save it in the wrapper
src->GetStringFromMarker ( str, true );
rvGEWindowWrapper::GetWrapper ( this )->GetVariableDict().Set ( va("definefloat\t\"%s\"",token.c_str()), str );
}
#endif
}
else if ( token == "definevec4" ) {
src->ReadToken(&token);
work = token;
work.ToLower();
idWinVec4 *var = new idWinVec4();
var->SetName(work);
// set the marker so we can determine what was parsed
// set the marker after the vec4 name
src->SetMarker ( );
// FIXME: how about we add the var to the desktop instead of this window so it won't get deleted
// when this window is destoyed which even happens during parsing with simple windows ?
//definedVars.Append(var);
gui->GetDesktop()->definedVars.Append( var );
gui->GetDesktop()->regList.AddReg( work, idRegister::VEC4, src, gui->GetDesktop(), var );
// store the original vec4 for the editor
// If we are in the gui editor then add the float to the defines
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
idStr str;
// Grab the string from the last marker and save it in the wrapper
src->GetStringFromMarker ( str, true );
rvGEWindowWrapper::GetWrapper ( this )->GetVariableDict().Set ( va("definevec4\t\"%s\"",token.c_str()), str );
}
#endif
}
else if ( token == "float" ) {
src->ReadToken(&token);
work = token;
work.ToLower();
idWinFloat *varf = new idWinFloat();
varf->SetName(work);
definedVars.Append(varf);
// add the float to the editors wrapper dict
// set the marker to after the float name
src->SetMarker ( );
// Parse the float
regList.AddReg(work, idRegister::FLOAT, src, this, varf);
// If we are in the gui editor then add the float to the defines
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
idStr str;
// Grab the string from the last marker and save it in the wrapper
src->GetStringFromMarker ( str, true );
rvGEWindowWrapper::GetWrapper ( this )->GetVariableDict().Set ( va("float\t\"%s\"",token.c_str()), str );
}
#endif
}
else if (ParseScriptEntry(token, src)) {
// add the script to the wrappers script list
// If we are in the gui editor then add the internal var to the
// the wrapper
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
idStr str;
idStr out;
// Grab the string from the last marker
src->GetStringFromMarker ( str, false );
// Parse it one more time to knock unwanted tabs out
idLexer src2( str, str.Length(), "", src->GetFlags() );
src2.ParseBracedSectionExact ( out, 1);
// Save the script
rvGEWindowWrapper::GetWrapper ( this )->GetScriptDict().Set ( token, out );
}
#endif
} else if (ParseInternalVar(token, src)) {
// gui editor support
// If we are in the gui editor then add the internal var to the
// the wrapper
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
idStr str;
src->GetStringFromMarker ( str );
rvGEWindowWrapper::GetWrapper ( this )->SetStateKey ( token, str, false );
}
#endif
}
else {
ParseRegEntry(token, src);
// hook into the main window parsing for the gui editor
// If we are in the gui editor then add the internal var to the
// the wrapper
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
idStr str;
src->GetStringFromMarker ( str );
rvGEWindowWrapper::GetWrapper ( this )->SetStateKey ( token, str, false );
}
#endif
}
if ( !src->ReadToken( &token ) ) {
src->Error( "Unexpected end of file" );
ret = false;
break;
}
}
if (ret) {
EvalRegs(-1, true);
}
SetupFromState();
PostParse();
// hook into the main window parsing for the gui editor
// If we are in the gui editor then add the internal var to the
// the wrapper
#ifdef ID_ALLOW_TOOLS
if ( com_editors & EDITOR_GUI ) {
rvGEWindowWrapper::GetWrapper ( this )->Finish ( );
}
#endif
return ret;
}
/*
================
idWindow::FindSimpleWinByName
================
*/
idSimpleWindow *idWindow::FindSimpleWinByName(const char *_name) {
int c = drawWindows.Num();
for (int i = 0; i < c; i++) {
if (drawWindows[i].simp == NULL) {
continue;
}
if ( idStr::Icmp(drawWindows[i].simp->name, _name) == 0 ) {
return drawWindows[i].simp;
}
}
return NULL;
}
/*
================
idWindow::FindChildByName
================
*/
drawWin_t *idWindow::FindChildByName(const char *_name) {
static drawWin_t dw;
if (idStr::Icmp(name,_name) == 0) {
dw.simp = NULL;
dw.win = this;
return &dw;
}
int c = drawWindows.Num();
for (int i = 0; i < c; i++) {
if (drawWindows[i].win) {
if (idStr::Icmp(drawWindows[i].win->name, _name) == 0) {
return &drawWindows[i];
}
drawWin_t *win = drawWindows[i].win->FindChildByName(_name);
if (win) {
return win;
}
} else {
if (idStr::Icmp(drawWindows[i].simp->name, _name) == 0) {
return &drawWindows[i];
}
}
}
return NULL;
}
/*
================
idWindow::GetStrPtrByName
================
*/
idStr* idWindow::GetStrPtrByName(const char *_name) {
return NULL;
}
/*
================
idWindow::AddTransition
================
*/
void idWindow::AddTransition(idWinVar *dest, idVec4 from, idVec4 to, int time, float accelTime, float decelTime) {
idTransitionData data;
data.data = dest;
data.interp.Init(gui->GetTime(), accelTime * time, decelTime * time, time, from, to);
transitions.Append(data);
}
/*
================
idWindow::StartTransition
================
*/
void idWindow::StartTransition() {
flags |= WIN_INTRANSITION;
}
/*
================
idWindow::ResetCinematics
================
*/
void idWindow::ResetCinematics() {
if ( background ) {
background->ResetCinematicTime( gui->GetTime() );
}
}
/*
================
idWindow::ResetTime
================
*/
void idWindow::ResetTime(int t) {
timeLine = gui->GetTime() - t;
int i, c = timeLineEvents.Num();
for ( i = 0; i < c; i++ ) {
if ( timeLineEvents[i]->time >= t ) {
timeLineEvents[i]->pending = true;
}
}
noTime = false;
c = transitions.Num();
for ( i = 0; i < c; i++ ) {
idTransitionData *data = &transitions[i];
if ( data->interp.IsDone( gui->GetTime() ) && data->data ) {
transitions.RemoveIndex( i );
i--;
c--;
}
}
}
/*
================
idWindow::RunScriptList
================
*/
bool idWindow::RunScriptList(idGuiScriptList *src) {
if (src == NULL) {
return false;
}
src->Execute(this);
return true;
}
/*
================
idWindow::RunScript
================
*/
bool idWindow::RunScript(int n) {
if (n >= ON_MOUSEENTER && n < SCRIPT_COUNT) {
return RunScriptList(scripts[n]);
}
return false;
}
/*
================
idWindow::ExpressionConstant
================
*/
int idWindow::ExpressionConstant(float f) {
int i;
for ( i = WEXP_REG_NUM_PREDEFINED ; i < expressionRegisters.Num() ; i++ ) {
if ( !registerIsTemporary[i] && expressionRegisters[i] == f ) {
return i;
}
}
if ( expressionRegisters.Num() == MAX_EXPRESSION_REGISTERS ) {
common->Warning( "expressionConstant: gui %s hit MAX_EXPRESSION_REGISTERS", gui->GetSourceFile() );
return 0;
}
int c = expressionRegisters.Num();
if (i > c) {
while (i > c) {
expressionRegisters.Append(-9999999);
i--;
}
}
i = expressionRegisters.Append(f);
registerIsTemporary[i] = false;
return i;
}
/*
================
idWindow::ExpressionTemporary
================
*/
int idWindow::ExpressionTemporary() {
if ( expressionRegisters.Num() == MAX_EXPRESSION_REGISTERS ) {
common->Warning( "expressionTemporary: gui %s hit MAX_EXPRESSION_REGISTERS", gui->GetSourceFile());
return 0;
}
int i = expressionRegisters.Num();
registerIsTemporary[i] = true;
i = expressionRegisters.Append(0);
return i;
}
/*
================
idWindow::ExpressionOp
================
*/
wexpOp_t *idWindow::ExpressionOp() {
if ( ops.Num() == MAX_EXPRESSION_OPS ) {
common->Warning( "expressionOp: gui %s hit MAX_EXPRESSION_OPS", gui->GetSourceFile());
return &ops[0];
}
wexpOp_t wop;
memset(&wop, 0, sizeof(wexpOp_t));
int i = ops.Append(wop);
return &ops[i];
}
/*
================
idWindow::EmitOp
================
*/
intptr_t idWindow::EmitOp( intptr_t a, intptr_t b, wexpOpType_t opType, wexpOp_t **opp ) {
wexpOp_t *op;
/*
// optimize away identity operations
if ( opType == WOP_TYPE_ADD ) {
if ( !registerIsTemporary[a] && shaderRegisters[a] == 0 ) {
return b;
}
if ( !registerIsTemporary[b] && shaderRegisters[b] == 0 ) {
return a;
}
if ( !registerIsTemporary[a] && !registerIsTemporary[b] ) {
return ExpressionConstant( shaderRegisters[a] + shaderRegisters[b] );
}
}
if ( opType == WOP_TYPE_MULTIPLY ) {
if ( !registerIsTemporary[a] && shaderRegisters[a] == 1 ) {
return b;
}
if ( !registerIsTemporary[a] && shaderRegisters[a] == 0 ) {
return a;
}
if ( !registerIsTemporary[b] && shaderRegisters[b] == 1 ) {
return a;
}
if ( !registerIsTemporary[b] && shaderRegisters[b] == 0 ) {
return b;
}
if ( !registerIsTemporary[a] && !registerIsTemporary[b] ) {
return ExpressionConstant( shaderRegisters[a] * shaderRegisters[b] );
}
}
*/
op = ExpressionOp();
op->opType = opType;
op->a = a;
op->b = b;
op->c = ExpressionTemporary();
if (opp) {
*opp = op;
}
return op->c;
}
/*
================
idWindow::ParseEmitOp
================
*/
intptr_t idWindow::ParseEmitOp( idParser *src, intptr_t a, wexpOpType_t opType, int priority, wexpOp_t **opp ) {
intptr_t b = ParseExpressionPriority( src, priority );
return EmitOp( a, b, opType, opp );
}
/*
================
idWindow::ParseTerm
Returns a register index
=================
*/
intptr_t idWindow::ParseTerm( idParser *src, idWinVar *var, intptr_t component ) {
idToken token;
intptr_t a, b;
src->ReadToken( &token );
if ( token == "(" ) {
a = ParseExpression( src );
src->ExpectTokenString(")");
return a;
}
if ( !token.Icmp( "time" ) ) {
return WEXP_REG_TIME;
}
// parse negative numbers
if ( token == "-" ) {
src->ReadToken( &token );
if ( token.type == TT_NUMBER || token == "." ) {
return ExpressionConstant( -(float) token.GetFloatValue() );
}
src->Warning( "Bad negative number '%s'", token.c_str() );
return 0;
}
if ( token.type == TT_NUMBER || token == "." || token == "-" ) {
return ExpressionConstant( (float) token.GetFloatValue() );
}
// see if it is a table name
const idDeclTable *table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, token.c_str(), false ) );
if ( table ) {
a = table->Index();
// parse a table expression
src->ExpectTokenString("[");
b = ParseExpression(src);
src->ExpectTokenString("]");
return EmitOp( a, b, WOP_TYPE_TABLE );
}
if (var == NULL) {
var = GetWinVarByName(token, true);
}
if (var) {
a = (intptr_t)var;
//assert(dynamic_cast<idWinVec4*>(var));
var->Init(token, this);
b = component;
if (dynamic_cast<idWinVec4*>(var)) {
if (src->ReadToken(&token)) {
if (token == "[") {
b = ParseExpression(src);
src->ExpectTokenString("]");
} else {
src->UnreadToken(&token);
}
}
return EmitOp(a, b, WOP_TYPE_VAR);
} else if (dynamic_cast<idWinFloat*>(var)) {
return EmitOp(a, b, WOP_TYPE_VARF);
} else if (dynamic_cast<idWinInt*>(var)) {
return EmitOp(a, b, WOP_TYPE_VARI);
} else if (dynamic_cast<idWinBool*>(var)) {
return EmitOp(a, b, WOP_TYPE_VARB);
} else if (dynamic_cast<idWinStr*>(var)) {
return EmitOp(a, b, WOP_TYPE_VARS);
} else {
src->Warning("Var expression not vec4, float or int '%s'", token.c_str());
}
return 0;
} else {
// ugly but used for post parsing to fixup named vars
char *p = new char[token.Length()+1];
strcpy(p, token);
a = (intptr_t)p;
b = -2;
return EmitOp(a, b, WOP_TYPE_VAR);
}
}
/*
=================
idWindow::ParseExpressionPriority
Returns a register index
=================
*/
#define TOP_PRIORITY 4
intptr_t idWindow::ParseExpressionPriority( idParser *src, int priority, idWinVar *var, intptr_t component ) {
idToken token;
intptr_t a;
if ( priority == 0 ) {
return ParseTerm( src, var, component );
}
a = ParseExpressionPriority( src, priority - 1, var, component );
if ( !src->ReadToken( &token ) ) {
// we won't get EOF in a real file, but we can
// when parsing from generated strings
return a;
}
if ( priority == 1 && token == "*" ) {
return ParseEmitOp( src, a, WOP_TYPE_MULTIPLY, priority );
}
if ( priority == 1 && token == "/" ) {
return ParseEmitOp( src, a, WOP_TYPE_DIVIDE, priority );
}
if ( priority == 1 && token == "%" ) { // implied truncate both to integer
return ParseEmitOp( src, a, WOP_TYPE_MOD, priority );
}
if ( priority == 2 && token == "+" ) {
return ParseEmitOp( src, a, WOP_TYPE_ADD, priority );
}
if ( priority == 2 && token == "-" ) {
return ParseEmitOp( src, a, WOP_TYPE_SUBTRACT, priority );
}
if ( priority == 3 && token == ">" ) {
return ParseEmitOp( src, a, WOP_TYPE_GT, priority );
}
if ( priority == 3 && token == ">=" ) {
return ParseEmitOp( src, a, WOP_TYPE_GE, priority );
}
if ( priority == 3 && token == "<" ) {
return ParseEmitOp( src, a, WOP_TYPE_LT, priority );
}
if ( priority == 3 && token == "<=" ) {
return ParseEmitOp( src, a, WOP_TYPE_LE, priority );
}
if ( priority == 3 && token == "==" ) {
return ParseEmitOp( src, a, WOP_TYPE_EQ, priority );
}
if ( priority == 3 && token == "!=" ) {
return ParseEmitOp( src, a, WOP_TYPE_NE, priority );
}
if ( priority == 4 && token == "&&" ) {
return ParseEmitOp( src, a, WOP_TYPE_AND, priority );
}
if ( priority == 4 && token == "||" ) {
return ParseEmitOp( src, a, WOP_TYPE_OR, priority );
}
if ( priority == 4 && token == "?" ) {
wexpOp_t *oop = NULL;
intptr_t o = ParseEmitOp( src, a, WOP_TYPE_COND, priority, &oop );
if ( !src->ReadToken( &token ) ) {
return o;
}
if (token == ":") {
a = ParseExpressionPriority( src, priority - 1, var );
oop->d = a;
}
return o;
}
// assume that anything else terminates the expression
// not too robust error checking...
src->UnreadToken( &token );
return a;
}
/*
================
idWindow::ParseExpression
Returns a register index
================
*/
intptr_t idWindow::ParseExpression(idParser *src, idWinVar *var, intptr_t component) {
return ParseExpressionPriority( src, TOP_PRIORITY, var );
}
/*
================
idWindow::ParseBracedExpression
================
*/
void idWindow::ParseBracedExpression(idParser *src) {
src->ExpectTokenString("{");
ParseExpression(src);
src->ExpectTokenString("}");
}
/*
===============
idWindow::EvaluateRegisters
Parameters are taken from the localSpace and the renderView,
then all expressions are evaluated, leaving the shader registers
set to their apropriate values.
===============
*/
void idWindow::EvaluateRegisters(float *registers) {
int i, b;
wexpOp_t *op;
idVec4 v;
int erc = expressionRegisters.Num();
int oc = ops.Num();
// copy the constants
for ( i = WEXP_REG_NUM_PREDEFINED ; i < erc ; i++ ) {
registers[i] = expressionRegisters[i];
}
// copy the local and global parameters
registers[WEXP_REG_TIME] = gui->GetTime();
for ( i = 0 ; i < oc ; i++ ) {
op = &ops[i];
if (op->b == -2) {
continue;
}
switch( op->opType ) {
case WOP_TYPE_ADD:
registers[op->c] = registers[op->a] + registers[op->b];
break;
case WOP_TYPE_SUBTRACT:
registers[op->c] = registers[op->a] - registers[op->b];
break;
case WOP_TYPE_MULTIPLY:
registers[op->c] = registers[op->a] * registers[op->b];
break;
case WOP_TYPE_DIVIDE:
if ( registers[op->b] == 0.0f ) {
common->Warning( "Divide by zero in window '%s' in %s", GetName(), gui->GetSourceFile() );
registers[op->c] = registers[op->a];
} else {
registers[op->c] = registers[op->a] / registers[op->b];
}
break;
case WOP_TYPE_MOD:
b = (int)registers[op->b];
b = b != 0 ? b : 1;
registers[op->c] = (int)registers[op->a] % b;
break;
case WOP_TYPE_TABLE:
{
const idDeclTable *table = static_cast<const idDeclTable *>( declManager->DeclByIndex( DECL_TABLE, op->a ) );
registers[op->c] = table->TableLookup( registers[op->b] );
}
break;
case WOP_TYPE_GT:
registers[op->c] = registers[ op->a ] > registers[op->b];
break;
case WOP_TYPE_GE:
registers[op->c] = registers[ op->a ] >= registers[op->b];
break;
case WOP_TYPE_LT:
registers[op->c] = registers[ op->a ] < registers[op->b];
break;
case WOP_TYPE_LE:
registers[op->c] = registers[ op->a ] <= registers[op->b];
break;
case WOP_TYPE_EQ:
registers[op->c] = registers[ op->a ] == registers[op->b];
break;
case WOP_TYPE_NE:
registers[op->c] = registers[ op->a ] != registers[op->b];
break;
case WOP_TYPE_COND:
registers[op->c] = (registers[ op->a ]) ? registers[op->b] : registers[op->d];
break;
case WOP_TYPE_AND:
registers[op->c] = registers[ op->a ] && registers[op->b];
break;
case WOP_TYPE_OR:
registers[op->c] = registers[ op->a ] || registers[op->b];
break;
case WOP_TYPE_VAR:
if ( !op->a ) {
registers[op->c] = 0.0f;
break;
}
if ( op->b >= 0 && registers[op->b] >= 0 && registers[op->b] < 4 ) {
// grabs vector components
idWinVec4 *var = (idWinVec4 *)( op->a );
registers[op->c] = ((idVec4&)var)[registers[op->b]];
} else {
registers[op->c] = ((idWinVar*)(op->a))->x();
}
break;
case WOP_TYPE_VARS:
if (op->a) {
idWinStr *var = (idWinStr*)(op->a);
registers[op->c] = atof(var->c_str());
} else {
registers[op->c] = 0;
}
break;
case WOP_TYPE_VARF:
if (op->a) {
idWinFloat *var = (idWinFloat*)(op->a);
registers[op->c] = *var;
} else {
registers[op->c] = 0;
}
break;
case WOP_TYPE_VARI:
if (op->a) {
idWinInt *var = (idWinInt*)(op->a);
registers[op->c] = *var;
} else {
registers[op->c] = 0;
}
break;
case WOP_TYPE_VARB:
if (op->a) {
idWinBool *var = (idWinBool*)(op->a);
registers[op->c] = *var;
} else {
registers[op->c] = 0;
}
break;
default:
common->FatalError( "R_EvaluateExpression: bad opcode" );
}
}
}
/*
================
idWindow::ReadFromDemoFile
================
*/
void idWindow::ReadFromDemoFile( class idDemoFile *f, bool rebuild ) {
// should never hit unless we re-enable WRITE_GUIS
#ifndef WRITE_GUIS
assert( false );
#else
if (rebuild) {
CommonInit();
}
f->SetLog(true, "window1");
backGroundName = f->ReadHashString();
f->SetLog(true, backGroundName);
if ( backGroundName[0] ) {
background = declManager->FindMaterial(backGroundName);
} else {
background = NULL;
}
f->ReadUnsignedChar( cursor );
f->ReadUnsignedInt( flags );
f->ReadInt( timeLine );
f->ReadInt( lastTimeRun );
idRectangle rct = rect;
f->ReadFloat( rct.x );
f->ReadFloat( rct.y );
f->ReadFloat( rct.w );
f->ReadFloat( rct.h );
f->ReadFloat( drawRect.x );
f->ReadFloat( drawRect.y );
f->ReadFloat( drawRect.w );
f->ReadFloat( drawRect.h );
f->ReadFloat( clientRect.x );
f->ReadFloat( clientRect.y );
f->ReadFloat( clientRect.w );
f->ReadFloat( clientRect.h );
f->ReadFloat( textRect.x );
f->ReadFloat( textRect.y );
f->ReadFloat( textRect.w );
f->ReadFloat( textRect.h );
f->ReadFloat( xOffset);
f->ReadFloat( yOffset);
int i, c;
idStr work;
if (rebuild) {
f->SetLog(true, (work + "-scripts"));
for (i = 0; i < SCRIPT_COUNT; i++) {
bool b;
f->ReadBool( b );
if (b) {
delete scripts[i];
scripts[i] = new idGuiScriptList;
scripts[i]->ReadFromDemoFile(f);
}
}
f->SetLog(true, (work + "-timelines"));
f->ReadInt( c );
for (i = 0; i < c; i++) {
idTimeLineEvent *tl = new idTimeLineEvent;
f->ReadInt( tl->time );
f->ReadBool( tl->pending );
tl->event->ReadFromDemoFile(f);
if (rebuild) {
timeLineEvents.Append(tl);
} else {
assert(i < timeLineEvents.Num());
timeLineEvents[i]->time = tl->time;
timeLineEvents[i]->pending = tl->pending;
}
}
}
f->SetLog(true, (work + "-transitions"));
f->ReadInt( c );
for (i = 0; i < c; i++) {
idTransitionData td;
td.data = NULL;
f->ReadInt ( td.offset );
float startTime, accelTime, linearTime, decelTime;
idVec4 startValue, endValue;
f->ReadFloat( startTime );
f->ReadFloat( accelTime );
f->ReadFloat( linearTime );
f->ReadFloat( decelTime );
f->ReadVec4( startValue );
f->ReadVec4( endValue );
td.interp.Init( startTime, accelTime, decelTime, accelTime + linearTime + decelTime, startValue, endValue );
// read this for correct data padding with the win32 savegames
// the extrapolate is correctly initialized through the above Init call
int extrapolationType;
float duration;
idVec4 baseSpeed, speed;
float currentTime;
idVec4 currentValue;
f->ReadInt( extrapolationType );
f->ReadFloat( startTime );
f->ReadFloat( duration );
f->ReadVec4( startValue );
f->ReadVec4( baseSpeed );
f->ReadVec4( speed );
f->ReadFloat( currentTime );
f->ReadVec4( currentValue );
transitions.Append(td);
}
f->SetLog(true, (work + "-regstuff"));
if (rebuild) {
f->ReadInt( c );
for (i = 0; i < c; i++) {
wexpOp_t w;
f->ReadInt( (int&)w.opType );
f->ReadInt( w.a );
f->ReadInt( w.b );
f->ReadInt( w.c );
f->ReadInt( w.d );
ops.Append(w);
}
f->ReadInt( c );
for (i = 0; i < c; i++) {
float ff;
f->ReadFloat( ff );
expressionRegisters.Append(ff);
}
regList.ReadFromDemoFile(f);
}
f->SetLog(true, (work + "-children"));
f->ReadInt( c );
for (i = 0; i < c; i++) {
if (rebuild) {
idWindow *win = new idWindow(dc, gui);
win->ReadFromDemoFile(f);
AddChild(win);
} else {
for (int j = 0; j < c; j++) {
if (children[j]->childID == i) {
children[j]->ReadFromDemoFile(f,rebuild);
break;
} else {
continue;
}
}
}
}
#endif /* WRITE_GUIS */
}
/*
================
idWindow::WriteToDemoFile
================
*/
void idWindow::WriteToDemoFile( class idDemoFile *f ) {
// should never hit unless we re-enable WRITE_GUIS
#ifndef WRITE_GUIS
assert( false );
#else
f->SetLog(true, "window");
f->WriteHashString(backGroundName);
f->SetLog(true, backGroundName);
f->WriteUnsignedChar( cursor );
f->WriteUnsignedInt( flags );
f->WriteInt( timeLine );
f->WriteInt( lastTimeRun );
idRectangle rct = rect;
f->WriteFloat( rct.x );
f->WriteFloat( rct.y );
f->WriteFloat( rct.w );
f->WriteFloat( rct.h );
f->WriteFloat( drawRect.x );
f->WriteFloat( drawRect.y );
f->WriteFloat( drawRect.w );
f->WriteFloat( drawRect.h );
f->WriteFloat( clientRect.x );
f->WriteFloat( clientRect.y );
f->WriteFloat( clientRect.w );
f->WriteFloat( clientRect.h );
f->WriteFloat( textRect.x );
f->WriteFloat( textRect.y );
f->WriteFloat( textRect.w );
f->WriteFloat( textRect.h );
f->WriteFloat( xOffset );
f->WriteFloat( yOffset );
idStr work;
f->SetLog(true, work);
int i, c;
f->SetLog(true, (work + "-transitions"));
c = transitions.Num();
f->WriteInt( c );
for (i = 0; i < c; i++) {
f->WriteInt( 0 );
f->WriteInt( transitions[i].offset );
f->WriteFloat( transitions[i].interp.GetStartTime() );
f->WriteFloat( transitions[i].interp.GetAccelTime() );
f->WriteFloat( transitions[i].interp.GetLinearTime() );
f->WriteFloat( transitions[i].interp.GetDecelTime() );
f->WriteVec4( transitions[i].interp.GetStartValue() );
f->WriteVec4( transitions[i].interp.GetEndValue() );
// write to keep win32 render demo format compatiblity - we don't actually read them back anymore
f->WriteInt( transitions[i].interp.GetExtrapolate()->GetExtrapolationType() );
f->WriteFloat( transitions[i].interp.GetExtrapolate()->GetStartTime() );
f->WriteFloat( transitions[i].interp.GetExtrapolate()->GetDuration() );
f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetStartValue() );
f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetBaseSpeed() );
f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetSpeed() );
f->WriteFloat( transitions[i].interp.GetExtrapolate()->GetCurrentTime() );
f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetCurrentValue() );
}
f->SetLog(true, (work + "-regstuff"));
f->SetLog(true, (work + "-children"));
c = children.Num();
f->WriteInt( c );
for (i = 0; i < c; i++) {
for (int j = 0; j < c; j++) {
if (children[j]->childID == i) {
children[j]->WriteToDemoFile(f);
break;
} else {
continue;
}
}
}
#endif /* WRITE_GUIS */
}
/*
===============
idWindow::WriteString
===============
*/
void idWindow::WriteSaveGameString( const char *string, idFile *savefile ) {
int len = strlen( string );
savefile->Write( &len, sizeof( len ) );
savefile->Write( string, len );
}
/*
===============
idWindow::WriteSaveGameTransition
===============
*/
void idWindow::WriteSaveGameTransition( idTransitionData &trans, idFile *savefile ) {
drawWin_t dw, *fdw;
idStr winName("");
dw.simp = NULL;
dw.win = NULL;
int offset = gui->GetDesktop()->GetWinVarOffset( trans.data, &dw );
if ( dw.win || dw.simp ) {
winName = ( dw.win ) ? dw.win->GetName() : dw.simp->name.c_str();
}
fdw = gui->GetDesktop()->FindChildByName( winName );
if ( offset != -1 && fdw && ( fdw->win || fdw->simp ) ) {
savefile->Write( &offset, sizeof( offset ) );
WriteSaveGameString( winName, savefile );
savefile->Write( &trans.interp, sizeof( trans.interp ) );
} else {
offset = -1;
savefile->Write( &offset, sizeof( offset ) );
}
}
/*
===============
idWindow::ReadSaveGameTransition
===============
*/
void idWindow::ReadSaveGameTransition( idTransitionData &trans, idFile *savefile ) {
int offset;
savefile->Read( &offset, sizeof( offset ) );
if ( offset != -1 ) {
idStr winName;
ReadSaveGameString( winName, savefile );
savefile->Read( &trans.interp, sizeof( trans.interp ) );
trans.data = NULL;
trans.offset = offset;
if ( winName.Length() ) {
idWinStr *strVar = new idWinStr();
strVar->Set( winName );
trans.data = dynamic_cast< idWinVar* >( strVar );
}
}
}
/*
===============
idWindow::WriteToSaveGame
===============
*/
void idWindow::WriteToSaveGame( idFile *savefile ) {
int i;
WriteSaveGameString( cmd, savefile );
savefile->Write( &actualX, sizeof( actualX ) );
savefile->Write( &actualY, sizeof( actualY ) );
savefile->Write( &childID, sizeof( childID ) );
savefile->Write( &flags, sizeof( flags ) );
savefile->Write( &lastTimeRun, sizeof( lastTimeRun ) );
savefile->Write( &drawRect, sizeof( drawRect ) );
savefile->Write( &clientRect, sizeof( clientRect ) );
savefile->Write( &origin, sizeof( origin ) );
savefile->Write( &fontNum, sizeof( fontNum ) );
savefile->Write( &timeLine, sizeof( timeLine ) );
savefile->Write( &xOffset, sizeof( xOffset ) );
savefile->Write( &yOffset, sizeof( yOffset ) );
savefile->Write( &cursor, sizeof( cursor ) );
savefile->Write( &forceAspectWidth, sizeof( forceAspectWidth ) );
savefile->Write( &forceAspectHeight, sizeof( forceAspectHeight ) );
savefile->Write( &matScalex, sizeof( matScalex ) );
savefile->Write( &matScaley, sizeof( matScaley ) );
savefile->Write( &borderSize, sizeof( borderSize ) );
savefile->Write( &textAlign, sizeof( textAlign ) );
savefile->Write( &textAlignx, sizeof( textAlignx ) );
savefile->Write( &textAligny, sizeof( textAligny ) );
savefile->Write( &textShadow, sizeof( textShadow ) );
savefile->Write( &shear, sizeof( shear ) );
WriteSaveGameString( name, savefile );
WriteSaveGameString( comment, savefile );
// WinVars
noTime.WriteToSaveGame( savefile );
visible.WriteToSaveGame( savefile );
rect.WriteToSaveGame( savefile );
backColor.WriteToSaveGame( savefile );
matColor.WriteToSaveGame( savefile );
foreColor.WriteToSaveGame( savefile );
hoverColor.WriteToSaveGame( savefile );
borderColor.WriteToSaveGame( savefile );
textScale.WriteToSaveGame( savefile );
noEvents.WriteToSaveGame( savefile );
rotate.WriteToSaveGame( savefile );
text.WriteToSaveGame( savefile );
backGroundName.WriteToSaveGame( savefile );
hideCursor.WriteToSaveGame(savefile);
// Defined Vars
for ( i = 0; i < definedVars.Num(); i++ ) {
definedVars[i]->WriteToSaveGame( savefile );
}
savefile->Write( &textRect, sizeof( textRect ) );
// Window pointers saved as the child ID of the window
int winID;
winID = focusedChild ? focusedChild->childID : -1 ;
savefile->Write( &winID, sizeof( winID ) );
winID = captureChild ? captureChild->childID : -1 ;
savefile->Write( &winID, sizeof( winID ) );
winID = overChild ? overChild->childID : -1 ;
savefile->Write( &winID, sizeof( winID ) );
// Scripts
for ( i = 0; i < SCRIPT_COUNT; i++ ) {
if ( scripts[i] ) {
scripts[i]->WriteToSaveGame( savefile );
}
}
// TimeLine Events
for ( i = 0; i < timeLineEvents.Num(); i++ ) {
if ( timeLineEvents[i] ) {
savefile->Write( &timeLineEvents[i]->pending, sizeof( timeLineEvents[i]->pending ) );
savefile->Write( &timeLineEvents[i]->time, sizeof( timeLineEvents[i]->time ) );
if ( timeLineEvents[i]->event ) {
timeLineEvents[i]->event->WriteToSaveGame( savefile );
}
}
}
// Transitions
int num = transitions.Num();
savefile->Write( &num, sizeof( num ) );
for ( i = 0; i < transitions.Num(); i++ ) {
WriteSaveGameTransition( transitions[ i ], savefile );
}
// Named Events
for ( i = 0; i < namedEvents.Num(); i++ ) {
if ( namedEvents[i] ) {
WriteSaveGameString( namedEvents[i]->mName, savefile );
if ( namedEvents[i]->mEvent ) {
namedEvents[i]->mEvent->WriteToSaveGame( savefile );
}
}
}
// regList
regList.WriteToSaveGame( savefile );
// Save children
for ( i = 0; i < drawWindows.Num(); i++ ) {
drawWin_t window = drawWindows[i];
if ( window.simp ) {
window.simp->WriteToSaveGame( savefile );
} else if ( window.win ) {
window.win->WriteToSaveGame( savefile );
}
}
}
/*
===============
idWindow::ReadSaveGameString
===============
*/
void idWindow::ReadSaveGameString( idStr &string, idFile *savefile ) {
int len;
savefile->Read( &len, sizeof( len ) );
if ( len < 0 ) {
common->Warning( "idWindow::ReadSaveGameString: invalid length" );
}
string.Fill( ' ', len );
savefile->Read( &string[0], len );
}
/*
===============
idWindow::ReadFromSaveGame
===============
*/
void idWindow::ReadFromSaveGame( idFile *savefile ) {
int i;
transitions.Clear();
ReadSaveGameString( cmd, savefile );
savefile->Read( &actualX, sizeof( actualX ) );
savefile->Read( &actualY, sizeof( actualY ) );
savefile->Read( &childID, sizeof( childID ) );
savefile->Read( &flags, sizeof( flags ) );
savefile->Read( &lastTimeRun, sizeof( lastTimeRun ) );
savefile->Read( &drawRect, sizeof( drawRect ) );
savefile->Read( &clientRect, sizeof( clientRect ) );
savefile->Read( &origin, sizeof( origin ) );
savefile->Read( &fontNum, sizeof( fontNum ) );
savefile->Read( &timeLine, sizeof( timeLine ) );
savefile->Read( &xOffset, sizeof( xOffset ) );
savefile->Read( &yOffset, sizeof( yOffset ) );
savefile->Read( &cursor, sizeof( cursor ) );
savefile->Read( &forceAspectWidth, sizeof( forceAspectWidth ) );
savefile->Read( &forceAspectHeight, sizeof( forceAspectHeight ) );
savefile->Read( &matScalex, sizeof( matScalex ) );
savefile->Read( &matScaley, sizeof( matScaley ) );
savefile->Read( &borderSize, sizeof( borderSize ) );
savefile->Read( &textAlign, sizeof( textAlign ) );
savefile->Read( &textAlignx, sizeof( textAlignx ) );
savefile->Read( &textAligny, sizeof( textAligny ) );
savefile->Read( &textShadow, sizeof( textShadow ) );
savefile->Read( &shear, sizeof( shear ) );
ReadSaveGameString( name, savefile );
ReadSaveGameString( comment, savefile );
// WinVars
noTime.ReadFromSaveGame( savefile );
visible.ReadFromSaveGame( savefile );
rect.ReadFromSaveGame( savefile );
backColor.ReadFromSaveGame( savefile );
matColor.ReadFromSaveGame( savefile );
foreColor.ReadFromSaveGame( savefile );
hoverColor.ReadFromSaveGame( savefile );
borderColor.ReadFromSaveGame( savefile );
textScale.ReadFromSaveGame( savefile );
noEvents.ReadFromSaveGame( savefile );
rotate.ReadFromSaveGame( savefile );
text.ReadFromSaveGame( savefile );
backGroundName.ReadFromSaveGame( savefile );
if ( session->GetSaveGameVersion() >= 17 ) {
hideCursor.ReadFromSaveGame(savefile);
} else {
hideCursor = false;
}
// Defined Vars
for ( i = 0; i < definedVars.Num(); i++ ) {
definedVars[i]->ReadFromSaveGame( savefile );
}
savefile->Read( &textRect, sizeof( textRect ) );
// Window pointers saved as the child ID of the window
int winID = -1;
savefile->Read( &winID, sizeof( winID ) );
for ( i = 0; i < children.Num(); i++ ) {
if ( children[i]->childID == winID ) {
focusedChild = children[i];
}
}
savefile->Read( &winID, sizeof( winID ) );
for ( i = 0; i < children.Num(); i++ ) {
if ( children[i]->childID == winID ) {
captureChild = children[i];
}
}
savefile->Read( &winID, sizeof( winID ) );
for ( i = 0; i < children.Num(); i++ ) {
if ( children[i]->childID == winID ) {
overChild = children[i];
}
}
// Scripts
for ( i = 0; i < SCRIPT_COUNT; i++ ) {
if ( scripts[i] ) {
scripts[i]->ReadFromSaveGame( savefile );
}
}
// TimeLine Events
for ( i = 0; i < timeLineEvents.Num(); i++ ) {
if ( timeLineEvents[i] ) {
savefile->Read( &timeLineEvents[i]->pending, sizeof( timeLineEvents[i]->pending ) );
savefile->Read( &timeLineEvents[i]->time, sizeof( timeLineEvents[i]->time ) );
if ( timeLineEvents[i]->event ) {
timeLineEvents[i]->event->ReadFromSaveGame( savefile );
}
}
}
// Transitions
int num;
savefile->Read( &num, sizeof( num ) );
for ( i = 0; i < num; i++ ) {
idTransitionData trans;
trans.data = NULL;
ReadSaveGameTransition( trans, savefile );
if ( trans.data ) {
transitions.Append( trans );
}
}
// Named Events
for ( i = 0; i < namedEvents.Num(); i++ ) {
if ( namedEvents[i] ) {
ReadSaveGameString( namedEvents[i]->mName, savefile );
if ( namedEvents[i]->mEvent ) {
namedEvents[i]->mEvent->ReadFromSaveGame( savefile );
}
}
}
// regList
regList.ReadFromSaveGame( savefile );
// Read children
for ( i = 0; i < drawWindows.Num(); i++ ) {
drawWin_t window = drawWindows[i];
if ( window.simp ) {
window.simp->ReadFromSaveGame( savefile );
} else if ( window.win ) {
window.win->ReadFromSaveGame( savefile );
}
}
if ( flags & WIN_DESKTOP ) {
FixupTransitions();
}
}
/*
===============
idWindow::NumTransitions
===============
*/
int idWindow::NumTransitions() {
int c = transitions.Num();
for ( int i = 0; i < children.Num(); i++ ) {
c += children[i]->NumTransitions();
}
return c;
}
/*
===============
idWindow::FixupTransitions
===============
*/
void idWindow::FixupTransitions() {
int i, c = transitions.Num();
for ( i = 0; i < c; i++ ) {
drawWin_t *dw = gui->GetDesktop()->FindChildByName( ( ( idWinStr* )transitions[i].data )->c_str() );
delete transitions[i].data;
transitions[i].data = NULL;
if ( dw && ( dw->win || dw->simp ) ){
if ( dw->win ) {
if ( transitions[i].offset == (ptrdiff_t)&this->rect - (ptrdiff_t)this ) {
transitions[i].data = &dw->win->rect;
} else if ( transitions[i].offset == (ptrdiff_t)&this->backColor - (ptrdiff_t)this ) {
transitions[i].data = &dw->win->backColor;
} else if ( transitions[i].offset == (ptrdiff_t)&this->matColor - (ptrdiff_t)this ) {
transitions[i].data = &dw->win->matColor;
} else if ( transitions[i].offset == (ptrdiff_t)&this->foreColor - (ptrdiff_t)this ) {
transitions[i].data = &dw->win->foreColor;
} else if ( transitions[i].offset == (ptrdiff_t)&this->borderColor - (ptrdiff_t)this ) {
transitions[i].data = &dw->win->borderColor;
} else if ( transitions[i].offset == (ptrdiff_t)&this->textScale - (ptrdiff_t)this ) {
transitions[i].data = &dw->win->textScale;
} else if ( transitions[i].offset == (ptrdiff_t)&this->rotate - (ptrdiff_t)this ) {
transitions[i].data = &dw->win->rotate;
}
} else {
if ( transitions[i].offset == (ptrdiff_t)&this->rect - (ptrdiff_t)this ) {
transitions[i].data = &dw->simp->rect;
} else if ( transitions[i].offset == (ptrdiff_t)&this->backColor - (ptrdiff_t)this ) {
transitions[i].data = &dw->simp->backColor;
} else if ( transitions[i].offset == (ptrdiff_t)&this->matColor - (ptrdiff_t)this ) {
transitions[i].data = &dw->simp->matColor;
} else if ( transitions[i].offset == (ptrdiff_t)&this->foreColor - (ptrdiff_t)this ) {
transitions[i].data = &dw->simp->foreColor;
} else if ( transitions[i].offset == (ptrdiff_t)&this->borderColor - (ptrdiff_t)this ) {
transitions[i].data = &dw->simp->borderColor;
} else if ( transitions[i].offset == (ptrdiff_t)&this->textScale - (ptrdiff_t)this ) {
transitions[i].data = &dw->simp->textScale;
} else if ( transitions[i].offset == (ptrdiff_t)&this->rotate - (ptrdiff_t)this ) {
transitions[i].data = &dw->simp->rotate;
}
}
}
if ( transitions[i].data == NULL ) {
transitions.RemoveIndex( i );
i--;
c--;
}
}
for ( c = 0; c < children.Num(); c++ ) {
children[c]->FixupTransitions();
}
}
/*
===============
idWindow::AddChild
===============
*/
void idWindow::AddChild(idWindow *win) {
win->childID = children.Append(win);
}
/*
================
idWindow::FixupParms
================
*/
void idWindow::FixupParms() {
int i;
int c = children.Num();
for (i = 0; i < c; i++) {
children[i]->FixupParms();
}
for (i = 0; i < SCRIPT_COUNT; i++) {
if (scripts[i]) {
scripts[i]->FixupParms(this);
}
}
c = timeLineEvents.Num();
for (i = 0; i < c; i++) {
timeLineEvents[i]->event->FixupParms(this);
}
c = namedEvents.Num();
for (i = 0; i < c; i++) {
namedEvents[i]->mEvent->FixupParms(this);
}
c = ops.Num();
for (i = 0; i < c; i++) {
if (ops[i].b == -2) {
// need to fix this up
const char *p = (const char*)(ops[i].a);
idWinVar *var = GetWinVarByName(p, true);
delete []p;
ops[i].a = (intptr_t)var;
ops[i].b = -1;
}
}
if (flags & WIN_DESKTOP) {
CalcRects(0,0);
}
}
/*
================
idWindow::IsSimple
================
*/
bool idWindow::IsSimple() {
// dont do simple windows when in gui editor
if ( com_editors & EDITOR_GUI ) {
return false;
}
if (ops.Num()) {
return false;
}
if (flags & (WIN_HCENTER | WIN_VCENTER)) {
return false;
}
if (children.Num() || drawWindows.Num()) {
return false;
}
for (int i = 0; i < SCRIPT_COUNT; i++) {
if (scripts[i]) {
return false;
}
}
if (timeLineEvents.Num()) {
return false;
}
if ( namedEvents.Num() ) {
return false;
}
return true;
}
/*
================
idWindow::ContainsStateVars
================
*/
bool idWindow::ContainsStateVars() {
if ( updateVars.Num() ) {
return true;
}
int c = children.Num();
for (int i = 0; i < c; i++) {
if ( children[i]->ContainsStateVars() ) {
return true;
}
}
return false;
}
/*
================
idWindow::Interactive
================
*/
bool idWindow::Interactive() {
if ( scripts[ ON_ACTION ] ) {
return true;
}
int c = children.Num();
for (int i = 0; i < c; i++) {
if (children[i]->Interactive()) {
return true;
}
}
return false;
}
/*
================
idWindow::SetChildWinVarVal
================
*/
void idWindow::SetChildWinVarVal(const char *name, const char *var, const char *val) {
drawWin_t *dw = FindChildByName(name);
idWinVar *wv = NULL;
if (dw && dw->simp) {
wv = dw->simp->GetWinVarByName(var);
} else if (dw && dw->win) {
wv = dw->win->GetWinVarByName(var);
}
if (wv) {
wv->Set(val);
wv->SetEval(false);
}
}
/*
================
idWindow::FindChildByPoint
Finds the window under the given point
================
*/
idWindow* idWindow::FindChildByPoint ( float x, float y, idWindow** below ) {
int c = children.Num();
// If we are looking for a window below this one then
// the next window should be good, but this one wasnt it
if ( *below == this ) {
*below = NULL;
return NULL;
}
if ( !Contains ( drawRect, x, y ) ) {
return NULL;
}
for (int i = c - 1; i >= 0 ; i-- ) {
idWindow* found = children[i]->FindChildByPoint ( x, y, below );
if ( found ) {
if ( *below ) {
continue;
}
return found;
}
}
return this;
}
/*
================
idWindow::FindChildByPoint
================
*/
idWindow* idWindow::FindChildByPoint ( float x, float y, idWindow* below )
{
return FindChildByPoint ( x, y, &below );
}
/*
================
idWindow::GetChildCount
Returns the number of children
================
*/
int idWindow::GetChildCount ( void )
{
return drawWindows.Num ( );
}
/*
================
idWindow::GetChild
Returns the child window at the given index
================
*/
idWindow* idWindow::GetChild ( int index )
{
return drawWindows[index].win;
}
/*
================
idWindow::GetChildIndex
Returns the index of the given child window
================
*/
int idWindow::GetChildIndex ( idWindow* window ) {
int find;
for ( find = 0; find < drawWindows.Num(); find ++ ) {
if ( drawWindows[find].win == window ) {
return find;
}
}
return -1;
}
/*
================
idWindow::RemoveChild
Removes the child from the list of children. Note that the child window being
removed must still be deallocated by the caller
================
*/
void idWindow::RemoveChild ( idWindow *win ) {
int find;
// Remove the child window
children.Remove ( win );
for ( find = 0; find < drawWindows.Num(); find ++ )
{
if ( drawWindows[find].win == win )
{
drawWindows.RemoveIndex ( find );
break;
}
}
}
/*
================
idWindow::InsertChild
Inserts the given window as a child into the given location in the zorder.
================
*/
bool idWindow::InsertChild ( idWindow *win, idWindow* before )
{
AddChild ( win );
win->parent = this;
drawWin_t dwt;
dwt.simp = NULL;
dwt.win = win;
// If not inserting before anything then just add it at the end
if ( before ) {
int index;
index = GetChildIndex ( before );
if ( index != -1 ) {
drawWindows.Insert ( dwt, index );
return true;
}
}
drawWindows.Append ( dwt );
return true;
}
/*
================
idWindow::ScreenToClient
================
*/
void idWindow::ScreenToClient ( idRectangle* r ) {
int x;
int y;
idWindow* p;
for ( p = this, x = 0, y = 0; p; p = p->parent ) {
x += p->rect.x();
y += p->rect.y();
}
r->x -= x;
r->y -= y;
}
/*
================
idWindow::ClientToScreen
================
*/
void idWindow::ClientToScreen ( idRectangle* r ) {
int x;
int y;
idWindow* p;
for ( p = this, x = 0, y = 0; p; p = p->parent ) {
x += p->rect.x();
y += p->rect.y();
}
r->x += x;
r->y += y;
}
/*
================
idWindow::SetDefaults
Set the window do a default window with no text, no background and
default colors, etc..
================
*/
void idWindow::SetDefaults ( void ) {
forceAspectWidth = 640.0f;
forceAspectHeight = 480.0f;
matScalex = 1;
matScaley = 1;
borderSize = 0;
noTime = false;
visible = true;
textAlign = 0;
textAlignx = 0;
textAligny = 0;
noEvents = false;
rotate = 0;
shear.Zero();
textScale = 0.35f;
backColor.Zero();
foreColor = idVec4(1, 1, 1, 1);
hoverColor = idVec4(1, 1, 1, 1);
matColor = idVec4(1, 1, 1, 1);
borderColor.Zero();
text = "";
background = NULL;
backGroundName = "";
}
/*
================
idWindow::UpdateFromDictionary
The editor only has a dictionary to work with so the easiest way to push the
values of the dictionary onto the window is for the window to interpret the
dictionary as if were a file being parsed.
================
*/
bool idWindow::UpdateFromDictionary ( idDict& dict ) {
const idKeyValue* kv;
int i;
SetDefaults ( );
// Clear all registers since they will get recreated
regList.Reset ( );
expressionRegisters.Clear ( );
ops.Clear ( );
for ( i = 0; i < dict.GetNumKeyVals(); i ++ ) {
kv = dict.GetKeyVal ( i );
// Special case name
if ( !kv->GetKey().Icmp ( "name" ) ) {
name = kv->GetValue();
continue;
}
idParser src( kv->GetValue().c_str(), kv->GetValue().Length(), "",
LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
if ( !ParseInternalVar ( kv->GetKey(), &src ) ) {
// Kill the old register since the parse reg entry will add a new one
if ( !ParseRegEntry ( kv->GetKey(), &src ) ) {
continue;
}
}
}
EvalRegs(-1, true);
SetupFromState();
PostParse();
return true;
}