DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

Window.cpp (95160B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 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.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #pragma hdrstop
     30 #include "../idlib/precompiled.h"
     31 
     32 #include "DeviceContext.h"
     33 #include "Window.h"
     34 #include "UserInterfaceLocal.h"
     35 #include "EditWindow.h"
     36 #include "ChoiceWindow.h"
     37 #include "SliderWindow.h"
     38 #include "BindWindow.h"
     39 #include "ListWindow.h"
     40 #include "RenderWindow.h"
     41 #include "FieldWindow.h"
     42 
     43 #include "GameSSDWindow.h"
     44 #include "GameBearShootWindow.h"
     45 #include "GameBustOutWindow.h"
     46 
     47 bool idWindow::registerIsTemporary[MAX_EXPRESSION_REGISTERS];		// statics to assist during parsing
     48 //float idWindow::shaderRegisters[MAX_EXPRESSION_REGISTERS];
     49 //wexpOp_t idWindow::shaderOps[MAX_EXPRESSION_OPS];
     50 
     51 idCVar idWindow::gui_debug( "gui_debug", "0", CVAR_GUI | CVAR_BOOL, "" );
     52 idCVar idWindow::gui_edit( "gui_edit", "0", CVAR_GUI | CVAR_BOOL, "" );
     53 
     54 idCVar hud_titlesafe( "hud_titlesafe", "0.0", CVAR_GUI | CVAR_FLOAT, "fraction of the screen to leave around hud for titlesafe area" );
     55 
     56 extern idCVar r_skipGuiShaders;		// 1 = don't render any gui elements on surfaces
     57 
     58 //  made RegisterVars a member of idWindow
     59 const idRegEntry idWindow::RegisterVars[] = {
     60 	{ "forecolor", idRegister::VEC4 },
     61 	{ "hovercolor", idRegister::VEC4 },
     62 	{ "backcolor", idRegister::VEC4 },
     63 	{ "bordercolor", idRegister::VEC4 },
     64 	{ "rect", idRegister::RECTANGLE },
     65 	{ "matcolor", idRegister::VEC4 },
     66 	{ "scale", idRegister::VEC2 },
     67 	{ "translate", idRegister::VEC2 },
     68 	{ "rotate", idRegister::FLOAT },
     69 	{ "textscale", idRegister::FLOAT },
     70 	{ "visible", idRegister::BOOL },
     71 	{ "noevents", idRegister::BOOL },
     72 	{ "text", idRegister::STRING },
     73 	{ "background", idRegister::STRING },
     74 	{ "runscript", idRegister::STRING },
     75 	{ "varbackground", idRegister::STRING },
     76 	{ "cvar", idRegister::STRING },
     77 	{ "choices", idRegister::STRING },
     78 	{ "choiceVar", idRegister::STRING },
     79 	{ "bind", idRegister::STRING },
     80 	{ "modelRotate", idRegister::VEC4 },
     81 	{ "modelOrigin", idRegister::VEC4 },
     82 	{ "lightOrigin", idRegister::VEC4 },
     83 	{ "lightColor", idRegister::VEC4 },
     84 	{ "viewOffset", idRegister::VEC4 },
     85 	{ "hideCursor", idRegister::BOOL}
     86 };
     87 
     88 const int idWindow::NumRegisterVars = sizeof(RegisterVars) / sizeof(idRegEntry);
     89 
     90 const char *idWindow::ScriptNames[] = {
     91 	"onMouseEnter",
     92 	"onMouseExit",
     93 	"onAction",
     94 	"onActivate",
     95 	"onDeactivate",
     96 	"onESC",
     97 	"onEvent",
     98 	"onTrigger",
     99 	"onActionRelease",
    100 	"onEnter",
    101 	"onEnterRelease"
    102 };
    103 
    104 /*
    105 ================
    106 idWindow::CommonInit
    107 ================
    108 */
    109 void idWindow::CommonInit() {
    110 	childID = 0;
    111 	flags = 0;
    112 	lastTimeRun = 0;
    113 	origin.Zero();
    114 	font = renderSystem->RegisterFont( "" );
    115 	timeLine = -1;
    116 	xOffset = yOffset = 0.0;
    117 	cursor = 0;
    118 	forceAspectWidth = 640;
    119 	forceAspectHeight = 480;
    120 	matScalex = 1;
    121 	matScaley = 1;
    122 	borderSize = 0;
    123 	noTime = false;
    124 	visible = true;
    125 	textAlign = 0;
    126 	textAlignx = 0;
    127 	textAligny = 0;
    128 	noEvents = false;
    129 	rotate = 0;
    130 	shear.Zero();
    131 	textScale = 0.35f;
    132 	backColor.Zero();
    133 	foreColor = idVec4(1, 1, 1, 1);
    134 	hoverColor = idVec4(1, 1, 1, 1);
    135 	matColor = idVec4(1, 1, 1, 1);
    136 	borderColor.Zero();
    137 	background = NULL;
    138 	backGroundName = "";
    139 	focusedChild = NULL;
    140 	captureChild = NULL;
    141 	overChild = NULL;
    142 	parent = NULL;
    143 	saveOps = NULL;
    144 	saveRegs = NULL;
    145 	timeLine = -1;
    146 	textShadow = 0;
    147 	hover = false;
    148 
    149 	for (int i = 0; i < SCRIPT_COUNT; i++) {
    150 		scripts[i] = NULL;
    151 	}
    152 
    153 	hideCursor = false;
    154 }
    155 
    156 /*
    157 ================
    158 idWindow::Size
    159 ================
    160 */
    161 size_t idWindow::Size() {
    162 	int c = children.Num();
    163 	int sz = 0;
    164 	for (int i = 0; i < c; i++) {
    165 		sz += children[i]->Size();
    166 	}
    167 	sz += sizeof(*this) + Allocated();
    168 	return sz;
    169 }
    170 
    171 /*
    172 ================
    173 idWindow::Allocated
    174 ================
    175 */
    176 size_t idWindow::Allocated() {
    177 	int i, c;
    178 	int sz = name.Allocated();
    179 	sz += text.Size();
    180 	sz += backGroundName.Size();
    181 
    182 	c = definedVars.Num();
    183 	for (i = 0; i < c; i++) {
    184 		sz += definedVars[i]->Size();
    185 	}
    186 
    187 	for (i = 0; i < SCRIPT_COUNT; i++) {
    188 		if (scripts[i]) {
    189 			sz += scripts[i]->Size();
    190 		}
    191 	}
    192 	c = timeLineEvents.Num();
    193 	for (i = 0; i < c; i++) {
    194 		sz += timeLineEvents[i]->Size();
    195 	}
    196 
    197 	c = namedEvents.Num();
    198 	for (i = 0; i < c; i++) {
    199 		sz += namedEvents[i]->Size();
    200 	}
    201 
    202 	c = drawWindows.Num();
    203 	for (i = 0; i < c; i++) {
    204 		if (drawWindows[i].simp) {
    205 			sz += drawWindows[i].simp->Size();
    206 		}
    207 	}
    208 
    209 	return sz;
    210 }
    211 
    212 /*
    213 ================
    214 idWindow::idWindow
    215 ================
    216 */
    217 idWindow::idWindow(idUserInterfaceLocal *ui) {
    218 	gui = ui;
    219 	CommonInit();
    220 }
    221 				  
    222 /*
    223 ================
    224 idWindow::CleanUp
    225 ================
    226 */
    227 void idWindow::CleanUp() {
    228 	int i, c = drawWindows.Num();
    229 	for (i = 0; i < c; i++) {
    230 		delete drawWindows[i].simp;
    231 	}
    232 
    233 	// ensure the register list gets cleaned up
    234 	regList.Reset ( );
    235 	
    236 	// Cleanup the named events
    237 	namedEvents.DeleteContents(true);
    238 
    239 	drawWindows.Clear();
    240 	children.DeleteContents(true);
    241 	definedVars.DeleteContents(true);
    242 	timeLineEvents.DeleteContents(true);
    243 	for (i = 0; i < SCRIPT_COUNT; i++) {
    244 		delete scripts[i];
    245 	}
    246 	CommonInit();
    247 }
    248 
    249 /*
    250 ================
    251 idWindow::~idWindow
    252 ================
    253 */
    254 idWindow::~idWindow() {
    255 	CleanUp();
    256 }
    257 
    258 /*
    259 ================
    260 idWindow::Move
    261 ================
    262 */
    263 void idWindow::Move(float x, float y) {
    264 	idRectangle rct = rect;
    265 	rct.x = x;
    266 	rct.y = y;
    267 	idRegister *reg = RegList()->FindReg("rect");
    268 	if (reg) {
    269 		reg->Enable(false);
    270 	}
    271 	rect = rct;
    272 }
    273 
    274 /*
    275 ================
    276 idWindow::SetFont
    277 ================
    278 */
    279 void idWindow::SetFont() {
    280 	dc->SetFont( font );
    281 }
    282 
    283 /*
    284 ================
    285 idWindow::GetMaxCharHeight
    286 ================
    287 */
    288 float idWindow::GetMaxCharHeight() {
    289 	SetFont();
    290 	return dc->MaxCharHeight(textScale);
    291 }
    292 
    293 /*
    294 ================
    295 idWindow::GetMaxCharWidth
    296 ================
    297 */
    298 float idWindow::GetMaxCharWidth() {
    299 	SetFont();
    300 	return dc->MaxCharWidth(textScale);
    301 }
    302 
    303 /*
    304 ================
    305 idWindow::Draw
    306 ================
    307 */
    308 void idWindow::Draw( int time, float x, float y ) {
    309 	if ( text.Length() == 0 ) {
    310 		return;
    311 	}
    312 	if ( textShadow ) {
    313 		idStr shadowText = text;
    314 		idRectangle shadowRect = textRect;
    315 
    316 		shadowText.RemoveColors();
    317 		shadowRect.x += textShadow;
    318 		shadowRect.y += textShadow;
    319 
    320 		dc->DrawText( shadowText, textScale, textAlign, colorBlack, shadowRect, !( flags & WIN_NOWRAP ), -1 );
    321 	}
    322 	dc->DrawText( text, textScale, textAlign, foreColor, textRect, !( flags & WIN_NOWRAP ), -1 );
    323 
    324 	if ( gui_edit.GetBool() ) {
    325 		dc->EnableClipping( false );
    326 		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 );
    327 		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 );
    328 		dc->EnableClipping( true );
    329 	}
    330 
    331 }
    332 
    333 /*
    334 ================
    335 idWindow::BringToTop
    336 ================
    337 */
    338 void idWindow::BringToTop(idWindow *w) {
    339 	
    340 	if (w && !(w->flags & WIN_MODAL)) {
    341 		return;
    342 	}
    343 
    344 	int c = children.Num();
    345 	for (int i = 0; i < c; i++) {
    346 		if (children[i] == w) {
    347 			// this is it move from i - 1 to 0 to i to 1 then shove this one into 0
    348 			for (int j = i+1; j < c; j++) {
    349 				children[j-1] = children[j];
    350 			}
    351 			children[c-1] = w;
    352 			break;
    353 		}
    354 	}
    355 }
    356 
    357 /*
    358 ================
    359 idWindow::Size
    360 ================
    361 */
    362 void idWindow::Size(float x, float y, float w, float h) {
    363 	idRectangle rct = rect;
    364 	rct.x = x;
    365 	rct.y = y;
    366 	rct.w = w;
    367 	rct.h = h;
    368 	rect = rct;
    369 	CalcClientRect(0,0);
    370 }
    371 
    372 /*
    373 ================
    374 idWindow::MouseEnter
    375 ================
    376 */
    377 void idWindow::MouseEnter() {
    378 	
    379 	if (noEvents) {
    380 		return;
    381 	}
    382 
    383 	RunScript(ON_MOUSEENTER);
    384 }
    385 
    386 /*
    387 ================
    388 idWindow::MouseExit
    389 ================
    390 */
    391 void idWindow::MouseExit() {
    392 	
    393 	if (noEvents) {
    394 		return;
    395 	}
    396 
    397 	RunScript(ON_MOUSEEXIT);
    398 }
    399 
    400 /*
    401 ================
    402 idWindow::GetChildWithOnAction
    403 ================
    404 */
    405 idWindow * idWindow::GetChildWithOnAction( float xd, float yd ) {
    406 
    407 	int c = children.Num();
    408 	while ( c > 0 ) {
    409 		idWindow *child = children[--c];
    410 		if ( child->visible && child->Contains(child->drawRect, gui->CursorX(), gui->CursorY() ) && !child->noEvents ) {
    411 			child->hover = true;
    412 			if ( child->cursor > 0 ) {
    413 				return child;
    414 			}
    415 		}
    416 
    417 		idWindow * check = child->GetChildWithOnAction( xd, yd );
    418 		if ( check != NULL && check != child ) {
    419 			return check;
    420 		}
    421 	}
    422 
    423 	return this;
    424 
    425 }
    426 
    427 /*
    428 ================
    429 idWindow::RouteMouseCoords
    430 ================
    431 */
    432 const char *idWindow::RouteMouseCoords(float xd, float yd) {
    433 	idStr str;
    434 	if (GetCaptureChild()) {
    435 		//FIXME: unkludge this whole mechanism
    436 		return GetCaptureChild()->RouteMouseCoords(xd, yd);
    437 	}
    438 	
    439 	if (xd == -2000 || yd == -2000) {
    440 		return "";
    441 	}
    442 
    443 	idWindow * child = GetChildWithOnAction( xd, yd );
    444 	if ( overChild != child ) {
    445 		if ( overChild ) {
    446 			overChild->MouseExit();
    447 			str = overChild->cmd;
    448 			if (str.Length()) {
    449 				gui->GetDesktop()->AddCommand(str);
    450 				overChild->cmd = "";
    451 			}
    452 		}
    453 		overChild = child;
    454 		if ( overChild ) {
    455 			overChild->MouseEnter();
    456 			str = overChild->cmd;
    457 			if (str.Length()) {
    458 				gui->GetDesktop()->AddCommand(str);
    459 				overChild->cmd = "";
    460 			}
    461 
    462 			dc->SetCursor( overChild->cursor );
    463 		}
    464 	}
    465 
    466 	return "";
    467 }
    468 
    469 /*
    470 ================
    471 idWindow::Activate
    472 ================
    473 */
    474 void idWindow::Activate( bool activate,	idStr &act ) {
    475 
    476 	int n = (activate) ? ON_ACTIVATE : ON_DEACTIVATE;
    477 
    478 	//  make sure win vars are updated before activation
    479 	UpdateWinVars ( );
    480 
    481 	RunScript(n);
    482 	int c = children.Num();
    483 	for (int i = 0; i < c; i++) {
    484 		children[i]->Activate( activate, act );
    485 	}
    486 
    487 	if ( act.Length() ) {
    488 		act += " ; ";
    489 	}
    490 }
    491 
    492 /*
    493 ================
    494 idWindow::Trigger
    495 ================
    496 */
    497 void idWindow::Trigger() {
    498 	RunScript( ON_TRIGGER );
    499 	int c = children.Num();
    500 	for ( int i = 0; i < c; i++ ) {
    501 		children[i]->Trigger();
    502 	}
    503 	StateChanged( true );
    504 }
    505 
    506 /*
    507 ================
    508 idWindow::StateChanged
    509 ================
    510 */
    511 void idWindow::StateChanged( bool redraw ) {
    512 
    513 	UpdateWinVars();
    514 
    515 	if (expressionRegisters.Num() && ops.Num()) {
    516 		EvalRegs();
    517 	}
    518 
    519 	int c = drawWindows.Num();
    520 	for ( int i = 0; i < c; i++ ) {
    521 		if ( drawWindows[i].win ) {
    522 			drawWindows[i].win->StateChanged( redraw );
    523 		} else {
    524 			drawWindows[i].simp->StateChanged( redraw );
    525 		}
    526 	}
    527 }
    528 
    529 /*
    530 ================
    531 idWindow::SetCapture
    532 ================
    533 */
    534 idWindow *idWindow::SetCapture(idWindow *w) {
    535 	// only one child can have the focus
    536 
    537 	idWindow *last = NULL;
    538 	int c = children.Num();
    539 	for (int i = 0; i < c; i++) {
    540 		if ( children[i]->flags & WIN_CAPTURE ) {
    541 			last = children[i];
    542 			//last->flags &= ~WIN_CAPTURE;
    543 			last->LoseCapture();
    544 			break;
    545 		}
    546 	}
    547 
    548 	w->flags |= WIN_CAPTURE;
    549 	w->GainCapture();
    550 	gui->GetDesktop()->captureChild = w;
    551 	return last;
    552 }
    553 
    554 /*
    555 ================
    556 idWindow::AddUpdateVar
    557 ================
    558 */
    559 void idWindow::AddUpdateVar(idWinVar *var) {
    560 	updateVars.AddUnique(var);
    561 }
    562 
    563 /*
    564 ================
    565 idWindow::UpdateWinVars
    566 ================
    567 */
    568 void idWindow::UpdateWinVars() {
    569 	int c = updateVars.Num();
    570 	for (int i = 0; i < c; i++) {
    571 		updateVars[i]->Update();
    572 	}
    573 }
    574 
    575 /*
    576 ================
    577 idWindow::RunTimeEvents
    578 ================
    579 */
    580 bool idWindow::RunTimeEvents(int time) {
    581 
    582 	if ( time == lastTimeRun ) {
    583 		return false;
    584 	}
    585 
    586 	lastTimeRun = time;
    587 
    588 	UpdateWinVars();
    589 
    590 	if (expressionRegisters.Num() && ops.Num()) {
    591 		EvalRegs();
    592 	}
    593 
    594 	if ( flags & WIN_INTRANSITION ) {
    595 		Transition();
    596 	}
    597 
    598 	Time();
    599 
    600 	// renamed ON_EVENT to ON_FRAME
    601 	RunScript(ON_FRAME);
    602 
    603 	int c = children.Num();
    604 	for (int i = 0; i < c; i++) {
    605 		children[i]->RunTimeEvents(time);
    606 	}
    607 
    608 	return true;
    609 }
    610 
    611 /*
    612 ================
    613 idWindow::RunNamedEvent
    614 ================
    615 */
    616 void idWindow::RunNamedEvent ( const char* eventName )
    617 {
    618 	int i;
    619 	int c;
    620 
    621 	// Find and run the event	
    622 	c = namedEvents.Num( );
    623 	for ( i = 0; i < c; i ++ ) {
    624 		if ( namedEvents[i]->mName.Icmp( eventName ) ) {	
    625 			continue;
    626 		}
    627 
    628 		UpdateWinVars();
    629 
    630 		// Make sure we got all the current values for stuff
    631 		if (expressionRegisters.Num() && ops.Num()) {
    632 			EvalRegs(-1, true);
    633 		}
    634 		
    635 		RunScriptList( namedEvents[i]->mEvent );
    636 		
    637 		break;
    638 	}
    639 	
    640 	// Run the event in all the children as well
    641 	c = children.Num();
    642 	for ( i = 0; i < c; i++ ) {
    643 		children[i]->RunNamedEvent ( eventName );
    644 	}
    645 }
    646 
    647 /*
    648 ================
    649 idWindow::Contains
    650 ================
    651 */
    652 bool idWindow::Contains(const idRectangle &sr, float x, float y) {
    653 	idRectangle r = sr;
    654 	r.x += actualX - drawRect.x;
    655 	r.y += actualY - drawRect.y;
    656 	return r.Contains(x, y);
    657 }
    658 
    659 /*
    660 ================
    661 idWindow::Contains
    662 ================
    663 */
    664 bool idWindow::Contains(float x, float y) {
    665 	idRectangle r = drawRect;
    666 	r.x = actualX;
    667 	r.y = actualY;
    668 	return r.Contains(x, y);
    669 }
    670 
    671 /*
    672 ================
    673 idWindow::AddCommand
    674 ================
    675 */
    676 void idWindow::AddCommand(const char *_cmd) {
    677 	idStr str = cmd;
    678 	if (str.Length()) {
    679 		str += " ; ";
    680 		str += _cmd;
    681 	} else {
    682 		str = _cmd;
    683 	}
    684 	cmd = str;
    685 }
    686 
    687 /*
    688 ================
    689 idWindow::HandleEvent
    690 ================
    691 */
    692 const char *idWindow::HandleEvent(const sysEvent_t *event, bool *updateVisuals) {
    693 	static bool actionDownRun;
    694 	static bool actionUpRun;
    695 
    696 	cmd = "";
    697 
    698 	if ( flags & WIN_DESKTOP ) {
    699 		actionDownRun = false;
    700 		actionUpRun = false;
    701 		if (expressionRegisters.Num() && ops.Num()) {
    702 			EvalRegs();
    703 		}
    704 		RunTimeEvents(gui->GetTime());
    705 		CalcRects(0,0);
    706 
    707 		if ( overChild != NULL ) {
    708 			dc->SetCursor( overChild->cursor );
    709 		} else {
    710 			dc->SetCursor( idDeviceContext::CURSOR_ARROW );
    711 		}
    712 	}
    713 
    714 	if (visible && !noEvents) {
    715 
    716 		if (event->evType == SE_KEY) {
    717 			EvalRegs(-1, true);
    718 			if (updateVisuals) {
    719 				*updateVisuals = true;
    720 			}
    721 
    722 			if (event->evValue == K_MOUSE1) {
    723 
    724 				if (!event->evValue2 && GetCaptureChild()) {
    725 					GetCaptureChild()->LoseCapture();
    726 					gui->GetDesktop()->captureChild = NULL;
    727 					return "";
    728 				} 
    729 
    730 				int c = children.Num();
    731 				while (--c >= 0) {
    732 					if (children[c]->visible && children[c]->Contains(children[c]->drawRect, gui->CursorX(), gui->CursorY()) && !(children[c]->noEvents)) {
    733 						idWindow *child = children[c];
    734 						if (event->evValue2) {
    735 							BringToTop(child);
    736 							SetFocus(child);
    737 							if (child->flags & WIN_HOLDCAPTURE) {
    738 								SetCapture(child);
    739 							}
    740 						}
    741 						if (child->Contains(child->clientRect, gui->CursorX(), gui->CursorY())) {
    742 							//if ((gui_edit.GetBool() && (child->flags & WIN_SELECTED)) || (!gui_edit.GetBool() && (child->flags & WIN_MOVABLE))) {
    743 							//	SetCapture(child);
    744 							//}
    745 							SetFocus(child);
    746 							const char *childRet = child->HandleEvent(event, updateVisuals);
    747 							if (childRet != NULL && *childRet != NULL) {
    748 								return childRet;
    749 							} 
    750 							if (child->flags & WIN_MODAL) {
    751 								return "";
    752 							}
    753 						} else {
    754 							if (event->evValue2) {
    755 								SetFocus(child);
    756 								bool capture = true;
    757 								if (capture && ((child->flags & WIN_MOVABLE) || gui_edit.GetBool())) {
    758 									SetCapture(child);
    759 								}
    760 								return "";
    761 							} else {
    762 							}
    763 						}
    764 					}
    765 				}
    766 				if (event->evValue2 && !actionDownRun) {
    767 					actionDownRun = RunScript( ON_ACTION );
    768 				} else if (!actionUpRun) {
    769 					actionUpRun = RunScript( ON_ACTIONRELEASE );
    770 				}
    771 			} else if (event->evValue == K_MOUSE2) {
    772 
    773 				if (!event->evValue2 && GetCaptureChild()) {
    774 					GetCaptureChild()->LoseCapture();
    775 					gui->GetDesktop()->captureChild = NULL;
    776 					return "";
    777 				}
    778 
    779 				int c = children.Num();
    780 				while (--c >= 0) {
    781 					if (children[c]->visible && children[c]->Contains(children[c]->drawRect, gui->CursorX(), gui->CursorY()) && !(children[c]->noEvents)) {
    782 						idWindow *child = children[c];
    783 						if (event->evValue2) {
    784 							BringToTop(child);
    785 							SetFocus(child);
    786 						}
    787 						if (child->Contains(child->clientRect,gui->CursorX(), gui->CursorY()) || GetCaptureChild() == child) {
    788 							if ((gui_edit.GetBool() && (child->flags & WIN_SELECTED)) || (!gui_edit.GetBool() && (child->flags & WIN_MOVABLE))) {
    789 								SetCapture(child);
    790 							}
    791 							const char *childRet = child->HandleEvent(event, updateVisuals);
    792 							if (childRet && *childRet) {
    793 								return childRet;
    794 							} 
    795 							if (child->flags & WIN_MODAL) {
    796 								return "";
    797 							}
    798 						}
    799 					}
    800 				}
    801 			} else if (event->evValue == K_MOUSE3) {
    802 				if (gui_edit.GetBool()) {
    803 					int c = children.Num();
    804 					for (int i = 0; i < c; i++) {
    805 						if (children[i]->drawRect.Contains(gui->CursorX(), gui->CursorY())) {
    806 							if (event->evValue2) {
    807 								children[i]->flags ^= WIN_SELECTED;
    808 								if (children[i]->flags & WIN_SELECTED) {
    809 									flags &= ~WIN_SELECTED;
    810 									return "childsel";
    811 								}
    812 							}
    813 						}
    814 					}
    815 				}
    816 			} else if (event->evValue == K_TAB && event->evValue2) {
    817 				if (GetFocusedChild()) {
    818 					const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
    819 					if (childRet && *childRet) {
    820 						return childRet;
    821 					}
    822 
    823 					// If the window didn't handle the tab, then move the focus to the next window
    824 					// or the previous window if shift is held down
    825 
    826 					int direction = 1;
    827 					if ( idKeyInput::IsDown( K_LSHIFT ) || idKeyInput::IsDown( K_RSHIFT ) ) {
    828 						direction = -1;
    829 					}
    830 
    831 					idWindow *currentFocus = GetFocusedChild();
    832 					idWindow *child = GetFocusedChild();
    833 					idWindow *parent = child->GetParent();
    834 					while ( parent ) {
    835 						bool foundFocus = false;
    836 						bool recurse = false;
    837 						int index = 0;
    838 						if ( child ) {
    839 							index = parent->GetChildIndex( child ) + direction;
    840 						} else if ( direction < 0 ) {
    841 							index = parent->GetChildCount() - 1;
    842 						}
    843 						while ( index < parent->GetChildCount() && index >= 0) {
    844 							idWindow *testWindow = parent->GetChild( index );
    845 							if ( testWindow == currentFocus ) {
    846 								// we managed to wrap around and get back to our starting window
    847 								foundFocus = true;
    848 								break;
    849 							}
    850 							if ( testWindow && !testWindow->noEvents && testWindow->visible ) {
    851 								if ( testWindow->flags & WIN_CANFOCUS ) {
    852 									SetFocus( testWindow );
    853 									foundFocus = true;
    854 									break;
    855 								} else if ( testWindow->GetChildCount() > 0 ) {
    856 									parent = testWindow;
    857 									child = NULL;
    858 									recurse = true;
    859 									break;
    860 								}
    861 							}
    862 							index += direction;
    863 						}
    864 						if ( foundFocus ) {
    865 							// We found a child to focus on
    866 							break;
    867 						} else if ( recurse ) {
    868 							// We found a child with children
    869 							continue;
    870 						} else {
    871 							// We didn't find anything, so go back up to our parent
    872 							child = parent;
    873 							parent = child->GetParent();
    874 							if ( parent == gui->GetDesktop() ) {
    875 								// We got back to the desktop, so wrap around but don't actually go to the desktop
    876 								parent = NULL;
    877 								child = NULL;
    878 							}
    879 						}
    880 					}
    881 				}
    882 			} else if ( ( event->evValue == K_ESCAPE || event->evValue == K_JOY9 ) && event->evValue2) {
    883 				if (GetFocusedChild()) {
    884 					const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
    885 					if (childRet && *childRet) {
    886 						return childRet;
    887 					}
    888 				}
    889 				RunScript( ON_ESC );
    890 			} else if (event->evValue == K_ENTER ) {
    891 				if (GetFocusedChild()) {
    892 					const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
    893 					if (childRet && *childRet) {
    894 						return childRet;
    895 					}
    896 				}
    897 				if ( flags & WIN_WANTENTER ) {
    898 					if ( event->evValue2 ) {
    899 						RunScript( ON_ACTION );
    900 					} else {
    901 						RunScript( ON_ACTIONRELEASE );
    902 					}
    903 				}
    904 			} else {
    905 				if (GetFocusedChild()) {
    906 					const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
    907 					if (childRet && *childRet) {
    908 						return childRet;
    909 					}
    910 				}
    911 			}
    912 
    913 		} else if (event->evType == SE_MOUSE) {
    914 			if (updateVisuals) {
    915 				*updateVisuals = true;
    916 			}
    917 			const char *mouseRet = RouteMouseCoords(event->evValue, event->evValue2);
    918 			if (mouseRet != NULL && *mouseRet != NULL) {
    919 				return mouseRet;
    920 			}
    921 		} else if (event->evType == SE_NONE) {
    922 		} else if (event->evType == SE_CHAR) {
    923 			if (GetFocusedChild()) {
    924 				const char *childRet = GetFocusedChild()->HandleEvent(event, updateVisuals);
    925 				if (childRet && *childRet) {
    926 					return childRet;
    927 				}
    928 			}
    929 		}
    930 	}
    931 
    932 	gui->GetReturnCmd() = cmd;
    933 	if ( gui->GetPendingCmd().Length() ) {
    934 		gui->GetReturnCmd() += " ; ";
    935 		gui->GetReturnCmd() += gui->GetPendingCmd();
    936 		gui->GetPendingCmd().Clear();
    937 	}
    938 	cmd = "";
    939 	return gui->GetReturnCmd();
    940 }
    941 
    942 /*
    943 ================
    944 idWindow::DebugDraw
    945 ================
    946 */
    947 void idWindow::DebugDraw(int time, float x, float y) {
    948 	static char buff[16384] = { 0 };
    949 	if (dc) {
    950 		dc->EnableClipping(false);
    951 		if (gui_debug.GetInteger() == 1) {
    952 			dc->DrawRect(drawRect.x, drawRect.y, drawRect.w, drawRect.h, 1, idDeviceContext::colorRed);
    953 		} else if (gui_debug.GetInteger() == 2) {
    954 			char out[1024];
    955 			idStr str;
    956 			str = text.c_str();
    957 			
    958 			if (str.Length()) {
    959 				sprintf(buff, "%s\n", str.c_str());
    960 			}
    961 
    962 			sprintf(out, "Rect: %0.1f, %0.1f, %0.1f, %0.1f\n", rect.x(), rect.y(), rect.w(), rect.h());
    963 			strcat(buff, out);
    964 			sprintf(out, "Draw Rect: %0.1f, %0.1f, %0.1f, %0.1f\n", drawRect.x, drawRect.y, drawRect.w, drawRect.h);
    965 			strcat(buff, out);
    966 			sprintf(out, "Client Rect: %0.1f, %0.1f, %0.1f, %0.1f\n", clientRect.x, clientRect.y, clientRect.w, clientRect.h);
    967 			strcat(buff, out);
    968 			sprintf(out, "Cursor: %0.1f : %0.1f\n", gui->CursorX(), gui->CursorY());
    969 			strcat(buff, out);
    970 
    971 
    972 			//idRectangle tempRect = textRect;
    973 			//tempRect.x += offsetX;
    974 			//drawRect.y += offsetY;
    975 			dc->DrawText(buff, textScale, textAlign, foreColor, textRect, true);
    976 		} 
    977 		dc->EnableClipping(true);
    978 	}
    979 }
    980 
    981 /*
    982 ================
    983 idWindow::Transition
    984 ================
    985 */
    986 void idWindow::Transition() {
    987 	int i, c = transitions.Num();
    988 	bool clear = true;
    989 
    990 	for ( i = 0; i < c; i++ ) {
    991 		idTransitionData *data = &transitions[i];
    992 		idWinRectangle *r = NULL;
    993 		idWinVec4 *v4 = dynamic_cast<idWinVec4*>(data->data);
    994 		idWinFloat* val = NULL;
    995 		if (v4 == NULL) {
    996 			r = dynamic_cast<idWinRectangle*>(data->data);
    997 			if ( r == NULL ) {
    998 				val = dynamic_cast<idWinFloat*>(data->data);
    999 			}
   1000 		}
   1001 		if ( data->interp.IsDone( gui->GetTime() ) && data->data) {
   1002 			if (v4) {
   1003 				*v4 = data->interp.GetEndValue();
   1004 			} else if ( val ) {
   1005 				*val = data->interp.GetEndValue()[0];
   1006 			} else if ( r != NULL ) {
   1007 				*r = data->interp.GetEndValue();
   1008 			}
   1009 		} else {
   1010 			clear = false;
   1011 			if (data->data) {
   1012 				if (v4) {
   1013 					*v4 = data->interp.GetCurrentValue( gui->GetTime() );
   1014 				} else if ( val ) {
   1015 					*val = data->interp.GetCurrentValue( gui->GetTime() )[0];
   1016 				} else if ( r != NULL ) {
   1017 					*r = data->interp.GetCurrentValue( gui->GetTime() );
   1018 				}
   1019 			} else {
   1020 				common->Warning("Invalid transitional data for window %s in gui %s", GetName(), gui->GetSourceFile());
   1021 			}
   1022 		}
   1023 	}
   1024 
   1025 	if ( clear ) {
   1026 		transitions.SetNum( 0 );
   1027 		flags &= ~WIN_INTRANSITION;
   1028 	}
   1029 }
   1030 
   1031 /*
   1032 ================
   1033 idWindow::Time
   1034 ================
   1035 */
   1036 void idWindow::Time() {
   1037 	
   1038 	if ( noTime ) {
   1039 		return;
   1040 	}
   1041 
   1042 	if ( timeLine == -1 ) {
   1043 		timeLine = gui->GetTime();
   1044 	}
   1045 
   1046 	cmd = "";
   1047 
   1048 	int c = timeLineEvents.Num();
   1049 	if ( c > 0 ) {
   1050 		for (int i = 0; i < c; i++) {
   1051 			if ( timeLineEvents[i]->pending && gui->GetTime() - timeLine >= timeLineEvents[i]->time ) {
   1052 				timeLineEvents[i]->pending = false;
   1053 				RunScriptList( timeLineEvents[i]->event );
   1054 			}
   1055 		}
   1056 	}
   1057 
   1058 	if ( gui->Active() ) {
   1059 		if ( gui->GetPendingCmd().Length() > 0 ) {
   1060 			gui->GetPendingCmd() += ";";
   1061 		}
   1062 		gui->GetPendingCmd() += cmd;
   1063 	}
   1064 }
   1065 
   1066 /*
   1067 ================
   1068 idWindow::EvalRegs
   1069 ================
   1070 */
   1071 float idWindow::EvalRegs(int test, bool force) {
   1072 	static float regs[MAX_EXPRESSION_REGISTERS];
   1073 	static idWindow *lastEval = NULL;
   1074 
   1075 	if (!force && test >= 0 && test < MAX_EXPRESSION_REGISTERS && lastEval == this) {
   1076 		return regs[test];
   1077 	}
   1078 
   1079 	lastEval = this;
   1080 
   1081 	if (expressionRegisters.Num()) {
   1082 		regList.SetToRegs(regs);
   1083 		EvaluateRegisters(regs);
   1084 		regList.GetFromRegs(regs);
   1085 	}
   1086 
   1087 	if (test >= 0 && test < MAX_EXPRESSION_REGISTERS) {
   1088 		return regs[test];
   1089 	}
   1090 
   1091 	return 0.0;
   1092 }
   1093 
   1094 /*
   1095 ================
   1096 idWindow::DrawBackground
   1097 ================
   1098 */
   1099 void idWindow::DrawBackground(const idRectangle &drawRect) {
   1100 	if ( backColor.w() ) {
   1101 		dc->DrawFilledRect(drawRect.x, drawRect.y, drawRect.w, drawRect.h, backColor);
   1102 	}
   1103 
   1104 	if ( background && matColor.w() ) {
   1105 		float scalex, scaley;
   1106 		if ( flags & WIN_NATURALMAT ) {
   1107 			scalex = drawRect.w / background->GetImageWidth();
   1108 			scaley = drawRect.h / background->GetImageHeight();
   1109 		} else {
   1110 			scalex = matScalex;
   1111 			scaley = matScaley;
   1112 		}
   1113 		dc->DrawMaterial(drawRect.x, drawRect.y, drawRect.w, drawRect.h, background, matColor, scalex, scaley);
   1114 	}
   1115 }
   1116 
   1117 /*
   1118 ================
   1119 idWindow::DrawBorderAndCaption
   1120 ================
   1121 */
   1122 void idWindow::DrawBorderAndCaption(const idRectangle &drawRect) {
   1123 	if ( flags & WIN_BORDER && borderSize && borderColor.w() ) {
   1124 		dc->DrawRect(drawRect.x, drawRect.y, drawRect.w, drawRect.h, borderSize, borderColor);
   1125 	}
   1126 }
   1127 
   1128 /*
   1129 ================
   1130 idWindow::SetupTransforms
   1131 ================
   1132 */
   1133 void idWindow::SetupTransforms(float x, float y) {
   1134 	static idMat3 trans;
   1135 	static idVec3 org;
   1136 	
   1137 	trans.Identity();
   1138 	org.Set( origin.x + x, origin.y + y, 0 );
   1139 
   1140 	if ( rotate ) {
   1141 		static idRotation rot;
   1142 		static idVec3 vec(0, 0, 1);
   1143 		rot.Set( org, vec, rotate );
   1144 		trans = rot.ToMat3();
   1145 	}
   1146 
   1147 	if ( shear.x || shear.y ) {
   1148 		static idMat3 smat;
   1149 		smat.Identity();
   1150 		smat[0][1] = shear.x;
   1151 		smat[1][0] = shear.y;
   1152 		trans *= smat;
   1153 	}
   1154 
   1155 	if ( !trans.IsIdentity() ) {
   1156 		dc->SetTransformInfo( org, trans );
   1157 	}
   1158 }
   1159 
   1160 /*
   1161 ================
   1162 idWindow::CalcRects
   1163 ================
   1164 */
   1165 void idWindow::CalcRects(float x, float y) {
   1166 	CalcClientRect(0, 0);
   1167 	drawRect.Offset(x, y);
   1168 	clientRect.Offset(x, y);
   1169 	actualX = drawRect.x;
   1170 	actualY = drawRect.y;
   1171 	int c = drawWindows.Num();
   1172 	for (int i = 0; i < c; i++) {
   1173 		if (drawWindows[i].win) {
   1174 			drawWindows[i].win->CalcRects(clientRect.x + xOffset, clientRect.y + yOffset);
   1175 		}
   1176 	}
   1177 	drawRect.Offset(-x, -y);
   1178 	clientRect.Offset(-x, -y);
   1179 }
   1180 
   1181 /*
   1182 ================
   1183 idWindow::Redraw
   1184 ================
   1185 */
   1186 void idWindow::Redraw(float x, float y, bool hud) {
   1187 	idStr str;
   1188 
   1189 	if (r_skipGuiShaders.GetInteger() == 1 || dc == NULL ) {
   1190 		return;
   1191 	}
   1192 	
   1193 	int time = gui->GetTime();
   1194 
   1195 	if ( flags & WIN_DESKTOP && r_skipGuiShaders.GetInteger() != 3 ) {
   1196 		RunTimeEvents( time );
   1197 	}
   1198 
   1199 	if ( r_skipGuiShaders.GetInteger() == 2 ) {
   1200 		return;
   1201 	}
   1202 
   1203 	if ( flags & WIN_SHOWTIME ) {
   1204 		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);
   1205 	}
   1206 
   1207 	if ( flags & WIN_SHOWCOORDS ) {
   1208 		dc->EnableClipping(false);
   1209 		sprintf(str, "x: %i y: %i  cursorx: %i cursory: %i", (int)rect.x(), (int)rect.y(), (int)gui->CursorX(), (int)gui->CursorY());
   1210 		dc->DrawText(str, 0.25f, 0, dc->colorWhite, idRectangle(0, 0, 100, 20), false);
   1211 		dc->EnableClipping(true);
   1212 	}
   1213 
   1214 	if (!visible) {
   1215 		return;
   1216 	}
   1217 
   1218 	CalcClientRect(0, 0);
   1219 
   1220 	SetFont();
   1221 
   1222 	if ( hud ) {
   1223 		float tileSafeOffset = hud_titlesafe.GetFloat();
   1224 		float tileSafeScale = 1.0f / ( 1.0f - hud_titlesafe.GetFloat() * 2.0f );
   1225 		dc->SetSize( forceAspectWidth * tileSafeScale, forceAspectHeight * tileSafeScale );
   1226 		dc->SetOffset( forceAspectWidth * tileSafeOffset, forceAspectHeight * tileSafeOffset );
   1227 	} else {
   1228 		dc->SetSize( forceAspectWidth, forceAspectHeight );
   1229 		dc->SetOffset( 0.0f, 0.0f );
   1230 	}
   1231 
   1232 	//FIXME: go to screen coord tracking
   1233 	drawRect.Offset(x, y);
   1234 	clientRect.Offset(x, y);
   1235 	textRect.Offset(x, y);
   1236 	actualX = drawRect.x;
   1237 	actualY = drawRect.y;
   1238 
   1239 	idVec3	oldOrg;
   1240 	idMat3	oldTrans;
   1241 		
   1242 	dc->GetTransformInfo( oldOrg, oldTrans );
   1243 
   1244 	SetupTransforms(x, y);
   1245 	DrawBackground(drawRect);
   1246 	DrawBorderAndCaption(drawRect);
   1247 
   1248 	if ( !( flags & WIN_NOCLIP) ) {
   1249 		dc->PushClipRect(clientRect);
   1250 	} 
   1251 
   1252 	if ( r_skipGuiShaders.GetInteger() < 5 ) {
   1253 		Draw(time, x, y);
   1254 	}
   1255 
   1256 	if ( gui_debug.GetInteger() ) {
   1257 		DebugDraw(time, x, y);
   1258 	}
   1259 
   1260 	int c = drawWindows.Num();
   1261 	for ( int i = 0; i < c; i++ ) {
   1262 		if ( drawWindows[i].win ) {
   1263 			drawWindows[i].win->Redraw( clientRect.x + xOffset, clientRect.y + yOffset, hud );
   1264 		} else {
   1265 			drawWindows[i].simp->Redraw( clientRect.x + xOffset, clientRect.y + yOffset );
   1266 		}
   1267 	}
   1268 
   1269 	// Put transforms back to what they were before the children were processed
   1270 	dc->SetTransformInfo(oldOrg, oldTrans);
   1271 
   1272 	if ( ! ( flags & WIN_NOCLIP ) ) {
   1273 		dc->PopClipRect();
   1274 	} 
   1275 
   1276 	if (gui_edit.GetBool()  || (flags & WIN_DESKTOP && !( flags & WIN_NOCURSOR )  && !hideCursor && (gui->Active() || ( flags & WIN_MENUGUI ) ))) {
   1277 		dc->SetTransformInfo(vec3_origin, mat3_identity);
   1278 		gui->DrawCursor();
   1279 	}
   1280 
   1281 	if (gui_debug.GetInteger() && flags & WIN_DESKTOP) {
   1282 		dc->EnableClipping(false);
   1283 		sprintf(str, "x: %1.f y: %1.f",  gui->CursorX(), gui->CursorY());
   1284 		dc->DrawText(str, 0.25, 0, dc->colorWhite, idRectangle(0, 0, 100, 20), false);
   1285 		dc->DrawText(gui->GetSourceFile(), 0.25, 0, dc->colorWhite, idRectangle(0, 20, 300, 20), false);
   1286 		dc->EnableClipping(true);
   1287 	}
   1288 
   1289 	drawRect.Offset(-x, -y);
   1290 	clientRect.Offset(-x, -y);
   1291 	textRect.Offset(-x, -y);
   1292 }
   1293 
   1294 /*
   1295 ================
   1296 idWindow::ArchiveToDictionary
   1297 ================
   1298 */
   1299 void idWindow::ArchiveToDictionary(idDict *dict, bool useNames) {
   1300 	//FIXME: rewrite without state
   1301 	int c = children.Num();
   1302 	for (int i = 0; i < c; i++) {
   1303 		children[i]->ArchiveToDictionary(dict);
   1304 	}
   1305 }
   1306 
   1307 /*
   1308 ================
   1309 idWindow::InitFromDictionary
   1310 ================
   1311 */
   1312 void idWindow::InitFromDictionary(idDict *dict, bool byName) {
   1313 	//FIXME: rewrite without state
   1314 	int c = children.Num();
   1315 	for (int i = 0; i < c; i++) {
   1316 		children[i]->InitFromDictionary(dict);
   1317 	}
   1318 }
   1319 
   1320 /*
   1321 ================
   1322 idWindow::CalcClientRect
   1323 ================
   1324 */
   1325 void idWindow::CalcClientRect(float xofs, float yofs) {
   1326 	drawRect = rect;
   1327 
   1328 	if ( flags & WIN_INVERTRECT ) {
   1329 		drawRect.x = rect.x() - rect.w();
   1330 		drawRect.y = rect.y() - rect.h();
   1331 	}
   1332 	
   1333 	if (flags & (WIN_HCENTER | WIN_VCENTER) && parent) {
   1334 		// in this case treat xofs and yofs as absolute top left coords
   1335 		// and ignore the original positioning
   1336 		if (flags & WIN_HCENTER) {
   1337 			drawRect.x = (parent->rect.w() - rect.w()) / 2;
   1338 		} else {
   1339 			drawRect.y = (parent->rect.h() - rect.h()) / 2;
   1340 		}
   1341 	}
   1342 
   1343 	drawRect.x += xofs;
   1344 	drawRect.y += yofs;
   1345 
   1346 	clientRect = drawRect;
   1347 	if (rect.h() > 0.0 && rect.w() > 0.0) {
   1348 
   1349 		if (flags & WIN_BORDER && borderSize != 0.0) {
   1350 			clientRect.x += borderSize;
   1351 			clientRect.y += borderSize;
   1352 			clientRect.w -= borderSize;
   1353 			clientRect.h -= borderSize;
   1354 		}
   1355 
   1356 		textRect = clientRect;
   1357 		textRect.x += 2.0;
   1358 	 	textRect.w -= 2.0;
   1359 		textRect.y += 2.0;
   1360 		textRect.h -= 2.0;
   1361 
   1362 		textRect.x += textAlignx;
   1363 		textRect.y += textAligny;
   1364 
   1365 	}
   1366 	origin.Set( rect.x() + (rect.w() / 2 ), rect.y() + ( rect.h() / 2 ) );
   1367 
   1368 }
   1369 
   1370 /*
   1371 ================
   1372 idWindow::SetupBackground
   1373 ================
   1374 */
   1375 void idWindow::SetupBackground() {
   1376 	if (backGroundName.Length()) {
   1377 		background = declManager->FindMaterial(backGroundName);
   1378 		if ( background != NULL && !background->TestMaterialFlag( MF_DEFAULTED ) ) {
   1379 			background->SetSort(SS_GUI );
   1380 		}
   1381 	}
   1382 	backGroundName.SetMaterialPtr(&background);
   1383 }
   1384 
   1385 /*
   1386 ================
   1387 idWindow::SetupFromState
   1388 ================
   1389 */
   1390 void idWindow::SetupFromState() {
   1391 	idStr str;
   1392 	background = NULL;
   1393 
   1394 	SetupBackground();
   1395 
   1396 	if (borderSize) {
   1397 		flags |= WIN_BORDER;
   1398 	}
   1399 
   1400 	if (regList.FindReg("rotate") || regList.FindReg("shear")) {
   1401 		flags |= WIN_TRANSFORM;
   1402 	}
   1403 	
   1404 	CalcClientRect(0,0);
   1405 	if ( scripts[ ON_ACTION ] ) {
   1406 		cursor = idDeviceContext::CURSOR_HAND;
   1407 		flags |= WIN_CANFOCUS;
   1408 	}
   1409 }
   1410 
   1411 /*
   1412 ================
   1413 idWindow::Moved
   1414 ================
   1415 */
   1416 void idWindow::Moved() {
   1417 }
   1418 
   1419 /*
   1420 ================
   1421 idWindow::Sized
   1422 ================
   1423 */
   1424 void idWindow::Sized() {
   1425 }
   1426 
   1427 /*
   1428 ================
   1429 idWindow::GainFocus
   1430 ================
   1431 */
   1432 void idWindow::GainFocus() {
   1433 }
   1434 
   1435 /*
   1436 ================
   1437 idWindow::LoseFocus
   1438 ================
   1439 */
   1440 void idWindow::LoseFocus() {
   1441 }
   1442 
   1443 /*
   1444 ================
   1445 idWindow::GainCapture
   1446 ================
   1447 */
   1448 void idWindow::GainCapture() {
   1449 }
   1450 
   1451 /*
   1452 ================
   1453 idWindow::LoseCapture
   1454 ================
   1455 */
   1456 void idWindow::LoseCapture() {
   1457 	flags &= ~WIN_CAPTURE;
   1458 }
   1459 
   1460 /*
   1461 ================
   1462 idWindow::SetFlag
   1463 ================
   1464 */
   1465 void idWindow::SetFlag(unsigned int f) {
   1466 	flags |= f;
   1467 }
   1468 
   1469 /*
   1470 ================
   1471 idWindow::ClearFlag
   1472 ================
   1473 */
   1474 void idWindow::ClearFlag(unsigned int f) {
   1475 	flags &= ~f;
   1476 }
   1477 
   1478 
   1479 /*
   1480 ================
   1481 idWindow::SetParent
   1482 ================
   1483 */
   1484 void idWindow::SetParent(idWindow *w) {
   1485 	parent = w;
   1486 }
   1487 
   1488 /*
   1489 ================
   1490 idWindow::GetCaptureChild
   1491 ================
   1492 */
   1493 idWindow *idWindow::GetCaptureChild() {
   1494 	if (flags & WIN_DESKTOP) {
   1495 		return gui->GetDesktop()->captureChild;
   1496 	}
   1497 	return NULL;
   1498 }
   1499 
   1500 /*
   1501 ================
   1502 idWindow::GetFocusedChild
   1503 ================
   1504 */
   1505 idWindow *idWindow::GetFocusedChild() {
   1506 	if (flags & WIN_DESKTOP) {
   1507 		return gui->GetDesktop()->focusedChild;
   1508 	}
   1509 	return NULL;
   1510 }
   1511 
   1512 
   1513 /*
   1514 ================
   1515 idWindow::SetFocus
   1516 ================
   1517 */
   1518 idWindow *idWindow::SetFocus(idWindow *w, bool scripts) {
   1519 	// only one child can have the focus
   1520 	idWindow *lastFocus = NULL;
   1521 	if (w->flags & WIN_CANFOCUS) {
   1522 		lastFocus = gui->GetDesktop()->focusedChild;
   1523 		if ( lastFocus ) {
   1524 			lastFocus->flags &= ~WIN_FOCUS;
   1525 			lastFocus->LoseFocus();
   1526 		}
   1527 
   1528 		//  call on lose focus
   1529 		if ( scripts && lastFocus ) {
   1530 			// calling this broke all sorts of guis
   1531 			// lastFocus->RunScript(ON_MOUSEEXIT);
   1532 		}
   1533 		//  call on gain focus
   1534 		if ( scripts && w ) {
   1535 			// calling this broke all sorts of guis
   1536 			// w->RunScript(ON_MOUSEENTER);
   1537 		}
   1538 
   1539 		w->flags |= WIN_FOCUS;
   1540 		w->GainFocus();
   1541 		gui->GetDesktop()->focusedChild = w;
   1542 	}
   1543 
   1544 	return lastFocus;
   1545 }
   1546 
   1547 /*
   1548 ================
   1549 idWindow::ParseScript
   1550 ================
   1551 */
   1552 bool idWindow::ParseScript(idTokenParser *src, idGuiScriptList &list, int *timeParm, bool elseBlock ) {
   1553 
   1554 	bool	ifElseBlock = false;
   1555 
   1556 	idToken token;
   1557 
   1558 	// scripts start with { ( unless parm is true ) and have ; separated command lists.. commands are command,
   1559 	// arg.. basically we want everything between the { } as it will be interpreted at
   1560 	// run time
   1561 	
   1562 	if ( elseBlock ) {
   1563 		src->ReadToken ( &token );
   1564 	
   1565 		if ( !token.Icmp ( "if" ) ) {
   1566 			ifElseBlock = true;
   1567 		}
   1568 		
   1569 		src->UnreadToken ( &token );
   1570 
   1571 		if ( !ifElseBlock && !src->ExpectTokenString( "{" ) ) {
   1572 			return false;
   1573 		}
   1574 	}
   1575 	else if ( !src->ExpectTokenString( "{" ) ) {
   1576 		return false;
   1577 	}
   1578 
   1579 	int nest = 0;
   1580 
   1581 	while (1) {
   1582 		if ( !src->ReadToken(&token) ) {
   1583 			src->Error( "Unexpected end of file" );
   1584 			return false;
   1585 		}
   1586 
   1587 		if ( token == "{" ) {
   1588 			nest++;
   1589 		}
   1590 
   1591 		if ( token == "}" ) {
   1592 			if (nest-- <= 0) {
   1593 				return true;
   1594 			}
   1595 		}
   1596 
   1597 		idGuiScript *gs = new (TAG_OLD_UI) idGuiScript();
   1598 		if (token.Icmp("if") == 0) {
   1599 			gs->conditionReg = ParseExpression(src);
   1600 			gs->ifList = new (TAG_OLD_UI) idGuiScriptList();
   1601 			ParseScript(src, *gs->ifList, NULL);
   1602 			if (src->ReadToken(&token)) {
   1603 				if (token == "else") {
   1604 					gs->elseList = new (TAG_OLD_UI) idGuiScriptList();
   1605 					// pass true to indicate we are parsing an else condition
   1606 					ParseScript(src, *gs->elseList, NULL, true );
   1607 				} else {
   1608 					src->UnreadToken(&token);
   1609 				}
   1610 			}
   1611 
   1612 			list.Append(gs);
   1613 
   1614 			// if we are parsing an else if then return out so 
   1615 			// the initial "if" parser can handle the rest of the tokens
   1616 			if ( ifElseBlock ) {
   1617 				return true;
   1618 			}
   1619 			continue;
   1620 		} else {
   1621 			src->UnreadToken(&token);
   1622 		}
   1623 
   1624 		// empty { } is not allowed
   1625 		if ( token == "{" ) {
   1626 			 src->Error ( "Unexpected {" );
   1627 			 delete gs;
   1628 			 return false;
   1629 		}
   1630 
   1631 		gs->Parse(src);
   1632 		list.Append(gs);
   1633 	}
   1634 
   1635 }
   1636 
   1637 /*
   1638 ================
   1639 idWindow::SaveExpressionParseState
   1640 ================
   1641 */
   1642 void idWindow::SaveExpressionParseState() {
   1643 	saveTemps = (bool*)Mem_Alloc(MAX_EXPRESSION_REGISTERS * sizeof(bool), TAG_CRAP);
   1644 	memcpy(saveTemps, registerIsTemporary, MAX_EXPRESSION_REGISTERS * sizeof(bool));
   1645 }
   1646 
   1647 /*
   1648 ================
   1649 idWindow::RestoreExpressionParseState
   1650 ================
   1651 */
   1652 void idWindow::RestoreExpressionParseState() {
   1653 	memcpy(registerIsTemporary, saveTemps, MAX_EXPRESSION_REGISTERS * sizeof(bool));
   1654 	Mem_Free(saveTemps);
   1655 }
   1656 
   1657 /*
   1658 ================
   1659 idWindow::ParseScriptEntry
   1660 ================
   1661 */
   1662 bool idWindow::ParseScriptEntry(const char *name, idTokenParser *src) {
   1663 	for (int i = 0; i < SCRIPT_COUNT; i++) {
   1664 		if (idStr::Icmp(name, ScriptNames[i]) == 0) {
   1665 			delete scripts[i];
   1666 			scripts[i] = new (TAG_OLD_UI) idGuiScriptList;
   1667 			return ParseScript(src, *scripts[i]);
   1668 		}
   1669 	}
   1670 	return false;
   1671 }
   1672 
   1673 /*
   1674 ================
   1675 idWindow::DisableRegister
   1676 ================
   1677 */
   1678 void idWindow::DisableRegister(const char *_name) {
   1679 	idRegister *reg = RegList()->FindReg(_name);
   1680 	if (reg) {
   1681 		reg->Enable(false);
   1682 	}
   1683 }
   1684 
   1685 /*
   1686 ================================
   1687 idSort_TimeLine
   1688 ================================
   1689 */
   1690 class idSort_TimeLine : public idSort_Quick< idTimeLineEvent *, idSort_TimeLine > {
   1691 public:
   1692 	int Compare( idTimeLineEvent * const & a, idTimeLineEvent * const & b ) const {
   1693 		return a->time - b->time;
   1694 	}
   1695 };
   1696 
   1697 /*
   1698 ================
   1699 idWindow::PostParse
   1700 ================
   1701 */
   1702 void idWindow::PostParse() {
   1703 	// Sort timeline events
   1704 	idSort_TimeLine sorter;
   1705 	timeLineEvents.SortWithTemplate( sorter );
   1706 }
   1707 	
   1708 /*
   1709 ================
   1710 idWindow::GetWinVarOffset
   1711 ================
   1712 */
   1713 int idWindow::GetWinVarOffset( idWinVar *wv, drawWin_t* owner) {
   1714 	int ret = -1;
   1715 
   1716 	if ( wv == &rect ) {
   1717 		ret = (int)&( ( idWindow * ) 0 )->rect;
   1718 	}
   1719 
   1720 	if ( wv == &backColor ) {
   1721 		ret = (int)&( ( idWindow * ) 0 )->backColor;
   1722 	}
   1723 
   1724 	if ( wv == &matColor ) {
   1725 		ret = (int)&( ( idWindow * ) 0 )->matColor;
   1726 	}
   1727 
   1728 	if ( wv == &foreColor ) {
   1729 		ret = (int)&( ( idWindow * ) 0 )->foreColor;
   1730 	}
   1731 
   1732 	if ( wv == &hoverColor ) {
   1733 		ret = (int)&( ( idWindow * ) 0 )->hoverColor;
   1734 	}
   1735 
   1736 	if ( wv == &borderColor ) {
   1737 		ret = (int)&( ( idWindow * ) 0 )->borderColor;
   1738 	}
   1739 
   1740 	if ( wv == &textScale ) {
   1741 		ret = (int)&( ( idWindow * ) 0 )->textScale;
   1742 	}
   1743 
   1744 	if ( wv == &rotate ) {
   1745 		ret = (int)&( ( idWindow * ) 0 )->rotate;
   1746 	}
   1747 
   1748 	if ( ret != -1 ) {
   1749 		owner->win = this;
   1750 		return ret;
   1751 	}
   1752 
   1753 	for ( int i = 0; i < drawWindows.Num(); i++ ) {
   1754 		if ( drawWindows[i].win ) {
   1755 			ret = drawWindows[i].win->GetWinVarOffset( wv, owner );
   1756 		} else {
   1757 			ret = drawWindows[i].simp->GetWinVarOffset( wv, owner );
   1758 		}
   1759 		if ( ret != -1 ) {
   1760 			break;
   1761 		}
   1762 	}
   1763 
   1764 	return ret;
   1765 }
   1766 
   1767 /*
   1768 ================
   1769 idWindow::GetWinVarByName
   1770 ================
   1771 */
   1772 idWinVar *idWindow::GetWinVarByName(const char *_name, bool fixup, drawWin_t** owner) {
   1773 	idWinVar *retVar = NULL;
   1774 
   1775 	if ( owner ) {
   1776 		*owner = NULL;
   1777 	}
   1778 
   1779 	if (idStr::Icmp(_name, "notime") == 0) {
   1780 		retVar = &noTime;
   1781 	}
   1782 	if (idStr::Icmp(_name, "background") == 0) {
   1783 		retVar = &backGroundName;
   1784 	}
   1785 	if (idStr::Icmp(_name, "visible") == 0) {
   1786 		retVar = &visible;
   1787 	}
   1788 	if (idStr::Icmp(_name, "rect") == 0) {
   1789 		retVar = &rect;
   1790 	}
   1791 	if (idStr::Icmp(_name, "backColor") == 0) {
   1792 		retVar = &backColor;
   1793 	}
   1794 	if (idStr::Icmp(_name, "matColor") == 0) {
   1795 		retVar = &matColor;
   1796 	}
   1797 	if (idStr::Icmp(_name, "foreColor") == 0) {
   1798 		retVar = &foreColor;
   1799 	}
   1800 	if (idStr::Icmp(_name, "hoverColor") == 0) {
   1801 		retVar = &hoverColor;
   1802 	}
   1803 	if (idStr::Icmp(_name, "borderColor") == 0) {
   1804 		retVar = &borderColor;
   1805 	}
   1806 	if (idStr::Icmp(_name, "textScale") == 0) {
   1807 		retVar = &textScale;
   1808 	}
   1809 	if (idStr::Icmp(_name, "rotate") == 0) {
   1810 		retVar = &rotate;
   1811 	}
   1812 	if (idStr::Icmp(_name, "noEvents") == 0) {
   1813 		retVar = &noEvents;
   1814 	}
   1815 	if (idStr::Icmp(_name, "text") == 0) {
   1816 		retVar = &text;
   1817 	}
   1818 	if (idStr::Icmp(_name, "backGroundName") == 0) {
   1819 		retVar = &backGroundName;
   1820 	}
   1821 	if (idStr::Icmp(_name, "hidecursor") == 0) {
   1822 		retVar = &hideCursor;
   1823 	}
   1824 
   1825 	idStr key = _name;
   1826 	bool guiVar = (key.Find(VAR_GUIPREFIX) >= 0);
   1827 	int c = definedVars.Num();
   1828 	for (int i = 0; i < c; i++) {
   1829 		if (idStr::Icmp(_name, (guiVar) ? va("%s",definedVars[i]->GetName()) : definedVars[i]->GetName()) == 0) {
   1830 			retVar = definedVars[i];
   1831 			break;
   1832 		}
   1833 	}
   1834 
   1835 	if (retVar) {
   1836 		if (fixup && *_name != '$') {
   1837 			DisableRegister(_name);
   1838 		}
   1839 
   1840 		if ( owner && parent ) {
   1841 			*owner = parent->FindChildByName ( name );
   1842 		}
   1843 
   1844 		return retVar;
   1845 	}
   1846 
   1847 	int len = key.Length();
   1848 	if ( len > 5 && guiVar ) {
   1849 		idWinVar *var = new (TAG_OLD_UI) idWinStr;
   1850 		var->Init(_name, this);
   1851 		definedVars.Append(var);
   1852 		return var;
   1853 	} else if (fixup) {
   1854 		int n = key.Find("::");
   1855 		if (n > 0) {
   1856 			idStr winName = key.Left(n);
   1857 			idStr var = key.Right(key.Length() - n - 2);
   1858 			drawWin_t *win = GetGui()->GetDesktop()->FindChildByName(winName);
   1859 			if (win) {
   1860 				if (win->win) {
   1861 					return win->win->GetWinVarByName(var, false, owner);
   1862 				} else {
   1863 					if ( owner ) {
   1864 						*owner = win;
   1865 					}
   1866 					return win->simp->GetWinVarByName(var);
   1867 				}
   1868 			} 
   1869 		}
   1870 	}
   1871 	return NULL;
   1872 }
   1873 
   1874 /*
   1875 ================
   1876 idWindow::ParseString
   1877 ================
   1878 */
   1879 void idWindow::ParseString(idTokenParser *src, idStr &out) {
   1880 	idToken tok;
   1881 	if (src->ReadToken(&tok)) {
   1882 		out = tok;
   1883 	}
   1884 }
   1885 
   1886 /*
   1887 ================
   1888 idWindow::ParseVec4
   1889 ================
   1890 */
   1891 void idWindow::ParseVec4(idTokenParser *src, idVec4 &out) {
   1892 	idToken tok;
   1893 	src->ReadToken(&tok);
   1894 	out.x = atof(tok);
   1895 	src->ExpectTokenString(",");
   1896 	src->ReadToken(&tok);
   1897 	out.y = atof(tok);
   1898 	src->ExpectTokenString(",");
   1899 	src->ReadToken(&tok);
   1900 	out.z = atof(tok);
   1901 	src->ExpectTokenString(",");
   1902 	src->ReadToken(&tok);
   1903 	out.w = atof(tok);
   1904 }
   1905 
   1906 /*
   1907 ================
   1908 idWindow::ParseInternalVar
   1909 ================
   1910 */
   1911 bool idWindow::ParseInternalVar(const char *_name, idTokenParser *src) {
   1912 
   1913 	if (idStr::Icmp(_name, "showtime") == 0) {
   1914 		if ( src->ParseBool() ) {
   1915 			flags |= WIN_SHOWTIME;
   1916 		}
   1917 		return true;
   1918 	}
   1919 	if (idStr::Icmp(_name, "showcoords") == 0) {
   1920 		if ( src->ParseBool() ) {
   1921 			flags |= WIN_SHOWCOORDS;
   1922 		}
   1923 		return true;
   1924 	}
   1925 	if (idStr::Icmp(_name, "forceaspectwidth") == 0) {
   1926 		forceAspectWidth = src->ParseFloat();
   1927 		return true;
   1928 	}
   1929 	if (idStr::Icmp(_name, "forceaspectheight") == 0) {
   1930 		forceAspectHeight = src->ParseFloat();
   1931 		return true;
   1932 	}
   1933 	if (idStr::Icmp(_name, "matscalex") == 0) {
   1934 		matScalex = src->ParseFloat();
   1935 		return true;
   1936 	}
   1937 	if (idStr::Icmp(_name, "matscaley") == 0) {
   1938 		matScaley = src->ParseFloat();
   1939 		return true;
   1940 	}
   1941 	if (idStr::Icmp(_name, "bordersize") == 0) {
   1942 		borderSize = src->ParseFloat();
   1943 		return true;
   1944 	}
   1945 	if (idStr::Icmp(_name, "nowrap") == 0) {
   1946 		if ( src->ParseBool() ) {
   1947 			flags |= WIN_NOWRAP;
   1948 		}
   1949 		return true;
   1950 	}
   1951 	if (idStr::Icmp(_name, "shadow") == 0) {
   1952 		textShadow = src->ParseInt();
   1953 		return true;
   1954 	}
   1955 	if (idStr::Icmp(_name, "textalign") == 0) {
   1956 		textAlign = src->ParseInt();
   1957 		return true;
   1958 	}
   1959 	if (idStr::Icmp(_name, "textalignx") == 0) {
   1960 		textAlignx = src->ParseFloat();
   1961 		return true;
   1962 	}
   1963 	if (idStr::Icmp(_name, "textaligny") == 0) {
   1964 		textAligny = src->ParseFloat();
   1965 		return true;
   1966 	}
   1967 	if (idStr::Icmp(_name, "shear") == 0) {
   1968 		shear.x = src->ParseFloat();
   1969 		idToken tok;
   1970 		src->ReadToken( &tok );
   1971 		if ( tok.Icmp( "," ) ) {
   1972 			src->Error( "Expected comma in shear definiation" );
   1973 			return false;
   1974 		}
   1975 		shear.y = src->ParseFloat();
   1976 		return true;
   1977 	}
   1978 	if (idStr::Icmp(_name, "wantenter") == 0) {
   1979 		if ( src->ParseBool() ) {
   1980 			flags |= WIN_WANTENTER;
   1981 		}
   1982 		return true;
   1983 	}
   1984 	if (idStr::Icmp(_name, "naturalmatscale") == 0) {
   1985 		if ( src->ParseBool() ) {
   1986 			flags |= WIN_NATURALMAT;
   1987 		}
   1988 		return true;
   1989 	}
   1990 	if (idStr::Icmp(_name, "noclip") == 0) {
   1991 		if ( src->ParseBool() ) {
   1992 			flags |= WIN_NOCLIP;
   1993 		}
   1994 		return true;
   1995 	}
   1996 	if (idStr::Icmp(_name, "nocursor") == 0) {
   1997 		if ( src->ParseBool() ) {
   1998 			flags |= WIN_NOCURSOR;
   1999 		}
   2000 		return true;
   2001 	}
   2002 	if (idStr::Icmp(_name, "menugui") == 0) {
   2003 		if ( src->ParseBool() ) {
   2004 			flags |= WIN_MENUGUI;
   2005 		}
   2006 		return true;
   2007 	}
   2008 	if (idStr::Icmp(_name, "modal") == 0) {
   2009 		if ( src->ParseBool() ) {
   2010 			flags |= WIN_MODAL;
   2011 		}
   2012 		return true;
   2013 	}
   2014 	if (idStr::Icmp(_name, "invertrect") == 0) {
   2015 		if ( src->ParseBool() ) {
   2016 			flags |= WIN_INVERTRECT;
   2017 		}
   2018 		return true;
   2019 	}
   2020 	if (idStr::Icmp(_name, "name") == 0) {
   2021 		ParseString(src, name);
   2022 		return true;
   2023 	}
   2024 	if (idStr::Icmp(_name, "play") == 0) {
   2025 		common->Warning( "play encountered during gui parse.. see Robert\n" );
   2026 		idStr playStr;
   2027 		ParseString(src, playStr);
   2028 		return true;
   2029 	}
   2030 	if (idStr::Icmp(_name, "comment") == 0) {
   2031 		ParseString(src, comment);
   2032 		return true;
   2033 	}
   2034 	if ( idStr::Icmp( _name, "font" ) == 0 ) {
   2035 		idStr fontName;
   2036 		ParseString( src, fontName );
   2037 		font = renderSystem->RegisterFont( fontName );
   2038 		return true;
   2039 	}
   2040 	return false;
   2041 }
   2042 
   2043 /*
   2044 ================
   2045 idWindow::ParseRegEntry
   2046 ================
   2047 */
   2048 bool idWindow::ParseRegEntry(const char *name, idTokenParser *src) {
   2049 	idStr work;
   2050 	work = name;
   2051 	work.ToLower();
   2052 
   2053 	idWinVar *var = GetWinVarByName(work, NULL);
   2054 	if ( var ) {
   2055 		for (int i = 0; i < NumRegisterVars; i++) {
   2056 			if (idStr::Icmp(work, RegisterVars[i].name) == 0) {
   2057 				regList.AddReg(work, RegisterVars[i].type, src, this, var);
   2058 				return true;
   2059 			}
   2060 		}
   2061 	}
   2062 
   2063 	// not predefined so just read the next token and add it to the state
   2064 	idToken tok;
   2065 	idVec4 v;	
   2066 	idWinInt *vari;
   2067 	idWinFloat *varf;
   2068 	idWinStr *vars;
   2069 	if (src->ReadToken(&tok)) {
   2070 		if (var) {
   2071 			var->Set(tok);
   2072 			return true;
   2073 		}
   2074 		switch (tok.type) {
   2075 			case TT_NUMBER : 
   2076 				if (tok.subtype & TT_INTEGER) {
   2077 					vari = new (TAG_OLD_UI) idWinInt();
   2078 					*vari = atoi(tok);
   2079 					vari->SetName(work);
   2080 					definedVars.Append(vari);
   2081 				} else if (tok.subtype & TT_FLOAT) {
   2082 					varf = new (TAG_OLD_UI) idWinFloat();
   2083 					*varf = atof(tok);
   2084 					varf->SetName(work);
   2085 					definedVars.Append(varf);
   2086 				} else {
   2087 					vars = new (TAG_OLD_UI) idWinStr();
   2088 					*vars = tok;
   2089 					vars->SetName(work);
   2090 					definedVars.Append(vars);
   2091 				}
   2092 				break;
   2093 			default :
   2094 				vars = new (TAG_OLD_UI) idWinStr();
   2095 				*vars = tok;
   2096 				vars->SetName(work);
   2097 				definedVars.Append(vars);
   2098 				break;
   2099 		}
   2100 	}
   2101 
   2102 	return true;
   2103 }
   2104 
   2105 /*
   2106 ================
   2107 idWindow::SetInitialState
   2108 ================
   2109 */
   2110 void idWindow::SetInitialState(const char *_name) {
   2111 	name = _name;
   2112 	matScalex = 1.0;
   2113 	matScaley = 1.0;
   2114 	forceAspectWidth = 640.0;
   2115 	forceAspectHeight = 480.0;
   2116 	noTime = false;
   2117 	visible = true;
   2118 	flags = 0;
   2119 }
   2120 
   2121 /*
   2122 ================
   2123 idWindow::Parse
   2124 ================
   2125 */
   2126 bool idWindow::Parse( idTokenParser *src, bool rebuild) {
   2127 	idToken token, token2, token3, token4, token5, token6, token7;
   2128 	idStr work;
   2129 
   2130 	if (rebuild) {
   2131 		CleanUp();
   2132 	}
   2133 
   2134 	drawWin_t dwt;
   2135 
   2136 	timeLineEvents.Clear();
   2137 	transitions.Clear();
   2138 
   2139 	namedEvents.DeleteContents( true );
   2140 
   2141 	src->ExpectTokenType( TT_NAME, 0, &token );
   2142 
   2143 	SetInitialState(token);
   2144 
   2145 	src->ExpectTokenString( "{" );
   2146 	src->ExpectAnyToken( &token );
   2147 
   2148 	bool ret = true;
   2149 
   2150 	while( token != "}" ) {
   2151 		// track what was parsed so we can maintain it for the guieditor
   2152 		src->SetMarker ( );
   2153 
   2154 		if ( token == "windowDef" || token == "animationDef" ) {
   2155 			if (token == "animationDef") {
   2156 				visible = false;
   2157 				rect = idRectangle(0,0,0,0);
   2158 			}
   2159 			src->ExpectTokenType( TT_NAME, 0, &token );
   2160 			token2 = token;
   2161 			src->UnreadToken(&token);
   2162 			drawWin_t *dw = FindChildByName(token2.c_str());
   2163 			if (dw != NULL && dw->win != NULL) {
   2164 				SaveExpressionParseState();
   2165 				dw->win->Parse(src, rebuild);
   2166 				RestoreExpressionParseState();
   2167 			} else {
   2168 				idWindow *win = new (TAG_OLD_UI) idWindow(gui);
   2169 				SaveExpressionParseState();
   2170 				win->Parse(src, rebuild);
   2171 				RestoreExpressionParseState();
   2172 				win->SetParent(this);
   2173 				dwt.simp = NULL;
   2174 				dwt.win = NULL;
   2175 				if (win->IsSimple()) {
   2176 					idSimpleWindow *simple = new (TAG_OLD_UI) idSimpleWindow(win);
   2177 					dwt.simp = simple;
   2178 					drawWindows.Append(dwt);
   2179 					delete win;
   2180 				} else {
   2181 					AddChild(win);
   2182 					SetFocus(win,false);
   2183 					dwt.win = win;
   2184 					drawWindows.Append(dwt);
   2185 				}
   2186 			}
   2187 		} 
   2188 		else if ( token == "editDef" ) {
   2189 			idEditWindow *win = new (TAG_OLD_UI) idEditWindow(gui);
   2190 		  	SaveExpressionParseState();
   2191 			win->Parse(src, rebuild);	
   2192 		  	RestoreExpressionParseState();
   2193 			AddChild(win);
   2194 			win->SetParent(this);
   2195 			dwt.simp = NULL;
   2196 			dwt.win = win;
   2197 			drawWindows.Append(dwt);
   2198 		}
   2199 		else if ( token == "choiceDef" ) {
   2200 			idChoiceWindow *win = new (TAG_OLD_UI) idChoiceWindow(gui);
   2201 		  	SaveExpressionParseState();
   2202 			win->Parse(src, rebuild);	
   2203 		  	RestoreExpressionParseState();
   2204 			AddChild(win);
   2205 			win->SetParent(this);
   2206 			dwt.simp = NULL;
   2207 			dwt.win = win;
   2208 			drawWindows.Append(dwt);
   2209 		}
   2210 		else if ( token == "sliderDef" ) {
   2211 			idSliderWindow *win = new (TAG_OLD_UI) idSliderWindow(gui);
   2212 		  	SaveExpressionParseState();
   2213 			win->Parse(src, rebuild);	
   2214 		  	RestoreExpressionParseState();
   2215 			AddChild(win);
   2216 			win->SetParent(this);
   2217 			dwt.simp = NULL;
   2218 			dwt.win = win;
   2219 			drawWindows.Append(dwt);
   2220 		}
   2221 		else if ( token == "bindDef" ) {
   2222 			idBindWindow *win = new (TAG_OLD_UI) idBindWindow(gui);
   2223 		  	SaveExpressionParseState();
   2224 			win->Parse(src, rebuild);	
   2225 		  	RestoreExpressionParseState();
   2226 			AddChild(win);
   2227 			win->SetParent(this);
   2228 			dwt.simp = NULL;
   2229 			dwt.win = win;
   2230 			drawWindows.Append(dwt);
   2231 		}
   2232 		else if ( token == "listDef" ) {
   2233 			idListWindow *win = new (TAG_OLD_UI) idListWindow(gui);
   2234 		  	SaveExpressionParseState();
   2235 			win->Parse(src, rebuild);	
   2236 		  	RestoreExpressionParseState();
   2237 			AddChild(win);
   2238 			win->SetParent(this);
   2239 			dwt.simp = NULL;
   2240 			dwt.win = win;
   2241 			drawWindows.Append(dwt);
   2242 		}
   2243 		else if ( token == "fieldDef" ) {
   2244 			idFieldWindow *win = new (TAG_OLD_UI) idFieldWindow(gui);
   2245 		  	SaveExpressionParseState();
   2246 			win->Parse(src, rebuild);	
   2247 		  	RestoreExpressionParseState();
   2248 			AddChild(win);
   2249 			win->SetParent(this);
   2250 			dwt.simp = NULL;
   2251 			dwt.win = win;
   2252 			drawWindows.Append(dwt);
   2253 		}
   2254 		else if ( token == "renderDef" ) {
   2255 			// D3 could render a 3D model in a subrect of a full screen
   2256 			// GUI for the main menus, but we have cut that ability so
   2257 			// we don't need to deal with offset viewports on all platforms.
   2258 			idRenderWindow *win = new (TAG_OLD_UI) idRenderWindow(gui);
   2259 		  	SaveExpressionParseState();
   2260 			win->Parse(src, rebuild);	
   2261 		  	RestoreExpressionParseState();
   2262 			AddChild(win);
   2263 			win->SetParent(this);
   2264 			dwt.simp = NULL;
   2265 			dwt.win = win;
   2266 			drawWindows.Append(dwt);
   2267 		}
   2268 		else if ( token == "gameSSDDef" ) {
   2269 			idGameSSDWindow *win = new (TAG_OLD_UI) idGameSSDWindow(gui);
   2270 			SaveExpressionParseState();
   2271 			win->Parse(src, rebuild);	
   2272 			RestoreExpressionParseState();
   2273 			AddChild(win);
   2274 			win->SetParent(this);
   2275 			dwt.simp = NULL;
   2276 			dwt.win = win;
   2277 			drawWindows.Append(dwt);
   2278 		}
   2279 		else if ( token == "gameBearShootDef" ) {
   2280 			idGameBearShootWindow *win = new (TAG_OLD_UI) idGameBearShootWindow(gui);
   2281 			SaveExpressionParseState();
   2282 			win->Parse(src, rebuild);	
   2283 			RestoreExpressionParseState();
   2284 			AddChild(win);
   2285 			win->SetParent(this);
   2286 			dwt.simp = NULL;
   2287 			dwt.win = win;
   2288 			drawWindows.Append(dwt);
   2289 		}
   2290 		else if ( token == "gameBustOutDef" ) {
   2291 			idGameBustOutWindow *win = new (TAG_OLD_UI) idGameBustOutWindow(gui);
   2292 			SaveExpressionParseState();
   2293 			win->Parse(src, rebuild);	
   2294 			RestoreExpressionParseState();
   2295 			AddChild(win);
   2296 			win->SetParent(this);
   2297 			dwt.simp = NULL;
   2298 			dwt.win = win;
   2299 			drawWindows.Append(dwt);
   2300 		}
   2301 // 
   2302 //  added new onEvent
   2303 		else if ( token == "onNamedEvent" ) {
   2304 			// Read the event name
   2305 			if ( !src->ReadToken(&token) ) {
   2306 				src->Error( "Expected event name" );
   2307 				return false;
   2308 			}
   2309 
   2310 			rvNamedEvent* ev = new (TAG_OLD_UI) rvNamedEvent ( token );
   2311 			
   2312 			src->SetMarker ( );
   2313 			
   2314 			if ( !ParseScript ( src, *ev->mEvent ) ) {
   2315 				ret = false;
   2316 				break;
   2317 			}
   2318 
   2319 			namedEvents.Append(ev);
   2320 		}
   2321 		else if ( token == "onTime" ) {
   2322 			idTimeLineEvent *ev = new (TAG_OLD_UI) idTimeLineEvent;
   2323 
   2324 			if ( !src->ReadToken(&token) ) {
   2325 				src->Error( "Unexpected end of file" );
   2326 				return false;
   2327 			}
   2328 			ev->time = atoi(token.c_str());
   2329 			
   2330 			// reset the mark since we dont want it to include the time
   2331 			src->SetMarker ( );
   2332 
   2333 			if (!ParseScript(src, *ev->event, &ev->time)) {
   2334 				ret = false;
   2335 				break;
   2336 			}
   2337 
   2338 			// this is a timeline event
   2339 			ev->pending = true;
   2340 			timeLineEvents.Append(ev);
   2341 		}
   2342 		else if ( token == "definefloat" ) {
   2343 			src->ReadToken(&token);
   2344 			work = token;
   2345 			work.ToLower();
   2346 			idWinFloat *varf = new (TAG_OLD_UI) idWinFloat();
   2347 			varf->SetName(work);
   2348 			definedVars.Append(varf);
   2349 
   2350 			// add the float to the editors wrapper dict
   2351 			// Set the marker after the float name
   2352 			src->SetMarker ( );
   2353 
   2354 			// Read in the float 
   2355 			regList.AddReg(work, idRegister::FLOAT, src, this, varf);
   2356 		}
   2357 		else if ( token == "definevec4" ) {
   2358 			src->ReadToken(&token);
   2359 			work = token;
   2360 			work.ToLower();
   2361 			idWinVec4 *var = new (TAG_OLD_UI) idWinVec4();
   2362 			var->SetName(work);
   2363 
   2364 			// set the marker so we can determine what was parsed
   2365 			// set the marker after the vec4 name
   2366 			src->SetMarker ( );
   2367 
   2368 			// FIXME: how about we add the var to the desktop instead of this window so it won't get deleted
   2369 			//        when this window is destoyed which even happens during parsing with simple windows ?
   2370 			//definedVars.Append(var);
   2371 			gui->GetDesktop()->definedVars.Append( var );
   2372 			gui->GetDesktop()->regList.AddReg( work, idRegister::VEC4, src, gui->GetDesktop(), var );
   2373 		}
   2374 		else if ( token == "float" ) {
   2375 			src->ReadToken(&token);
   2376 			work = token;
   2377 			work.ToLower();
   2378 			idWinFloat *varf = new (TAG_OLD_UI) idWinFloat();
   2379 			varf->SetName(work);
   2380 			definedVars.Append(varf);
   2381 
   2382 			// add the float to the editors wrapper dict
   2383 			// set the marker to after the float name
   2384 			src->SetMarker ( );
   2385 
   2386 			// Parse the float
   2387 			regList.AddReg(work, idRegister::FLOAT, src, this, varf);
   2388 		}
   2389 		else if (ParseScriptEntry(token, src)) {
   2390 
   2391 		} else if (ParseInternalVar(token, src)) {
   2392 
   2393 		}
   2394 		else {
   2395 			ParseRegEntry(token, src);
   2396 		} 
   2397 		if ( !src->ReadToken( &token ) ) {
   2398 			src->Error( "Unexpected end of file" );
   2399 			ret = false;
   2400 			break;
   2401 		}
   2402 	}
   2403 
   2404 	if (ret) {
   2405 		EvalRegs(-1, true);
   2406 	}
   2407 
   2408 	SetupFromState();
   2409 	PostParse();
   2410 
   2411 	return ret;
   2412 }
   2413 
   2414 /*
   2415 ================
   2416 idWindow::FindSimpleWinByName
   2417 ================
   2418 */
   2419 idSimpleWindow *idWindow::FindSimpleWinByName(const char *_name) {
   2420 	int c = drawWindows.Num();
   2421 	for (int i = 0; i < c; i++) {
   2422 		if (drawWindows[i].simp == NULL) {
   2423 			continue;
   2424 		}
   2425 		if ( idStr::Icmp(drawWindows[i].simp->name, _name) == 0 ) {
   2426 			return drawWindows[i].simp;
   2427 		} 
   2428 	}
   2429 	return NULL;
   2430 }
   2431 
   2432 /*
   2433 ================
   2434 idWindow::FindChildByName
   2435 ================
   2436 */
   2437 drawWin_t *idWindow::FindChildByName(const char *_name) {
   2438 	static drawWin_t dw;
   2439 	if (idStr::Icmp(name,_name) == 0) {
   2440 		dw.simp = NULL;
   2441 		dw.win = this;
   2442 		return &dw;
   2443 	}
   2444 	int c = drawWindows.Num();
   2445 	for (int i = 0; i < c; i++) {
   2446 		if (drawWindows[i].win) {
   2447 			if (idStr::Icmp(drawWindows[i].win->name, _name) == 0) {
   2448 				return &drawWindows[i];
   2449 			}
   2450 			drawWin_t *win = drawWindows[i].win->FindChildByName(_name);
   2451 			if (win) {
   2452 				return win;
   2453 			}
   2454 		} else {
   2455 			if (idStr::Icmp(drawWindows[i].simp->name, _name) == 0) {
   2456 				return &drawWindows[i];
   2457 			}
   2458 		}
   2459 	}
   2460 	return NULL;
   2461 }
   2462 
   2463 /*
   2464 ================
   2465 idWindow::GetStrPtrByName
   2466 ================
   2467 */
   2468 idStr* idWindow::GetStrPtrByName(const char *_name) {
   2469 	return NULL;
   2470 }
   2471 
   2472 /*
   2473 ================
   2474 idWindow::AddTransition
   2475 ================
   2476 */
   2477 void idWindow::AddTransition(idWinVar *dest, idVec4 from, idVec4 to, int time, float accelTime, float decelTime) {
   2478 	idTransitionData data;
   2479 	data.data = dest;
   2480 	data.interp.Init(gui->GetTime(), accelTime * time, decelTime * time, time, from, to);
   2481 	transitions.Append(data);
   2482 }
   2483 
   2484 
   2485 /*
   2486 ================
   2487 idWindow::StartTransition
   2488 ================
   2489 */
   2490 void idWindow::StartTransition() {
   2491 	flags |= WIN_INTRANSITION;
   2492 }
   2493 
   2494 /*
   2495 ================
   2496 idWindow::ResetCinematics
   2497 ================
   2498 */
   2499 void idWindow::ResetCinematics() {
   2500 	if ( background ) {
   2501 		background->ResetCinematicTime( gui->GetTime() );
   2502 	}
   2503 }
   2504 
   2505 /*
   2506 ================
   2507 idWindow::ResetTime
   2508 ================
   2509 */
   2510 void idWindow::ResetTime(int t) {
   2511 
   2512 	timeLine = gui->GetTime() - t;
   2513 
   2514 	int i, c = timeLineEvents.Num();
   2515 	for ( i = 0; i < c; i++ ) {
   2516 		if ( timeLineEvents[i]->time >= t ) {
   2517 			timeLineEvents[i]->pending = true;
   2518 		}
   2519 	}
   2520 
   2521 	noTime = false;
   2522 
   2523 	c = transitions.Num();
   2524 	for ( i = 0; i < c; i++ ) {
   2525 		idTransitionData *data = &transitions[i];
   2526 		if ( data->interp.IsDone( gui->GetTime() ) && data->data ) {
   2527 			transitions.RemoveIndex( i );
   2528 			i--;
   2529 			c--;
   2530 		}
   2531 	}
   2532 
   2533 }
   2534 
   2535 
   2536 /*
   2537 ================
   2538 idWindow::RunScriptList
   2539 ================
   2540 */
   2541 bool idWindow::RunScriptList(idGuiScriptList *src) {
   2542 	if (src == NULL) {
   2543 		return false;
   2544 	}
   2545 	src->Execute(this);
   2546 	return true;
   2547 }
   2548 
   2549 /*
   2550 ================
   2551 idWindow::RunScript
   2552 ================
   2553 */
   2554 bool idWindow::RunScript(int n) {
   2555 	if (n >= ON_MOUSEENTER && n < SCRIPT_COUNT) {
   2556 		return RunScriptList(scripts[n]);
   2557 	}
   2558 	return false;
   2559 }
   2560 
   2561 /*
   2562 ================
   2563 idWindow::ExpressionConstant
   2564 ================
   2565 */
   2566 int idWindow::ExpressionConstant(float f) {
   2567 	int		i;
   2568 
   2569 	for ( i = WEXP_REG_NUM_PREDEFINED ; i < expressionRegisters.Num() ; i++ ) {
   2570 		if ( !registerIsTemporary[i] && expressionRegisters[i] == f ) {
   2571 			return i;
   2572 		}
   2573 	}
   2574 	if ( expressionRegisters.Num() == MAX_EXPRESSION_REGISTERS ) {
   2575 		common->Warning( "expressionConstant: gui %s hit MAX_EXPRESSION_REGISTERS", gui->GetSourceFile() );
   2576 		return 0;
   2577 	}
   2578 
   2579 	int c = expressionRegisters.Num();
   2580 	if (i > c) {
   2581 		while (i > c) {
   2582 			expressionRegisters.Append(-9999999);
   2583 			i--;
   2584 		}
   2585 	}
   2586 
   2587 	i = expressionRegisters.Append(f);
   2588 	registerIsTemporary[i] = false;
   2589 	return i;
   2590 }
   2591 
   2592 /*
   2593 ================
   2594 idWindow::ExpressionTemporary
   2595 ================
   2596 */
   2597 int idWindow::ExpressionTemporary() {
   2598 	if ( expressionRegisters.Num() == MAX_EXPRESSION_REGISTERS ) {
   2599 		common->Warning( "expressionTemporary: gui %s hit MAX_EXPRESSION_REGISTERS", gui->GetSourceFile());
   2600 		return 0;
   2601 	}
   2602 	int i = expressionRegisters.Num();
   2603 	registerIsTemporary[i] = true;
   2604 	i = expressionRegisters.Append(0);
   2605 	return i;
   2606 }
   2607 
   2608 /*
   2609 ================
   2610 idWindow::ExpressionOp
   2611 ================
   2612 */
   2613 wexpOp_t *idWindow::ExpressionOp() {
   2614 	if ( ops.Num() == MAX_EXPRESSION_OPS ) {
   2615 		common->Warning( "expressionOp: gui %s hit MAX_EXPRESSION_OPS", gui->GetSourceFile());
   2616 		return &ops[0];
   2617 	}
   2618 	wexpOp_t wop;
   2619 	memset(&wop, 0, sizeof(wexpOp_t));
   2620 	int i = ops.Append(wop);
   2621 	return &ops[i];
   2622 }
   2623 
   2624 /*
   2625 ================
   2626 idWindow::EmitOp
   2627 ================
   2628 */
   2629 
   2630 int idWindow::EmitOp( int a, int b, wexpOpType_t opType, wexpOp_t **opp ) {
   2631 	wexpOp_t *op;
   2632 /*
   2633 	// optimize away identity operations
   2634 	if ( opType == WOP_TYPE_ADD ) {
   2635 		if ( !registerIsTemporary[a] && shaderRegisters[a] == 0 ) {
   2636 			return b;
   2637 		}
   2638 		if ( !registerIsTemporary[b] && shaderRegisters[b] == 0 ) {
   2639 			return a;
   2640 		}
   2641 		if ( !registerIsTemporary[a] && !registerIsTemporary[b] ) {
   2642 			return ExpressionConstant( shaderRegisters[a] + shaderRegisters[b] );
   2643 		}
   2644 	}
   2645 	if ( opType == WOP_TYPE_MULTIPLY ) {
   2646 		if ( !registerIsTemporary[a] && shaderRegisters[a] == 1 ) {
   2647 			return b;
   2648 		}
   2649 		if ( !registerIsTemporary[a] && shaderRegisters[a] == 0 ) {
   2650 			return a;
   2651 		}
   2652 		if ( !registerIsTemporary[b] && shaderRegisters[b] == 1 ) {
   2653 			return a;
   2654 		}
   2655 		if ( !registerIsTemporary[b] && shaderRegisters[b] == 0 ) {
   2656 			return b;
   2657 		}
   2658 		if ( !registerIsTemporary[a] && !registerIsTemporary[b] ) {
   2659 			return ExpressionConstant( shaderRegisters[a] * shaderRegisters[b] );
   2660 		}
   2661 	}
   2662 */
   2663 	op = ExpressionOp();
   2664 
   2665 	op->opType = opType;
   2666 	op->a = a;
   2667 	op->b = b;
   2668 	op->c = ExpressionTemporary();
   2669 
   2670 	if (opp) {
   2671 		*opp = op;
   2672 	}
   2673 	return op->c;
   2674 }
   2675 
   2676 /*
   2677 ================
   2678 idWindow::ParseEmitOp
   2679 ================
   2680 */
   2681 int idWindow::ParseEmitOp( idTokenParser *src, int a, wexpOpType_t opType, int priority, wexpOp_t **opp ) {
   2682 	int b = ParseExpressionPriority( src, priority );
   2683 	return EmitOp( a, b, opType, opp );  
   2684 }
   2685 
   2686 
   2687 /*
   2688 ================
   2689 idWindow::ParseTerm
   2690 
   2691 Returns a register index
   2692 =================
   2693 */
   2694 int idWindow::ParseTerm( idTokenParser *src,	idWinVar *var, int component ) {
   2695 	idToken token;
   2696 	int		a, b;
   2697 
   2698 	src->ReadToken( &token );
   2699 
   2700 	if ( token == "(" ) {
   2701 		a = ParseExpression( src );
   2702 		src->ExpectTokenString(")");
   2703 		return a;
   2704 	}
   2705 
   2706 	if ( !token.Icmp( "time" ) ) {
   2707 		return WEXP_REG_TIME;
   2708 	}
   2709 
   2710 	// parse negative numbers
   2711 	if ( token == "-" ) {
   2712 		src->ReadToken( &token );
   2713 		if ( token.type == TT_NUMBER || token == "." ) {
   2714 			return ExpressionConstant( -(float) token.GetFloatValue() );
   2715 		}
   2716 		src->Warning( "Bad negative number '%s'", token.c_str() );
   2717 		return 0;
   2718 	}
   2719 
   2720 	if ( token.type == TT_NUMBER || token == "." || token == "-" ) {
   2721 		return ExpressionConstant( (float) token.GetFloatValue() );
   2722 	}
   2723 
   2724 	// see if it is a table name
   2725 	const idDeclTable *table = static_cast<const idDeclTable *>( declManager->FindType( DECL_TABLE, token.c_str(), false ) );
   2726 	if ( table ) {
   2727 		a = table->Index();
   2728 		// parse a table expression
   2729 		src->ExpectTokenString("[");
   2730 		b = ParseExpression(src);
   2731 		src->ExpectTokenString("]");
   2732 		return EmitOp( a, b, WOP_TYPE_TABLE );
   2733 	}
   2734 	
   2735 	if (var == NULL) {
   2736 		var = GetWinVarByName(token, true);
   2737 	}
   2738 	if (var) {
   2739 		a = (int)var;
   2740 		//assert(dynamic_cast<idWinVec4*>(var));
   2741 		var->Init(token, this);
   2742 		b = component;
   2743 		if (dynamic_cast<idWinVec4*>(var)) {
   2744 			if (src->ReadToken(&token)) {
   2745 				if (token == "[") {
   2746 					b = ParseExpression(src);
   2747 					src->ExpectTokenString("]");
   2748 				} else {
   2749 					src->UnreadToken(&token);
   2750 				}
   2751 			}
   2752 			return EmitOp(a, b, WOP_TYPE_VAR);
   2753 		} else if (dynamic_cast<idWinFloat*>(var)) {
   2754 			return EmitOp(a, b, WOP_TYPE_VARF);
   2755 		} else if (dynamic_cast<idWinInt*>(var)) {
   2756 			return EmitOp(a, b, WOP_TYPE_VARI);
   2757 		} else if (dynamic_cast<idWinBool*>(var)) {
   2758 			return EmitOp(a, b, WOP_TYPE_VARB);
   2759 		} else if (dynamic_cast<idWinStr*>(var)) {
   2760 			return EmitOp(a, b, WOP_TYPE_VARS);
   2761 		} else {
   2762 			src->Warning("Var expression not vec4, float or int '%s'", token.c_str());
   2763 		}
   2764 		return 0;
   2765 	} else {
   2766 		// ugly but used for post parsing to fixup named vars
   2767 		char *p = new (TAG_OLD_UI) char[token.Length()+1];
   2768 		strcpy(p, token);
   2769 		a = (int)p;
   2770 		b = -2;
   2771 		return EmitOp(a, b, WOP_TYPE_VAR);
   2772 	}
   2773 
   2774 }
   2775 
   2776 /*
   2777 =================
   2778 idWindow::ParseExpressionPriority
   2779 
   2780 Returns a register index
   2781 =================
   2782 */
   2783 #define	TOP_PRIORITY 4
   2784 int idWindow::ParseExpressionPriority( idTokenParser *src, int priority, idWinVar *var, int component ) {
   2785 	idToken token;
   2786 	int		a;
   2787 
   2788 	if ( priority == 0 ) {
   2789 		return ParseTerm( src, var, component );
   2790 	}
   2791 
   2792 	a = ParseExpressionPriority( src, priority - 1, var, component );
   2793 
   2794 	if ( !src->ReadToken( &token ) ) {
   2795 		// we won't get EOF in a real file, but we can
   2796 		// when parsing from generated strings
   2797 		return a;
   2798 	}
   2799 
   2800 	if ( priority == 1 && token == "*" ) {
   2801 		return ParseEmitOp( src, a, WOP_TYPE_MULTIPLY, priority );
   2802 	}
   2803 	if ( priority == 1 && token == "/" ) {
   2804 		return ParseEmitOp( src, a, WOP_TYPE_DIVIDE, priority );
   2805 	}
   2806 	if ( priority == 1 && token == "%" ) {	// implied truncate both to integer
   2807 		return ParseEmitOp( src, a, WOP_TYPE_MOD, priority );
   2808 	}
   2809 	if ( priority == 2 && token == "+" ) {
   2810 		return ParseEmitOp( src, a, WOP_TYPE_ADD, priority );
   2811 	}
   2812 	if ( priority == 2 && token == "-" ) {
   2813 		return ParseEmitOp( src, a, WOP_TYPE_SUBTRACT, priority );
   2814 	}
   2815 	if ( priority == 3 && token == ">" ) {
   2816 		return ParseEmitOp( src, a, WOP_TYPE_GT, priority );
   2817 	}
   2818 	if ( priority == 3 && token == ">=" ) {
   2819 		return ParseEmitOp( src, a, WOP_TYPE_GE, priority );
   2820 	}
   2821 	if ( priority == 3 && token == "<" ) {
   2822 		return ParseEmitOp( src, a, WOP_TYPE_LT, priority );
   2823 	}
   2824 	if ( priority == 3 && token == "<=" ) {
   2825 		return ParseEmitOp( src, a, WOP_TYPE_LE, priority );
   2826 	}
   2827 	if ( priority == 3 && token == "==" ) {
   2828 		return ParseEmitOp( src, a, WOP_TYPE_EQ, priority );
   2829 	}
   2830 	if ( priority == 3 && token == "!=" ) {
   2831 		return ParseEmitOp( src, a, WOP_TYPE_NE, priority );
   2832 	}
   2833 	if ( priority == 4 && token == "&&" ) {
   2834 		return ParseEmitOp( src, a, WOP_TYPE_AND, priority );
   2835 	}
   2836 	if ( priority == 4 && token == "||" ) {
   2837 		return ParseEmitOp( src, a, WOP_TYPE_OR, priority );
   2838 	}
   2839 	if ( priority == 4 && token == "?" ) {
   2840 		wexpOp_t *oop = NULL;
   2841 		int o = ParseEmitOp( src, a, WOP_TYPE_COND, priority, &oop );
   2842 		if ( !src->ReadToken( &token ) ) {
   2843 			return o;
   2844 		}
   2845 		if (token == ":") {
   2846 			a = ParseExpressionPriority( src, priority - 1, var );
   2847 			oop->d = a;
   2848 		}
   2849 		return o;
   2850 	}
   2851 
   2852 	// assume that anything else terminates the expression
   2853 	// not too robust error checking...
   2854 
   2855 	src->UnreadToken( &token );
   2856 
   2857 	return a;
   2858 }
   2859 
   2860 /*
   2861 ================
   2862 idWindow::ParseExpression
   2863 
   2864 Returns a register index
   2865 ================
   2866 */
   2867 int idWindow::ParseExpression(idTokenParser *src, idWinVar *var, int component) {
   2868 	return ParseExpressionPriority( src, TOP_PRIORITY, var );
   2869 }
   2870 
   2871 /*
   2872 ================
   2873 idWindow::ParseBracedExpression
   2874 ================
   2875 */
   2876 void idWindow::ParseBracedExpression(idTokenParser *src) {
   2877 	src->ExpectTokenString("{");
   2878 	ParseExpression(src);
   2879 	src->ExpectTokenString("}");
   2880 }
   2881 
   2882 /*
   2883 ===============
   2884 idWindow::EvaluateRegisters
   2885 
   2886 Parameters are taken from the localSpace and the renderView,
   2887 then all expressions are evaluated, leaving the shader registers
   2888 set to their apropriate values.
   2889 ===============
   2890 */
   2891 void idWindow::EvaluateRegisters(float *registers) {
   2892 	int		i, b;
   2893 	wexpOp_t	*op;
   2894 	idVec4 v;
   2895 
   2896 	int erc = expressionRegisters.Num();
   2897 	int oc = ops.Num();
   2898 	// copy the constants
   2899 	for ( i = WEXP_REG_NUM_PREDEFINED ; i < erc ; i++ ) {
   2900 		registers[i] = expressionRegisters[i];
   2901 	}
   2902 
   2903 	// copy the local and global parameters
   2904 	registers[WEXP_REG_TIME] = gui->GetTime();
   2905 
   2906 	for ( i = 0 ; i < oc ; i++ ) {
   2907 		op = &ops[i];
   2908 		if (op->b == -2) {
   2909 			continue;
   2910 		}
   2911 		switch( op->opType ) {
   2912 		case WOP_TYPE_ADD:
   2913 			registers[op->c] = registers[op->a] + registers[op->b];
   2914 			break;
   2915 		case WOP_TYPE_SUBTRACT:
   2916 			registers[op->c] = registers[op->a] - registers[op->b];
   2917 			break;
   2918 		case WOP_TYPE_MULTIPLY:
   2919 			registers[op->c] = registers[op->a] * registers[op->b];
   2920 			break;
   2921 		case WOP_TYPE_DIVIDE:
   2922 			if ( registers[op->b] == 0.0f ) {
   2923 				common->Warning( "Divide by zero in window '%s' in %s", GetName(), gui->GetSourceFile() );
   2924 				registers[op->c] = registers[op->a];
   2925 			} else {
   2926 				registers[op->c] = registers[op->a] / registers[op->b];
   2927 			}
   2928 			break;
   2929 		case WOP_TYPE_MOD:
   2930 			b = (int)registers[op->b];
   2931 			b = b != 0 ? b : 1;
   2932 			registers[op->c] = (int)registers[op->a] % b;
   2933 			break;
   2934 		case WOP_TYPE_TABLE:
   2935 			{
   2936 				const idDeclTable *table = static_cast<const idDeclTable *>( declManager->DeclByIndex( DECL_TABLE, op->a ) );
   2937 				registers[op->c] = table->TableLookup( registers[op->b] );
   2938 			}
   2939 			break;
   2940 		case WOP_TYPE_GT:
   2941 			registers[op->c] = registers[ op->a ] > registers[op->b];
   2942 			break;
   2943 		case WOP_TYPE_GE:
   2944 			registers[op->c] = registers[ op->a ] >= registers[op->b];
   2945 			break;
   2946 		case WOP_TYPE_LT:
   2947 			registers[op->c] = registers[ op->a ] < registers[op->b];
   2948 			break;
   2949 		case WOP_TYPE_LE:
   2950 			registers[op->c] = registers[ op->a ] <= registers[op->b];
   2951 			break;
   2952 		case WOP_TYPE_EQ:
   2953 			registers[op->c] = registers[ op->a ] == registers[op->b];
   2954 			break;
   2955 		case WOP_TYPE_NE:
   2956 			registers[op->c] = registers[ op->a ] != registers[op->b];
   2957 			break;
   2958 		case WOP_TYPE_COND:
   2959 			registers[op->c] = (registers[ op->a ]) ? registers[op->b] : registers[op->d];
   2960 			break;
   2961 		case WOP_TYPE_AND:
   2962 			registers[op->c] = registers[ op->a ] && registers[op->b];
   2963 			break;
   2964 		case WOP_TYPE_OR:
   2965 			registers[op->c] = registers[ op->a ] || registers[op->b];
   2966 			break;
   2967 		case WOP_TYPE_VAR:
   2968 			if ( !op->a ) {
   2969 				registers[op->c] = 0.0f;
   2970 				break;
   2971 			}
   2972 			if ( op->b >= 0 && registers[op->b] >= 0 && registers[op->b] < 4 ) {
   2973 				// grabs vector components
   2974 				idWinVec4 *var = (idWinVec4 *)( op->a );
   2975 				registers[op->c] = ((idVec4&)var)[registers[op->b]];
   2976 			} else {
   2977 				registers[op->c] = ((idWinVar*)(op->a))->x();
   2978 			}
   2979 			break;
   2980 		case WOP_TYPE_VARS:
   2981 			if (op->a) {
   2982 				idWinStr *var = (idWinStr*)(op->a);
   2983 				registers[op->c] = atof(var->c_str());
   2984 			} else {
   2985 				registers[op->c] = 0;
   2986 			}
   2987 			break;
   2988 		case WOP_TYPE_VARF:
   2989 			if (op->a) {
   2990 				idWinFloat *var = (idWinFloat*)(op->a);
   2991 				registers[op->c] = *var;
   2992 			} else {
   2993 				registers[op->c] = 0;
   2994 			}
   2995 			break;
   2996 		case WOP_TYPE_VARI:
   2997 			if (op->a) {
   2998 				idWinInt *var = (idWinInt*)(op->a);
   2999 				registers[op->c] = *var;
   3000 			} else {
   3001 				registers[op->c] = 0;
   3002 			}
   3003 			break;
   3004 		case WOP_TYPE_VARB:
   3005 			if (op->a) {
   3006 				idWinBool *var = (idWinBool*)(op->a);
   3007 				registers[op->c] = *var;
   3008 			} else {
   3009 				registers[op->c] = 0;
   3010 			}
   3011 			break;
   3012 		default:
   3013 			common->FatalError( "R_EvaluateExpression: bad opcode" );
   3014 		}
   3015 	}
   3016 
   3017 }
   3018 
   3019 /*
   3020 ================
   3021 idWindow::ReadFromDemoFile
   3022 ================
   3023 */
   3024 void idWindow::ReadFromDemoFile( class idDemoFile *f, bool rebuild ) {
   3025 
   3026 	// should never hit unless we re-enable WRITE_GUIS
   3027 #ifndef WRITE_GUIS
   3028 	assert( false );
   3029 #else
   3030 
   3031 	if (rebuild) {
   3032 		CommonInit();
   3033 	}
   3034 	
   3035 	f->SetLog(true, "window1");
   3036 	backGroundName = f->ReadHashString();
   3037 	f->SetLog(true, backGroundName);
   3038 	if ( backGroundName[0] ) {
   3039 		background = declManager->FindMaterial(backGroundName);
   3040 	} else {
   3041 		background = NULL;
   3042 	}
   3043 	f->ReadUnsignedChar( cursor );
   3044 	f->ReadUnsignedInt( flags );
   3045 	f->ReadInt( timeLine );
   3046 	f->ReadInt( lastTimeRun );
   3047 	idRectangle rct = rect;
   3048 	f->ReadFloat( rct.x );
   3049 	f->ReadFloat( rct.y );
   3050 	f->ReadFloat( rct.w );
   3051 	f->ReadFloat( rct.h );
   3052 	f->ReadFloat( drawRect.x );
   3053 	f->ReadFloat( drawRect.y );
   3054 	f->ReadFloat( drawRect.w );
   3055 	f->ReadFloat( drawRect.h );
   3056 	f->ReadFloat( clientRect.x );
   3057 	f->ReadFloat( clientRect.y );
   3058 	f->ReadFloat( clientRect.w );
   3059 	f->ReadFloat( clientRect.h );
   3060 	f->ReadFloat( textRect.x );
   3061 	f->ReadFloat( textRect.y );
   3062 	f->ReadFloat( textRect.w );
   3063 	f->ReadFloat( textRect.h );
   3064 	f->ReadFloat( xOffset);
   3065 	f->ReadFloat( yOffset);
   3066 	int i, c;
   3067 
   3068 	idStr work;
   3069 	if (rebuild) {
   3070 		f->SetLog(true, (work + "-scripts"));
   3071 		for (i = 0; i < SCRIPT_COUNT; i++) {
   3072 			bool b;
   3073 			f->ReadBool( b );
   3074 			if (b) {
   3075 				delete scripts[i];
   3076 				scripts[i] = new (TAG_OLD_UI) idGuiScriptList;
   3077 				scripts[i]->ReadFromDemoFile(f);
   3078 			}
   3079 		}
   3080 
   3081 		f->SetLog(true, (work + "-timelines"));
   3082 		f->ReadInt( c );
   3083 		for (i = 0; i < c; i++) {
   3084 			idTimeLineEvent *tl = new (TAG_OLD_UI) idTimeLineEvent;
   3085 			f->ReadInt( tl->time );
   3086 			f->ReadBool( tl->pending );
   3087 			tl->event->ReadFromDemoFile(f);
   3088 			if (rebuild) {
   3089 				timeLineEvents.Append(tl);
   3090 			} else {
   3091 				assert(i < timeLineEvents.Num());
   3092 				timeLineEvents[i]->time = tl->time;
   3093 				timeLineEvents[i]->pending = tl->pending;
   3094 			}
   3095 		}
   3096 	}
   3097 
   3098 	f->SetLog(true, (work + "-transitions"));
   3099 	f->ReadInt( c );
   3100 	for (i = 0; i < c; i++) {
   3101 		idTransitionData td;
   3102 		td.data = NULL;
   3103 		f->ReadInt ( td.offset );
   3104 
   3105 		float startTime, accelTime, linearTime, decelTime;
   3106 		idVec4 startValue, endValue;	   
   3107 		f->ReadFloat( startTime );
   3108 		f->ReadFloat( accelTime );
   3109 		f->ReadFloat( linearTime );
   3110 		f->ReadFloat( decelTime );
   3111 		f->ReadVec4( startValue );
   3112 		f->ReadVec4( endValue );
   3113 		td.interp.Init( startTime, accelTime, decelTime, accelTime + linearTime + decelTime, startValue, endValue );
   3114 		
   3115 		// read this for correct data padding with the win32 savegames
   3116 		// the extrapolate is correctly initialized through the above Init call
   3117 		int extrapolationType;
   3118 		float duration;
   3119 		idVec4 baseSpeed, speed;
   3120 		float currentTime;
   3121 		idVec4 currentValue;
   3122 		f->ReadInt( extrapolationType );
   3123 		f->ReadFloat( startTime );
   3124 		f->ReadFloat( duration );
   3125 		f->ReadVec4( startValue );
   3126 		f->ReadVec4( baseSpeed );
   3127 		f->ReadVec4( speed );
   3128 		f->ReadFloat( currentTime );
   3129 		f->ReadVec4( currentValue );
   3130 
   3131 		transitions.Append(td);
   3132 	}
   3133 
   3134 	f->SetLog(true, (work + "-regstuff"));
   3135 	if (rebuild) {
   3136 		f->ReadInt( c );
   3137 		for (i = 0; i < c; i++) {
   3138 			wexpOp_t w;
   3139 			f->ReadInt( (int&)w.opType );
   3140 			f->ReadInt( w.a );
   3141 			f->ReadInt( w.b );
   3142 			f->ReadInt( w.c );
   3143 			f->ReadInt( w.d );
   3144 			ops.Append(w);
   3145 		}
   3146 
   3147 		f->ReadInt( c );
   3148 		for (i = 0; i < c; i++) {
   3149 			float ff;
   3150 			f->ReadFloat( ff );
   3151 			expressionRegisters.Append(ff);
   3152 		}
   3153 	
   3154 		regList.ReadFromDemoFile(f);
   3155 
   3156 	}
   3157 	f->SetLog(true, (work + "-children"));
   3158 	f->ReadInt( c );
   3159 	for (i = 0; i < c; i++) {
   3160 		if (rebuild) {
   3161 			idWindow *win = new (TAG_OLD_UI) idWindow(dc, gui);
   3162 			win->ReadFromDemoFile(f);
   3163 			AddChild(win);
   3164 		} else {
   3165 			for (int j = 0; j < c; j++) {
   3166 				if (children[j]->childID == i) {
   3167 					children[j]->ReadFromDemoFile(f,rebuild);
   3168 					break;
   3169 				} else {
   3170 					continue;
   3171 				}
   3172 			}
   3173 		}
   3174 	}
   3175 #endif /* WRITE_GUIS */
   3176 }
   3177 
   3178 /*
   3179 ================
   3180 idWindow::WriteToDemoFile
   3181 ================
   3182 */
   3183 void idWindow::WriteToDemoFile( class idDemoFile *f ) {
   3184 	// should never hit unless we re-enable WRITE_GUIS
   3185 #ifndef WRITE_GUIS
   3186 	assert( false );
   3187 #else
   3188 
   3189 	f->SetLog(true, "window");
   3190 	f->WriteHashString(backGroundName);
   3191 	f->SetLog(true, backGroundName);
   3192 	f->WriteUnsignedChar( cursor );
   3193 	f->WriteUnsignedInt( flags );
   3194 	f->WriteInt( timeLine );
   3195 	f->WriteInt( lastTimeRun );
   3196 	idRectangle rct = rect;
   3197 	f->WriteFloat( rct.x );
   3198 	f->WriteFloat( rct.y );
   3199 	f->WriteFloat( rct.w );
   3200 	f->WriteFloat( rct.h );
   3201 	f->WriteFloat( drawRect.x );
   3202 	f->WriteFloat( drawRect.y );
   3203 	f->WriteFloat( drawRect.w );
   3204 	f->WriteFloat( drawRect.h );
   3205 	f->WriteFloat( clientRect.x );
   3206 	f->WriteFloat( clientRect.y );
   3207 	f->WriteFloat( clientRect.w );
   3208 	f->WriteFloat( clientRect.h );
   3209 	f->WriteFloat( textRect.x );
   3210 	f->WriteFloat( textRect.y );
   3211 	f->WriteFloat( textRect.w );
   3212 	f->WriteFloat( textRect.h );
   3213 	f->WriteFloat( xOffset );
   3214 	f->WriteFloat( yOffset );
   3215 	idStr work;
   3216 	f->SetLog(true, work);
   3217 
   3218  	int i, c;
   3219 
   3220 	f->SetLog(true, (work + "-transitions"));
   3221 	c = transitions.Num();
   3222 	f->WriteInt( c );
   3223 	for (i = 0; i < c; i++) {
   3224 		f->WriteInt( 0 );
   3225 		f->WriteInt( transitions[i].offset );
   3226 		
   3227 		f->WriteFloat( transitions[i].interp.GetStartTime() );
   3228 		f->WriteFloat( transitions[i].interp.GetAccelTime() );
   3229 		f->WriteFloat( transitions[i].interp.GetLinearTime() );
   3230 		f->WriteFloat( transitions[i].interp.GetDecelTime() );
   3231 		f->WriteVec4( transitions[i].interp.GetStartValue() );
   3232 		f->WriteVec4( transitions[i].interp.GetEndValue() );
   3233 
   3234 		// write to keep win32 render demo format compatiblity - we don't actually read them back anymore
   3235 		f->WriteInt( transitions[i].interp.GetExtrapolate()->GetExtrapolationType() );
   3236 		f->WriteFloat( transitions[i].interp.GetExtrapolate()->GetStartTime() );
   3237 		f->WriteFloat( transitions[i].interp.GetExtrapolate()->GetDuration() );
   3238 		f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetStartValue() );
   3239 		f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetBaseSpeed() );
   3240 		f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetSpeed() );
   3241 		f->WriteFloat( transitions[i].interp.GetExtrapolate()->GetCurrentTime() );
   3242 		f->WriteVec4( transitions[i].interp.GetExtrapolate()->GetCurrentValue() );
   3243 	}
   3244 
   3245 	f->SetLog(true, (work + "-regstuff"));
   3246 
   3247 	f->SetLog(true, (work + "-children"));
   3248 	c = children.Num();
   3249 	f->WriteInt( c );
   3250 	for (i = 0; i < c; i++) {
   3251 		for (int j = 0; j < c; j++) {
   3252 			if (children[j]->childID == i) {
   3253 				children[j]->WriteToDemoFile(f);
   3254 				break;
   3255 			} else {
   3256 				continue;
   3257 			}
   3258 		}
   3259 	}
   3260 #endif /* WRITE_GUIS */
   3261 }
   3262 
   3263 /*
   3264 ===============
   3265 idWindow::WriteString
   3266 ===============
   3267 */
   3268 void idWindow::WriteSaveGameString( const char *string, idFile *savefile ) {
   3269 	int len = strlen( string );
   3270 
   3271 	savefile->Write( &len, sizeof( len ) );
   3272 	savefile->Write( string, len );
   3273 }
   3274 
   3275 /*
   3276 ===============
   3277 idWindow::WriteSaveGameTransition
   3278 ===============
   3279 */
   3280 void idWindow::WriteSaveGameTransition( idTransitionData &trans, idFile *savefile ) {
   3281 	drawWin_t dw, *fdw;
   3282 	idStr winName("");
   3283 	dw.simp = NULL;
   3284 	dw.win = NULL;
   3285 	int offset = gui->GetDesktop()->GetWinVarOffset( trans.data, &dw );
   3286 	if ( dw.win || dw.simp ) {
   3287 		winName = ( dw.win ) ? dw.win->GetName() : dw.simp->name.c_str();
   3288 	}
   3289 	fdw = gui->GetDesktop()->FindChildByName( winName );
   3290 	if ( offset != -1 && fdw != NULL && ( fdw->win != NULL || fdw->simp != NULL ) ) {
   3291 		savefile->Write( &offset, sizeof( offset ) );
   3292 		WriteSaveGameString( winName, savefile );
   3293 		savefile->Write( &trans.interp, sizeof( trans.interp ) );
   3294 	} else {
   3295 		offset = -1;
   3296 		savefile->Write( &offset, sizeof( offset ) );
   3297 	}
   3298 }
   3299 
   3300 /*
   3301 ===============
   3302 idWindow::ReadSaveGameTransition
   3303 ===============
   3304 */
   3305 void idWindow::ReadSaveGameTransition( idTransitionData &trans, idFile *savefile ) {
   3306 	int offset;
   3307 
   3308 	savefile->Read( &offset, sizeof( offset ) );
   3309 	if ( offset != -1 ) {
   3310 		idStr winName;
   3311 		ReadSaveGameString( winName, savefile );
   3312 		savefile->Read( &trans.interp, sizeof( trans.interp ) );
   3313 		trans.data = NULL;
   3314 		trans.offset = offset;
   3315 		if ( winName.Length() ) {
   3316 			idWinStr *strVar = new (TAG_OLD_UI) idWinStr();
   3317 			strVar->Set( winName );
   3318 			trans.data = dynamic_cast< idWinVar* >( strVar );
   3319 		}
   3320 	}
   3321 }
   3322 
   3323 /*
   3324 ===============
   3325 idWindow::WriteToSaveGame
   3326 ===============
   3327 */
   3328 void idWindow::WriteToSaveGame( idFile *savefile ) {
   3329 	int i;
   3330 
   3331 	WriteSaveGameString( cmd, savefile );
   3332 
   3333 	savefile->Write( &actualX, sizeof( actualX ) );
   3334 	savefile->Write( &actualY, sizeof( actualY ) );
   3335 	savefile->Write( &childID, sizeof( childID ) );
   3336 	savefile->Write( &flags, sizeof( flags ) );
   3337 	savefile->Write( &lastTimeRun, sizeof( lastTimeRun ) );
   3338 	savefile->Write( &drawRect, sizeof( drawRect ) );
   3339 	savefile->Write( &clientRect, sizeof( clientRect ) );
   3340 	savefile->Write( &origin, sizeof( origin ) );
   3341 	savefile->Write( &timeLine, sizeof( timeLine ) );
   3342 	savefile->Write( &xOffset, sizeof( xOffset ) );
   3343 	savefile->Write( &yOffset, sizeof( yOffset ) );
   3344 	savefile->Write( &cursor, sizeof( cursor ) );
   3345 	savefile->Write( &forceAspectWidth, sizeof( forceAspectWidth ) );
   3346 	savefile->Write( &forceAspectHeight, sizeof( forceAspectHeight ) );
   3347 	savefile->Write( &matScalex, sizeof( matScalex ) );
   3348 	savefile->Write( &matScaley, sizeof( matScaley ) );
   3349 	savefile->Write( &borderSize, sizeof( borderSize ) );
   3350 	savefile->Write( &textAlign, sizeof( textAlign ) );
   3351 	savefile->Write( &textAlignx, sizeof( textAlignx ) );
   3352 	savefile->Write( &textAligny, sizeof( textAligny ) );
   3353 	savefile->Write( &textShadow, sizeof( textShadow ) );
   3354 	savefile->Write( &shear, sizeof( shear ) );
   3355 
   3356 	savefile->WriteString( font->GetName() );
   3357 
   3358 	WriteSaveGameString( name, savefile );
   3359 	WriteSaveGameString( comment, savefile );
   3360 
   3361 	// WinVars
   3362 	noTime.WriteToSaveGame( savefile );
   3363 	visible.WriteToSaveGame( savefile );
   3364 	rect.WriteToSaveGame( savefile );
   3365 	backColor.WriteToSaveGame( savefile );
   3366 	matColor.WriteToSaveGame( savefile );
   3367 	foreColor.WriteToSaveGame( savefile );
   3368 	hoverColor.WriteToSaveGame( savefile );
   3369 	borderColor.WriteToSaveGame( savefile );
   3370 	textScale.WriteToSaveGame( savefile );
   3371 	noEvents.WriteToSaveGame( savefile );
   3372 	rotate.WriteToSaveGame( savefile );
   3373 	text.WriteToSaveGame( savefile );
   3374 	backGroundName.WriteToSaveGame( savefile );
   3375 	hideCursor.WriteToSaveGame(savefile);
   3376 
   3377 	// Defined Vars
   3378 	for ( i = 0; i < definedVars.Num(); i++ ) {
   3379 		definedVars[i]->WriteToSaveGame( savefile );
   3380 	}
   3381 
   3382 	savefile->Write( &textRect, sizeof( textRect ) );
   3383 
   3384 	// Window pointers saved as the child ID of the window
   3385 	int winID;
   3386 
   3387 	winID = focusedChild ? focusedChild->childID : -1 ;
   3388 	savefile->Write( &winID, sizeof( winID ) );
   3389 
   3390 	winID = captureChild ? captureChild->childID : -1 ;
   3391 	savefile->Write( &winID, sizeof( winID ) );
   3392 
   3393 	winID = overChild ? overChild->childID : -1 ;
   3394 	savefile->Write( &winID, sizeof( winID ) );
   3395 
   3396 
   3397 	// Scripts
   3398 	for ( i = 0; i < SCRIPT_COUNT; i++ ) {
   3399 		if ( scripts[i] ) {
   3400 			scripts[i]->WriteToSaveGame( savefile );
   3401 		}
   3402 	}
   3403 
   3404 	// TimeLine Events
   3405 	for ( i = 0; i < timeLineEvents.Num(); i++ ) {
   3406 		if ( timeLineEvents[i] ) {
   3407 			savefile->Write( &timeLineEvents[i]->pending, sizeof( timeLineEvents[i]->pending ) );
   3408 			savefile->Write( &timeLineEvents[i]->time, sizeof( timeLineEvents[i]->time ) );
   3409 			if ( timeLineEvents[i]->event ) {
   3410 				timeLineEvents[i]->event->WriteToSaveGame( savefile );
   3411 			}
   3412 		}
   3413 	}
   3414 
   3415 	// Transitions
   3416 	int num = transitions.Num();
   3417 
   3418 	savefile->Write( &num, sizeof( num ) );
   3419 	for ( i = 0; i < transitions.Num(); i++ ) {
   3420 		WriteSaveGameTransition( transitions[ i ], savefile );
   3421 	}
   3422 
   3423 
   3424 	// Named Events
   3425 	for ( i = 0; i < namedEvents.Num(); i++ ) {
   3426 		if ( namedEvents[i] ) {
   3427 			WriteSaveGameString( namedEvents[i]->mName, savefile );
   3428 			if ( namedEvents[i]->mEvent ) {
   3429 				namedEvents[i]->mEvent->WriteToSaveGame( savefile );
   3430 			}
   3431 		}
   3432 	}
   3433 
   3434 	// regList
   3435 	regList.WriteToSaveGame( savefile );
   3436 
   3437 	if ( background ) {
   3438 		savefile->WriteInt( background->GetCinematicStartTime() );
   3439 	} else {
   3440 		savefile->WriteInt( -1 );
   3441 	}
   3442 
   3443 	// Save children
   3444 	for ( i = 0; i < drawWindows.Num(); i++ ) {
   3445 		drawWin_t	window = drawWindows[i];
   3446 
   3447 		if ( window.simp ) {
   3448 			window.simp->WriteToSaveGame( savefile );
   3449 		} else if ( window.win ) {
   3450 			window.win->WriteToSaveGame( savefile );
   3451 		}
   3452 	}
   3453 }
   3454 
   3455 /*
   3456 ===============
   3457 idWindow::ReadSaveGameString
   3458 ===============
   3459 */
   3460 void idWindow::ReadSaveGameString( idStr &string, idFile *savefile ) {
   3461 	int len;
   3462 
   3463 	savefile->Read( &len, sizeof( len ) );
   3464 	if ( len < 0 ) {
   3465 		common->Warning( "idWindow::ReadSaveGameString: invalid length" );
   3466 	}
   3467 
   3468 	string.Fill( ' ', len );
   3469 	savefile->Read( &string[0], len );
   3470 }
   3471 
   3472 /*
   3473 ===============
   3474 idWindow::ReadFromSaveGame
   3475 ===============
   3476 */
   3477 void idWindow::ReadFromSaveGame( idFile *savefile ) {
   3478 	int i;
   3479 
   3480 	transitions.Clear();
   3481 
   3482 	ReadSaveGameString( cmd, savefile );
   3483 
   3484 	savefile->Read( &actualX, sizeof( actualX ) );
   3485 	savefile->Read( &actualY, sizeof( actualY ) );
   3486 	savefile->Read( &childID, sizeof( childID ) );
   3487 	savefile->Read( &flags, sizeof( flags ) );
   3488 	savefile->Read( &lastTimeRun, sizeof( lastTimeRun ) );
   3489 	savefile->Read( &drawRect, sizeof( drawRect ) );
   3490 	savefile->Read( &clientRect, sizeof( clientRect ) );
   3491 	savefile->Read( &origin, sizeof( origin ) );
   3492 /*	if ( savefile->GetFileVersion() < BUILD_NUMBER_8TH_ANNIVERSARY_1 ) {
   3493 		unsigned char fontNum;
   3494 		savefile->Read( &fontNum, sizeof( fontNum ) );
   3495 		font = renderSystem->RegisterFont( "" );
   3496 	}*/
   3497 	savefile->Read( &timeLine, sizeof( timeLine ) );
   3498 	savefile->Read( &xOffset, sizeof( xOffset ) );
   3499 	savefile->Read( &yOffset, sizeof( yOffset ) );
   3500 	savefile->Read( &cursor, sizeof( cursor ) );
   3501 	savefile->Read( &forceAspectWidth, sizeof( forceAspectWidth ) );
   3502 	savefile->Read( &forceAspectHeight, sizeof( forceAspectHeight ) );
   3503 	savefile->Read( &matScalex, sizeof( matScalex ) );
   3504 	savefile->Read( &matScaley, sizeof( matScaley ) );
   3505 	savefile->Read( &borderSize, sizeof( borderSize ) );
   3506 	savefile->Read( &textAlign, sizeof( textAlign ) );
   3507 	savefile->Read( &textAlignx, sizeof( textAlignx ) );
   3508 	savefile->Read( &textAligny, sizeof( textAligny ) );
   3509 	savefile->Read( &textShadow, sizeof( textShadow ) );
   3510 	savefile->Read( &shear, sizeof( shear ) );
   3511 
   3512 //	if ( savefile->GetFileVersion() >= BUILD_NUMBER_8TH_ANNIVERSARY_1 ) {
   3513 		idStr fontName;
   3514 		savefile->ReadString( fontName );
   3515 		font = renderSystem->RegisterFont( fontName );
   3516 //	} 
   3517 
   3518 	ReadSaveGameString( name, savefile );
   3519 	ReadSaveGameString( comment, savefile );
   3520 
   3521 	// WinVars
   3522 	noTime.ReadFromSaveGame( savefile );
   3523 	visible.ReadFromSaveGame( savefile );
   3524 	rect.ReadFromSaveGame( savefile );
   3525 	backColor.ReadFromSaveGame( savefile );
   3526 	matColor.ReadFromSaveGame( savefile );
   3527 	foreColor.ReadFromSaveGame( savefile );
   3528 	hoverColor.ReadFromSaveGame( savefile );
   3529 	borderColor.ReadFromSaveGame( savefile );
   3530 	textScale.ReadFromSaveGame( savefile );
   3531 	noEvents.ReadFromSaveGame( savefile );
   3532 	rotate.ReadFromSaveGame( savefile );
   3533 	text.ReadFromSaveGame( savefile );
   3534 	backGroundName.ReadFromSaveGame( savefile );
   3535 	hideCursor.ReadFromSaveGame(savefile);
   3536 
   3537 	// Defined Vars
   3538 	for ( i = 0; i < definedVars.Num(); i++ ) {
   3539 		definedVars[i]->ReadFromSaveGame( savefile );
   3540 	}
   3541 
   3542 	savefile->Read( &textRect, sizeof( textRect ) );
   3543 
   3544 	// Window pointers saved as the child ID of the window
   3545 	int winID = -1;
   3546 
   3547 	savefile->Read( &winID, sizeof( winID ) );
   3548 	for ( i = 0; i < children.Num(); i++ ) {
   3549 		if ( children[i]->childID == winID ) {
   3550 			focusedChild = children[i];
   3551 		}
   3552 	}
   3553 	savefile->Read( &winID, sizeof( winID ) );
   3554 	for ( i = 0; i < children.Num(); i++ ) {
   3555 		if ( children[i]->childID == winID ) {
   3556 			captureChild = children[i];
   3557 		}
   3558 	}
   3559 	savefile->Read( &winID, sizeof( winID ) );
   3560 	for ( i = 0; i < children.Num(); i++ ) {
   3561 		if ( children[i]->childID == winID ) {
   3562 			overChild = children[i];
   3563 		}
   3564 	}
   3565 	
   3566 	// Scripts
   3567 	for ( i = 0; i < SCRIPT_COUNT; i++ ) {
   3568 		if ( scripts[i] ) {
   3569 			scripts[i]->ReadFromSaveGame( savefile );
   3570 		}
   3571 	}
   3572 
   3573 	// TimeLine Events
   3574 	for ( i = 0; i < timeLineEvents.Num(); i++ ) {
   3575 		if ( timeLineEvents[i] ) {
   3576 			savefile->Read( &timeLineEvents[i]->pending, sizeof( timeLineEvents[i]->pending ) );
   3577 			savefile->Read( &timeLineEvents[i]->time, sizeof( timeLineEvents[i]->time ) );
   3578 			if ( timeLineEvents[i]->event ) {
   3579 				timeLineEvents[i]->event->ReadFromSaveGame( savefile );
   3580 			}
   3581 		}
   3582 	}
   3583 
   3584 
   3585 	// Transitions
   3586 	int num;
   3587 	savefile->Read( &num, sizeof( num ) );
   3588 	for ( i = 0; i < num; i++ ) {
   3589 		idTransitionData trans;
   3590 		trans.data = NULL;
   3591 		ReadSaveGameTransition( trans, savefile );
   3592 		if ( trans.data ) {
   3593 			transitions.Append( trans );
   3594 		}
   3595 	}
   3596 
   3597 
   3598 	// Named Events
   3599 	for ( i = 0; i < namedEvents.Num(); i++ ) {
   3600 		if ( namedEvents[i] ) {
   3601 			ReadSaveGameString( namedEvents[i]->mName, savefile );
   3602 			if ( namedEvents[i]->mEvent ) {
   3603 				namedEvents[i]->mEvent->ReadFromSaveGame( savefile );
   3604 			}
   3605 		}
   3606 	}
   3607 
   3608 	// regList
   3609 	regList.ReadFromSaveGame( savefile );
   3610 
   3611 	int cinematicStartTime = 0;
   3612 	savefile->ReadInt( cinematicStartTime );
   3613 	if ( background ) {
   3614 		background->ResetCinematicTime( cinematicStartTime );
   3615 	}
   3616 
   3617 	// Read children
   3618 	for ( i = 0; i < drawWindows.Num(); i++ ) {
   3619 		drawWin_t	window = drawWindows[i];
   3620 
   3621 		if ( window.simp ) {
   3622 			window.simp->ReadFromSaveGame( savefile );
   3623 		} else if ( window.win ) {
   3624 			window.win->ReadFromSaveGame( savefile );
   3625 		}
   3626 	}
   3627 
   3628 	if ( flags & WIN_DESKTOP ) {
   3629 		FixupTransitions();
   3630 	}
   3631 }
   3632 
   3633 /*
   3634 ===============
   3635 idWindow::NumTransitions
   3636 ===============
   3637 */
   3638 int idWindow::NumTransitions() {
   3639 	int c = transitions.Num();
   3640 	for ( int i = 0; i < children.Num(); i++ ) {
   3641 		c += children[i]->NumTransitions();
   3642 	}
   3643 	return c;
   3644 }
   3645 
   3646 
   3647 /*
   3648 ===============
   3649 idWindow::FixupTransitions
   3650 ===============
   3651 */
   3652 void idWindow::FixupTransitions() {
   3653 	int i, c = transitions.Num();
   3654 	for ( i = 0; i < c; i++ ) {
   3655 		drawWin_t *dw = gui->GetDesktop()->FindChildByName( ( ( idWinStr* )transitions[i].data )->c_str() );
   3656 		delete transitions[i].data;
   3657 		transitions[i].data = NULL;
   3658 		if ( dw != NULL && ( dw->win != NULL || dw->simp != NULL ) ){
   3659 			if ( dw->win != NULL ) {
   3660 				if ( transitions[i].offset == (int)&( ( idWindow * ) 0 )->rect ) {
   3661 					transitions[i].data = &dw->win->rect;
   3662 				} else if ( transitions[i].offset == (int)&( ( idWindow * ) 0 )->backColor ) {
   3663 					transitions[i].data = &dw->win->backColor;
   3664 				} else if ( transitions[i].offset == (int)&( ( idWindow * ) 0 )->matColor ) {
   3665 					transitions[i].data = &dw->win->matColor;
   3666 				} else if ( transitions[i].offset == (int)&( ( idWindow * ) 0 )->foreColor ) {
   3667 					transitions[i].data = &dw->win->foreColor;
   3668 				} else if ( transitions[i].offset == (int)&( ( idWindow * ) 0 )->borderColor ) {
   3669 					transitions[i].data = &dw->win->borderColor;
   3670 				} else if ( transitions[i].offset == (int)&( ( idWindow * ) 0 )->textScale ) {
   3671 					transitions[i].data = &dw->win->textScale;
   3672 				} else if ( transitions[i].offset == (int)&( ( idWindow * ) 0 )->rotate ) {
   3673 					transitions[i].data = &dw->win->rotate;
   3674 				}
   3675 			} else {
   3676 				if ( transitions[i].offset == (int)&( ( idSimpleWindow * ) 0 )->rect ) {
   3677 					transitions[i].data = &dw->simp->rect;
   3678 				} else if ( transitions[i].offset == (int)&( ( idSimpleWindow * ) 0 )->backColor ) {
   3679 					transitions[i].data = &dw->simp->backColor;
   3680 				} else if ( transitions[i].offset == (int)&( ( idSimpleWindow * ) 0 )->matColor ) {
   3681 					transitions[i].data = &dw->simp->matColor;
   3682 				} else if ( transitions[i].offset == (int)&( ( idSimpleWindow * ) 0 )->foreColor ) {
   3683 					transitions[i].data = &dw->simp->foreColor;
   3684 				} else if ( transitions[i].offset == (int)&( ( idSimpleWindow * ) 0 )->borderColor ) {
   3685 					transitions[i].data = &dw->simp->borderColor;
   3686 				} else if ( transitions[i].offset == (int)&( ( idSimpleWindow * ) 0 )->textScale ) {
   3687 					transitions[i].data = &dw->simp->textScale;
   3688 				} else if ( transitions[i].offset == (int)&( ( idSimpleWindow * ) 0 )->rotate ) {
   3689 					transitions[i].data = &dw->simp->rotate;
   3690 				}
   3691 			}
   3692 		}
   3693 		if ( transitions[i].data == NULL ) {
   3694 			transitions.RemoveIndex( i );
   3695 			i--;
   3696 			c--;
   3697 		}
   3698 	}
   3699 	for ( c = 0; c < children.Num(); c++ ) {
   3700 		children[c]->FixupTransitions();
   3701 	}
   3702 }
   3703 
   3704 
   3705 /*
   3706 ===============
   3707 idWindow::AddChild
   3708 ===============
   3709 */
   3710 void idWindow::AddChild(idWindow *win) {
   3711 	win->childID = children.Append(win);
   3712 }
   3713 
   3714 /*
   3715 ================
   3716 idWindow::FixupParms
   3717 ================
   3718 */
   3719 void idWindow::FixupParms() {
   3720 	int i;
   3721 	int c = children.Num();
   3722 	for (i = 0; i < c; i++) {
   3723 		children[i]->FixupParms();
   3724 	}
   3725 	for (i = 0; i < SCRIPT_COUNT; i++) {
   3726 		if (scripts[i]) {
   3727 			scripts[i]->FixupParms(this);
   3728 		}
   3729 	}
   3730 
   3731 	c = timeLineEvents.Num();
   3732 	for (i = 0; i < c; i++) {
   3733 		timeLineEvents[i]->event->FixupParms(this);
   3734 	}
   3735 
   3736 	c = namedEvents.Num();
   3737 	for (i = 0; i < c; i++) {
   3738 		namedEvents[i]->mEvent->FixupParms(this);
   3739 	}
   3740 
   3741 	c = ops.Num();
   3742 	for (i = 0; i < c; i++) {
   3743 		if (ops[i].b == -2) {
   3744 			// need to fix this up
   3745 			const char *p = (const char*)(ops[i].a);
   3746 			idWinVar *var = GetWinVarByName(p, true);
   3747 			delete []p;
   3748 			ops[i].a = (int)var;
   3749 			ops[i].b = -1;
   3750 		}
   3751 	}
   3752 	
   3753 	
   3754 	if (flags & WIN_DESKTOP) {
   3755 		CalcRects(0,0);
   3756 	}
   3757 
   3758 }
   3759 
   3760 /*
   3761 ================
   3762 idWindow::IsSimple
   3763 ================
   3764 */
   3765 bool idWindow::IsSimple() {
   3766 
   3767 	if (ops.Num()) {
   3768 		return false;
   3769 	}
   3770 	if (flags & (WIN_HCENTER | WIN_VCENTER)) {
   3771 		return false;
   3772 	}
   3773 	if (children.Num() || drawWindows.Num()) {
   3774 		return false;
   3775 	}
   3776 	for (int i = 0; i < SCRIPT_COUNT; i++) {
   3777 		if (scripts[i]) {
   3778 			return false;
   3779 		}
   3780 	}
   3781 	if (timeLineEvents.Num()) {
   3782 		return false;
   3783 	}
   3784 
   3785 	if ( namedEvents.Num() ) {
   3786 		return false;
   3787 	}
   3788 
   3789 	return true;
   3790 }
   3791 
   3792 /*
   3793 ================
   3794 idWindow::ContainsStateVars
   3795 ================
   3796 */
   3797 bool idWindow::ContainsStateVars() {
   3798 	if ( updateVars.Num() ) {
   3799 		return true;
   3800 	}
   3801 	int c = children.Num();
   3802 	for (int i = 0; i < c; i++) {
   3803 		if ( children[i]->ContainsStateVars() ) {
   3804 			return true;
   3805 		}
   3806 	}
   3807 	return false;
   3808 }
   3809 
   3810 /*
   3811 ================
   3812 idWindow::Interactive
   3813 ================
   3814 */
   3815 bool idWindow::Interactive() {
   3816 	if ( scripts[ ON_ACTION ] ) {
   3817 		return true;
   3818 	}
   3819 	int c = children.Num();
   3820 	for (int i = 0; i < c; i++) {
   3821 		if (children[i]->Interactive()) {
   3822 			return true;
   3823 		}
   3824 	}
   3825 	return false;
   3826 }
   3827 
   3828 /*
   3829 ================
   3830 idWindow::SetChildWinVarVal
   3831 ================
   3832 */
   3833 void idWindow::SetChildWinVarVal(const char *name, const char *var, const char *val) {
   3834 	drawWin_t *dw = FindChildByName(name);
   3835 	idWinVar *wv = NULL;
   3836 	if (dw != NULL && dw->simp != NULL) {
   3837 		wv = dw->simp->GetWinVarByName(var);
   3838 	} else if (dw != NULL && dw->win != NULL) {
   3839 		wv = dw->win->GetWinVarByName(var);
   3840 	}
   3841 	if (wv) {
   3842 		wv->Set(val);
   3843 		wv->SetEval(false);
   3844 	}
   3845 }
   3846 
   3847 
   3848 /*
   3849 ================
   3850 idWindow::FindChildByPoint
   3851 
   3852 Finds the window under the given point
   3853 ================
   3854 */
   3855 idWindow* idWindow::FindChildByPoint ( float x, float y, idWindow** below ) {
   3856 	int c = children.Num();
   3857 
   3858 	// If we are looking for a window below this one then
   3859 	// the next window should be good, but this one wasnt it
   3860 	if ( *below == this ) {
   3861 		*below = NULL;
   3862 		return NULL;
   3863 	}
   3864 
   3865 	if ( !Contains ( drawRect, x, y ) ) {
   3866 		return NULL;
   3867 	}
   3868 		
   3869 	for (int i = c - 1; i >= 0 ; i-- ) {
   3870 		idWindow* found = children[i]->FindChildByPoint ( x, y, below );
   3871 		if ( found ) {
   3872 			if ( *below ) {
   3873 				continue;
   3874 			}
   3875 			
   3876 			return found;
   3877 		}									
   3878 	}
   3879 
   3880 	return this;
   3881 }
   3882 
   3883 /*
   3884 ================
   3885 idWindow::FindChildByPoint
   3886 ================
   3887 */
   3888 idWindow* idWindow::FindChildByPoint ( float x, float y, idWindow* below )
   3889 {
   3890 	return FindChildByPoint ( x, y, &below );
   3891 }
   3892 
   3893 /*
   3894 ================
   3895 idWindow::GetChildCount
   3896 
   3897 Returns the number of children
   3898 ================
   3899 */
   3900 int idWindow::GetChildCount ()
   3901 {
   3902 	return drawWindows.Num ( );
   3903 }
   3904 
   3905 /*
   3906 ================
   3907 idWindow::GetChild
   3908 
   3909 Returns the child window at the given index
   3910 ================
   3911 */
   3912 idWindow* idWindow::GetChild ( int index )
   3913 {
   3914 	return drawWindows[index].win;
   3915 }
   3916 
   3917 /*
   3918 ================
   3919 idWindow::GetChildIndex
   3920 
   3921 Returns the index of the given child window
   3922 ================
   3923 */
   3924 int idWindow::GetChildIndex ( idWindow* window ) {
   3925 	int find;
   3926 	for ( find = 0; find < drawWindows.Num(); find ++ ) {
   3927 		if ( drawWindows[find].win == window ) {
   3928 			return find;
   3929 		}
   3930 	}
   3931 	return -1;
   3932 }
   3933 
   3934 /*
   3935 ================
   3936 idWindow::RemoveChild
   3937 
   3938 Removes the child from the list of children.   Note that the child window being
   3939 removed must still be deallocated by the caller
   3940 ================
   3941 */
   3942 void idWindow::RemoveChild ( idWindow *win ) {
   3943 	int find;
   3944 
   3945 	// Remove the child window
   3946 	children.Remove ( win );
   3947 	
   3948 	for ( find = 0; find < drawWindows.Num(); find ++ )
   3949 	{
   3950 		if ( drawWindows[find].win == win )
   3951 		{
   3952 			drawWindows.RemoveIndex ( find );
   3953 			break;
   3954 		}
   3955 	}
   3956 }
   3957 
   3958 /*
   3959 ================
   3960 idWindow::InsertChild
   3961 
   3962 Inserts the given window as a child into the given location in the zorder.
   3963 ================
   3964 */
   3965 bool idWindow::InsertChild ( idWindow *win, idWindow* before )
   3966 {
   3967 	AddChild ( win );
   3968 		
   3969 	win->parent = this;
   3970 
   3971 	drawWin_t dwt;
   3972 	dwt.simp = NULL;
   3973 	dwt.win = win;
   3974 
   3975 	// If not inserting before anything then just add it at the end
   3976 	if ( before ) {		
   3977 		int index;
   3978 		index = GetChildIndex ( before );
   3979 		if ( index != -1 ) {
   3980 			drawWindows.Insert ( dwt, index );
   3981 			return true;
   3982 		}
   3983 	}
   3984 	
   3985 	drawWindows.Append ( dwt );
   3986 	return true;
   3987 }
   3988 
   3989 /*
   3990 ================
   3991 idWindow::ScreenToClient
   3992 ================
   3993 */
   3994 void idWindow::ScreenToClient ( idRectangle* r ) {
   3995 	int		  x;
   3996 	int		  y;
   3997 	idWindow* p;
   3998 	
   3999 	for ( p = this, x = 0, y = 0; p; p = p->parent ) {
   4000 		x += p->rect.x();
   4001 		y += p->rect.y();
   4002 	}
   4003 	
   4004 	r->x -= x;
   4005 	r->y -= y;
   4006 }
   4007 
   4008 /*
   4009 ================
   4010 idWindow::ClientToScreen
   4011 ================
   4012 */
   4013 void idWindow::ClientToScreen ( idRectangle* r ) {
   4014 	int		  x;
   4015 	int		  y;
   4016 	idWindow* p;
   4017 	
   4018 	for ( p = this, x = 0, y = 0; p; p = p->parent ) {
   4019 		x += p->rect.x();
   4020 		y += p->rect.y();
   4021 	}
   4022 	
   4023 	r->x += x;
   4024 	r->y += y;	
   4025 }
   4026 
   4027 /*
   4028 ================
   4029 idWindow::SetDefaults
   4030 
   4031 Set the window do a default window with no text, no background and 
   4032 default colors, etc..
   4033 ================
   4034 */
   4035 void idWindow::SetDefaults () {	
   4036 	forceAspectWidth = 640.0f;
   4037 	forceAspectHeight = 480.0f;
   4038 	matScalex = 1;
   4039 	matScaley = 1;
   4040 	borderSize = 0;
   4041 	noTime = false;
   4042 	visible = true;
   4043 	textAlign = 0;
   4044 	textAlignx = 0;
   4045 	textAligny = 0;
   4046 	noEvents = false;
   4047 	rotate = 0;
   4048 	shear.Zero();
   4049 	textScale = 0.35f;
   4050 	backColor.Zero();
   4051 	foreColor = idVec4(1, 1, 1, 1);
   4052 	hoverColor = idVec4(1, 1, 1, 1);
   4053 	matColor = idVec4(1, 1, 1, 1);
   4054 	borderColor.Zero();
   4055 	text = "";	
   4056 
   4057 	background = NULL;
   4058 	backGroundName = "";
   4059 }
   4060 
   4061 /*
   4062 ================
   4063 idWindow::UpdateFromDictionary
   4064 
   4065 The editor only has a dictionary to work with so the easiest way to push the
   4066 values of the dictionary onto the window is for the window to interpret the 
   4067 dictionary as if were a file being parsed.
   4068 ================
   4069 */
   4070 bool idWindow::UpdateFromDictionary ( idDict& dict ) {
   4071 	const idKeyValue*	kv;
   4072 	int					i;
   4073 	
   4074 	SetDefaults ( );
   4075 	
   4076 	// Clear all registers since they will get recreated
   4077 	regList.Reset ( );
   4078 	expressionRegisters.Clear ( );
   4079 	ops.Clear ( );
   4080 	
   4081 	for ( i = 0; i < dict.GetNumKeyVals(); i ++ ) {
   4082 		kv = dict.GetKeyVal ( i );
   4083 
   4084 		// Special case name
   4085 		if ( !kv->GetKey().Icmp ( "name" ) ) {
   4086 			name = kv->GetValue();
   4087 			continue;
   4088 		}
   4089 
   4090 		idParser src( kv->GetValue().c_str(), kv->GetValue().Length(), "",
   4091 					  LEXFL_NOFATALERRORS | LEXFL_NOSTRINGCONCAT | LEXFL_ALLOWMULTICHARLITERALS | LEXFL_ALLOWBACKSLASHSTRINGCONCAT );
   4092 		idTokenParser src2;
   4093 		src2.LoadFromParser( src, "temp" );
   4094 		src2.StartParsing( "temp" );
   4095 		if ( !ParseInternalVar ( kv->GetKey(), &src2 ) ) {
   4096 			// Kill the old register since the parse reg entry will add a new one
   4097 			if ( !ParseRegEntry ( kv->GetKey(), &src2 ) ) {
   4098 				continue;
   4099 			}
   4100 		}
   4101 	}
   4102 			
   4103 	EvalRegs(-1, true);
   4104 
   4105 	SetupFromState();
   4106 	PostParse();
   4107 	
   4108 	return true;
   4109 }