KF2-Server-Extension/ServerExt/Classes/KFGUI_ColumnList.uc

442 lines
8.9 KiB
Ucode
Raw Normal View History

2017-10-20 02:00:49 +00:00
// Columned list box (only for text lines).
Class KFGUI_ColumnList extends KFGUI_List;
struct FColumnItem
{
var() string Text;
var() float Width;
var transient bool bHidden;
var transient int X,XSize;
};
var() array<FColumnItem> Columns;
var() class<KFGUI_ListItem> ListItemClass;
var() int FontSize;
var() color FocusedLineColor,SelectedLineColor;
var KFGUI_ColumnTop ColumnComp;
var Canvas.FontRenderInfo LineFontInfo;
var int SelectedRowIndex;
var int LastSortedColumn;
var transient float TextHeight,ScalerSize,TextScaler;
var transient int OldItemsPerFrame;
var KFGUI_ListItem FirstItem,UnusedItem;
var transient bool bListSizeDirty;
var bool bLastSortedReverse;
var() bool bShouldSortList; // Should sort any new items added to the list instantly.
var() bool bCanSortColumn; // Allow user to sort columns.
2020-11-28 20:04:55 +00:00
delegate OnSelectedRow(KFGUI_ListItem Item, int Row, bool bRight, bool bDblClick);
2017-10-20 02:00:49 +00:00
2020-11-28 20:04:55 +00:00
function KFGUI_ListItem AddLine(string Value, optional int iValue, optional string SortValue, optional int Index=-1)
2017-10-20 02:00:49 +00:00
{
local KFGUI_ListItem N,O;
local int i;
// Allocate list item object.
2020-11-28 20:12:58 +00:00
if (UnusedItem!=None)
2017-10-20 02:00:49 +00:00
{
N = UnusedItem;
UnusedItem = N.Next;
N.Next = None;
}
else N = new (None) ListItemClass;
// Setup column text value.
N.SetValue(Value,iValue,SortValue);
// Insert into list.
2020-11-28 20:12:58 +00:00
if (bShouldSortList && Index==-1)
2017-10-20 02:00:49 +00:00
{
N.Temp = N.GetSortStr(LastSortedColumn);
2020-11-28 20:12:58 +00:00
if (ListCount==0) // No sorting needed yet.
2017-10-20 02:00:49 +00:00
{
N.Next = FirstItem;
FirstItem = N;
}
2020-11-28 20:12:58 +00:00
else if (bLastSortedReverse)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (FirstItem.Temp<N.Temp)
2017-10-20 02:00:49 +00:00
{
N.Next = FirstItem;
FirstItem = N;
}
else
{
2020-11-28 20:12:58 +00:00
for (O=FirstItem; O!=None; O=O.Next)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (O.Next==None || O.Next.Temp<N.Temp)
2017-10-20 02:00:49 +00:00
{
N.Next = O.Next;
O.Next = N;
break;
}
}
}
}
2020-11-28 20:12:58 +00:00
else if (FirstItem.Temp>N.Temp)
2017-10-20 02:00:49 +00:00
{
N.Next = FirstItem;
FirstItem = N;
}
else
{
2020-11-28 20:12:58 +00:00
for (O=FirstItem; O!=None; O=O.Next)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (O.Next==None || O.Next.Temp>N.Temp)
2017-10-20 02:00:49 +00:00
{
N.Next = O.Next;
O.Next = N;
break;
}
}
}
}
2020-11-28 20:12:58 +00:00
else if (Index==-1 || Index>ListCount)
2017-10-20 02:00:49 +00:00
Index = ListCount;
2020-11-28 20:12:58 +00:00
if (Index==0)
2017-10-20 02:00:49 +00:00
{
N.Next = FirstItem;
FirstItem = N;
}
else
{
i = 0;
2020-11-28 20:12:58 +00:00
for (O=FirstItem; O!=None; O=O.Next)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if ((++i)==Index)
2017-10-20 02:00:49 +00:00
{
N.Next = O.Next;
O.Next = N;
break;
}
}
}
UpdateListSize();
return N;
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
final function RemoveLine(KFGUI_ListItem I)
2017-10-20 02:00:49 +00:00
{
local KFGUI_ListItem N;
2020-11-28 20:12:58 +00:00
if (I.Index==-1)
2017-10-20 02:00:49 +00:00
return;
// Update selected row info.
2020-11-28 20:12:58 +00:00
if (SelectedRowIndex==I.Index)
2017-10-20 02:00:49 +00:00
SelectedRowIndex = -1;
2020-11-28 20:12:58 +00:00
else if (SelectedRowIndex>I.Index)
2017-10-20 02:00:49 +00:00
--SelectedRowIndex;
// Remove from list.
2020-11-28 20:12:58 +00:00
if (FirstItem==I)
2017-10-20 02:00:49 +00:00
FirstItem = I.Next;
else
{
2020-11-28 20:12:58 +00:00
for (N=FirstItem; N!=None; N=N.Next)
if (N.Next==I)
2017-10-20 02:00:49 +00:00
{
N.Next = I.Next;
break;
}
}
// Add to unused list.
I.Next = UnusedItem;
UnusedItem = I;
I.Index = -1;
UpdateListSize();
}
2020-11-28 21:54:57 +00:00
2017-10-20 02:00:49 +00:00
final function EmptyList()
{
local KFGUI_ListItem N,I;
2020-11-28 20:12:58 +00:00
for (I=FirstItem; I!=None; I=N)
2017-10-20 02:00:49 +00:00
{
N = I.Next;
// Add to unused list.
I.Next = UnusedItem;
UnusedItem = I;
I.Index = -1;
}
FirstItem = None;
UpdateListSize();
}
2020-11-28 20:04:55 +00:00
final function KFGUI_ListItem GetFromIndex(int Index)
2017-10-20 02:00:49 +00:00
{
local KFGUI_ListItem N;
2020-11-28 20:12:58 +00:00
if (Index<0 || Index>=ListCount)
2017-10-20 02:00:49 +00:00
return None;
2020-11-28 20:12:58 +00:00
for (N=FirstItem; N!=None; N=N.Next)
if ((Index--)==0)
2017-10-20 02:00:49 +00:00
return N;
return None;
}
2020-11-28 20:04:55 +00:00
function SortColumn(int Column, optional bool bReverse)
2017-10-20 02:00:49 +00:00
{
local array<KFGUI_ListItem> List;
local KFGUI_ListItem Sel,N,P;
local int i;
2020-11-28 20:12:58 +00:00
if (!bCanSortColumn || Column<0 || Column>=Columns.Length)
2017-10-20 02:00:49 +00:00
return;
LastSortedColumn = Column;
bLastSortedReverse = bReverse;
bShouldSortList = true;
// Allocate memory space first.
List.Length = ListCount;
List.Length = 0;
// Grab current selected line.
Sel = GetFromIndex(SelectedRowIndex);
SelectedRowIndex = -1;
// Slow, sort it all.
2020-11-28 20:12:58 +00:00
for (N=FirstItem; N!=None; N=N.Next)
2017-10-20 02:00:49 +00:00
{
N.Temp = N.GetSortStr(Column);
2020-11-28 20:12:58 +00:00
if (bReverse)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
for (i=0; i<List.Length; ++i)
if (List[i].Temp<N.Temp)
2017-10-20 02:00:49 +00:00
break;
}
else
{
2020-11-28 20:12:58 +00:00
for (i=0; i<List.Length; ++i)
if (List[i].Temp>N.Temp)
2017-10-20 02:00:49 +00:00
break;
}
List.Insert(i,1);
List[i] = N;
}
// Rebuild list.
FirstItem = None;
P = None;
2020-11-28 20:12:58 +00:00
for (i=0; i<List.Length; ++i)
2017-10-20 02:00:49 +00:00
{
N = List[i];
2020-11-28 20:12:58 +00:00
if (Sel==N)
2017-10-20 02:00:49 +00:00
SelectedRowIndex = i;
N.Index = i;
N.Next = None;
2020-11-28 20:12:58 +00:00
if (P==None)
2017-10-20 02:00:49 +00:00
FirstItem = N;
else P.Next = N;
P = N;
}
}
2020-11-28 20:04:55 +00:00
function ChangeListSize(int NewSize);
2017-10-20 02:00:49 +00:00
final function UpdateListSize()
{
local KFGUI_ListItem N;
ListCount = 0;
2020-11-28 20:12:58 +00:00
for (N=FirstItem; N!=None; N=N.Next)
2017-10-20 02:00:49 +00:00
N.Index = ListCount++;
bListSizeDirty = true;
}
function InitMenu()
{
ListCount = 0;
Super.InitMenu();
ColumnComp = KFGUI_ColumnTop(FindComponentID('Columns'));
}
2020-11-28 20:04:55 +00:00
final function DrawStrClipped(string S)
2017-10-20 02:00:49 +00:00
{
Canvas.PushMaskRegion(Canvas.OrgX,Canvas.OrgY,Canvas.ClipX,Canvas.ClipY);
Canvas.DrawText(S,,TextScaler,TextScaler,LineFontInfo);
Canvas.PopMaskRegion();
}
function DrawMenu()
{
local int i,n,j;
local float Y,TextY,YClip,XOffset;
local KFGUI_ListItem C;
local bool bCheckMouse;
Canvas.DrawColor = BackgroundColor;
Canvas.SetPos(0.f,0.f);
Owner.CurrentStyle.DrawWhiteBox(CompPos[2],CompPos[3]);
// Mouse focused item check.
bCheckMouse = bClickable && bFocused;
FocusMouseItem = -1;
2020-11-28 20:12:58 +00:00
if (bCheckMouse)
2017-10-20 02:00:49 +00:00
MouseYHit = Owner.MousePosition.Y - CompPos[1];
n = ScrollBar.CurrentScroll;
i = 0;
2020-11-28 20:12:58 +00:00
for (C=FirstItem; C!=None; C=C.Next)
if ((i++)==n)
2017-10-20 02:00:49 +00:00
break;
Y = 0.f;
TextY = (ItemHeight-TextHeight)*0.5f;
XOffset = TextY*0.75;
YClip = CompPos[1]+CompPos[3];
Canvas.SetDrawColor(250,250,250,255);
2020-11-28 20:12:58 +00:00
for (i=0; (i<ListItemsPerPage && C!=None); ++i)
2017-10-20 02:00:49 +00:00
{
// Check for mouse hit.
2020-11-28 20:12:58 +00:00
if (bCheckMouse && FocusMouseItem==-1)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (MouseYHit<ItemHeight)
2017-10-20 02:00:49 +00:00
FocusMouseItem = n;
else MouseYHit-=ItemHeight;
}
// Draw selection background.
2020-11-28 20:12:58 +00:00
if (SelectedRowIndex==n) // Selected
2017-10-20 02:00:49 +00:00
{
Canvas.SetPos(0,Y);
Canvas.DrawColor = SelectedLineColor;
Owner.CurrentStyle.DrawWhiteBox(CompPos[2],ItemHeight);
Canvas.SetDrawColor(250,250,250,255);
}
2020-11-28 20:12:58 +00:00
else if (FocusMouseItem==n) // Focused
2017-10-20 02:00:49 +00:00
{
Canvas.SetPos(0,Y);
Canvas.DrawColor = FocusedLineColor;
Owner.CurrentStyle.DrawWhiteBox(CompPos[2],ItemHeight);
Canvas.SetDrawColor(250,250,250,255);
}
// Draw columns of text
2020-11-28 20:12:58 +00:00
for (j=0; j<Columns.Length; ++j)
if (!Columns[j].bHidden)
2017-10-20 02:00:49 +00:00
{
Canvas.SetClip(Columns[j].X+Columns[j].XSize,YClip);
Canvas.SetPos(Columns[j].X+XOffset,TextY);
DrawStrClipped(C.GetDisplayStr(j));
}
Y+=ItemHeight;
TextY+=ItemHeight;
++n;
C = C.Next;
}
}
function PreDraw()
{
local byte j;
local float XS,SpaceX;
ComputeCoords();
// Check font to use.
Canvas.Font = Owner.CurrentStyle.PickFont(Min(FontSize+Owner.CurrentStyle.DefaultFontSize,Owner.CurrentStyle.MaxFontScale),TextScaler);
Canvas.TextSize("ABC",XS,TextHeight,TextScaler,TextScaler);
2020-11-28 20:12:58 +00:00
for (j=0; j<4; ++j)
2017-10-20 02:00:49 +00:00
{
ScrollBar.InputPos[j] = CompPos[j];
ColumnComp.InputPos[j] = CompPos[j];
}
// Setup positioning.
// First compute the width scrollbar.
2020-11-28 20:12:58 +00:00
if (OldXSize!=InputPos[2])
2017-10-20 02:00:49 +00:00
{
OldXSize = InputPos[2];
ScalerSize = ScrollBar.GetWidth();
ScrollBar.XPosition = 1.f - ScalerSize;
ColumnComp.XSize = ScrollBar.XPosition;
}
SpaceX = ScalerSize*CompPos[2];
CompPos[2] -= SpaceX;
ScrollBar.InputPos[3] = CompPos[3];
// Draw columns.
ColumnComp.YSize = (TextHeight*1.05) / CompPos[3];
ColumnComp.Canvas = Canvas;
ColumnComp.PreDraw();
// Move down to give space for columns.
CompPos[1] += ColumnComp.CompPos[3];
CompPos[3] -= ColumnComp.CompPos[3];
// Compute how many rows fit in with this setting.
ItemHeight = TextHeight*1.025;
ListItemsPerPage = CompPos[3]/ItemHeight;
ItemHeight = CompPos[3]/ListItemsPerPage;
2020-11-28 20:12:58 +00:00
if (OldItemsPerFrame!=ListItemsPerPage || bListSizeDirty)
2017-10-20 02:00:49 +00:00
{
2020-11-28 20:12:58 +00:00
if (SelectedRowIndex>=ListCount)
2017-10-20 02:00:49 +00:00
SelectedRowIndex = -1;
OldItemsPerFrame = ListItemsPerPage;
bListSizeDirty = false;
UpdateListVis();
}
// Draw vertical scrollbar
ScrollBar.Canvas = Canvas;
ScrollBar.PreDraw();
// Draw self.
Canvas.SetOrigin(CompPos[0],CompPos[1]);
Canvas.SetClip(CompPos[0]+CompPos[2],CompPos[1]+CompPos[3]);
DrawMenu();
// Reset scaling to allow mouse to capture input.
CompPos[1] -= ColumnComp.CompPos[3];
CompPos[2] += SpaceX;
CompPos[3] += ColumnComp.CompPos[3];
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function InternalClickedItem(int Index, bool bRight, int MouseX, int MouseY)
2017-10-20 02:00:49 +00:00
{
SelectedRowIndex = Index;
OnSelectedRow(GetFromIndex(Index),Index,bRight,false);
}
2020-11-28 21:54:57 +00:00
2020-11-28 20:04:55 +00:00
function InternalDblClickedItem(int Index, bool bRight, int MouseX, int MouseY)
2017-10-20 02:00:49 +00:00
{
SelectedRowIndex = Index;
OnSelectedRow(GetFromIndex(Index),Index,bRight,true);
}
defaultproperties
{
ListItemClass=class'KFGUI_ListItem'
OnClickedItem=InternalClickedItem
OnDblClickedItem=InternalDblClickedItem
SelectedRowIndex=-1
bClickable=true
FocusedLineColor=(R=64,G=3,B=48,A=255)
SelectedLineColor=(R=84,G=26,B=128,A=255)
bCanSortColumn=true
Begin Object Class=KFGUI_ColumnTop Name=ColumnComps
XPosition=0
YPosition=0
XSize=1
YSize=0.04
ID="Columns"
End Object
Components.Add(ColumnComps)
LineFontInfo=(bClipText=true,bEnableShadow=false)
}