529 lines
12 KiB
Ucode
529 lines
12 KiB
Ucode
// ====================================================================
|
|
// Class: UT2K4UI.GUIMultiComponent
|
|
//
|
|
// GUIMultiComponents are collections of components that work together.
|
|
// When initialized, GUIMultiComponents transfer all of their components
|
|
// to the to the GUIPage that owns them.
|
|
//
|
|
// Written by Joe Wilcox
|
|
// Updated by Ron Prestenback
|
|
// (c) 2002, Epic Games, Inc. All Rights Reserved
|
|
// ====================================================================
|
|
|
|
class GUIMultiComponent extends GUIComponent
|
|
Abstract
|
|
Native;
|
|
|
|
cpptext
|
|
{
|
|
void PreDraw(UCanvas* Canvas); // Do any size/postitioning
|
|
void Draw(UCanvas* Canvas); // Draw the component
|
|
void PreDrawControls(UCanvas* Canvas);
|
|
void DrawControls(UCanvas* Canvas);
|
|
|
|
virtual void InitializeControls(); // Takes all GUIComponent members and assigns them to the controls array
|
|
virtual void RemapComponents();
|
|
|
|
UGUIComponent* UnderCursor(FLOAT MouseX, FLOAT MouseY);
|
|
|
|
UBOOL NativeKeyType(BYTE& iKey, TCHAR Unicode ); // A Key or Mouse button has pressed
|
|
UBOOL NativeKeyEvent(BYTE& iKey, BYTE& State, FLOAT Delta ); // A Key/Mouse event occured
|
|
|
|
void NativeInvalidate(UGUIComponent* Who);
|
|
UBOOL SpecialHit( UBOOL bForce );
|
|
|
|
UBOOL PerformHitTest(INT MouseX, INT MouseY);
|
|
|
|
UBOOL MousePressed(UBOOL IsRepeat); // The left mouse button was pressed
|
|
UBOOL MouseReleased(); // The mouse button was released
|
|
|
|
UGUIComponent* GetFocused() const { return FocusedControl; }
|
|
UBOOL IsFocusedOn( const UGUIComponent* Comp ) const { return Comp && Comp == GetFocused(); }
|
|
|
|
void NotifyResolutionChange( INT NewResX, INT NewResY );
|
|
#ifdef UCONST_Counter
|
|
virtual void ResetCounter();
|
|
#endif
|
|
}
|
|
|
|
var(Menu) editinlinenotify export array<GUIComponent> Controls; // An Array of Components that make up this Control
|
|
var(State) noexport editconst GUIComponent FocusedControl; // Which component inside this one has focus
|
|
var(Menu) noexport editconstarray array<GUIComponent> Components; // An Array of Controls that can be tabbed to
|
|
|
|
// Animation
|
|
var() noexport editconst int AnimationCount; // Every time a component begins an animation frame, this is increased
|
|
|
|
var() bool PropagateVisibility; // Does changes to visibility propagate down the line
|
|
var() bool bOldStyleMenus; // Is this a UT2003 menu or UT2004
|
|
var(State) bool bDrawFocusedLast; // Draw focused control last (focused control will always appear on top)
|
|
|
|
// If true, empty Controls array when InitializeControls() is called
|
|
// (Generally required in order to use automated components when subclassing classes that have Controls members
|
|
// defined in default properties)
|
|
var() bool bAlwaysAutomate;
|
|
|
|
delegate bool HandleContextMenuOpen(GUIComponent Sender, GUIContextMenu Menu, GUIComponent ContextMenuOwner)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
delegate bool HandleContextMenuClose(GUIContextMenu Sender)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
delegate bool NotifyContextSelect(GUIContextMenu Sender, int ClickIndex) { return false; }
|
|
delegate OnCreateComponent(GUIComponent NewComponent, GUIComponent Sender); // Hook to allow setting of component properties before initialization
|
|
|
|
// Adds all 'automated' GUIComponent subobjects to the Controls array (only if Controls array is empty).
|
|
native final function InitializeControls();
|
|
|
|
// Re-orders all controls with bTabStop = True, according to TabOrder, from lowest to highest
|
|
native final function RemapComponents();
|
|
|
|
// Returns the index into the Components array of GUIComponent Who
|
|
native final function int FindComponentIndex(GUIComponent Who);
|
|
|
|
// Stub
|
|
function InternalOnShow();
|
|
|
|
function InitComponent(GUIController MyController, GUIComponent MyOwner)
|
|
{
|
|
local int i;
|
|
|
|
Super.InitComponent(MyController, MyOwner);
|
|
|
|
InitializeControls(); // Build the Controls array
|
|
for (i=0;i<Controls.Length;i++)
|
|
{
|
|
if (Controls[i] == None)
|
|
{
|
|
if ( Controller.bModAuthor )
|
|
log(Name@"- Invalid control found in"@GetMenuPath()$"!! (Control"@i$")",'ModAuthor');
|
|
Controls.Remove(i--,1);
|
|
continue;
|
|
}
|
|
|
|
OnCreateComponent(Controls[i], Self);
|
|
Controls[i].InitComponent(MyController, Self);
|
|
}
|
|
|
|
RemapComponents();
|
|
}
|
|
|
|
event GUIComponent AddComponent(string ComponentClass, optional bool SkipRemap)
|
|
{
|
|
local class<GUIComponent> NewCompClass;
|
|
local GUIComponent NewComp;
|
|
|
|
if ( Controller != None )
|
|
NewCompClass = Controller.AddComponentClass(ComponentClass);
|
|
else NewCompClass = class<GUIComponent>(DynamicLoadObject(ComponentClass,class'class'));
|
|
if (NewCompClass != None)
|
|
{
|
|
|
|
NewComp = new(None) NewCompClass;
|
|
if (NewComp!=None)
|
|
{
|
|
NewComp = AppendComponent(NewComp, SkipRemap);
|
|
return NewComp;
|
|
}
|
|
}
|
|
|
|
log(Name@"could not create component"@ComponentClass,'AddComponent');
|
|
return none;
|
|
}
|
|
|
|
// This function allows you to append a component that has already been initialized
|
|
// Be very careful about how you handle the focus chain
|
|
event GUIComponent InsertComponent(GUIComponent NewComp, int Index, optional bool SkipRemap)
|
|
{
|
|
if (Index < 0 || Index >= Controls.Length)
|
|
return AppendComponent(NewComp);
|
|
|
|
Controls.Insert(Index, 1);
|
|
Controls[Index] = NewComp;
|
|
if (!SkipRemap)
|
|
RemapComponents();
|
|
return NewComp;
|
|
}
|
|
|
|
event GUIComponent AppendComponent(GUIComponent NewComp, optional bool SkipRemap)
|
|
{
|
|
local int index;
|
|
|
|
// Attempt to add it sorted in to the array. The Controls array is sorted by
|
|
// Render Weight.
|
|
|
|
while (Index<Controls.Length)
|
|
{
|
|
if (NewComp.RenderWeight < Controls[Index].RenderWeight) // We found our spot
|
|
{
|
|
Controls.Insert(Index,1);
|
|
break;
|
|
}
|
|
Index++;
|
|
}
|
|
|
|
// Couldn't find a spot, add it at the end
|
|
Controls[Index] = NewComp;
|
|
|
|
OnCreateComponent(NewComp, Self);
|
|
if ( NewComp.Controller == None )
|
|
NewComp.InitComponent(Controller, Self);
|
|
|
|
if (!SkipRemap)
|
|
RemapComponents();
|
|
|
|
// If current menu is already initialized, we need to call the opened event from here
|
|
if (Controller.bCurMenuInitialized)
|
|
NewComp.Opened(Self);
|
|
|
|
return NewComp;
|
|
}
|
|
|
|
event bool RemoveComponent(GUIComponent Comp, optional bool SkipRemap)
|
|
{
|
|
local int i;
|
|
for (i=0;i<Controls.Length;i++)
|
|
{
|
|
if (Controls[i] == Comp)
|
|
{
|
|
Controls.Remove(i,1);
|
|
|
|
if (!SkipRemap)
|
|
RemapComponents();
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function SetFocusInstead( GUIComponent InFocusComp )
|
|
{
|
|
local int i;
|
|
|
|
Super.SetFocusInstead(InFocusComp);
|
|
for ( i = 0; i < Controls.Length; i++ )
|
|
Controls[i].SetFocusInstead(InFocusComp);
|
|
}
|
|
|
|
event SetFocus(GUIComponent Who)
|
|
{
|
|
if (Who==None)
|
|
{
|
|
if ( !FocusFirst(None) )
|
|
Super.SetFocus(None);
|
|
|
|
return;
|
|
}
|
|
else
|
|
FocusedControl = Who;
|
|
|
|
MenuStateChange(MSAT_Focused);
|
|
|
|
if (MenuOwner!=None)
|
|
MenuOwner.SetFocus(self);
|
|
}
|
|
|
|
event LoseFocus(GUIComponent Sender)
|
|
{
|
|
FocusedControl = None;
|
|
Super.LoseFocus(Sender);
|
|
}
|
|
|
|
function bool CanAcceptFocus()
|
|
{
|
|
local int i;
|
|
|
|
if ( bAcceptsInput && Super.CanAcceptFocus() )
|
|
return true;
|
|
|
|
for ( i = 0; i < Controls.Length; i++ )
|
|
if ( Controls[i].CanAcceptFocus() )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
event bool FocusFirst(GUIComponent Sender)
|
|
{
|
|
local int i;
|
|
|
|
if (Components.Length>0)
|
|
{
|
|
for (i=0;i<Components.Length;i++)
|
|
{
|
|
if ( Components[i].FocusFirst(Sender) )
|
|
return true;
|
|
}
|
|
}
|
|
|
|
for (i=0;i<Controls.Length;i++)
|
|
{
|
|
if ( Controls[i].FocusFirst(Sender) )
|
|
return true;
|
|
}
|
|
|
|
if ( bAcceptsInput && Super.CanAcceptFocus() )
|
|
{
|
|
Super.SetFocus(None);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
event bool FocusLast(GUIComponent Sender)
|
|
{
|
|
local int i;
|
|
|
|
if (Components.Length>0)
|
|
{
|
|
for (i=Components.Length-1;i>=0;i--)
|
|
{
|
|
if (Components[i].FocusLast(Sender))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
for (i=Controls.Length-1;i>=0;i--)
|
|
{
|
|
if ( Controls[i].FocusLast(Sender) )
|
|
return true;
|
|
}
|
|
|
|
if ( bAcceptsInput && Super.CanAcceptFocus() )
|
|
{
|
|
Super.SetFocus(None);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
event bool NextControl(GUIComponent Sender)
|
|
{
|
|
local int Index;
|
|
|
|
Index = FindComponentIndex(Sender);
|
|
if ( Index >= 0 )
|
|
{
|
|
// Find the next possible component
|
|
while (++Index<Components.Length)
|
|
{
|
|
if ( Components[Index].FocusFirst(None) )
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if ( Super.NextControl(self) )
|
|
return true;
|
|
|
|
return FocusFirst(none);
|
|
}
|
|
|
|
event bool PrevControl(GUIComponent Sender)
|
|
{
|
|
|
|
local int Index;
|
|
|
|
Index = FindComponentIndex(Sender);
|
|
while (--Index>=0)
|
|
{
|
|
if (Components[Index].FocusLast(None))
|
|
return true;
|
|
}
|
|
|
|
if ( Super.PrevControl(self) )
|
|
return true;
|
|
|
|
return FocusLast(none);
|
|
|
|
}
|
|
|
|
singular function EnableMe()
|
|
{
|
|
local int i;
|
|
|
|
Super.EnableMe();
|
|
for ( i = 0; i < Controls.Length; i++ )
|
|
EnableComponent(Controls[i]);
|
|
}
|
|
|
|
singular function DisableMe()
|
|
{
|
|
local int i;
|
|
|
|
Super.DisableMe();
|
|
for ( i = 0; i < Controls.Length; i++ )
|
|
DisableComponent(Controls[i]);
|
|
}
|
|
|
|
event SetVisibility(bool bIsVisible)
|
|
{
|
|
local int i;
|
|
|
|
Super.SetVisibility(bIsVisible);
|
|
|
|
if ( !PropagateVisibility )
|
|
return;
|
|
|
|
for (i=0;i<Controls.Length;i++)
|
|
Controls[i].SetVisibility(bIsVisible);
|
|
}
|
|
|
|
event Opened(GUIComponent Sender)
|
|
{
|
|
local int i;
|
|
|
|
if (Sender == None)
|
|
Sender = Self;
|
|
|
|
Super.Opened(Sender);
|
|
for (i=0;i<Controls.Length;i++)
|
|
Controls[i].Opened(Sender);
|
|
}
|
|
|
|
event Closed(GUIComponent Sender, bool bCancelled)
|
|
{
|
|
local int i;
|
|
|
|
if (Sender == None)
|
|
Sender = Self;
|
|
|
|
Super.Closed(Sender, bCancelled);
|
|
for (i=0;i<Controls.Length;i++)
|
|
Controls[i].Closed(Sender, bCancelled);
|
|
}
|
|
|
|
event Free() // This control is no longer needed
|
|
{
|
|
local int i;
|
|
|
|
for (i=0;i<Controls.Length;i++)
|
|
Controls[i].Free();
|
|
|
|
Controls.Remove(0,Controls.Length);
|
|
Components.Remove(0,Components.Length);
|
|
|
|
FocusedControl = None;
|
|
Super.Free();
|
|
}
|
|
|
|
event BeginAnimation( GUIComponent Animating )
|
|
{
|
|
AnimationCount++;
|
|
if ( AnimationCount > 0 )
|
|
bAnimating = True;
|
|
|
|
if ( MenuOwner != None )
|
|
MenuOwner.BeginAnimation( Animating );
|
|
}
|
|
|
|
event EndAnimation( GUIComponent Animating, EAnimationType Type )
|
|
{
|
|
AnimationCount--;
|
|
if ( AnimationCount <= 0 )
|
|
{
|
|
bAnimating = False;
|
|
AnimationCount = 0;
|
|
}
|
|
|
|
if ( MenuOwner != None )
|
|
MenuOwner.EndAnimation( Animating, Type );
|
|
|
|
if ( Animating == Self )
|
|
OnEndAnimation(Animating, Type);
|
|
}
|
|
|
|
function LevelChanged()
|
|
{
|
|
local int i;
|
|
|
|
Super.LevelChanged();
|
|
for ( i = 0; i < Controls.Length; i++ )
|
|
Controls[i].LevelChanged();
|
|
}
|
|
|
|
function CenterMouse()
|
|
{
|
|
local int i;
|
|
|
|
if ( FocusedControl != None )
|
|
{
|
|
FocusedControl.CenterMouse();
|
|
return;
|
|
}
|
|
|
|
for ( i = 0; i < Components.Length; i++ )
|
|
{
|
|
if ( Components[i].CanAcceptFocus() )
|
|
{
|
|
Components[i].CenterMouse();
|
|
return;
|
|
}
|
|
}
|
|
|
|
Super.CenterMouse();
|
|
}
|
|
|
|
function DebugTabOrder()
|
|
{
|
|
local int i;
|
|
|
|
CheckInvalidTabOrder();
|
|
CheckDuplicateTabOrder();
|
|
for ( i = 0; i < Controls.Length; i++ )
|
|
Controls[i].DebugTabOrder();
|
|
}
|
|
|
|
function CheckInvalidTabOrder()
|
|
{
|
|
local int i;
|
|
|
|
for ( i = 0; i < Components.Length; i++ )
|
|
if ( Components[i].TabOrder == -1 )
|
|
log(GetMenuPath()@"Component["$i$"] ("$Components[i].GetMenuPath()$") has no tab order assigned!");
|
|
}
|
|
|
|
function CheckDuplicateTabOrder()
|
|
{
|
|
local int i, j;
|
|
local array<intbox> TabOrders;
|
|
local bool bDup;
|
|
|
|
for ( i = 0; i < Components.Length; i++ )
|
|
{
|
|
bDup = false;
|
|
if ( Components[i].TabOrder == -1 )
|
|
continue;
|
|
|
|
for ( j = 0; j < TabOrders.Length; j++ )
|
|
{
|
|
if ( Components[i].TabOrder == TabOrders[j].X2 )
|
|
{
|
|
log(GetMenuPath()@"Dulicate tab order ("$Components[i].TabOrder$") - components "$TabOrders[j].X1$" ("$Components[TabOrders[j].X1].GetMenuPath()$") & "$i$" ("$Components[i].GetMenuPath()$")");
|
|
bDup = True;
|
|
}
|
|
}
|
|
|
|
if ( !bDup )
|
|
{
|
|
j = TabOrders.Length;
|
|
TabOrders.Length = j + 1;
|
|
TabOrders[j].X1 = j;
|
|
TabOrders[j].X2 = Components[i].TabOrder;
|
|
}
|
|
}
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
bDrawFocusedLast=True
|
|
bTabStop=true
|
|
PropagateVisibility=false
|
|
}
|