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

370 lines
7.2 KiB
Ucode

// ====================================================================
// Class: UT2K4UI.GUICircularList
// Parent: UT2K4UI.GUIListBase
//
// <Enter a description here>
// ====================================================================
class GUICircularList extends GUIListBase
Native;
cpptext
{
void Draw(UCanvas* Canvas);
}
var() bool bCenterInBounds; // Center the list in the bounding box
var() bool bFillBounds; // If true, the list will take up the whole bounding box
var() bool bIgnoreBackClick; // If true, will ignore any click on back region
var() bool bAllowSelectEmpty; // If true, allows selection of empty slots
var() int FixedItemsPerPage; // There are a fixed number of items in the list
var() bool bWrapItems; // If itemcount < ItemsPerPage, should items be wrapped?
function InitComponent(GUIController MyController, GUIComponent MyOwner)
{
Super.Initcomponent(MyController, MyOwner);
// Sanity
if (bFillBounds)
bCenterInBounds=false;
if (!bAllowSelectEmpty && ItemCount == 0)
Index = -1;
}
function float CalculateOffset(float MouseX)
{
local float x,x1,x2,Width,xMod;
local int i;
x1 = ClientBounds[0];
x2 = ClientBounds[2];
if ( (MouseX<x1) || (MouseX>x2) )
return -1.0;
width = x2-x1;
if ( (bCenterInBounds) && (ItemsPerPage*ItemWidth<Width) )
{
xMod = (Width - (ItemsPerPage*ItemWidth)) / 2;
x1+=xMod;
x2-=xMod;
if ( (MouseX>=x1) && (MouseX<=x2) )
return (MouseX-x1) / ItemWidth;
else
return -1;
}
if ( (bFillBounds) && (ItemsPerPage*ItemWidth<Width) )
{
xMod = (Width - (ItemsPerPage*ItemWidth)) / ItemsPerPage;
i = 0;
x = x1;
while (x<=x2)
{
if ((MouseX>=x) && (MouseX<=x+ItemWidth) )
return i;
i++;
x+= ItemWidth+xmod;
}
return -1;
}
return (MouseX-x1)/ItemWidth;
}
event int CalculateIndex( optional bool bRequireValidIndex )
{
local int i, NewIndex;
i = (Top + CalculateOffset(Controller.MouseX)) % ItemCount;
if ( bRequireValidIndex && !IsValidIndex(i) )
i = -1;
NewIndex = Min( i, ItemCount - 1 );
return NewIndex;
}
function bool InternalOnClick(GUIComponent Sender)
{
local int NewIndex;
if ( ( !IsInClientBounds() ) || (ItemsPerPage==0) )
return false;
// Get the Col
NewIndex = CalculateIndex(True);
// Keep selected index in range
if (NewIndex < 0 && bIgnoreBackClick)
return false;
// check if allowed to go out of range
if ( !bAllowSelectEmpty && !IsValidIndex(NewIndex) )
return false;
SetIndex(NewIndex);
return true;
}
function WheelUp()
{
MoveLeft();
}
function WheelDown()
{
MoveRight();
}
function bool MoveLeft()
{
local int last;
if (ItemCount<2) return true;
Last = Index;
if (Index==0)
Index=ItemCount-1;
else
Index--;
if (Last==Top)
Top=Index;
OnChange(self);
return true;
}
function bool MoveRight()
{
local int last;
if (ItemCount<2) return true;
Last = Index;
Index++;
if (Index==ItemCOunt)
Index = 0;
if (Last==(Top+ItemsPerPage-1)%ItemCount)
{
Top++;
if (Top==ItemCount)
Top=0;
}
OnChange(self);
return true;
}
function Home()
{
if (ItemCount<2) return;
SetIndex(0);
Top = 0;
OnChange(self);
}
function End()
{
if (ItemCount<2) return;
Top = ItemCount - ItemsPerPage;
if (Top<0)
Top = 0;
SetIndex(ItemCount-1);
}
function PgUp()
{
local int moveCount, Last;
if (ItemCount<2) return;
for(moveCount=0; moveCount<ItemsPerPage-1; moveCount++)
{
Last = Index;
if (Index==0)
Index=ItemCount-1;
else
Index--;
if (Last==Top)
Top=Index;
}
OnChange(self);
}
function PgDown()
{
local int moveCount, Last;
if (ItemCount<2) return;
for(moveCount=0; moveCount<ItemsPerPage-1; moveCount++)
{
Last = Index;
Index++;
if (Index==ItemCOunt)
Index = 0;
if (Last==(Top+ItemsPerPage-1)%ItemCount)
{
Top++;
if (Top==ItemCount)
Top=0;
}
}
OnChange(self);
}
function bool IsValid()
{
return Index != -1;
}
// We've received a mouse click in the drop source
function InternalOnMousePressed(GUIComponent Sender, bool IsRepeat)
{
local int NewIndex, i, j, k;
if ( !IsInClientBounds() || ItemsPerPage == 0 )
return;
// If not holding down the mouse
if (!IsRepeat && ItemCount > 0)
{
NewIndex = CalculateIndex( True );
if (NewIndex == -1 && bIgnoreBackClick)
return;
LastPressX = Controller.MouseX;
LastPressY = Controller.MouseY;
if (NewIndex >= ItemCount)
NewIndex = ItemCount - 1;
// If we had an Item selected, go ahead and add it to the drag-n-drop list
if ( Controller.CtrlPressed && bMultiSelect && SelectedItems.Length == 0 && NewIndex != Index )
SelectedItems[SelectedItems.Length] = Index;
// If shift is pressed, do shift selection
if ( Controller.ShiftPressed && IsMultiSelect() )
{
if ( LastSelected == -1 )
LastSelected = 0;
// If not pressing Ctrl, clear out the SelectedItems array
if ( !Controller.CtrlPressed )
for ( j = SelectedItems.Length - 1; j >= 0; j-- )
if ( SelectedItems[j] != Index )
SelectedItems.Remove(j,1);
for ( j = Min(LastSelected, NewIndex); j <= Max(LastSelected, NewIndex); j++ )
{
for ( k = 0; k < SelectedItems.Length; k++ )
if ( SelectedItems[k] == j )
break;
if ( k == SelectedItems.Length )
SelectedItems[k] = j;
}
return;
}
else
{
LastSelected = NewIndex;
if ( IsMultiSelect() )
Index = NewIndex;
}
// Find out if the this index is already in our selected list
for (i = 0; i < SelectedItems.Length; i++)
if (SelectedItems[i] == NewIndex)
break;
// If it was found, remove it (allows toggling an Item's selectedness)
// don't remove it immediately, but set MightRemove. This way, if the user drags
// the selected Item, instead of releasing the mouse, we won't deselect it.
if (i < SelectedItems.Length)
MightRemove = i;
else if (Controller.CtrlPressed && bMultiSelect)
SelectedItems[i] = NewIndex;
else if (SelectedItems.Length > 0 && MightRemove == -1)
SelectedItems.Remove(0, SelectedItems.Length);
}
}
// Find out if we were clicking on any Item - if so, add it to SelectedItems
function CheckDragSelect()
{
local int i;
i = CalculateIndex(True);
if (i < 0 && bIgnoreBackClick)
return;
if (i >= ItemCount)
i = ItemCount - 1;
SetIndex(i);
SelectedItems[SelectedItems.Length] = i;
}
// Called on whatever component the data is being dragged over
function InternalOnDragOver(GUIComponent Sender)
{
local int NewIndex;
if (Controller.DropTarget == Self)
{
NewIndex = CalculateIndex(True);
// Keep selected index in range
if (NewIndex == -1 && bIgnoreBackClick)
return;
if (NewIndex >= ItemCount)
{
DropIndex = -1;
return;
}
if (Controller.DropSource != Self && SelectedItems.Length > 0)
SelectedItems.Remove(0, SelectedItems.Length);
DropIndex = NewIndex;
}
}
defaultproperties
{
OnClick=InternalOnClick
bWrapItems=True
bCenterInBounds=true
bIgnoreBackClick=true
FixedItemsPerPage=0
bAllowSelectEmpty=true
bRequiresStyle=True
}