rott/kf_sources/XInterface/Classes/GUIMultiComponent.uc
2026-07-14 20:27:09 +07:00

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
}