410 lines
8.5 KiB
Ucode
410 lines
8.5 KiB
Ucode
//==============================================================================
|
|
// Created on: 09/16/2003
|
|
// Support for creating circular lists like the character lists, using other materials
|
|
//
|
|
// Written by Ron Prestenback
|
|
// © 2003, Epic Games, Inc. All Rights Reserved
|
|
//==============================================================================
|
|
class GUICircularImageList extends GUICircularList
|
|
native;
|
|
|
|
cpptext
|
|
{
|
|
void PreDraw(UCanvas* Canvas);
|
|
protected:
|
|
void DrawItem(UCanvas* Canvas, INT Item, FLOAT X, FLOAT Y, FLOAT W, FLOAT HT, UBOOL bSelected, UBOOL bPending);
|
|
public:
|
|
}
|
|
|
|
|
|
var() editconst editconstarray protected array<GUIListElem> Elements;
|
|
|
|
function Add( Material Img, optional string Str )
|
|
{
|
|
local int NewIndex;
|
|
|
|
if ( !bAllowEmptyItems && Img == None && Str == "" )
|
|
return;
|
|
|
|
if (bSorted && Elements.Length > 0)
|
|
{
|
|
while (NewIndex < Elements.Length && Elements[NewIndex].Item < Str)
|
|
NewIndex++;
|
|
}
|
|
else NewIndex = Elements.Length;
|
|
|
|
Elements.Insert(NewIndex, 1);
|
|
|
|
Elements[NewIndex].Item = Str;
|
|
Elements[NewIndex].ExtraData = Img;
|
|
|
|
ItemCount = Elements.Length;
|
|
if (Elements.Length == 1 && bInitializeList)
|
|
SetIndex(0);
|
|
else CheckLinkedObjects(Self);
|
|
}
|
|
|
|
function Replace(int i, Material Img, optional string Str)
|
|
{
|
|
if ( !IsValidIndex(i) )
|
|
Add(img,Str);
|
|
else
|
|
{
|
|
if ( !bAllowEmptyItems && img == None && Str == "" )
|
|
return;
|
|
|
|
Elements[i].Item = Str;
|
|
Elements[i].ExtraData = img;
|
|
|
|
if ( bNotify )
|
|
OnChange(self);
|
|
}
|
|
}
|
|
|
|
function Insert(int i, Material Img, optional string Str)
|
|
{
|
|
if ( !IsValidIndex(i) )
|
|
Add(Img,Str);
|
|
else
|
|
{
|
|
if ( !bAllowEmptyItems && Img == None && Str == "" )
|
|
return;
|
|
|
|
Elements.Insert(i,1);
|
|
Elements[i].Item=Str;
|
|
Elements[i].ExtraData=Img;
|
|
ItemCount=Elements.Length;
|
|
|
|
if ( bNotify )
|
|
OnChange(self);
|
|
}
|
|
}
|
|
|
|
event Swap(int IndexA, int IndexB)
|
|
{
|
|
local GUI.GUIListElem elem;
|
|
|
|
if ( IsValidIndex(IndexA) && IsValidIndex(IndexB) )
|
|
{
|
|
elem = Elements[IndexA];
|
|
Elements[IndexA] = Elements[IndexB];
|
|
Elements[IndexB] = elem;
|
|
}
|
|
}
|
|
|
|
function LoadFrom(GUICircularImageList Source, optional bool bClearFirst)
|
|
{
|
|
local string t1,t2;
|
|
local object obj;
|
|
local int i;
|
|
|
|
if (bClearfirst)
|
|
Clear();
|
|
|
|
for (i=0;i<Source.Elements.Length;i++)
|
|
{
|
|
Source.GetAtIndex(i,t1,obj,t2);
|
|
Add(material(obj),t1);
|
|
}
|
|
}
|
|
|
|
function int RemoveSilent(int i, optional int Count)
|
|
{
|
|
bNotify = False;
|
|
i = Remove(i, Count);
|
|
bNotify = True;
|
|
return i;
|
|
}
|
|
|
|
function int Remove(int i, optional int Count)
|
|
{
|
|
Count = Max( Count, 1 );
|
|
if (!IsValidIndex(i))
|
|
return Index;
|
|
|
|
Elements.Remove(i, Min(Count, Elements.Length - i));
|
|
|
|
ItemCount = Elements.Length;
|
|
|
|
// In case we now have an invalid index
|
|
SetIndex(Index);
|
|
|
|
return Index;
|
|
}
|
|
|
|
function int RemoveElement(GUIListElem Elem, optional int Count)
|
|
{
|
|
local int i;
|
|
|
|
Count = Max(Count, 1);
|
|
for ( i = 0; i < Elements.Length; i++ )
|
|
{
|
|
if ( Elements[i] == Elem )
|
|
{
|
|
Elements.Remove(i, Min(Count, Elements.Length - i));
|
|
break;
|
|
}
|
|
}
|
|
|
|
ItemCount = Elements.Length;
|
|
|
|
// In case we now have an invalid index
|
|
SetIndex(Index);
|
|
|
|
return Index;
|
|
}
|
|
|
|
function Clear()
|
|
{
|
|
if (Elements.Length == 0)
|
|
return;
|
|
|
|
Elements.Remove(0,Elements.Length);
|
|
ItemCount = 0;
|
|
Super.Clear();
|
|
}
|
|
|
|
//##############################################################################
|
|
//
|
|
// Query functions
|
|
//
|
|
|
|
// Current listitem
|
|
function string Get(optional bool bGuarantee)
|
|
{
|
|
if ( !IsValid() )
|
|
{
|
|
if (bGuarantee && Elements.Length > 0)
|
|
return Elements[0].Item;
|
|
|
|
return "";
|
|
}
|
|
|
|
return Elements[Index].Item;
|
|
}
|
|
|
|
function Material GetImage(optional bool bGuarantee)
|
|
{
|
|
if ( !IsValid() )
|
|
{
|
|
if ( bGuarantee && Elements.Length > 0 )
|
|
return Material(Elements[0].ExtraData);
|
|
|
|
return none;
|
|
}
|
|
|
|
return Material(Elements[Index].ExtraData);
|
|
}
|
|
|
|
// Arbitrary list Item
|
|
function string GetItemAtIndex(int i)
|
|
{
|
|
if (!IsValidIndex(i))
|
|
return "";
|
|
|
|
return Elements[i].Item;
|
|
}
|
|
|
|
function Material GetImageAtIndex(int i)
|
|
{
|
|
if (!IsValidIndex(i))
|
|
return None;
|
|
|
|
return Material(Elements[i].ExtraData);
|
|
}
|
|
|
|
function GetAtIndex(int i, out string ItemStr, out Object Img, out string ExtraStr)
|
|
{
|
|
if (!IsValidIndex(i))
|
|
return;
|
|
|
|
ItemStr = Elements[i].Item;
|
|
Img = Elements[i].ExtraData;
|
|
ExtraStr = Elements[i].ExtraStrData;
|
|
}
|
|
|
|
// Specify true for bGuarantee to receive the selected item if there are no "pending" items
|
|
function array<string> GetPendingItems(optional bool bGuarantee)
|
|
{
|
|
local int i;
|
|
local array<string> Items;
|
|
|
|
if ( (DropState == DRP_Source && Controller.DropSource == Self ) || bGuarantee )
|
|
{
|
|
for ( i = 0; i < SelectedItems.Length; i++ )
|
|
if ( IsValidIndex(SelectedItems[i]) )
|
|
Items[Items.Length] = Elements[SelectedItems[i]].Item;
|
|
|
|
if ( Items.Length == 0 && IsValid() )
|
|
Items[0] = Get();
|
|
}
|
|
|
|
return Items;
|
|
}
|
|
|
|
function array<GUIListElem> GetPendingElements(optional bool bGuarantee)
|
|
{
|
|
local int i;
|
|
local array<GUIListElem> PendingItem;
|
|
|
|
if ( (DropState == DRP_Source && Controller.DropSource == Self) || bGuarantee )
|
|
{
|
|
for (i = 0; i < SelectedItems.Length; i++)
|
|
if (IsValidIndex(SelectedItems[i]))
|
|
PendingItem[PendingItem.Length] = Elements[SelectedItems[i]];
|
|
|
|
if ( PendingItem.Length == 0 && IsValid() )
|
|
{
|
|
PendingItem.Length = PendingItem.Length + 1;
|
|
GetAtIndex(Index, PendingItem[0].Item, PendingItem[0].ExtraData, PendingItem[0].ExtraStrData);
|
|
}
|
|
|
|
}
|
|
return PendingItem;
|
|
}
|
|
|
|
//##############################################################################
|
|
//
|
|
// Assignment functions
|
|
//
|
|
|
|
function SetItemAtIndex(int i, string NewItem)
|
|
{
|
|
if (!IsValidIndex(i))
|
|
return;
|
|
|
|
Elements[i].Item = NewItem;
|
|
}
|
|
|
|
function SetImageAtIndex(int i, Material Img)
|
|
{
|
|
if (!IsValidIndex(i))
|
|
return;
|
|
|
|
Elements[i].ExtraData = Img;
|
|
}
|
|
|
|
function RemoveItem(string Item)
|
|
{
|
|
local int i;
|
|
|
|
// Work through array. If we find it, remove it (will reduce Elements.Length).
|
|
// If we don't, move on to next one.
|
|
while( i < Elements.Length)
|
|
{
|
|
if(Item ~= Elements[i].Item)
|
|
Elements.Remove(i, 1);
|
|
else
|
|
i++;
|
|
}
|
|
|
|
ItemCount = Elements.Length;
|
|
SetIndex(-1);
|
|
}
|
|
|
|
function RemoveImage(Material Img)
|
|
{
|
|
local int i;
|
|
|
|
while (i < Elements.Length)
|
|
{
|
|
if (Img == Elements[i].ExtraData)
|
|
Elements.Remove(i, 1);
|
|
else i++;
|
|
}
|
|
|
|
ItemCount = Elements.Length;
|
|
SetIndex(-1);
|
|
}
|
|
|
|
|
|
//##############################################################################
|
|
//
|
|
// Search functions
|
|
//
|
|
|
|
function int FindIndex(Material Img, optional string Test)
|
|
{
|
|
local int i;
|
|
|
|
if (Img != None)
|
|
{
|
|
for (i = 0; i < Elements.Length; i++)
|
|
if ( Img == Elements[i].ExtraData )
|
|
return i;
|
|
}
|
|
|
|
else if (Test != "")
|
|
{
|
|
for ( i = 0; i < Elements.Length; i++)
|
|
if ( Elements[i].Item ~= Test )
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// Called on the drop source when when an Item has been dropped. bAccepted tells it whether
|
|
// the operation was successful or not.
|
|
function InternalOnEndDrag(GUIComponent Accepting, bool bAccepted)
|
|
{
|
|
local int i;
|
|
local array<GUIListElem> TempElem;
|
|
|
|
if (bAccepted && Accepting != None)
|
|
{
|
|
for (i = 0; i < SelectedItems.Length; i++)
|
|
TempElem[TempElem.Length] = Elements[SelectedItems[i]];
|
|
|
|
for (i = 0; i < TempElem.Length; i++)
|
|
RemoveElement(TempElem[i]);
|
|
|
|
bRepeatClick = False;
|
|
// InternalOnMouseRelease(Accepting);
|
|
}
|
|
|
|
// Simulate repeat click if the operation was a failure to prevent InternalOnMouseRelease from clearing
|
|
// the SelectedItems array
|
|
// This way we don't lose the items we clicked on
|
|
if (Accepting == None)
|
|
bRepeatClick = True;
|
|
|
|
SetOutlineAlpha(255);
|
|
if ( bNotify )
|
|
CheckLinkedObjects(Self);
|
|
}
|
|
|
|
// Called on the drop target when the mouse is released - Sender is always DropTarget
|
|
function bool InternalOnDragDrop(GUIComponent Sender)
|
|
{
|
|
local array<GUIListElem> NewItem;
|
|
local int i;
|
|
|
|
if (Controller.DropTarget == Self)
|
|
{
|
|
if (Controller.DropSource != None && GUIList(Controller.DropSource) != None)
|
|
{
|
|
NewItem = GUIList(Controller.DropSource).GetPendingElements();
|
|
|
|
if (DropIndex >= 0 && DropIndex < ItemCount)
|
|
{
|
|
for (i = NewItem.Length - 1; i >= 0; i--)
|
|
Insert(DropIndex, Material(NewItem[i].ExtraData), NewItem[i].Item);
|
|
}
|
|
else
|
|
{
|
|
DropIndex = ItemCount;
|
|
for (i = 0; i < NewItem.Length; i++)
|
|
Add(Material(NewItem[i].ExtraData), NewItem[i].Item);
|
|
}
|
|
|
|
SetIndex(DropIndex);
|
|
// InternalOnMouseRelease(Self);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|