1056 lines
34 KiB
Ucode
1056 lines
34 KiB
Ucode
// ====================================================================
|
|
// Class: UT2K4UI.GUIComponent
|
|
//
|
|
// GUIComponents are the most basic building blocks of menus.
|
|
//
|
|
// Written by Joe Wilcox
|
|
// (c) 2002, Epic Games, Inc. All Rights Reserved
|
|
// ====================================================================
|
|
|
|
class GUIComponent extends GUI
|
|
Abstract
|
|
Native;
|
|
|
|
cpptext
|
|
{
|
|
TCHAR* GetMenuPath( TCHAR* Str = NULL ) const;
|
|
virtual void PreDraw(UCanvas *Canvas); // Should be overridden in a subclass
|
|
virtual void Draw(UCanvas* Canvas); // Should be overridden in a subclass
|
|
|
|
UBOOL WithinBounds( FLOAT PosX, FLOAT PosY ) const { return PosX >= Bounds[0] && PosX <= Bounds[2] && PosY >= Bounds[1] && PosY <= Bounds[3]; }
|
|
virtual UBOOL PerformHitTest(INT MouseX, INT MouseY); // Check to see if a mouse press affects the control
|
|
virtual void UpdateBounds(); // Updates the Bounds for hit tests and such
|
|
FLOAT ActualWidth( FLOAT Val = INDEX_NONE, UBOOL bForce = 0 ) const; // Returns the actual width (including scaling) of a component
|
|
FLOAT ActualHeight( FLOAT Val = INDEX_NONE, UBOOL bForce = 0 ) const; // Returns the actual height (including scaling) of a component
|
|
FLOAT ActualLeft( FLOAT Val = INDEX_NONE, UBOOL bForce = 0 ) const; // Returns the actual left (including scaling) of a component
|
|
FLOAT ActualTop( FLOAT Val = INDEX_NONE, UBOOL bForce = 0 ) const; // Returns the actual top (including scaling) of a component
|
|
FLOAT RelativeWidth( FLOAT RealWidth = INDEX_NONE, UBOOL bForce = 0 ) const;
|
|
FLOAT RelativeHeight( FLOAT RealHeight = INDEX_NONE, UBOOL bForce = 0) const;
|
|
FLOAT RelativeLeft( FLOAT RealLeft = INDEX_NONE, UBOOL bForce = 0 ) const;
|
|
FLOAT RelativeTop( FLOAT RealTop = INDEX_NONE, UBOOL bForce = 0 ) const;
|
|
virtual UGUIComponent* UnderCursor(FLOAT MouseX, FLOAT MouseY);
|
|
|
|
// Focusing stubs
|
|
virtual UGUIComponent* GetFocused() const { return NULL; }
|
|
virtual UBOOL IsFocusedOn( const UGUIComponent* Comp ) const { return 0; }
|
|
|
|
virtual UBOOL MouseMove(INT XDelta, INT YDelta); // The Mouse has moved
|
|
virtual UBOOL MousePressed(UBOOL IsRepeat); // The Mouse was pressed
|
|
virtual UBOOL MouseReleased(); // The Mouse was released
|
|
virtual UBOOL MouseHover(); // The Mouse is over a non-pressed thing
|
|
|
|
virtual UBOOL NativeKeyType(BYTE& iKey, TCHAR Unicode ); // Handle key presses
|
|
virtual UBOOL NativeKeyEvent(BYTE& iKey, BYTE& State, FLOAT Delta); // Handle key events
|
|
virtual UBOOL PerformDoubleClick();
|
|
|
|
virtual void SetAdjustedDims(FLOAT Width, FLOAT Height, FLOAT Left, FLOAT Top); // Smarter version of SetDims that takes into account scaling and bounding
|
|
virtual void SetDims(FLOAT Width, FLOAT Height, FLOAT Left, FLOAT Top); // Set the dims quickly
|
|
virtual void CloneDims(UGUIComponent* From); // Clones the Width,Height, Top, Left settings
|
|
virtual UBOOL IsAnimating()
|
|
{
|
|
for ( UGUIComponent* Comp = this; Comp; Comp = Comp->MenuOwner )
|
|
if ( Comp->bAnimating )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
virtual UBOOL SpecialHit( UBOOL bForce );
|
|
virtual void NativeInvalidate(UGUIComponent* Who);
|
|
|
|
virtual void UpdateOffset(FLOAT PosX, FLOAT PosY, FLOAT PosW, FLOAT PosH);
|
|
virtual void AutoPosition( TArray<UGUIComponent*>& Components, FLOAT PosL, FLOAT PosT, FLOAT PosR, FLOAT PosB, INT Col = 1, FLOAT ColSpace = 0.f );
|
|
virtual void AutoPositionOn( TArray<UGUIComponent*>& Components, UGUIComponent* Frame, FLOAT LPerc, FLOAT TPerc, FLOAT RPerc, FLOAT BPerc, INT Col = 1, FLOAT ColSpace = 0.f );
|
|
virtual void NotifyResolutionChange( INT NewResX, INT NewResY );
|
|
|
|
#ifdef UCONST_Counter
|
|
virtual void ResetCounter();
|
|
#endif
|
|
}
|
|
|
|
// Variables
|
|
var(Menu) noexport editconst GUIPage PageOwner; // Callback to the GUIPage that contains this control
|
|
var(Menu) noexport editconst GUIComponent MenuOwner; // Callback to the Component that owns this one
|
|
var(State) noexport GUIComponent FocusInstead; // Who should get the focus instead of this control if bNeverFocus
|
|
var(State) noexport eMenuState MenuState; // Used to determine the current state of this component
|
|
var(State) editconst noexport eMenuState LastMenuState; // The previous MenuState of this component
|
|
var(State) noexport eDropState DropState; // Used to determine the current drop state of this component
|
|
var(Style) eFontScale FontScale; // If this component has a style, which size font should be applied to the style
|
|
|
|
// RenderStyle and MenuColor are usually pulled from the Parent menu, unless specificlly overridden
|
|
|
|
var() string IniOption; // Points to the INI option to load for this component
|
|
var() string IniDefault; // The default value for a missing ini option
|
|
var(Style) string StyleName; // Name of my Style
|
|
var() localized string Hint; // The hint that gets displayed for this component
|
|
var() noexport GUILabel FriendlyLabel; // My state is projected on this objects state.
|
|
var(Menu) float WinTop,WinLeft; // Where does this component exist (in world space) - Grr.. damn Left()
|
|
var(Menu) float WinWidth,WinHeight; // Where does this component exist (in world space) - Grr.. damn Left()
|
|
var() float RenderWeight; // Used to determine sorting in the controls stack
|
|
var(Style) int MouseCursorIndex; // The mouse cursor to use when over this control
|
|
var(Menu) int TabOrder; // Used to figure out tabbing
|
|
var() int Tag; // Free (can be used for anything)
|
|
|
|
var() bool bDebugging;
|
|
var(Menu) bool bTabStop; // Does a TAB/Shift-Tab stop here
|
|
var() bool bFocusOnWatch; // If true, watching focuses
|
|
var(Menu) bool bBoundToParent; // Use the Parents Bounds for all positioning
|
|
var(Menu) bool bScaleToParent; // Use the Parent for scaling
|
|
var(State) noexport bool bHasFocus; // Does this component currently have input focus
|
|
var(State) bool bVisible; // Is this component currently visible
|
|
var(State) bool bAcceptsInput; // Does this control accept input
|
|
var() bool bCaptureTabs; // If true, OnKeyEvent() is called for tab presses, overriding default behavior (NextControl()/PrevControl())
|
|
var(State) bool bCaptureMouse; // Control should capture the mouse when pressed
|
|
var(State) bool bNeverFocus; // This control should never fully receive focus
|
|
var(State) bool bRepeatClick; // Whether this component should receive OnClick() events when the mouse button is held down
|
|
var(State) bool bRequireReleaseClick; // If True, this component wants the click on release even if it's not active
|
|
var() bool bMouseOverSound; // Should component bleep when mouse goes over it
|
|
var() bool bDropSource; // Can this component act as a drag-n-drop source
|
|
var() bool bDropTarget; // Can this component act as a drag-n-drop target
|
|
var(State) noexport bool bPendingFocus; // Big big hack for ComboBoxes..
|
|
var() bool bInit; // Can be used by any component as an "initialization" hook
|
|
var() bool bNeverScale; // Do not treat position/dimension values in the -2.0 to 2.0 range as scaled values
|
|
// useful for internally managed components (GUIComboBox's list, button, etc.)
|
|
|
|
/*
|
|
This property is solely for the benefit of mod authors, to indicate components which
|
|
will be skipped by the native rendering code if the component doesn't have a valid style.
|
|
Mod authors: changing the value of this property in your subclasses will cause your menus to crash the game
|
|
*/
|
|
var const noexport bool bRequiresStyle;
|
|
var() editconst const noexport bool bPositioned; // Whether this component has been positioned yet (first Pre-Render)
|
|
var() editconst noexport bool bAnimating; // If true, all input/focus/etc will be ignored
|
|
var() editconst noexport const bool bTravelling, bSizing; // Travelling is true when animating position, Sizing is true when animating dimensions
|
|
var() editconst noexport const array<vector> MotionFrame, SizeFrame;
|
|
|
|
// Notes about the Top/Left/Width/Height : This is a somewhat hack but it's really good for functionality. If
|
|
// the value is < 2, then the control is considered to be scaled. If they are >= 2 they are considered to be normal world coords.
|
|
// If bNeverScale is set, then values between -2/2 will also be considered actual values
|
|
// 0 = 0, 1 = 100%, 2 = 2px
|
|
var(Menu) editconst const noexport float Bounds[4]; // Internal normalized positions in world space
|
|
var(Menu) editconst const noexport float ClientBounds[4]; // The bounds of the actual client area (minus any borders)
|
|
|
|
|
|
// Timer Support
|
|
var() bool bTimerRepeat;
|
|
var() noexport editconst const int TimerIndex; // For easier maintenance
|
|
var() float TimerCountdown;
|
|
var() float TimerInterval;
|
|
|
|
var noexport const float MouseOffset[4]; // Used natively for drawing outlines
|
|
var() editconst GUIContextMenu ContextMenu;
|
|
var() editconst GUIToolTip ToolTip;
|
|
|
|
// Used for Saving the last state before drawing natively
|
|
var noexport const color WhiteColor;
|
|
|
|
// Style holds a pointer to the GUI style of this component.
|
|
var(Style) noexport GUIStyles Style; // My GUI Style
|
|
var(Style) enum EClickSound
|
|
{
|
|
CS_None,
|
|
CS_Click,
|
|
CS_Edit,
|
|
CS_Up,
|
|
CS_Down,
|
|
CS_Drag,
|
|
CS_Fade,
|
|
CS_Hover,
|
|
CS_Slide,
|
|
} OnClickSound;
|
|
|
|
var() enum EParentScaleType // Used to bound/scale in one dimension only
|
|
{
|
|
SCALE_All,
|
|
SCALE_X,
|
|
SCALE_Y,
|
|
} BoundingType, ScalingType;
|
|
|
|
var(Menu) bool bStandardized;
|
|
var(Menu) float StandardHeight;
|
|
|
|
// FOR TESTING
|
|
var editconst const noexport int PreDrawCount, DrawCount;
|
|
var editconst noexport int OnRenderCount, OnRenderedCount, OnPreDrawCount, OnDrawCount;
|
|
// Delegates
|
|
|
|
Delegate OnArrival(GUIComponent Sender, EAnimationType Type); // Called when an animating component arrives at a spot
|
|
Delegate OnEndAnimation( GUIComponent Sender, EAnimationType Type ); // Called immediately after the component arrives at the last keypoint
|
|
|
|
// Drawing delegates return true if you want to short-circuit the default drawing code
|
|
// Called for all components, but natively, only ContextMenus do not perform native PreDraw if delegate returns false
|
|
// Bounds/ClientBounds are updated just before the call to OnPreDraw().
|
|
// If you modify the positions of the component, you can force an immediate refresh of the Bounds by returning true from OnPreDraw
|
|
/*
|
|
Delegate bool OnPreDraw(canvas Canvas); // Called from the GUIComponent's native PreDraw function.
|
|
Delegate bool OnDraw(canvas Canvas); // Called the moment the native Draw function is called on a component
|
|
Delegate OnRender(canvas Canvas); // Called immediately after a component's native Super.Draw is called
|
|
Delegate OnRendered(canvas Canvas); // Called immediately after a component has finished rendering.
|
|
*/
|
|
|
|
// The "default" versions of these delegates are only called if GUI.Counter > 0
|
|
Delegate bool OnPreDraw(canvas Canvas)
|
|
{
|
|
if ( Counter < 1 )
|
|
return false;
|
|
|
|
OnPreDrawCount++;
|
|
if ( OnPreDrawCount > Counter )
|
|
log("OnPreDraw called"@OnPreDrawCount@"times: "$GetMenuPath());
|
|
|
|
return false;
|
|
}
|
|
|
|
Delegate bool OnDraw(canvas Canvas)
|
|
{
|
|
if ( COUNTER < 1 )
|
|
return false;
|
|
|
|
OnDrawCount++;
|
|
if ( OnDrawCount > Counter )
|
|
log("OnDraw called"@OnDrawCount@"times: "$GetMenuPath());
|
|
|
|
return false;
|
|
}
|
|
Delegate OnRender(canvas Canvas)
|
|
{
|
|
if ( COUNTER < 1 )
|
|
return;
|
|
|
|
OnRenderCount++;
|
|
if ( OnRenderCount > Counter )
|
|
log("OnRender called"@OnRenderCount@"times: "$GetMenuPath());
|
|
}
|
|
Delegate OnRendered(canvas Canvas)
|
|
{
|
|
if ( COUNTER < 1 )
|
|
return;
|
|
OnRenderedCount++;
|
|
if ( OnRenderedCount > Counter )
|
|
log("OnRendered called"@OnRenderedCount@"times:"@GetMenuPath());
|
|
}
|
|
|
|
Delegate OnActivate(); // Called when the component gains focus
|
|
Delegate OnDeActivate(); // Called when the component loses focus
|
|
Delegate OnWatch(); // Called when the component is being watched
|
|
Delegate OnHitTest(float MouseX, float MouseY); // Called when Hit test is performed for mouse input
|
|
Delegate OnMessage(coerce string Msg, float MsgLife); // When a message comes down the line
|
|
Delegate OnHide();
|
|
Delegate OnShow();
|
|
|
|
// Called just before OnHover()
|
|
// Controller assigns the value of its MouseOver property to the result of this function
|
|
delegate GUIToolTip OnBeginTooltip()
|
|
{
|
|
if ( ToolTip != None )
|
|
return ToolTip.EnterArea();
|
|
|
|
else if ( MenuOwner != None )
|
|
return MenuOwner.OnBeginTooltip();
|
|
|
|
return None;
|
|
}
|
|
|
|
// Called on the current ActiveControl when the mouse is moved over a new component
|
|
// This is called before OnBeginTooltip is called on the new control
|
|
// Return false if the tooltip will remain visible after leaving this control
|
|
delegate bool OnEndTooltip()
|
|
{
|
|
if ( ToolTip != None )
|
|
return ToolTip.LeaveArea();
|
|
|
|
else if ( MenuOwner != None )
|
|
return MenuOwner.OnEndTooltip();
|
|
|
|
return true;
|
|
}
|
|
|
|
Delegate OnInvalidate(GUIComponent Who); // Called when the background is clicked
|
|
|
|
// Return true to override default behavior
|
|
// Called on both the active control & active page
|
|
delegate bool OnHover( GUIComponent Sender ) { return false; }
|
|
|
|
// -- Input event delegates
|
|
Delegate bool OnClick(GUIComponent Sender); // The mouse was clicked on this control
|
|
Delegate bool OnDblClick(GUIComponent Sender); // The mouse was double-clicked on this control
|
|
Delegate bool OnRightClick(GUIComponent Sender); // Return false to prevent context menu from appearing
|
|
|
|
Delegate OnMousePressed(GUIComponent Sender, bool bRepeat); // Sent when a mouse is pressed (initially)
|
|
Delegate OnMouseRelease(GUIComponent Sender); // Sent when the mouse is released.
|
|
|
|
Delegate OnTimer(GUIComponent Sender); // Called from Timer()
|
|
Delegate OnChange(GUIComponent Sender); // Called when a component changes it's value
|
|
|
|
Delegate bool OnKeyType(out byte Key, optional string Unicode) // Key Strokes
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Delegate bool OnKeyEvent(out byte Key, out byte State, float delta)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
delegate bool OnDesignModeKeyEvent( Interactions.EInputKey Key, Interactions.EInputAction State )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Delegate bool OnCapturedMouseMove(float deltaX, float deltaY)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Delegate OnLoadINI(GUIComponent Sender, string s); // Do the actual work here
|
|
Delegate string OnSaveINI(GUIComponent Sender); // Do the actual work here
|
|
|
|
// drag-n-drop
|
|
// Called when mouse is released over the DropSource to detemine whether OnClick() should be called
|
|
delegate bool OnMultiSelect( GUIComponent Sender )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
delegate bool OnBeginDrag(GUIComponent Sender) // Called on the source component when a drag & drop operation begins
|
|
{
|
|
return bDropSource;
|
|
}
|
|
|
|
delegate OnEndDrag(GUIComponent Sender, bool bAccepted);
|
|
|
|
// Called on the target component when data is dropped
|
|
// DropStateChange() will be called on the source - DRP_Accept if it returns true, DRP_Reject if it returns false
|
|
delegate bool OnDragDrop(GUIComponent Sender)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
delegate OnDragEnter(GUIComponent Sender); // Called on the target component when the mouse enters the components bounds
|
|
delegate OnDragLeave(GUIComponent Sender); // Called on a target component when the mouse leaves the components bounds
|
|
delegate OnDragOver(GUIComponent Sender); // Called when the mouse is moved inside a target's bounds
|
|
|
|
|
|
native(812) final function PlayerController PlayerOwner();
|
|
|
|
native(813) function final SetTimer(float Interval, optional bool bRepeat);
|
|
native(814) function final KillTimer();
|
|
|
|
// Auto-positioning - accounts for bBoundToParent & bScaleToParent
|
|
native(815) final function AutoPosition(
|
|
array<GUIComponent> Components,
|
|
float LeftBound, float UpperBound, float RightBound, float LowerBound,
|
|
float LeftPad, float UpperPad, float RightPad, float LowerPad,
|
|
optional int NumberOfColumns, optional float ColumnPadding
|
|
);
|
|
|
|
native(816) final function AutoPositionOn(
|
|
array<GUIComponent> Components, GUIComponent Frame,
|
|
float LeftPadPerc, float UpperPadPerc, float RightPadPerc, float LowerPadPerc,
|
|
optional int NumberOfColumns, optional float ColumnPadding
|
|
);
|
|
|
|
native(817) final function UpdateOffset(float PosX, float PosY, float PosW, float PosH);
|
|
//native(818) final function DrawSpriteWidget(Canvas C, float ResScaleX, float ResScaleY, out HudBase.SpriteWidget Widget);
|
|
//native(819) final function DrawNumericWidget(Canvas C, float ResScaleX, float ResScaleY, out HudBase.NumericWidget Widget, out HudBase.DigitSet Digit);
|
|
|
|
// The ActualXXXX functions are not viable until after the first pre-render so don't
|
|
// use them in inits
|
|
native(820) final function float ActualWidth( optional coerce float Val, optional bool bForce );
|
|
native(821) final function float ActualHeight( optional coerce float Val, optional bool bForce );
|
|
native(822) final function float ActualLeft( optional coerce float Val, optional bool bForce );
|
|
native(823) final function Float ActualTop( optional coerce float Val, optional bool bForce );
|
|
|
|
native(824) final function float RelativeLeft( optional coerce float RealLeft, optional bool bForce );
|
|
native(825) final function float RelativeTop( optional coerce float RealTop, optional bool bForce );
|
|
native(826) final function float RelativeWidth( optional coerce float RealWidth, optional bool bForce );
|
|
native(827) final function float RelativeHeight( optional coerce float RealHeight, optional bool bForce );
|
|
|
|
event ResolutionChanged( int ResX, int ResY );
|
|
|
|
function SetPosition( float NewLeft, float NewTop, float NewWidth, float NewHeight, optional bool bForceRelative )
|
|
{
|
|
if ( bDebugging && (Controller == None || Controller.bModAuthor) )
|
|
log(Name$".SetPosition( "$NewLeft$","@NewTop$","@NewWidth$","@NewHeight$","@bForceRelative,'ModAuthor');
|
|
|
|
if ( bForceRelative )
|
|
{
|
|
WinLeft = RelativeLeft(NewLeft);
|
|
WinTop = RelativeTop(NewTop);
|
|
WinWidth = RelativeWidth(NewWidth);
|
|
WinHeight = RelativeHeight(NewHeight);
|
|
}
|
|
else
|
|
{
|
|
WinLeft = NewLeft;
|
|
WinTop = NewTop;
|
|
WinWidth = NewWidth;
|
|
WinHeight = NewHeight;
|
|
}
|
|
|
|
if ( bDebugging && bForceRelative && (Controller == None || Controller.bModAuthor) )
|
|
log(Name@"SetPosition() Current L:"$WinLeft$"("$Bounds[0]$") T:"$WinTop$"("$Bounds[1]$") W:"$WinWidth$"("$Bounds[0]+Bounds[2]$") H:"$WinHeight$"("$Bounds[1]+Bounds[3]$")",'ModAuthor');
|
|
}
|
|
|
|
// For debugging
|
|
native(828) final function string GetMenuPath();
|
|
// Used only for design mode - performs raw hit detection, without regard to properties that affect
|
|
// hit detection (bAcceptsInput, MenuState, etc.)
|
|
native(829) final function bool SpecialHit( optional bool bForce );
|
|
|
|
event string AdditionalDebugString() { return ""; }
|
|
|
|
event Timer()
|
|
{
|
|
OnTimer(Self);
|
|
}
|
|
|
|
event Opened(GUIComponent Sender) // Called when the Menu Owner is opened
|
|
{
|
|
LoadIni();
|
|
if ( ToolTip != None )
|
|
{
|
|
ToolTip.InitComponent( Controller, Self );
|
|
SetToolTipText( Hint );
|
|
}
|
|
}
|
|
|
|
event Closed(GUIComponent Sender, bool bCancelled) // Called when the Menu Owner is closed
|
|
{
|
|
if (!bCancelled)
|
|
SaveIni();
|
|
}
|
|
|
|
event Free() // This control is no longer needed
|
|
{
|
|
MenuOwner = None;
|
|
PageOwner = None;
|
|
Controller = None;
|
|
FocusInstead = None;
|
|
FriendlyLabel = None;
|
|
Style = None;
|
|
if ( ToolTip != None )
|
|
ToolTip.Free();
|
|
|
|
ToolTip = None;
|
|
}
|
|
|
|
function string LoadINI()
|
|
{
|
|
local string s;
|
|
|
|
if ( (PlayerOwner()==None) || (INIOption=="") )
|
|
return "";
|
|
|
|
if ( IniOption ~= "@Internal" )
|
|
{
|
|
OnLoadIni(Self,"");
|
|
return "";
|
|
}
|
|
|
|
|
|
s = PlayerOwner().ConsoleCommand("get"@IniOption);
|
|
if (s=="")
|
|
s = IniDefault;
|
|
|
|
OnLoadINI(Self,s);
|
|
return s;
|
|
}
|
|
|
|
function SaveINI(optional string Value)
|
|
{
|
|
if (PlayerOwner()==None)
|
|
return;
|
|
|
|
OnSaveINI(Self);
|
|
}
|
|
|
|
// Take a string and strip out colour codes
|
|
static function string StripColorCodes(string InString)
|
|
{
|
|
local int CodePos;
|
|
|
|
CodePos = InStr(InString, Chr(27));
|
|
// while(CodePos != -1 && CodePos < Len(InString)-3) // ignore colour codes at the end of the string
|
|
while ( CodePos != -1 ) // do not ignore color codes at the end of the word, or they aren't stripped
|
|
{
|
|
InString = Left(InString, CodePos)$Mid(InString, CodePos+4);
|
|
CodePos = InStr(InString, Chr(27));
|
|
}
|
|
|
|
return InString;
|
|
}
|
|
|
|
static function string MakeColorCode(color NewColor)
|
|
{
|
|
// Text colours use 1 as 0.
|
|
if(NewColor.R == 0)
|
|
NewColor.R = 1;
|
|
|
|
if(NewColor.G == 0)
|
|
NewColor.G = 1;
|
|
|
|
if(NewColor.B == 0)
|
|
NewColor.B = 1;
|
|
|
|
return Chr(0x1B)$Chr(NewColor.R)$Chr(NewColor.G)$Chr(NewColor.B);
|
|
}
|
|
|
|
// Functions
|
|
|
|
event MenuStateChange(eMenuState Newstate)
|
|
{
|
|
//log("MenuStateChange:"$NewState@Self.Name);
|
|
|
|
if ( MenuState != MSAT_Watched )
|
|
LastMenuState = MenuState;
|
|
|
|
bPendingFocus = false;
|
|
MenuState = NewState;
|
|
switch (MenuState)
|
|
{
|
|
case MSAT_Focused:
|
|
if ( !bNeverFocus )
|
|
{
|
|
bHasFocus = true;
|
|
break;
|
|
}
|
|
|
|
MenuState = MSAT_Blurry;
|
|
|
|
case MSAT_Blurry:
|
|
bHasFocus = false;
|
|
if ( LastMenuState != MSAT_Blurry && LastMenuState != MSAT_Disabled )
|
|
OnDeActivate();
|
|
break;
|
|
|
|
case MSAT_Watched:
|
|
if (bFocusOnWatch)
|
|
{
|
|
SetFocus(None);
|
|
return;
|
|
}
|
|
|
|
OnWatch();
|
|
break;
|
|
|
|
case MSAT_Disabled:
|
|
if (Controller.ActiveControl == Self)
|
|
Controller.ActiveControl = None;
|
|
|
|
if (Controller.FocusedControl == Self)
|
|
LoseFocus(None);
|
|
|
|
break;
|
|
}
|
|
|
|
if ( FriendlyLabel != None )
|
|
FriendlyLabel.MenuState = MenuState;
|
|
}
|
|
|
|
event bool IsMultiSelect()
|
|
{
|
|
if ( Controller == None )
|
|
return false;
|
|
|
|
return bDropSource && DropState != DRP_Source && Controller.CtrlPressed && OnMultiSelect(Self);
|
|
}
|
|
|
|
event DropStateChange(eDropState NewState)
|
|
{
|
|
if (Controller == None)
|
|
return;
|
|
|
|
// log( Name$".DropStateChange Current:"$GetEnum(enum'eDropState',DropState)@"New:"$GetEnum(enum'eDropState',NewState)
|
|
// @"DropSource:"$Controller.DropSource == Self@"DropTarget:"$Controller.DropTarget==Self);
|
|
|
|
switch (NewState)
|
|
{
|
|
case DRP_None:
|
|
// might be DropTarget with DropState == DRP_Source if we are mousing over the DropSource
|
|
if ( Controller.DropTarget == Self )
|
|
{
|
|
OnDragLeave(Self);
|
|
Controller.DropTarget = None;
|
|
|
|
// If this component is also the DropSource, do not alter the DropState
|
|
if ( Controller.DropSource == Self )
|
|
return;
|
|
}
|
|
|
|
else if (Controller.DropSource == Self)
|
|
{
|
|
UpdateOffset(0,0,0,0);
|
|
Controller.DropSource = None;
|
|
}
|
|
|
|
break;
|
|
|
|
case DRP_Source:
|
|
|
|
// Don't alter the drop state if component didn't want to begin a drag operation
|
|
if ( !OnBeginDrag(Self) )
|
|
return;
|
|
|
|
Controller.DropSource = Self;
|
|
Controller.PlayInterfaceSound(CS_Drag);
|
|
break;
|
|
|
|
case DRP_Target:
|
|
Controller.DropTarget = Self;
|
|
if (DropState == DRP_None)
|
|
OnDragEnter(Self);
|
|
|
|
break;
|
|
|
|
case DRP_Accept:
|
|
Controller.PlayInterfaceSound(CS_Up);
|
|
|
|
if ( Controller.DropSource != None )
|
|
Controller.DropSource.OnEndDrag(Self, True);
|
|
|
|
Controller.DropTarget = None;
|
|
NewState = DRP_None;
|
|
|
|
break;
|
|
|
|
case DRP_Reject:
|
|
Controller.PlayInterfaceSound(CS_Down);
|
|
if ( Controller.DropSource != None )
|
|
Controller.DropSource.OnEndDrag(Self, False);
|
|
|
|
Controller.DropTarget = None;
|
|
NewState = DRP_None;
|
|
break;
|
|
}
|
|
|
|
DropState = NewState;
|
|
}
|
|
|
|
event InitComponent(GUIController MyController, GUIComponent MyOwner)
|
|
{
|
|
Controller = MyController;
|
|
MenuOwner = MyOwner;
|
|
|
|
PageOwner = OwnerPage();
|
|
|
|
if (Style==None)
|
|
Style = Controller.GetStyle(StyleName, FontScale);
|
|
}
|
|
|
|
function bool IsInBounds() // Script version of PerformHitTest
|
|
{
|
|
return ( (Controller.MouseX >= Bounds[0] && Controller.MouseX<=Bounds[2]) && (Controller.MouseY >= Bounds[1] && Controller.MouseY <=Bounds[3]) );
|
|
}
|
|
|
|
function bool IsInClientBounds()
|
|
{
|
|
return ( (Controller.MouseX >= ClientBounds[0] && Controller.MouseX<=ClientBounds[2]) && (Controller.MouseY >= ClientBounds[1] && Controller.MouseY <=ClientBounds[3]) );
|
|
}
|
|
|
|
event bool CanAcceptFocus()
|
|
{
|
|
return MenuState != MSAT_Disabled && bVisible && !bNeverFocus;
|
|
}
|
|
|
|
event SetFocus(GUIComponent Who)
|
|
{
|
|
if (Who==None)
|
|
{
|
|
if (bNeverFocus)
|
|
{
|
|
if (FocusInstead != None)
|
|
FocusInstead.SetFocus(Who);
|
|
|
|
return;
|
|
}
|
|
bPendingFocus = true;
|
|
if (Controller.FocusedControl!=None)
|
|
{
|
|
if (Controller.FocusedControl == Self) // Already Focused
|
|
return;
|
|
else Controller.FocusedControl.LoseFocus(Self);
|
|
}
|
|
|
|
MenuStateChange(MSAT_Focused);
|
|
Controller.FocusedControl = self;
|
|
OnActivate();
|
|
}
|
|
else
|
|
MenuStateChange(MSAT_Focused);
|
|
|
|
|
|
if (MenuOwner!=None)
|
|
MenuOwner.SetFocus(self);
|
|
}
|
|
|
|
event LoseFocus(GUIComponent Sender)
|
|
{
|
|
if (Controller!=None)
|
|
Controller.FocusedControl = None;
|
|
|
|
if (MenuState != MSAT_Disabled)
|
|
MenuStateChange(MSAT_Blurry);
|
|
|
|
if (MenuOwner!=None)
|
|
MenuOwner.LoseFocus(Self);
|
|
}
|
|
|
|
event bool FocusFirst(GUIComponent Sender) // Focus your first child, or yourself if no childrean
|
|
{
|
|
if ( !bTabStop || !CanAcceptFocus() )
|
|
return false;
|
|
|
|
SetFocus(None);
|
|
return true;
|
|
}
|
|
|
|
event bool FocusLast(GUIComponent Sender) // Focus your last child, or yourself
|
|
{
|
|
if ( !bTabStop || !CanAcceptFocus() )
|
|
return false;
|
|
|
|
SetFocus(None);
|
|
return true;
|
|
}
|
|
|
|
event bool NextControl(GUIComponent Sender)
|
|
{
|
|
if (MenuOwner!=None)
|
|
return MenuOwner.NextControl(Self);
|
|
|
|
return false;
|
|
}
|
|
|
|
event bool PrevControl(GUIComponent Sender)
|
|
{
|
|
if (MenuOwner!=None)
|
|
return MenuOwner.PrevControl(Self);
|
|
|
|
return false;
|
|
}
|
|
|
|
event bool NextPage()
|
|
{
|
|
if (MenuOwner != None)
|
|
return MenuOwner.NextPage();
|
|
|
|
return false;
|
|
}
|
|
|
|
event bool PrevPage()
|
|
{
|
|
if (MenuOwner != None)
|
|
return MenuOwner.PrevPage();
|
|
|
|
return false;
|
|
}
|
|
|
|
// Force control to use same area as its MenuOwner.
|
|
function FillOwner()
|
|
{
|
|
WinLeft = 0.0;
|
|
WinTop = 0.0;
|
|
WinWidth = 1.0;
|
|
WinHeight = 1.0;
|
|
bScaleToParent = true;
|
|
bBoundToParent = true;
|
|
}
|
|
|
|
event SetVisibility( coerce bool bIsVisible)
|
|
{
|
|
bVisible = bIsVisible;
|
|
|
|
if (bVisible)
|
|
OnShow();
|
|
else OnHide();
|
|
}
|
|
|
|
function CenterMouse()
|
|
{
|
|
local PlayerController PC;
|
|
local float MidX, MidY;
|
|
|
|
PC = PlayerOwner();
|
|
if ( PC != None )
|
|
{
|
|
MidX = ActualLeft() + ActualWidth() / 2;
|
|
MidY = ActualTop() + ActualHeight() / 2;
|
|
PC.ConsoleCommand("SETMOUSE" @ MidX @ MidY);
|
|
}
|
|
}
|
|
|
|
event Hide()
|
|
{
|
|
SetVisibility(false);
|
|
}
|
|
|
|
event Show()
|
|
{
|
|
SetVisibility(true);
|
|
}
|
|
|
|
function SetFocusInstead( GUIComponent InFocusComp )
|
|
{
|
|
if ( InFocusComp != None )
|
|
bNeverFocus = true;
|
|
|
|
FocusInstead = InFocusComp;
|
|
}
|
|
|
|
function SetFriendlyLabel(GUILabel NewLabel)
|
|
{
|
|
FriendlyLabel = NewLabel;
|
|
}
|
|
|
|
function SetHint(string NewHint)
|
|
{
|
|
Hint = NewHint;
|
|
SetToolTipText(Hint);
|
|
}
|
|
|
|
function SetToolTipText( string NewToolTipText )
|
|
{
|
|
if ( ToolTip != None )
|
|
ToolTip.SetTip( NewToolTipText );
|
|
}
|
|
|
|
function SetTooltip( GUIToolTip InTooltip )
|
|
{
|
|
if ( ToolTip != None )
|
|
ToolTip.LeaveArea();
|
|
|
|
ToolTip = InToolTip;
|
|
if ( ToolTip != None )
|
|
ToolTip.InitComponent( Controller, Self );
|
|
}
|
|
|
|
function PadLeft( out string Src, int StrLen, optional string PadStr )
|
|
{
|
|
if ( PadStr == "" )
|
|
PadStr = " ";
|
|
|
|
while ( Len(Src) < StrLen )
|
|
Src = PadStr $ Src;
|
|
}
|
|
|
|
function PadRight( out string Src, int StrLen, optional string PadStr )
|
|
{
|
|
if ( PadStr == "" )
|
|
PadStr = " ";
|
|
|
|
while ( Len(Src) < StrLen )
|
|
Src = Src $ PadStr;
|
|
}
|
|
|
|
final function DebugFocus( GUIComponent Who, bool bLose )
|
|
{
|
|
return;
|
|
if ( Controller != None && Controller.CtrlPressed )
|
|
{
|
|
if ( bLose )
|
|
{
|
|
if ( Who == None )
|
|
log(Name@"losing focus chain down");
|
|
else log(Name@"losing focus of"@Who);
|
|
}
|
|
|
|
else
|
|
{
|
|
if ( Who == None )
|
|
log(Name@"sending focus chain down");
|
|
else log(Name@"setting focus to"@Who);
|
|
}
|
|
}
|
|
}
|
|
|
|
final function DebugFocusPosition( GUIComponent Who, bool Last )
|
|
{
|
|
return;
|
|
if ( Controller.CtrlPressed )
|
|
{
|
|
if ( Last )
|
|
{
|
|
if ( Who == None )
|
|
log(Name@"FocusLast going down");
|
|
else log(Name@"FocusLast call from"@Who);
|
|
}
|
|
|
|
else
|
|
{
|
|
if ( Who == None )
|
|
log(Name@"FocusFirst going down");
|
|
else log(Name@"FocusFirst call from"@Who);
|
|
}
|
|
}
|
|
}
|
|
|
|
event GUIPage OwnerPage()
|
|
{
|
|
local GUIComponent C;
|
|
|
|
if ( PageOwner != None )
|
|
return PageOwner;
|
|
|
|
C = Self;
|
|
while ( C != None )
|
|
{
|
|
if ( GUIPage(C) != None )
|
|
return GUIPage(C);
|
|
|
|
C = C.MenuOwner;
|
|
}
|
|
|
|
Warn( "OwnerPage not found!" );
|
|
return None;
|
|
}
|
|
|
|
// By default, we don't care which components are animating
|
|
// Input is disabled while bAnimating
|
|
event BeginAnimation( GUIComponent Animating )
|
|
{
|
|
bAnimating = True;
|
|
if ( MenuOwner != None )
|
|
MenuOwner.BeginAnimation(Animating);
|
|
}
|
|
|
|
event EndAnimation( GUIComponent Animating, EAnimationType Type )
|
|
{
|
|
bAnimating = False;
|
|
if ( MenuOwner != None )
|
|
MenuOwner.EndAnimation( Animating, Type );
|
|
|
|
if ( Animating == Self )
|
|
OnEndAnimation(Animating, Type);
|
|
}
|
|
|
|
// If you short circuit these functions (by modifying the animation arrays directly)
|
|
// you must call BeginAnimation() on the owning page for each frame
|
|
function Animate( float NewLeft, float NewTop, optional float Time )
|
|
{
|
|
local int i;
|
|
|
|
i = MotionFrame.Length;
|
|
MotionFrame.Length = i + 1;
|
|
MotionFrame[i].X = NewLeft;
|
|
MotionFrame[i].Y = NewTop;
|
|
MotionFrame[i].Z = Time;
|
|
|
|
if ( i < 1 )
|
|
BeginAnimation(Self);
|
|
}
|
|
|
|
function Resize( float NewWidth, float NewHeight, optional float Time )
|
|
{
|
|
local int i;
|
|
|
|
i = SizeFrame.Length;
|
|
SizeFrame.Length = i + 1;
|
|
SizeFrame[i].X = NewWidth;
|
|
SizeFrame[i].Y = NewHeight;
|
|
SizeFrame[i].Z = Time;
|
|
|
|
if ( i < 1 )
|
|
BeginAnimation(Self);
|
|
}
|
|
|
|
function DAnimate( float NewLeft, float NewTop, float NewWidth, float NewHeight, optional float PositionTime, optional float DimensionTime )
|
|
{
|
|
Animate( NewLeft, NewTop, PositionTime );
|
|
Resize( NewWidth, NewHeight, DimensionTime );
|
|
}
|
|
|
|
function KillAnimation()
|
|
{
|
|
if ( MotionFrame.Length > 0 )
|
|
{
|
|
MotionFrame.Remove( 0, MotionFrame.Length );
|
|
EndAnimation( Self, AT_Position );
|
|
}
|
|
|
|
if ( SizeFrame.Length > 0 )
|
|
{
|
|
SizeFrame.Remove( 0, SizeFrame.Length );
|
|
EndAnimation( Self, AT_Dimension );
|
|
}
|
|
}
|
|
|
|
final function EnableComponent(GUIComponent Comp)
|
|
{
|
|
if ( Comp == None )
|
|
return;
|
|
|
|
Comp.EnableMe();
|
|
}
|
|
|
|
final function DisableComponent(GUIComponent Comp)
|
|
{
|
|
if ( Comp == None )
|
|
return;
|
|
|
|
Comp.DisableMe();
|
|
}
|
|
|
|
function EnableMe()
|
|
{
|
|
if ( MenuState != MSAT_Disabled )
|
|
return;
|
|
|
|
MenuStateChange(MSAT_Blurry);
|
|
}
|
|
|
|
function DisableMe()
|
|
{
|
|
if ( MenuState == MSAT_Disabled )
|
|
return;
|
|
|
|
MenuStateChange(MSAT_Disabled);
|
|
}
|
|
|
|
function LevelChanged()
|
|
{
|
|
if ( ToolTip != None )
|
|
ToolTip.Free();
|
|
}
|
|
|
|
function DebugTabOrder();
|
|
|
|
defaultproperties
|
|
{
|
|
MenuState=MSAT_Blurry
|
|
FontScale=FNS_Medium
|
|
IniOption=""
|
|
bBoundToParent=false
|
|
bScaleToParent=false
|
|
bHasFocus=false
|
|
bVisible=true
|
|
bAcceptsInput=false
|
|
bCaptureTabs=false
|
|
bCaptureMouse=false
|
|
bNeverFocus=false
|
|
bRepeatClick=false
|
|
WinTop=0.0
|
|
WinLeft=0.0
|
|
WinWidth=1.0
|
|
WinHeight1.0
|
|
Tag=-1
|
|
MouseCursorIndex=0
|
|
bFocusOnWatch=false
|
|
bRequireReleaseClick=false
|
|
TimerIndex=-1
|
|
bMouseOverSound=false
|
|
OnClickSound=CS_None
|
|
RenderWeight=0.5
|
|
bTabStop=false
|
|
bInit=True
|
|
TabOrder=-1
|
|
|
|
BoundingType=SCALE_All
|
|
ScalingType=SCALE_All
|
|
WhiteColor=(R=253,G=237,B=244,A=255)
|
|
|
|
bStandardized=false
|
|
StandardHeight=0
|
|
|
|
}
|