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 = ▭
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