653 lines
16 KiB
Ucode
653 lines
16 KiB
Ucode
// ====================================================================
|
|
// GUITabControl - This control has a number of tabs
|
|
//
|
|
// Written by Joe Wilcox
|
|
// (c) 2003, Epic Games, Inc. All Rights Reserved
|
|
//
|
|
// Updated by Ron Prestenback
|
|
// ====================================================================
|
|
|
|
class GUITabControl extends GUIMultiComponent
|
|
Native;
|
|
|
|
cpptext
|
|
{
|
|
void PreDraw(UCanvas* Canvas);
|
|
void Draw(UCanvas* Canvas);
|
|
|
|
UGUIComponent* UnderCursor(FLOAT MouseX, FLOAT MouseY);
|
|
UBOOL SpecialHit( UBOOL bForce );
|
|
UBOOL MousePressed(UBOOL IsRepeat); // The Mouse was pressed
|
|
UBOOL MouseReleased(); // The Mouse was released
|
|
|
|
UBOOL IsFocusedOn( const UGUIComponent* Comp ) const;
|
|
|
|
#ifdef UCONST_Counter
|
|
virtual void ResetCounter();
|
|
#endif
|
|
}
|
|
|
|
var() bool bFillSpace; // Tab buttons should be resized if cumulative width is smaller than WinWidth
|
|
var() bool bDockPanels; // If true, associated panels will dock vertically with this control
|
|
var() bool bDrawTabAbove; // If true, tabs are drawn above the tab panels
|
|
|
|
var() bool bFillBackground;
|
|
var() color FillColor;
|
|
|
|
var() float FadeInTime;
|
|
var() float TabHeight;
|
|
|
|
var() string BackgroundStyleName;
|
|
var() Material BackgroundImage;
|
|
|
|
var() editconst noexport array<GUITabButton> TabStack;
|
|
var() editconst noexport GUITabButton ActiveTab, PendingTab;
|
|
var() editconst noexport GUIStyles BackgroundStyle;
|
|
var() editconst noexport GUIBorder MyFooter;
|
|
|
|
function InitComponent(GUIController MyController, GUIComponent MyOwner)
|
|
{
|
|
Super.InitComponent(MyController, MyOwner);
|
|
|
|
if (BackgroundStyleName != "")
|
|
BackgroundStyle = Controller.GetStyle(BackgroundStyleName,FontScale);
|
|
|
|
OnKeyEvent = InternalOnKeyEvent;
|
|
}
|
|
|
|
event Opened( GUIComponent Sender )
|
|
{
|
|
local int i;
|
|
|
|
Super.Opened(Sender);
|
|
for ( i = 0; i < TabStack.Length; i++ )
|
|
{
|
|
if ( TabStack[i] != None )
|
|
TabStack[i].Opened(Self);
|
|
}
|
|
|
|
if ( !bInit && bVisible && ActiveTab != None && ActiveTab.MyPanel != None )
|
|
ActivateTab(ActiveTab, True);
|
|
|
|
bInit = false;
|
|
}
|
|
|
|
event Closed( GUIComponent Sender, bool bCancelled )
|
|
{
|
|
local int i;
|
|
|
|
Super.Closed(Sender,bCancelled);
|
|
|
|
for ( i = 0; i < TabStack.Length; i++ )
|
|
if ( TabStack[i] != None )
|
|
TabStack[i].Closed(Sender,bCancelled);
|
|
}
|
|
|
|
function bool InternalOnKeyEvent(out byte Key, out byte State, float delta)
|
|
{
|
|
local int i,aTabIndex, StartIndex;
|
|
|
|
if ( (FocusedControl!=None) || (TabStack.Length<=0) )
|
|
return false;
|
|
|
|
if (ActiveTab == None)
|
|
return false;
|
|
|
|
for(i=0;i<TabStack.Length;i++)
|
|
{
|
|
if (TabStack[i]==ActiveTab)
|
|
{
|
|
aTabIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( Key==0x25 && State == 1 ) // Left
|
|
{
|
|
StartIndex = aTabIndex;
|
|
while (true)
|
|
{
|
|
if (aTabIndex==0)
|
|
aTabIndex=TabStack.Length-1;
|
|
else
|
|
aTabIndex--;
|
|
|
|
// Send false for bFocusPanel to ActivateTab here to continue using left/right
|
|
if (aTabIndex == StartIndex || ActivateTab(TabStack[aTabIndex], False))
|
|
break;
|
|
}
|
|
return true;
|
|
|
|
}
|
|
|
|
if ( Key==0x27 && State == 1 ) // Right
|
|
{
|
|
StartIndex = aTabIndex;
|
|
while (true)
|
|
{
|
|
aTabIndex++;
|
|
if (aTabIndex==TabStack.Length)
|
|
aTabIndex=0;
|
|
|
|
// Send false for bFocusPanel to ActivateTab here to continue using left/right
|
|
if (StartIndex == aTabIndex || ActivateTab(TabStack[aTabIndex], False))
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function GUITabPanel AddTabItem( GUITabItem Item )
|
|
{
|
|
return AddTab( Item.Caption, Item.ClassName, ,Item.Hint );
|
|
}
|
|
|
|
function GUITabPanel AddTab(string InCaption, string PanelClass, optional GUITabPanel ExistingPanel, optional string InHint, optional bool bForceActive)
|
|
{
|
|
local class<GUITabPanel> NewPanelClass;
|
|
|
|
local GUITabButton NewTabButton;
|
|
local GUITabPanel NewTabPanel;
|
|
|
|
local int i;
|
|
|
|
// Make sure this doesn't exist first
|
|
for (i=0;i<TabStack.Length;i++)
|
|
{
|
|
if (TabStack[i].Caption ~= InCaption)
|
|
{
|
|
log("A tab with the caption"@InCaption@"already exists.");
|
|
return none;
|
|
}
|
|
}
|
|
|
|
if (ExistingPanel==None)
|
|
NewPanelClass = class<GUITabPanel>(Controller.AddComponentClass(PanelClass));
|
|
|
|
if ( (ExistingPanel!=None) || (NewPanelClass != None) )
|
|
{
|
|
if (ExistingPanel != None)
|
|
NewTabPanel = GUITabPanel(AppendComponent(ExistingPanel,True));
|
|
else if (NewPanelClass != None)
|
|
NewTabPanel = GUITabPanel(AddComponent(PanelClass,True));
|
|
|
|
if (NewTabPanel == None)
|
|
{
|
|
log("Could not create panel for"@NewPanelClass);
|
|
return None;
|
|
}
|
|
|
|
if (NewTabPanel.MyButton != None)
|
|
NewTabButton = NewTabPanel.MyButton;
|
|
else
|
|
{
|
|
NewTabButton = new class'GUITabButton';
|
|
if (NewTabButton==None)
|
|
{
|
|
log("Could not create tab for"@NewPanelClass);
|
|
return None;
|
|
}
|
|
|
|
NewTabButton.InitComponent(Controller, Self);
|
|
NewTabButton.Opened(Self);
|
|
NewTabPanel.MyButton = NewTabButton;
|
|
if (!bDrawTabAbove)
|
|
{
|
|
NewTabPanel.MyButton.bBoundToParent = False;
|
|
NewTabPanel.MyButton.Style = Controller.GetStyle("FlippedTabButton",NewTabPanel.FontScale);
|
|
}
|
|
}
|
|
|
|
NewTabPanel.MyButton.Hint = Eval(InHint != "", InHint, NewTabPanel.Hint);
|
|
NewTabPanel.MyButton.Caption = Eval(InCaption != "", InCaption, NewTabPanel.PanelCaption);
|
|
NewTabPanel.MyButton.OnClick = InternalTabClick;
|
|
NewTabPanel.MyButton.MyPanel = NewTabPanel;
|
|
NewTabPanel.MyButton.FocusInstead = self;
|
|
NewTabPanel.MyButton.bNeverFocus = true;
|
|
|
|
NewTabPanel.InitPanel();
|
|
|
|
// Add the tab to controls
|
|
TabStack[TabStack.Length] = NewTabPanel.MyButton;
|
|
if ( (TabStack.Length==1 && bVisible) || (bForceActive) )
|
|
ActivateTab(NewTabPanel.MyButton,true);
|
|
else NewTabPanel.Hide();
|
|
|
|
return NewTabPanel;
|
|
|
|
}
|
|
|
|
return none;
|
|
}
|
|
|
|
function GUITabPanel InsertTab(int Pos, string Caption, string PanelClass, optional GUITabPanel ExistingPanel, optional string InHint, optional bool bForceActive)
|
|
{
|
|
local class<GUITabPanel> NewPanelClass;
|
|
local GUITabPanel NewTabPanel;
|
|
local GUITabButton NewTabButton;
|
|
|
|
if (ExistingPanel == None)
|
|
NewPanelClass = class<GUITabPanel>(Controller.AddComponentClass(PanelClass));
|
|
|
|
if ( ExistingPanel != None || NewPanelClass != None)
|
|
{
|
|
if (ExistingPanel != None)
|
|
NewTabPanel = GUITabPanel(AppendComponent(ExistingPanel,True));
|
|
else if (NewPanelClass != None)
|
|
NewTabPanel = GUITabPanel(AddComponent(PanelClass,True));
|
|
|
|
if (NewTabPanel == None)
|
|
{
|
|
log("Could not create panel for"@NewPanelClass);
|
|
return None;
|
|
}
|
|
|
|
if (NewTabPanel.MyButton != None)
|
|
NewTabButton = NewTabPanel.MyButton;
|
|
|
|
else
|
|
{
|
|
NewTabButton = new class'GUITabButton';
|
|
if (NewTabButton==None)
|
|
{
|
|
log("Could not create tab for"@NewPanelClass);
|
|
return None;
|
|
}
|
|
|
|
NewTabButton.InitComponent(Controller, Self);
|
|
NewTabButton.Opened(Self);
|
|
NewTabPanel.MyButton = NewTabButton;
|
|
}
|
|
|
|
|
|
NewTabPanel.MyButton.Caption = Caption;
|
|
NewTabPanel.MyButton.Hint = InHint;
|
|
NewTabPanel.MyButton.OnClick = InternalTabClick;
|
|
NewTabPanel.MyButton.MyPanel = NewTabPanel;
|
|
NewTabPanel.MyButton.FocusInstead = self;
|
|
NewTabPanel.MyButton.bNeverFocus = true;
|
|
NewTabPanel.InitPanel();
|
|
|
|
TabStack.Insert(Pos, 1);
|
|
TabStack[Pos] = NewTabPanel.MyButton;
|
|
if (TabStack.Length==1 || bForceActive)
|
|
ActivateTab(NewTabPanel.MyButton,true);
|
|
else NewTabPanel.Hide();
|
|
|
|
return NewTabPanel;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
function GUITabPanel ReplaceTab(GUITabButton Which, string Caption, string PanelClass, optional GUITabPanel ExistingPanel, optional string InHint, optional bool bForceActive)
|
|
{
|
|
local class<GUITabPanel> NewPanelClass;
|
|
|
|
local GUITabPanel NewTabPanel, OldTabPanel;
|
|
|
|
if (ExistingPanel==None)
|
|
NewPanelClass = class<GUITabPanel>(Controller.AddComponentClass(PanelClass));
|
|
|
|
if ( (ExistingPanel!=None) || (NewPanelClass != None) )
|
|
{
|
|
|
|
OldTabPanel = Which.MyPanel;
|
|
|
|
if (ExistingPanel==None)
|
|
NewTabPanel = GUITabPanel(AddComponent(PanelClass, True));
|
|
else
|
|
NewTabPanel = GUITabPanel(AppendComponent(ExistingPanel, True));
|
|
|
|
if (NewTabPanel==None)
|
|
{
|
|
log("Could not create panel"@NewPanelClass);
|
|
return none;
|
|
}
|
|
|
|
Which.Caption = Caption;
|
|
Which.Hint = InHint;
|
|
Which.MyPanel = NewTabPanel;
|
|
NewTabPanel.MyButton = Which;
|
|
|
|
// Init new panel
|
|
NewTabPanel.InitPanel();
|
|
|
|
// Make sure to notify old tab - so use ActivateTab
|
|
if ( bForceActive )
|
|
ActivateTab(NewTabPanel.MyButton, True);
|
|
else NewTabPanel.Hide();
|
|
|
|
// Notify old panel
|
|
RemoveComponent(OldTabPanel);
|
|
OldTabPanel.Free();
|
|
|
|
return NewTabPanel;
|
|
|
|
}
|
|
|
|
return none;
|
|
}
|
|
|
|
function RemoveTab(optional string Caption, optional GUITabButton who)
|
|
{
|
|
local int i;
|
|
local bool bActive;
|
|
local GUITabPanel OldPanel;
|
|
|
|
if ( (caption=="") && (Who==None) )
|
|
return;
|
|
|
|
if (Who==None)
|
|
i = TabIndex(Caption);
|
|
else i = TabIndex(Who.Caption);
|
|
|
|
if (i < 0)
|
|
return;
|
|
|
|
OldPanel = TabStack[i].MyPanel;
|
|
bActive = TabStack[i] == ActiveTab;
|
|
TabStack[i].OnClick = None;
|
|
TabStack[i].Free();
|
|
TabStack.Remove(i, 1);
|
|
|
|
RemoveComponent(OldPanel,True);
|
|
OldPanel.Free();
|
|
|
|
if (bActive)
|
|
LostActiveTab();
|
|
}
|
|
|
|
function bool LostActiveTab()
|
|
{
|
|
local int i;
|
|
|
|
if (!Controller.bCurMenuInitialized)
|
|
return false;
|
|
|
|
for (i = 0; i < TabStack.Length; i++)
|
|
if (ActivateTab(TabStack[i],true))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
event MakeTabActive(GUITabButton Who)
|
|
{
|
|
if (ActiveTab!=None)
|
|
ActiveTab.ChangeActiveState(false,false);
|
|
|
|
PendingTab = None;
|
|
ActiveTab = Who;
|
|
OnChange(Who);
|
|
}
|
|
|
|
function bool ActivateTab(GUITabButton Who, bool bFocusPanel)
|
|
{
|
|
|
|
if (Who == none || PendingTab != None || !Who.CanShowPanel()) // null or not selectable
|
|
return false;
|
|
|
|
Who.bForceFlash = False;
|
|
if (Who==ActiveTab) // Same Tab, just accept
|
|
{
|
|
if ( ActiveTab.ChangeActiveState(True, bFocusPanel) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
PendingTab = Who;
|
|
if ( PendingTab.ChangeActiveState(True, bFocusPanel) )
|
|
{
|
|
if (PendingTab.MyPanel.FadeInTime==0.0 || TabStack.Length<2)
|
|
MakeTabActive(Who);
|
|
|
|
else
|
|
{
|
|
FadeInTime = PendingTab.MyPanel.FadeInTime;
|
|
if (!Controller.bQuietMenu)
|
|
PlayerOwner().PlayOwnedSound(Controller.FadeSound,SLOT_Interface,1.0);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
PendingTab = None;
|
|
return false;
|
|
}
|
|
|
|
function bool ActivateTabByName(string tabname, bool bFocusPanel)
|
|
{
|
|
local int i;
|
|
|
|
i = TabIndex(TabName);
|
|
if (i < 0 || i >= TabStack.Length) return false;
|
|
return ActivateTab(TabStack[i], bFocusPanel);
|
|
}
|
|
|
|
function bool ActivateTabByPanel( GUITabPanel Panel, bool bFocusPanel )
|
|
{
|
|
local int i;
|
|
|
|
if ( Panel == None || !Panel.CanShowPanel() )
|
|
return false;
|
|
|
|
for ( i = 0; i < TabStack.Length; i++ )
|
|
if ( TabStack[i] != None && TabStack[i].MyPanel == Panel )
|
|
return ActivateTab(TabStack[i], bFocusPanel);
|
|
|
|
return false;
|
|
}
|
|
|
|
function bool InternalTabClick(GUIComponent Sender)
|
|
{
|
|
local GUITabButton But;
|
|
|
|
But = GUITabButton(Sender);
|
|
if (But==None)
|
|
return false;
|
|
|
|
ActivateTab(But,true);
|
|
return true;
|
|
}
|
|
|
|
event bool NextPage()
|
|
{
|
|
local int i;
|
|
|
|
// If 1 or no tabs in the stack, then query parents
|
|
if (TabStack.Length < 2)
|
|
return Super.NextPage();
|
|
|
|
if (ActiveTab == None)
|
|
i = 0;
|
|
else
|
|
{
|
|
i = TabIndex(ActiveTab.Caption) + 1;
|
|
if ( i >= TabStack.Length )
|
|
i = 0;
|
|
}
|
|
return ActivateTab(TabStack[i], true);
|
|
}
|
|
|
|
event bool PrevPage()
|
|
{
|
|
local int i;
|
|
|
|
if (TabStack.Length < 2)
|
|
return Super.PrevPage();
|
|
|
|
if (ActiveTab == None)
|
|
i = TabStack.Length - 1;
|
|
else
|
|
{
|
|
i = TabIndex(ActiveTab.Caption) - 1;
|
|
if ( i < 0 )
|
|
i = TabStack.Length - 1;
|
|
}
|
|
return ActivateTab(TabStack[i], true);
|
|
}
|
|
|
|
event bool NextControl(GUIComponent Sender)
|
|
{
|
|
|
|
if (Sender != None)
|
|
{
|
|
Super(GUIComponent).SetFocus(None);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if ( Super(GUIComponent).NextControl(Self) )
|
|
return true;
|
|
|
|
else FocusFirst(None);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
event bool PrevControl(GUIComponent Sender)
|
|
{
|
|
|
|
if ( Sender != None )
|
|
{
|
|
Super(GUIComponent).SetFocus(None);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if ( Super(GUIComponent).PrevControl(Self) )
|
|
return true;
|
|
|
|
else FocusLast(None);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function int TabIndex(string TabName)
|
|
{
|
|
local int i;
|
|
|
|
for (i = 0; i < TabStack.Length; i++)
|
|
if (TabStack[i].Caption ~= TabName)
|
|
return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
function GUITabPanel FindPanelClass( class<GUITabPanel> PanelClass )
|
|
{
|
|
local int i;
|
|
|
|
if ( PanelClass == None )
|
|
return None;
|
|
|
|
for ( i = 0; i < TabStack.Length; i++ )
|
|
{
|
|
if ( TabStack[i] != None && TabStack[i].MyPanel != None &&
|
|
ClassIsChildOf(TabStack[i].MyPanel.Class, PanelClass) )
|
|
|
|
return TabStack[i].MyPanel;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
function GUITabPanel BorrowPanel(string Caption)
|
|
{
|
|
local int i;
|
|
|
|
if (Caption == "") return None;
|
|
|
|
i = TabIndex(Caption);
|
|
if (i < 0) return None;
|
|
return TabStack[i].MyPanel;
|
|
}
|
|
|
|
function SetVisibility(bool bIsVisible)
|
|
{
|
|
Super.SetVisibility(bIsVisible);
|
|
|
|
if (ActiveTab != None)
|
|
ActiveTab.ChangeActiveState(bIsVisible, False);
|
|
}
|
|
|
|
function InternalOnActivate()
|
|
{
|
|
if (ActiveTab == None)
|
|
LostActiveTab();
|
|
}
|
|
|
|
function bool FocusFirst(GUIComponent Sender)
|
|
{
|
|
if ( ActiveTab != None && ActiveTab.MyPanel != None && ActiveTab.MyPanel.CanAcceptFocus() && ActiveTab.MyPanel.FocusFirst(None) )
|
|
return true;
|
|
|
|
else if (!Super.FocusFirst(Sender))
|
|
Super(GUIComponent).SetFocus(None);
|
|
|
|
return true;
|
|
}
|
|
|
|
function bool FocusLast(GUIComponent Sender)
|
|
{
|
|
if ( ActiveTab != None && ActiveTab.MyPanel != None && ActiveTab.MyPanel.CanAcceptFocus() && ActiveTab.MyPanel.FocusLast(None) )
|
|
return true;
|
|
|
|
else if ( !Super.FocusLast(Sender) )
|
|
Super(GUIComponent).SetFocus(None);
|
|
|
|
return true;
|
|
}
|
|
|
|
function CenterMouse()
|
|
{
|
|
if ( ActiveTab != None )
|
|
ActiveTab.CenterMouse();
|
|
|
|
else Super.CenterMouse();
|
|
}
|
|
|
|
event Free()
|
|
{
|
|
local int i;
|
|
|
|
for ( i = 0; i < TabStack.Length; i++ )
|
|
{
|
|
if ( TabStack[i] != None )
|
|
TabStack[i].Free();
|
|
}
|
|
|
|
Super.Free();
|
|
}
|
|
|
|
function LevelChanged()
|
|
{
|
|
local int i;
|
|
|
|
for ( i = 0; i < TabStack.Length; i++ )
|
|
{
|
|
if ( TabStack[i] != None )
|
|
TabStack[i].LevelChanged();
|
|
}
|
|
|
|
Super.LevelChanged();
|
|
}
|
|
|
|
defaultproperties
|
|
{
|
|
OnActivate=InternalOnActivate
|
|
bDrawTabAbove=true
|
|
TabHeight=0.0350
|
|
bFillSpace=false
|
|
bTabStop=true
|
|
bDockPanels=false
|
|
bFillBackground=true
|
|
}
|