1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** $Id: ui_widget.cpp 4339 2010-12-14 12:07:27Z dj_jl $
11 //**
12 //** Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //** This program is free software; you can redistribute it and/or
15 //** modify it under the terms of the GNU General Public License
16 //** as published by the Free Software Foundation; either version 2
17 //** of the License, or (at your option) any later version.
18 //**
19 //** This program is distributed in the hope that it will be useful,
20 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 //** GNU General Public License for more details.
23 //**
24 //**************************************************************************
25
26 // HEADER FILES ------------------------------------------------------------
27
28 #include "gamedefs.h"
29 #include "cl_local.h"
30 #include "drawer.h"
31 #include "ui.h"
32
33 // MACROS ------------------------------------------------------------------
34
35 // TYPES -------------------------------------------------------------------
36
37 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
38
39 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
40
41 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
42
43 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
44
45 // PUBLIC DATA DEFINITIONS -------------------------------------------------
46
47 IMPLEMENT_CLASS(V, Widget);
48
49 // PRIVATE DATA DEFINITIONS ------------------------------------------------
50
51 // CODE --------------------------------------------------------------------
52
53 //==========================================================================
54 //
55 // VWidget::CreateNewWidget
56 //
57 //==========================================================================
58
CreateNewWidget(VClass * AClass,VWidget * AParent)59 VWidget* VWidget::CreateNewWidget(VClass* AClass, VWidget* AParent)
60 {
61 guard(VWidget::CreateNewWidget);
62 VWidget* W = (VWidget*)StaticSpawnObject(AClass);
63 W->Init(AParent);
64 return W;
65 unguardf(("(%s)", AClass->GetName()));
66 }
67
68 //==========================================================================
69 //
70 // VWidget::Init
71 //
72 //==========================================================================
73
Init(VWidget * AParent)74 void VWidget::Init(VWidget* AParent)
75 {
76 guard(VWidget::Init);
77 // Set default values
78 SetFont(SmallFont);
79 SetTextAlign(hleft, vtop);
80
81 ParentWidget = AParent;
82 if (ParentWidget)
83 {
84 ParentWidget->AddChild(this);
85 }
86 ClipTree();
87 OnCreate();
88 unguard;
89 }
90
91 //==========================================================================
92 //
93 // VWidget::Destroy
94 //
95 //==========================================================================
96
Destroy()97 void VWidget::Destroy()
98 {
99 guard(VWidget::Destroy);
100 OnDestroy();
101 DestroyAllChildren();
102 if (ParentWidget)
103 {
104 ParentWidget->RemoveChild(this);
105 }
106 Super::Destroy();
107 unguard;
108 }
109
110 //==========================================================================
111 //
112 // VWidget::AddChild
113 //
114 //==========================================================================
115
AddChild(VWidget * NewChild)116 void VWidget::AddChild(VWidget* NewChild)
117 {
118 guard(VWidget::AddChild);
119 NewChild->PrevWidget = LastChildWidget;
120 NewChild->NextWidget = NULL;
121 if (LastChildWidget)
122 {
123 LastChildWidget->NextWidget = NewChild;
124 }
125 else
126 {
127 FirstChildWidget = NewChild;
128 }
129 LastChildWidget = NewChild;
130 OnChildAdded(NewChild);
131 if (!CurrentFocusChild)
132 {
133 SetCurrentFocusChild(NewChild);
134 }
135 unguard;
136 }
137
138 //==========================================================================
139 //
140 // VWidget::RemoveChild
141 //
142 //==========================================================================
143
RemoveChild(VWidget * InChild)144 void VWidget::RemoveChild(VWidget* InChild)
145 {
146 guard(VWidget::RemoveChild);
147 if (InChild->PrevWidget)
148 {
149 InChild->PrevWidget->NextWidget = InChild->NextWidget;
150 }
151 else
152 {
153 FirstChildWidget = InChild->NextWidget;
154 }
155 if (InChild->NextWidget)
156 {
157 InChild->NextWidget->PrevWidget = InChild->PrevWidget;
158 }
159 else
160 {
161 LastChildWidget = InChild->PrevWidget;
162 }
163 InChild->PrevWidget = NULL;
164 InChild->NextWidget = NULL;
165 InChild->ParentWidget = NULL;
166 OnChildRemoved(InChild);
167 if (CurrentFocusChild == InChild)
168 {
169 FindNewFocus();
170 }
171 unguard;
172 }
173
174 //==========================================================================
175 //
176 // VWidget::DestroyAllChildren
177 //
178 //==========================================================================
179
DestroyAllChildren()180 void VWidget::DestroyAllChildren()
181 {
182 guard(VWidget::DestroyAllChildren);
183 while (FirstChildWidget)
184 {
185 FirstChildWidget->ConditionalDestroy();
186 }
187 unguard;
188 }
189
190 //==========================================================================
191 //
192 // VWidget::GetRootWidget
193 //
194 //==========================================================================
195
GetRootWidget()196 VRootWidget* VWidget::GetRootWidget()
197 {
198 guard(VWidget::GetRootWidget);
199 VWidget* W = this;
200 while (W->ParentWidget)
201 {
202 W = W->ParentWidget;
203 }
204 return (VRootWidget*)W;
205 unguard;
206 }
207
208 //==========================================================================
209 //
210 // VWidget::Lower
211 //
212 //==========================================================================
213
Lower()214 void VWidget::Lower()
215 {
216 guard(VWidget::Lower);
217 if (!ParentWidget)
218 {
219 Sys_Error("Can't lower root window");
220 }
221
222 if (ParentWidget->FirstChildWidget == this)
223 {
224 // Already there
225 return;
226 }
227
228 // Unlink from current location
229 PrevWidget->NextWidget = NextWidget;
230 if (NextWidget)
231 {
232 NextWidget->PrevWidget = PrevWidget;
233 }
234 else
235 {
236 ParentWidget->LastChildWidget = PrevWidget;
237 }
238
239 // Link on bottom
240 PrevWidget = NULL;
241 NextWidget = ParentWidget->FirstChildWidget;
242 ParentWidget->FirstChildWidget->PrevWidget = this;
243 ParentWidget->FirstChildWidget = this;
244 unguard;
245 }
246
247 //==========================================================================
248 //
249 // VWidget::Raise
250 //
251 //==========================================================================
252
Raise()253 void VWidget::Raise()
254 {
255 guard(VWidget::Raise);
256 if (!ParentWidget)
257 {
258 Sys_Error("Can't raise root window");
259 }
260
261 if (ParentWidget->LastChildWidget == this)
262 {
263 // Already there
264 return;
265 }
266
267 // Unlink from current location
268 NextWidget->PrevWidget = PrevWidget;
269 if (PrevWidget)
270 {
271 PrevWidget->NextWidget = NextWidget;
272 }
273 else
274 {
275 ParentWidget->FirstChildWidget = NextWidget;
276 }
277
278 // Link on top
279 PrevWidget = ParentWidget->LastChildWidget;
280 NextWidget = NULL;
281 ParentWidget->LastChildWidget->NextWidget = this;
282 ParentWidget->LastChildWidget = this;
283 unguard;
284 }
285
286 //==========================================================================
287 //
288 // VWidget::MoveBefore
289 //
290 //==========================================================================
291
MoveBefore(VWidget * Other)292 void VWidget::MoveBefore(VWidget* Other)
293 {
294 guard(VWidget::MoveBefore);
295 if (ParentWidget != Other->ParentWidget)
296 {
297 Sys_Error("Must have the same parent widget");
298 }
299 if (Other == this)
300 {
301 Sys_Error("Can't move before self");
302 }
303
304 if (Other->PrevWidget == this)
305 {
306 // Already there
307 return;
308 }
309
310 // Unlink from current location
311 if (PrevWidget)
312 {
313 PrevWidget->NextWidget = NextWidget;
314 }
315 else
316 {
317 ParentWidget->FirstChildWidget = NextWidget;
318 }
319 if (NextWidget)
320 {
321 NextWidget->PrevWidget = PrevWidget;
322 }
323 else
324 {
325 ParentWidget->LastChildWidget = PrevWidget;
326 }
327
328 // Link in new position
329 PrevWidget = Other->PrevWidget;
330 NextWidget = Other;
331 Other->PrevWidget = this;
332 if (PrevWidget)
333 {
334 PrevWidget->NextWidget = this;
335 }
336 else
337 {
338 ParentWidget->FirstChildWidget = this;
339 }
340 unguard;
341 }
342
343 //==========================================================================
344 //
345 // VWidget::MoveAfter
346 //
347 //==========================================================================
348
MoveAfter(VWidget * Other)349 void VWidget::MoveAfter(VWidget* Other)
350 {
351 guard(VWidget::MoveAfter);
352 if (ParentWidget != Other->ParentWidget)
353 {
354 Sys_Error("Must have the same parent widget");
355 }
356 if (Other == this)
357 {
358 Sys_Error("Can't move after self");
359 }
360
361 if (Other->NextWidget == this)
362 {
363 // Already there
364 return;
365 }
366
367 // Unlink from current location
368 if (PrevWidget)
369 {
370 PrevWidget->NextWidget = NextWidget;
371 }
372 else
373 {
374 ParentWidget->FirstChildWidget = NextWidget;
375 }
376 if (NextWidget)
377 {
378 NextWidget->PrevWidget = PrevWidget;
379 }
380 else
381 {
382 ParentWidget->LastChildWidget = PrevWidget;
383 }
384
385 // Link in new position
386 NextWidget = Other->NextWidget;
387 PrevWidget = Other;
388 Other->NextWidget = this;
389 if (NextWidget)
390 {
391 NextWidget->PrevWidget = this;
392 }
393 else
394 {
395 ParentWidget->LastChildWidget = this;
396 }
397 unguard;
398 }
399
400 //==========================================================================
401 //
402 // VWidget::ClipTree
403 //
404 //==========================================================================
405
ClipTree()406 void VWidget::ClipTree()
407 {
408 guard(VWidget::ClipTree);
409 // Set up clipping rectangle.
410 if (ParentWidget)
411 {
412 // Clipping rectangle is relative to the parent widget.
413 ClipRect.OriginX = ParentWidget->ClipRect.OriginX +
414 ParentWidget->ClipRect.ScaleX * PosX;
415 ClipRect.OriginY = ParentWidget->ClipRect.OriginY +
416 ParentWidget->ClipRect.ScaleY * PosY;
417 ClipRect.ScaleX = ParentWidget->ClipRect.ScaleX * SizeScaleX;
418 ClipRect.ScaleY = ParentWidget->ClipRect.ScaleY * SizeScaleY;
419 ClipRect.ClipX1 = ClipRect.OriginX;
420 ClipRect.ClipY1 = ClipRect.OriginY;
421 ClipRect.ClipX2 = ClipRect.OriginX + ClipRect.ScaleX * SizeWidth;
422 ClipRect.ClipY2 = ClipRect.OriginY + ClipRect.ScaleY * SizeHeight;
423
424 // Clip against the parent widget's clipping rectangle.
425 if (ClipRect.ClipX1 < ParentWidget->ClipRect.ClipX1)
426 {
427 ClipRect.ClipX1 = ParentWidget->ClipRect.ClipX1;
428 }
429 if (ClipRect.ClipY1 < ParentWidget->ClipRect.ClipY1)
430 {
431 ClipRect.ClipY1 = ParentWidget->ClipRect.ClipY1;
432 }
433 if (ClipRect.ClipX2 > ParentWidget->ClipRect.ClipX2)
434 {
435 ClipRect.ClipX2 = ParentWidget->ClipRect.ClipX2;
436 }
437 if (ClipRect.ClipY2 > ParentWidget->ClipRect.ClipY2)
438 {
439 ClipRect.ClipY2 = ParentWidget->ClipRect.ClipY2;
440 }
441 }
442 else
443 {
444 // This is the root widget.
445 ClipRect.OriginX = PosX;
446 ClipRect.OriginY = PosY;
447 ClipRect.ScaleX = SizeScaleX;
448 ClipRect.ScaleY = SizeScaleY;
449 ClipRect.ClipX1 = ClipRect.OriginX;
450 ClipRect.ClipY1 = ClipRect.OriginY;
451 ClipRect.ClipX2 = ClipRect.OriginX + ClipRect.ScaleX * SizeWidth;
452 ClipRect.ClipY2 = ClipRect.OriginY + ClipRect.ScaleY * SizeHeight;
453 }
454
455 // Set up clipping rectangles in child widgets.
456 for (VWidget* W = FirstChildWidget; W; W = W->NextWidget)
457 {
458 W->ClipTree();
459 }
460 unguard;
461 }
462
463 //==========================================================================
464 //
465 // VWidget::SetConfiguration
466 //
467 //==========================================================================
468
SetConfiguration(int NewX,int NewY,int NewWidth,int HewHeight,float NewScaleX,float NewScaleY)469 void VWidget::SetConfiguration(int NewX, int NewY, int NewWidth,
470 int HewHeight, float NewScaleX, float NewScaleY)
471 {
472 guard(VWidget::SetConfiguration);
473 PosX = NewX;
474 PosY = NewY;
475 SizeWidth = NewWidth;
476 SizeHeight = HewHeight;
477 SizeScaleX = NewScaleX;
478 SizeScaleY = NewScaleY;
479 ClipTree();
480 OnConfigurationChanged();
481 unguard;
482 }
483
484 //==========================================================================
485 //
486 // VWidget::SetVisibility
487 //
488 //==========================================================================
489
SetVisibility(bool NewVisibility)490 void VWidget::SetVisibility(bool NewVisibility)
491 {
492 guard(VWidget::SetVisibility);
493 if (!!(WidgetFlags & WF_IsVisible) != NewVisibility)
494 {
495 if (NewVisibility)
496 {
497 WidgetFlags |= WF_IsVisible;
498 if (ParentWidget && !ParentWidget->CurrentFocusChild)
499 {
500 ParentWidget->SetCurrentFocusChild(this);
501 }
502 }
503 else
504 {
505 WidgetFlags &= ~WF_IsVisible;
506 if (ParentWidget && ParentWidget->CurrentFocusChild == this)
507 {
508 ParentWidget->FindNewFocus();
509 }
510 }
511 OnVisibilityChanged(NewVisibility);
512 }
513 unguard;
514 }
515
516 //==========================================================================
517 //
518 // VWidget::SetEnabled
519 //
520 //==========================================================================
521
SetEnabled(bool NewEnabled)522 void VWidget::SetEnabled(bool NewEnabled)
523 {
524 guard(VWidget::SetEnabled);
525 if (!!(WidgetFlags & WF_IsEnabled) != NewEnabled)
526 {
527 if (NewEnabled)
528 {
529 WidgetFlags |= WF_IsEnabled;
530 if (ParentWidget && !ParentWidget->CurrentFocusChild)
531 {
532 ParentWidget->SetCurrentFocusChild(this);
533 }
534 }
535 else
536 {
537 WidgetFlags &= ~WF_IsEnabled;
538 if (ParentWidget && ParentWidget->CurrentFocusChild == this)
539 {
540 ParentWidget->FindNewFocus();
541 }
542 }
543 OnEnableChanged(NewEnabled);
544 }
545 unguard;
546 }
547
548 //==========================================================================
549 //
550 // VWidget::SetFocusable
551 //
552 //==========================================================================
553
SetFocusable(bool NewFocusable)554 void VWidget::SetFocusable(bool NewFocusable)
555 {
556 guard(VWidget::SetFocusable);
557 if (!!(WidgetFlags & WF_IsFocusable) != NewFocusable)
558 {
559 if (NewFocusable)
560 {
561 WidgetFlags |= WF_IsFocusable;
562 if (ParentWidget && !ParentWidget->CurrentFocusChild)
563 {
564 ParentWidget->SetCurrentFocusChild(this);
565 }
566 }
567 else
568 {
569 WidgetFlags &= ~WF_IsFocusable;
570 if (ParentWidget && ParentWidget->CurrentFocusChild == this)
571 {
572 ParentWidget->FindNewFocus();
573 }
574 }
575 OnFocusableChanged(NewFocusable);
576 }
577 unguard;
578 }
579
580 //==========================================================================
581 //
582 // VWidget::SetCurrentFocusChild
583 //
584 //==========================================================================
585
SetCurrentFocusChild(VWidget * NewFocus)586 void VWidget::SetCurrentFocusChild(VWidget* NewFocus)
587 {
588 guard(VWidget::SetCurrentFocusChild);
589 // Check f it's already focused.
590 if (CurrentFocusChild == NewFocus)
591 {
592 return;
593 }
594
595 // Make sure it's visible, enabled and focusable.
596 if (NewFocus && (!(NewFocus->WidgetFlags & WF_IsVisible) ||
597 !(NewFocus->WidgetFlags & WF_IsEnabled) ||
598 !(NewFocus->WidgetFlags & WF_IsFocusable)))
599 {
600 return;
601 }
602
603 // If we have a focused child, send focus lost event.
604 if (CurrentFocusChild)
605 {
606 CurrentFocusChild->OnFocusLost();
607 }
608
609 // Make it the current focus.
610 CurrentFocusChild = NewFocus;
611 if (CurrentFocusChild)
612 {
613 CurrentFocusChild->OnFocusReceived();
614 }
615 unguard;
616 }
617
618 //==========================================================================
619 //
620 // VWidget::IsFocus
621 //
622 //==========================================================================
623
IsFocus(bool Recurse) const624 bool VWidget::IsFocus(bool Recurse) const
625 {
626 guard(VWidget::IsFocus);
627 // Root is always focused.
628 if (!ParentWidget)
629 {
630 return true;
631 }
632 if (Recurse)
633 {
634 const VWidget* W = this;
635 while (W->ParentWidget && W->ParentWidget->CurrentFocusChild == W)
636 {
637 W = W->ParentWidget;
638 }
639 return !W->ParentWidget;
640 }
641 else
642 {
643 return ParentWidget->CurrentFocusChild == this;
644 }
645 unguard;
646 }
647
648 //==========================================================================
649 //
650 // VWidget::SetFocus
651 //
652 //==========================================================================
653
SetFocus()654 void VWidget::SetFocus()
655 {
656 guard(VWidget::SetFocus);
657 if (ParentWidget)
658 {
659 ParentWidget->SetCurrentFocusChild(this);
660 }
661 unguard;
662 }
663
664 //==========================================================================
665 //
666 // VWidget::FindNewFocus
667 //
668 //==========================================================================
669
FindNewFocus()670 void VWidget::FindNewFocus()
671 {
672 guard(VWidget::FindNewFocus);
673 for (VWidget* W = CurrentFocusChild->NextWidget; W; W = W->NextWidget)
674 {
675 if ((W->WidgetFlags & WF_IsFocusable) &&
676 (W->WidgetFlags & WF_IsVisible) &&
677 (W->WidgetFlags & WF_IsEnabled))
678 {
679 SetCurrentFocusChild(W);
680 return;
681 }
682 }
683
684 for (VWidget* W = CurrentFocusChild->PrevWidget; W; W = W->PrevWidget)
685 {
686 if ((W->WidgetFlags & WF_IsFocusable) &&
687 (W->WidgetFlags & WF_IsVisible) &&
688 (W->WidgetFlags & WF_IsEnabled))
689 {
690 SetCurrentFocusChild(W);
691 return;
692 }
693 }
694
695 SetCurrentFocusChild(NULL);
696 unguard;
697 }
698
699 //==========================================================================
700 //
701 // VWidget::GetWidgetAt
702 //
703 //==========================================================================
704
GetWidgetAt(float X,float Y)705 VWidget* VWidget::GetWidgetAt(float X, float Y)
706 {
707 guard(VWidget::GetWidgetAt);
708 for (VWidget* W = LastChildWidget; W; W = W->PrevWidget)
709 {
710 if (!(W->WidgetFlags & WF_IsVisible))
711 {
712 continue;
713 }
714 if (X >= W->ClipRect.ClipX1 && X < W->ClipRect.ClipX2 &&
715 Y >= W->ClipRect.ClipY1 && Y < W->ClipRect.ClipY2)
716 {
717 return W->GetWidgetAt(X, Y);
718 }
719 }
720 return this;
721 unguard;
722 }
723
724 //==========================================================================
725 //
726 // VWidget::DrawTree
727 //
728 //==========================================================================
729
DrawTree()730 void VWidget::DrawTree()
731 {
732 guard(VWidget::DrawTree);
733 if (!(WidgetFlags & WF_IsVisible) || !ClipRect.HasArea())
734 {
735 // Not visible or clipped away.
736 return;
737 }
738
739 // Main draw event for this widget.
740 OnDraw();
741
742 // Draw chid widgets.
743 for (VWidget* c = FirstChildWidget; c; c = c->NextWidget)
744 {
745 c->DrawTree();
746 }
747
748 // Do any drawing after child wigets have been drawn.
749 OnPostDraw();
750 unguard;
751 }
752
753 //==========================================================================
754 //
755 // VWidget::TickTree
756 //
757 //==========================================================================
758
TickTree(float DeltaTime)759 void VWidget::TickTree(float DeltaTime)
760 {
761 guard(VWidget::TickTree);
762 if (WidgetFlags & WF_TickEnabled)
763 {
764 Tick(DeltaTime);
765 }
766 for (VWidget* c = FirstChildWidget; c; c = c->NextWidget)
767 {
768 c->TickTree(DeltaTime);
769 }
770 unguard;
771 }
772
773 //==========================================================================
774 //
775 // VWidget::TransferAndClipRect
776 //
777 //==========================================================================
778
TransferAndClipRect(float & X1,float & Y1,float & X2,float & Y2,float & S1,float & T1,float & S2,float & T2) const779 bool VWidget::TransferAndClipRect(float& X1, float& Y1, float& X2, float& Y2,
780 float& S1, float& T1, float& S2, float& T2) const
781 {
782 guard(VWidget::TransferAndClipRect);
783 X1 = ClipRect.ScaleX * X1 + ClipRect.OriginX;
784 Y1 = ClipRect.ScaleY * Y1 + ClipRect.OriginY;
785 X2 = ClipRect.ScaleX * X2 + ClipRect.OriginX;
786 Y2 = ClipRect.ScaleY * Y2 + ClipRect.OriginY;
787 if (X1 < ClipRect.ClipX1)
788 {
789 S1 = S1 + (X1 - ClipRect.ClipX1) / (X1 - X2) * (S2 - S1);
790 X1 = ClipRect.ClipX1;
791 }
792 if (X2 > ClipRect.ClipX2)
793 {
794 S2 = S2 + (X2 - ClipRect.ClipX2) / (X1 - X2) * (S2 - S1);
795 X2 = ClipRect.ClipX2;
796 }
797 if (Y1 < ClipRect.ClipY1)
798 {
799 T1 = T1 + (Y1 - ClipRect.ClipY1) / (Y1 - Y2) * (T2 - T1);
800 Y1 = ClipRect.ClipY1;
801 }
802 if (Y2 > ClipRect.ClipY2)
803 {
804 T2 = T2 + (Y2 - ClipRect.ClipY2) / (Y1 - Y2) * (T2 - T1);
805 Y2 = ClipRect.ClipY2;
806 }
807 return X1 < X2 && Y1 < Y2;
808 unguard;
809 }
810
811 //==========================================================================
812 //
813 // VWidget::DrawPic
814 //
815 //==========================================================================
816
DrawPic(int X,int Y,int Handle,float Alpha,int Trans)817 void VWidget::DrawPic(int X, int Y, int Handle, float Alpha, int Trans)
818 {
819 guard(VWidget::DrawPic);
820 DrawPic(X, Y, GTextureManager(Handle), Alpha, Trans);
821 unguard;
822 }
823
824 //==========================================================================
825 //
826 // VWidget::DrawPic
827 //
828 //==========================================================================
829
DrawPic(int X,int Y,VTexture * Tex,float Alpha,int Trans)830 void VWidget::DrawPic(int X, int Y, VTexture* Tex, float Alpha, int Trans)
831 {
832 guard(VWidget::DrawPic);
833 if (!Tex)
834 {
835 return;
836 }
837
838 X -= Tex->GetScaledSOffset();
839 Y -= Tex->GetScaledTOffset();
840 float X1 = X;
841 float Y1 = Y;
842 float X2 = X + Tex->GetScaledWidth();
843 float Y2 = Y + Tex->GetScaledHeight();
844 float S1 = 0;
845 float T1 = 0;
846 float S2 = Tex->GetWidth();
847 float T2 = Tex->GetHeight();
848 if (TransferAndClipRect(X1, Y1, X2, Y2, S1, T1, S2, T2))
849 {
850 Drawer->DrawPic(X1, Y1, X2, Y2, S1, T1, S2, T2, Tex,
851 R_GetCachedTranslation(Trans, NULL), Alpha);
852 }
853 unguard;
854 }
855
856 //==========================================================================
857 //
858 // VWidget::DrawShadowedPic
859 //
860 //==========================================================================
861
DrawShadowedPic(int X,int Y,int Handle)862 void VWidget::DrawShadowedPic(int X, int Y, int Handle)
863 {
864 guard(VWidget::DrawShadowedPic);
865 DrawShadowedPic(X, Y, GTextureManager(Handle));
866 unguard;
867 }
868
869 //==========================================================================
870 //
871 // VWidget::DrawShadowedPic
872 //
873 //==========================================================================
874
DrawShadowedPic(int X,int Y,VTexture * Tex)875 void VWidget::DrawShadowedPic(int X, int Y, VTexture* Tex)
876 {
877 guard(VWidget::DrawShadowedPic);
878 if (!Tex)
879 {
880 return;
881 }
882
883 float X1 = X - Tex->GetScaledSOffset() + 2;
884 float Y1 = Y - Tex->GetScaledTOffset() + 2;
885 float X2 = X - Tex->GetScaledSOffset() + 2 + Tex->GetScaledWidth();
886 float Y2 = Y - Tex->GetScaledTOffset() + 2 + Tex->GetScaledHeight();
887 float S1 = 0;
888 float T1 = 0;
889 float S2 = Tex->GetWidth();
890 float T2 = Tex->GetHeight();
891 if (TransferAndClipRect(X1, Y1, X2, Y2, S1, T1, S2, T2))
892 {
893 Drawer->DrawPicShadow(X1, Y1, X2, Y2, S1, T1, S2, T2, Tex, 0.625);
894 }
895
896 DrawPic(X, Y, Tex);
897 unguard;
898 }
899
900 //==========================================================================
901 //
902 // VWidget::FillRectWithFlat
903 //
904 //==========================================================================
905
FillRectWithFlat(int X,int Y,int Width,int Height,VName Name)906 void VWidget::FillRectWithFlat(int X, int Y, int Width, int Height,
907 VName Name)
908 {
909 guard(VWidget::FillRectWithFlat);
910 float X1 = X;
911 float Y1 = Y;
912 float X2 = X + Width;
913 float Y2 = Y + Height;
914 float S1 = 0;
915 float T1 = 0;
916 float S2 = Width;
917 float T2 = Height;
918 if (TransferAndClipRect(X1, Y1, X2, Y2, S1, T1, S2, T2))
919 {
920 Drawer->FillRectWithFlat(X1, Y1, X2, Y2, S1, T1, S2, T2,
921 GTextureManager(GTextureManager.NumForName(Name, TEXTYPE_Flat,
922 true, true)));
923 }
924 unguard;
925 }
926
927 //==========================================================================
928 //
929 // VWidget::ShadeRect
930 //
931 //==========================================================================
932
ShadeRect(int X,int Y,int Width,int Height,float Shade)933 void VWidget::ShadeRect(int X, int Y, int Width, int Height, float Shade)
934 {
935 guard(VWidget::ShadeRect);
936 float X1 = X;
937 float Y1 = Y;
938 float X2 = X + Width;
939 float Y2 = Y + Height;
940 float S1 = 0;
941 float T1 = 0;
942 float S2 = 0;
943 float T2 = 0;
944 if (TransferAndClipRect(X1, Y1, X2, Y2, S1, T1, S2, T2))
945 {
946 Drawer->ShadeRect((int)X1, (int)Y1, (int)X2 - (int)X1, (int)Y2 - (int)Y1, Shade);
947 }
948 unguard;
949 }
950
951 //==========================================================================
952 //
953 // VWidget::SetFont
954 //
955 //==========================================================================
956
SetFont(VFont * AFont)957 void VWidget::SetFont(VFont* AFont)
958 {
959 guard(VWidget::SetFont);
960 Font = AFont;
961 unguard;
962 }
963
964 //==========================================================================
965 //
966 // VWidget::SetFont
967 //
968 //==========================================================================
969
SetFont(VName FontName)970 void VWidget::SetFont(VName FontName)
971 {
972 guard(VWidget::SetFont);
973 VFont* F = VFont::GetFont(FontName, FontName);
974 if (F)
975 {
976 Font = F;
977 }
978 else
979 {
980 GCon->Logf("No such font %s", *FontName);
981 }
982 unguard;
983 }
984
985 //==========================================================================
986 //
987 // VWidget::SetTextAlign
988 //
989 //==========================================================================
990
SetTextAlign(halign_e NewHAlign,valign_e NewVAlign)991 void VWidget::SetTextAlign(halign_e NewHAlign, valign_e NewVAlign)
992 {
993 guard(VWidget::SetTextAlign);
994 HAlign = NewHAlign;
995 VAlign = NewVAlign;
996 unguard;
997 }
998
999 //==========================================================================
1000 //
1001 // VWidget::SetTextShadow
1002 //
1003 //==========================================================================
1004
SetTextShadow(bool State)1005 void VWidget::SetTextShadow(bool State)
1006 {
1007 if (State)
1008 WidgetFlags |= WF_TextShadowed;
1009 else
1010 WidgetFlags &= ~WF_TextShadowed;
1011 }
1012
1013 //==========================================================================
1014 //
1015 // VWidget::DrawString
1016 //
1017 //==========================================================================
1018
DrawString(int x,int y,const VStr & String,int NormalColour,int BoldColour,float Alpha)1019 void VWidget::DrawString(int x, int y, const VStr& String, int NormalColour,
1020 int BoldColour, float Alpha)
1021 {
1022 guard(VWidget::DrawNString);
1023 if (String.IsEmpty())
1024 return;
1025
1026 int cx = x;
1027 int cy = y;
1028 int Kerning = Font->GetKerning();
1029 int Colour = NormalColour;
1030
1031 if (HAlign == hcentre)
1032 cx -= Font->StringWidth(String) / 2;
1033 if (HAlign == hright)
1034 cx -= Font->StringWidth(String);
1035
1036 for (const char* SPtr = *String; *SPtr;)
1037 {
1038 int c = VStr::GetChar(SPtr);
1039
1040 // Check for colour escape.
1041 if (c == TEXT_COLOUR_ESCAPE)
1042 {
1043 Colour = VFont::ParseColourEscape(SPtr, NormalColour, BoldColour);
1044 continue;
1045 }
1046
1047 int w;
1048 VTexture* Tex = Font->GetChar(c, &w, Colour);
1049 if (Tex)
1050 {
1051 if (WidgetFlags & WF_TextShadowed)
1052 DrawShadowedPic(cx, cy, Tex);
1053 else
1054 DrawPic(cx, cy, Tex, Alpha);
1055 }
1056 cx += w + Kerning;
1057 }
1058 LastX = cx;
1059 LastY = cy;
1060 unguard;
1061 }
1062
1063 //==========================================================================
1064 //
1065 // VWidget::DrawText
1066 //
1067 //==========================================================================
1068
DrawText(int x,int y,const VStr & String,int NormalColour,int BoldColour,float Alpha)1069 void VWidget::DrawText(int x, int y, const VStr& String, int NormalColour,
1070 int BoldColour, float Alpha)
1071 {
1072 guard(VWidget::DrawText);
1073 int start = 0;
1074 int cx = x;
1075 int cy = y;
1076
1077 if (VAlign == vcentre)
1078 cy -= Font->TextHeight(String) / 2;
1079 if (VAlign == vbottom)
1080 cy -= Font->TextHeight(String);
1081
1082 // Need this for correct cursor position with empty strings.
1083 LastX = cx;
1084 LastY = cy;
1085
1086 for (size_t i = 0; i < String.Length(); i++)
1087 {
1088 if (String[i] == '\n')
1089 {
1090 VStr cs(String, start, i - start);
1091 DrawString(cx, cy, cs, NormalColour, BoldColour, Alpha);
1092 cy += Font->GetHeight();
1093 start = i + 1;
1094 }
1095 if (i == String.Length() - 1)
1096 {
1097 DrawString(cx, cy, VStr(String, start, String.Length() - start),
1098 NormalColour, BoldColour, Alpha);
1099 }
1100 }
1101 unguard;
1102 }
1103
1104 //==========================================================================
1105 //
1106 // VWidget::DrawCursor
1107 //
1108 //==========================================================================
1109
DrawCursor()1110 void VWidget::DrawCursor()
1111 {
1112 DrawCursorAt(LastX, LastY);
1113 }
1114
1115 //==========================================================================
1116 //
1117 // VWidget::DrawCursorAt
1118 //
1119 //==========================================================================
1120
DrawCursorAt(int x,int y)1121 void VWidget::DrawCursorAt(int x, int y)
1122 {
1123 guard(VWidget::DrawCursorAt);
1124 if ((int)(host_time * 4) & 1)
1125 {
1126 int w;
1127 DrawPic(x, y, Font->GetChar('_', &w, CR_UNTRANSLATED));
1128 }
1129 unguard;
1130 }
1131
1132 //==========================================================================
1133 //
1134 // Natives
1135 //
1136 //==========================================================================
1137
IMPLEMENT_FUNCTION(VWidget,NewChild)1138 IMPLEMENT_FUNCTION(VWidget, NewChild)
1139 {
1140 P_GET_PTR(VClass, ChildClass);
1141 P_GET_SELF;
1142 RET_REF(CreateNewWidget(ChildClass, Self));
1143 }
1144
IMPLEMENT_FUNCTION(VWidget,Destroy)1145 IMPLEMENT_FUNCTION(VWidget, Destroy)
1146 {
1147 P_GET_SELF;
1148 delete Self;
1149 Self = NULL;
1150 }
1151
IMPLEMENT_FUNCTION(VWidget,DestroyAllChildren)1152 IMPLEMENT_FUNCTION(VWidget, DestroyAllChildren)
1153 {
1154 P_GET_SELF;
1155 Self->DestroyAllChildren();
1156 }
1157
IMPLEMENT_FUNCTION(VWidget,GetRootWidget)1158 IMPLEMENT_FUNCTION(VWidget, GetRootWidget)
1159 {
1160 P_GET_SELF;
1161 RET_REF(Self->GetRootWidget());
1162 }
1163
IMPLEMENT_FUNCTION(VWidget,Lower)1164 IMPLEMENT_FUNCTION(VWidget, Lower)
1165 {
1166 P_GET_SELF;
1167 Self->Lower();
1168 }
1169
IMPLEMENT_FUNCTION(VWidget,Raise)1170 IMPLEMENT_FUNCTION(VWidget, Raise)
1171 {
1172 P_GET_SELF;
1173 Self->Raise();
1174 }
1175
IMPLEMENT_FUNCTION(VWidget,MoveBefore)1176 IMPLEMENT_FUNCTION(VWidget, MoveBefore)
1177 {
1178 P_GET_REF(VWidget, Other);
1179 P_GET_SELF;
1180 Self->MoveBefore(Other);
1181 }
1182
IMPLEMENT_FUNCTION(VWidget,MoveAfter)1183 IMPLEMENT_FUNCTION(VWidget, MoveAfter)
1184 {
1185 P_GET_REF(VWidget, Other);
1186 P_GET_SELF;
1187 Self->MoveAfter(Other);
1188 }
1189
IMPLEMENT_FUNCTION(VWidget,SetPos)1190 IMPLEMENT_FUNCTION(VWidget, SetPos)
1191 {
1192 P_GET_INT(NewY);
1193 P_GET_INT(NewX);
1194 P_GET_SELF;
1195 Self->SetPos(NewX, NewY);
1196 }
1197
IMPLEMENT_FUNCTION(VWidget,SetX)1198 IMPLEMENT_FUNCTION(VWidget, SetX)
1199 {
1200 P_GET_INT(NewX);
1201 P_GET_SELF;
1202 Self->SetX(NewX);
1203 }
1204
IMPLEMENT_FUNCTION(VWidget,SetY)1205 IMPLEMENT_FUNCTION(VWidget, SetY)
1206 {
1207 P_GET_INT(NewY);
1208 P_GET_SELF;
1209 Self->SetY(NewY);
1210 }
1211
IMPLEMENT_FUNCTION(VWidget,SetSize)1212 IMPLEMENT_FUNCTION(VWidget, SetSize)
1213 {
1214 P_GET_INT(NewHeight);
1215 P_GET_INT(NewWidth);
1216 P_GET_SELF;
1217 Self->SetSize(NewWidth, NewHeight);
1218 }
1219
IMPLEMENT_FUNCTION(VWidget,SetWidth)1220 IMPLEMENT_FUNCTION(VWidget, SetWidth)
1221 {
1222 P_GET_INT(NewWidth);
1223 P_GET_SELF;
1224 Self->SetWidth(NewWidth);
1225 }
1226
IMPLEMENT_FUNCTION(VWidget,SetHeight)1227 IMPLEMENT_FUNCTION(VWidget, SetHeight)
1228 {
1229 P_GET_INT(NewHeight);
1230 P_GET_SELF;
1231 Self->SetHeight(NewHeight);
1232 }
1233
IMPLEMENT_FUNCTION(VWidget,SetScale)1234 IMPLEMENT_FUNCTION(VWidget, SetScale)
1235 {
1236 P_GET_FLOAT(NewScaleY);
1237 P_GET_FLOAT(NewScaleX);
1238 P_GET_SELF;
1239 Self->SetScale(NewScaleX, NewScaleY);
1240 }
1241
IMPLEMENT_FUNCTION(VWidget,SetConfiguration)1242 IMPLEMENT_FUNCTION(VWidget, SetConfiguration)
1243 {
1244 P_GET_FLOAT_OPT(NewScaleY, 1.0);
1245 P_GET_FLOAT_OPT(NewScaleX, 1.0);
1246 P_GET_INT(NewHeight);
1247 P_GET_INT(NewWidth);
1248 P_GET_INT(NewY);
1249 P_GET_INT(NewX);
1250 P_GET_SELF;
1251 Self->SetConfiguration(NewX, NewY, NewWidth, NewHeight, NewScaleX,
1252 NewScaleY);
1253 }
1254
IMPLEMENT_FUNCTION(VWidget,SetVisibility)1255 IMPLEMENT_FUNCTION(VWidget, SetVisibility)
1256 {
1257 P_GET_BOOL(bNewVisibility);
1258 P_GET_SELF;
1259 Self->SetVisibility(bNewVisibility);
1260 }
1261
IMPLEMENT_FUNCTION(VWidget,Show)1262 IMPLEMENT_FUNCTION(VWidget, Show)
1263 {
1264 P_GET_SELF;
1265 Self->Show();
1266 }
1267
IMPLEMENT_FUNCTION(VWidget,Hide)1268 IMPLEMENT_FUNCTION(VWidget, Hide)
1269 {
1270 P_GET_SELF;
1271 Self->Hide();
1272 }
1273
IMPLEMENT_FUNCTION(VWidget,IsVisible)1274 IMPLEMENT_FUNCTION(VWidget, IsVisible)
1275 {
1276 P_GET_BOOL_OPT(Recurse, true);
1277 P_GET_SELF;
1278 RET_BOOL(Self->IsVisible(Recurse));
1279 }
1280
IMPLEMENT_FUNCTION(VWidget,SetEnabled)1281 IMPLEMENT_FUNCTION(VWidget, SetEnabled)
1282 {
1283 P_GET_BOOL(bNewEnabled);
1284 P_GET_SELF;
1285 Self->SetEnabled(bNewEnabled);
1286 }
1287
IMPLEMENT_FUNCTION(VWidget,Enable)1288 IMPLEMENT_FUNCTION(VWidget, Enable)
1289 {
1290 P_GET_SELF;
1291 Self->Enable();
1292 }
1293
IMPLEMENT_FUNCTION(VWidget,Disable)1294 IMPLEMENT_FUNCTION(VWidget, Disable)
1295 {
1296 P_GET_SELF;
1297 Self->Disable();
1298 }
1299
IMPLEMENT_FUNCTION(VWidget,IsEnabled)1300 IMPLEMENT_FUNCTION(VWidget, IsEnabled)
1301 {
1302 P_GET_BOOL_OPT(Recurse, true);
1303 P_GET_SELF;
1304 RET_BOOL(Self->IsEnabled(Recurse));
1305 }
1306
IMPLEMENT_FUNCTION(VWidget,SetFocusable)1307 IMPLEMENT_FUNCTION(VWidget, SetFocusable)
1308 {
1309 P_GET_BOOL(bNewFocusable);
1310 P_GET_SELF;
1311 Self->SetFocusable(bNewFocusable);
1312 }
1313
IMPLEMENT_FUNCTION(VWidget,IsFocusable)1314 IMPLEMENT_FUNCTION(VWidget, IsFocusable)
1315 {
1316 P_GET_SELF;
1317 RET_BOOL(Self->IsFocusable());
1318 }
1319
IMPLEMENT_FUNCTION(VWidget,SetCurrentFocusChild)1320 IMPLEMENT_FUNCTION(VWidget, SetCurrentFocusChild)
1321 {
1322 P_GET_REF(VWidget, NewFocus);
1323 P_GET_SELF;
1324 Self->SetCurrentFocusChild(NewFocus);
1325 }
1326
IMPLEMENT_FUNCTION(VWidget,GetCurrentFocus)1327 IMPLEMENT_FUNCTION(VWidget, GetCurrentFocus)
1328 {
1329 P_GET_SELF;
1330 RET_REF(Self->GetCurrentFocus());
1331 }
1332
IMPLEMENT_FUNCTION(VWidget,IsFocus)1333 IMPLEMENT_FUNCTION(VWidget, IsFocus)
1334 {
1335 P_GET_BOOL_OPT(Recurse, true);
1336 P_GET_SELF;
1337 RET_BOOL(Self->IsFocus(Recurse));
1338 }
1339
IMPLEMENT_FUNCTION(VWidget,SetFocus)1340 IMPLEMENT_FUNCTION(VWidget, SetFocus)
1341 {
1342 P_GET_SELF;
1343 Self->SetFocus();
1344 }
1345
IMPLEMENT_FUNCTION(VWidget,DrawPic)1346 IMPLEMENT_FUNCTION(VWidget, DrawPic)
1347 {
1348 P_GET_INT_OPT(Translation, 0);
1349 P_GET_FLOAT_OPT(Alpha, 1.0);
1350 P_GET_INT(Handle);
1351 P_GET_INT(Y);
1352 P_GET_INT(X);
1353 P_GET_SELF;
1354 Self->DrawPic(X, Y, Handle, Alpha, Translation);
1355 }
1356
IMPLEMENT_FUNCTION(VWidget,DrawShadowedPic)1357 IMPLEMENT_FUNCTION(VWidget, DrawShadowedPic)
1358 {
1359 P_GET_INT(Handle);
1360 P_GET_INT(Y);
1361 P_GET_INT(X);
1362 P_GET_SELF;
1363 Self->DrawShadowedPic(X, Y, Handle);
1364 }
1365
IMPLEMENT_FUNCTION(VWidget,FillRectWithFlat)1366 IMPLEMENT_FUNCTION(VWidget, FillRectWithFlat)
1367 {
1368 P_GET_NAME(Name);
1369 P_GET_INT(Height);
1370 P_GET_INT(Width);
1371 P_GET_INT(Y);
1372 P_GET_INT(X);
1373 P_GET_SELF;
1374 Self->FillRectWithFlat(X, Y, Width, Height, Name);
1375 }
1376
IMPLEMENT_FUNCTION(VWidget,ShadeRect)1377 IMPLEMENT_FUNCTION(VWidget, ShadeRect)
1378 {
1379 P_GET_FLOAT(Shade);
1380 P_GET_INT(Height);
1381 P_GET_INT(Width);
1382 P_GET_INT(Y);
1383 P_GET_INT(X);
1384 P_GET_SELF;
1385 Self->ShadeRect(X, Y, Width, Height, Shade);
1386 }
1387
IMPLEMENT_FUNCTION(VWidget,SetFont)1388 IMPLEMENT_FUNCTION(VWidget, SetFont)
1389 {
1390 P_GET_NAME(FontName);
1391 P_GET_SELF;
1392 Self->SetFont(FontName);
1393 }
1394
IMPLEMENT_FUNCTION(VWidget,SetTextAlign)1395 IMPLEMENT_FUNCTION(VWidget, SetTextAlign)
1396 {
1397 P_GET_INT(valign);
1398 P_GET_INT(halign);
1399 P_GET_SELF;
1400 Self->SetTextAlign((halign_e)halign, (valign_e)valign);
1401 }
1402
IMPLEMENT_FUNCTION(VWidget,SetTextShadow)1403 IMPLEMENT_FUNCTION(VWidget, SetTextShadow)
1404 {
1405 P_GET_BOOL(State);
1406 P_GET_SELF;
1407 Self->SetTextShadow(State);
1408 }
1409
IMPLEMENT_FUNCTION(VWidget,TextWidth)1410 IMPLEMENT_FUNCTION(VWidget, TextWidth)
1411 {
1412 P_GET_STR(text);
1413 P_GET_SELF;
1414 RET_INT(Self->Font->TextWidth(text));
1415 }
1416
IMPLEMENT_FUNCTION(VWidget,TextHeight)1417 IMPLEMENT_FUNCTION(VWidget, TextHeight)
1418 {
1419 P_GET_STR(text);
1420 P_GET_SELF;
1421 RET_INT(Self->Font->TextHeight(text));
1422 }
1423
IMPLEMENT_FUNCTION(VWidget,SplitText)1424 IMPLEMENT_FUNCTION(VWidget, SplitText)
1425 {
1426 P_GET_INT(MaxWidth);
1427 P_GET_PTR(TArray<VSplitLine>, Lines);
1428 P_GET_STR(Text);
1429 P_GET_SELF;
1430 RET_INT(Self->Font->SplitText(Text, *Lines, MaxWidth));
1431 }
1432
IMPLEMENT_FUNCTION(VWidget,SplitTextWithNewlines)1433 IMPLEMENT_FUNCTION(VWidget, SplitTextWithNewlines)
1434 {
1435 P_GET_INT(MaxWidth);
1436 P_GET_STR(Text);
1437 P_GET_SELF;
1438 RET_STR(Self->Font->SplitTextWithNewlines(Text, MaxWidth));
1439 }
1440
IMPLEMENT_FUNCTION(VWidget,DrawText)1441 IMPLEMENT_FUNCTION(VWidget, DrawText)
1442 {
1443 P_GET_FLOAT_OPT(Alpha, 1.0);
1444 P_GET_INT_OPT(BoldColour, CR_UNTRANSLATED);
1445 P_GET_INT_OPT(Colour, CR_UNTRANSLATED);
1446 P_GET_STR(String);
1447 P_GET_INT(Y);
1448 P_GET_INT(X);
1449 P_GET_SELF;
1450 Self->DrawText(X, Y, String, Colour, BoldColour, Alpha);
1451 }
1452
IMPLEMENT_FUNCTION(VWidget,DrawCursor)1453 IMPLEMENT_FUNCTION(VWidget, DrawCursor)
1454 {
1455 P_GET_SELF;
1456 Self->DrawCursor();
1457 }
1458
IMPLEMENT_FUNCTION(VWidget,FindTextColour)1459 IMPLEMENT_FUNCTION(VWidget, FindTextColour)
1460 {
1461 P_GET_STR(Name);
1462 RET_INT(VFont::FindTextColour(*Name.ToLower()));
1463 }
1464