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:04:55 +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:04:55 +00:00
|
|
|
if(bShouldSortList && Index==-1)
|
2017-10-20 02:00:49 +00:00
|
|
|
{
|
|
|
|
N.Temp = N.GetSortStr(LastSortedColumn);
|
|
|
|
|
2020-11-28 20:04:55 +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:04:55 +00:00
|
|
|
else if(bLastSortedReverse)
|
2017-10-20 02:00:49 +00:00
|
|
|
{
|
2020-11-28 20:04:55 +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:04:55 +00:00
|
|
|
for(O=FirstItem; O!=None; O=O.Next)
|
2017-10-20 02:00:49 +00:00
|
|
|
{
|
2020-11-28 20:04:55 +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:04:55 +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:04:55 +00:00
|
|
|
for(O=FirstItem; O!=None; O=O.Next)
|
2017-10-20 02:00:49 +00:00
|
|
|
{
|
2020-11-28 20:04:55 +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:04:55 +00:00
|
|
|
else if(Index==-1 || Index>ListCount)
|
2017-10-20 02:00:49 +00:00
|
|
|
Index = ListCount;
|
2020-11-28 20:04:55 +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:04:55 +00:00
|
|
|
for(O=FirstItem; O!=None; O=O.Next)
|
2017-10-20 02:00:49 +00:00
|
|
|
{
|
2020-11-28 20:04:55 +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 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:04:55 +00:00
|
|
|
if(I.Index==-1)
|
2017-10-20 02:00:49 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Update selected row info.
|
2020-11-28 20:04:55 +00:00
|
|
|
if(SelectedRowIndex==I.Index)
|
2017-10-20 02:00:49 +00:00
|
|
|
SelectedRowIndex = -1;
|
2020-11-28 20:04:55 +00:00
|
|
|
else if(SelectedRowIndex>I.Index)
|
2017-10-20 02:00:49 +00:00
|
|
|
--SelectedRowIndex;
|
|
|
|
|
|
|
|
// Remove from list.
|
2020-11-28 20:04:55 +00:00
|
|
|
if(FirstItem==I)
|
2017-10-20 02:00:49 +00:00
|
|
|
FirstItem = I.Next;
|
|
|
|
else
|
|
|
|
{
|
2020-11-28 20:04:55 +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();
|
|
|
|
}
|
|
|
|
final function EmptyList()
|
|
|
|
{
|
|
|
|
local KFGUI_ListItem N,I;
|
|
|
|
|
2020-11-28 20:04:55 +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:04:55 +00:00
|
|
|
if(Index<0 || Index>=ListCount)
|
2017-10-20 02:00:49 +00:00
|
|
|
return None;
|
2020-11-28 20:04:55 +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:04:55 +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:04:55 +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:04:55 +00:00
|
|
|
if(bReverse)
|
2017-10-20 02:00:49 +00:00
|
|
|
{
|
2020-11-28 20:04:55 +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:04:55 +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:04:55 +00:00
|
|
|
for(i=0; i<List.Length; ++i)
|
2017-10-20 02:00:49 +00:00
|
|
|
{
|
|
|
|
N = List[i];
|
2020-11-28 20:04:55 +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:04:55 +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:04:55 +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:04:55 +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:04:55 +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:04:55 +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:04:55 +00:00
|
|
|
if(bCheckMouse && FocusMouseItem==-1)
|
2017-10-20 02:00:49 +00:00
|
|
|
{
|
2020-11-28 20:04:55 +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:04:55 +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:04:55 +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:04:55 +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:04:55 +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:04:55 +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:04:55 +00:00
|
|
|
if(OldItemsPerFrame!=ListItemsPerPage || bListSizeDirty)
|
2017-10-20 02:00:49 +00:00
|
|
|
{
|
2020-11-28 20:04:55 +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 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 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)
|
|
|
|
}
|