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