KF2-YetAnotherScoreboard/ScoreboardExt/Classes/KFGUI_TextField.uc

493 lines
10 KiB
Ucode
Raw Normal View History

2020-01-10 13:14:11 +00:00
Class KFGUI_TextField extends KFGUI_MultiComponent;
2021-06-12 20:11:37 +00:00
`include(Build.uci)
`include(Logger.uci)
2020-01-10 13:14:11 +00:00
enum ETextFieldStyles
{
TEXT_FIELD_NONE,
TEXT_FIELD_HSV,
TEXT_FIELD_SCAN,
TEXT_FIELD_FLASH
2020-01-10 13:14:11 +00:00
};
struct FTextPart
{
var string S;
var ETextFieldStyles TextType;
var Color C;
var float X;
structdefaultproperties
{
TextType=TEXT_FIELD_NONE
}
2020-01-10 13:14:11 +00:00
};
struct FTextLineInfo
{
2021-06-13 02:53:33 +00:00
var array < FTextPart> Text;
var float Y;
2020-01-10 13:14:11 +00:00
};
var KFGUI_ScrollBarV ScrollBar;
var() string LineSplitter;
var() protected string Text;
var() Color TextColor;
var() Canvas.FontRenderInfo TextFontInfo;
var() float FontScale,MessageDisplayTime,MessageFadeInTime,MessageFadeOutTime;
var() bool bNoReset,bFadeInOut,bUseOutlineText;
var() int MaxHistory, OutlineSize;
2021-06-13 02:53:33 +00:00
var protected transient array < FTextLineInfo> Lines,OrgLines;
2020-01-10 13:14:11 +00:00
var transient float MaxHeight,ScrollWidth,OldSize[2],InitFontScale,TextHeight,FadeStartTime;
var transient Font InitFont;
var transient bool bShowScrollbar,bTextParsed;
2021-06-13 02:53:33 +00:00
function SetText( string S)
2020-01-10 13:14:11 +00:00
{
2021-06-13 02:53:33 +00:00
if (Text == S)
return;
Text = S;
OldSize[0] = -1; // Force to refresh.
Lines.Length = 0;
OrgLines.Length = 0;
bTextParsed = false;
2020-01-10 13:14:11 +00:00
}
2021-06-13 02:53:33 +00:00
function AddText( string S, optional bool bIgnoreSpam)
2020-01-10 13:14:11 +00:00
{
Text $= S;
OldSize[0] = -1;
Lines.Length = 0;
OrgLines.Length = 0;
bTextParsed = false;
2020-01-10 13:14:11 +00:00
}
final function string GetText()
{
return Text;
2020-01-10 13:14:11 +00:00
}
final function ParseTextLines()
{
2021-06-13 02:53:33 +00:00
local array < string> SA;
local int i,j,z;
local string S;
local color C;
local ETextFieldStyles TextType;
ParseStringIntoArray(Text,SA,LineSplitter,false);
Lines.Length = SA.Length;
C.A = 0;
TextType = TEXT_FIELD_NONE;
2021-06-13 02:53:33 +00:00
for (i=0; i < SA.Length; ++i)
{
Lines[i].Text.Length = 0;
S = SA[i];
2021-06-13 02:53:33 +00:00
if (S == "")
continue;
z = 0;
2021-06-13 02:53:33 +00:00
while( true)
{
j = InStr(S,"#{");
2021-06-13 02:53:33 +00:00
if (j > 0)
{
Lines[i].Text.Length = z+1;
Lines[i].Text[z].S = Left(S,j);
Lines[i].Text[z].C = C;
Lines[i].Text[z].TextType = TextType;
++z;
}
2021-06-13 02:53:33 +00:00
else if (j == -1)
break;
S = Mid(S,j+2);
2021-06-13 02:53:33 +00:00
if (Left(S,4) == "DEF}")
{
C.A = 0;
S = Mid(S,4);
TextType = TEXT_FIELD_NONE;
}
2021-06-13 02:53:33 +00:00
else if (Left(S,4) == "HSV}")
{
C.A = 0;
S = Mid(S,4);
TextType = TEXT_FIELD_HSV;
}
2021-06-13 02:53:33 +00:00
else if (Left(S,6) == "FLASH}")
{
C.A = 0;
S = Mid(S,6);
TextType = TEXT_FIELD_FLASH;
}
2021-06-13 02:53:33 +00:00
else if (Left(S,7) == "CFLASH=")
{
C.A = 0;
S = Mid(S,7);
TextType = TEXT_FIELD_FLASH;
C.R = GrabHexValue(Mid(S,0,2));
C.G = GrabHexValue(Mid(S,2,2));
C.B = GrabHexValue(Mid(S,4,2));
S = Mid(S,7);
C.A = 255;
}
else
{
C.R = GrabHexValue(Mid(S,0,2));
C.G = GrabHexValue(Mid(S,2,2));
C.B = GrabHexValue(Mid(S,4,2));
S = Mid(S,7);
C.A = 255;
TextType = TEXT_FIELD_NONE;
}
}
Lines[i].Text.Length = z+1;
Lines[i].Text[z].S = S;
Lines[i].Text[z].C = C;
Lines[i].Text[z].TextType = TextType;
}
OrgLines = Lines; // Create a backup.
2020-01-10 13:14:11 +00:00
}
2021-06-13 02:53:33 +00:00
final function byte GrabHexValue( string S)
2020-01-10 13:14:11 +00:00
{
local byte n;
2021-06-13 02:53:33 +00:00
n = (HexToInt(Asc(Left(S,1))) << 4) | HexToInt(Asc(Right(S,1)));
S = Mid(S,2);
return n;
2020-01-10 13:14:11 +00:00
}
2021-06-13 02:53:33 +00:00
final function byte HexToInt( byte n)
2020-01-10 13:14:11 +00:00
{
2021-06-13 02:53:33 +00:00
if (n >= 48 && n <= 57 ) // '0' - '9'
return n-48;
2021-06-13 02:53:33 +00:00
if (n >= 65 && n <= 70 ) // 'A' - 'F'
return n-55; // 'A' - 10
2021-06-13 02:53:33 +00:00
if (n >= 97 && n <= 102 ) // 'a' - 'f'
return n-87; // 'a' - 10
return 0;
2020-01-10 13:14:11 +00:00
}
function InitSize()
{
local byte i;
local float XS;
local int MaxScrollRange;
2021-06-13 02:53:33 +00:00
if (Canvas == None)
return;
OldSize[0] = CompPos[2];
OldSize[1] = CompPos[3];
2021-06-13 02:53:33 +00:00
if (!bTextParsed)
{
ParseTextLines();
bTextParsed = true;
}
else Lines = OrgLines;
InitFont = Owner.CurrentStyle.PickFont(InitFontScale);
InitFontScale *= FontScale;
// Compute Y-offsets of each line.
Canvas.Font = InitFont;
Canvas.TextSize("ABC",XS,TextHeight,InitFontScale,InitFontScale);
ParseLines(CompPos[2] / InitFontScale);
MaxHeight = (Lines.Length * TextHeight);
2021-06-13 02:53:33 +00:00
bShowScrollbar = (MaxHeight >= CompPos[3]);
bClickable = bShowScrollbar;
bCanFocus = bShowScrollbar;
2021-06-13 02:53:33 +00:00
if (bShowScrollbar)
{
2021-06-13 02:53:33 +00:00
if (ScrollBar == None)
{
ScrollBar = new(Self) class'KFGUI_ScrollBarV';
ScrollBar.SetPosition(0.9,0.0,0.1,1.0);
ScrollBar.Owner = Owner;
ScrollBar.ParentComponent = Self;
ScrollBar.InitMenu();
ScrollBar.SetVisibility(bVisible);
}
// Compute scrollbar size and X-position.
2021-06-13 02:53:33 +00:00
for (i=0; i < 4; ++i)
ScrollBar.InputPos[i] = CompPos[i];
ScrollWidth = ScrollBar.GetWidth();
ScrollBar.XPosition = 1.f - ScrollWidth;
ScrollWidth *= CompPos[2];
ScrollBar.ComputeCoords();
// Recompute line sizes because we now have a scrollbar.
Lines = OrgLines;
ParseLines((CompPos[2]-ScrollWidth) / InitFontScale);
2021-06-13 02:53:33 +00:00
if (Components.Find(ScrollBar) == -1)
Components.AddItem(ScrollBar);
MaxHeight = (Lines.Length * TextHeight);
MaxScrollRange = Max(((MaxHeight-CompPos[3])/TextHeight),1);
ScrollBar.UpdateScrollSize(bNoReset ? MaxScrollRange : 0,MaxScrollRange,1,1);
}
2021-06-13 02:53:33 +00:00
else if (ScrollBar != None)
Components.RemoveItem(ScrollBar);
2020-01-10 13:14:11 +00:00
}
// Parse textlines to see if they're too long.
2021-06-13 02:53:33 +00:00
final function ParseLines( float ClipX)
2020-01-10 13:14:11 +00:00
{
local float X,XS,YS;
local int i,j,z,n;
2021-06-13 02:53:33 +00:00
for (i=0; i < Lines.Length; ++i)
{
Lines[i].Y = i*TextHeight;
X = 0.f;
2021-06-13 02:53:33 +00:00
for (j=0; j < Lines[i].Text.Length; ++j)
{
Lines[i].Text[j].X = (X*InitFontScale);
Canvas.TextSize(Lines[i].Text[j].S,XS,YS);
2021-06-13 02:53:33 +00:00
if ((X+XS) > ClipX)
{
z = FindSplitPoint(Lines[i].Text[j].S,X,ClipX);
// Add new line.
Lines.Insert(i+1,1);
// Append the remaining lines there.
2021-06-13 02:53:33 +00:00
for (n=j; n < Lines[i].Text.Length; ++n)
Lines[i+1].Text.AddItem(Lines[i].Text[n]);
// Split the string at wrapping point.
Lines[i+1].Text[0].S = Mid(Lines[i].Text[j].S,z);
// Remove whitespaces in front of the string.
Lines[i+1].Text[0].S = StripWhiteSpaces(Lines[i+1].Text[0].S);
// If empty, clean it up.
2021-06-13 02:53:33 +00:00
if (Lines[i+1].Text[0].S == "")
Lines[i+1].Text.Remove(0,1);
// End the current line at wrapping point.
Lines[i].Text[j].S = Left(Lines[i].Text[j].S,z);
Lines[i].Text.Length = j+1;
break;
}
X+=XS;
}
}
2020-01-10 13:14:11 +00:00
}
// Slow, find wrapped splitting point in text.
2021-06-13 02:53:33 +00:00
final function int FindSplitPoint( string S, float X, float ClipX)
2020-01-10 13:14:11 +00:00
{
local int i,l,PrevWord;
local float XL,YL;
local bool bWasWhite,bStartedZero;
2021-06-13 02:53:33 +00:00
bStartedZero = (X == 0.f);
Canvas.TextSize(Mid(S,0,1),XL,YL);
X += XL;
i = 1;
l = Len(S);
PrevWord = 0;
bWasWhite = true;
2021-06-13 02:53:33 +00:00
while( i < l)
{
2021-06-13 02:53:33 +00:00
if (Mid(S,i,1) == " ")
{
2021-06-13 02:53:33 +00:00
if (!bWasWhite)
{
PrevWord = i;
bWasWhite = true;
}
}
else
{
bWasWhite = false;
}
Canvas.TextSize(Mid(S,i,1),XL,YL);
X+=XL;
2021-06-13 02:53:33 +00:00
if (X > ClipX ) // Split here if possible.
{
2021-06-13 02:53:33 +00:00
if (PrevWord == 0)
return (bStartedZero ? i : 0); // No wrap.
return PrevWord;
}
++i;
}
return l;
2020-01-10 13:14:11 +00:00
}
2021-06-13 02:53:33 +00:00
final function string StripWhiteSpaces( string S)
2020-01-10 13:14:11 +00:00
{
2021-06-13 02:53:33 +00:00
if (Left(S,1) == " ")
S = Mid(S,1);
return S;
2020-01-10 13:14:11 +00:00
}
function byte GetCursorStyle()
{
return `PEN_WHITE;
2020-01-10 13:14:11 +00:00
}
function DrawMenu()
{
local int i,j,Index;
local float Y;
2021-06-13 02:53:33 +00:00
if (Text == "" || !bVisible)
return;
// Need to figure out best fitting font.
2021-06-13 02:53:33 +00:00
if (OldSize[0] != CompPos[2] || OldSize[1] != CompPos[3])
InitSize();
2021-06-13 02:53:33 +00:00
if (MaxHistory != 0)
{
2021-06-13 02:53:33 +00:00
if (Lines.Length >= MaxHistory)
{
Index = InStr(Text, LineSplitter);
2021-06-13 02:53:33 +00:00
if (Index == INDEX_NONE)
Lines.Remove(0, 1);
else SetText(Mid(Text, Index+Len(LineSplitter)));
}
}
Canvas.Font = InitFont;
2021-06-13 02:53:33 +00:00
if (bShowScrollbar)
{
Canvas.SetClip(CompPos[0]+(CompPos[2]-ScrollWidth),CompPos[1]+CompPos[3]);
i = ScrollBar.GetValue();
}
else i = 0;
2021-06-13 02:53:33 +00:00
if (i < Lines.Length)
{
Y = Lines[i].Y;
2021-06-13 02:53:33 +00:00
for (i=i; i < Lines.Length; ++i)
{
2021-06-13 02:53:33 +00:00
if (Lines[i].Text.Length != 0)
{
2021-06-13 02:53:33 +00:00
if ((Lines[i].Y-Y+TextHeight) >= CompPos[3])
break;
2021-06-13 02:53:33 +00:00
for (j=0; j < Lines[i].Text.Length; ++j)
{
DrawTextField(Lines[i].Text[j].S, i, Lines[i].Text[j].X, Lines[i].Y-Y, Lines[i].Text[j].C, Lines[i].Text[j].TextType);
}
}
}
}
2020-01-10 13:14:11 +00:00
}
function DrawTextField(string S, int Index, float X, float Y, optional Color C, optional ETextFieldStyles TextStyle)
{
local float TempSize;
local int FadeAlpha;
local Color MainColor;
MainColor = C;
2021-06-13 02:53:33 +00:00
if (MainColor.A == 0)
MainColor = TextColor;
Canvas.DrawColor = GetColorFromStyle(MainColor, TextStyle);
2021-06-13 02:53:33 +00:00
if (bFadeInOut)
{
TempSize = `TimeSinceEx(GetPlayer(), FadeStartTime);
2021-06-13 02:53:33 +00:00
if (TempSize > MessageDisplayTime)
{
return;
}
2021-06-13 02:53:33 +00:00
if (TempSize < MessageFadeInTime)
{
FadeAlpha = int((TempSize / MessageFadeInTime) * 255.0);
}
2021-06-13 02:53:33 +00:00
else if (TempSize > MessageDisplayTime - MessageFadeOutTime)
{
FadeAlpha = int((1.0 - ((TempSize - (MessageDisplayTime - MessageFadeOutTime)) / MessageFadeOutTime)) * 255.0);
}
else
{
FadeAlpha = 255;
}
Canvas.DrawColor.A = FadeAlpha;
}
2021-06-13 02:53:33 +00:00
if (bUseOutlineText)
{
Owner.CurrentStyle.DrawTextShadow(S,X,Y,OutlineSize,InitFontScale);
}
else
{
Canvas.SetPos(X,Y);
Canvas.DrawText(S,,InitFontScale,InitFontScale,TextFontInfo);
}
2020-01-10 13:14:11 +00:00
}
function Color GetColorFromStyle(Color MainColor, ETextFieldStyles TextStyle)
{
local float ColorHUE,Value;
local HSVColour HSV;
2021-06-13 02:53:33 +00:00
if (TextStyle == TEXT_FIELD_HSV)
{
ColorHUE = Abs(Sin(GetPlayer().WorldInfo.TimeSeconds * 0.9) * 335);
HSV.H = ColorHUE;
HSV.S = 1.f;
HSV.V = 1.f;
HSV.A = MainColor.A / 255;
return class'KFColorHelper'.static.LinearColorToColor(class'KFColorHelper'.static.HSVToRGB(HSV));
}
2021-06-13 02:53:33 +00:00
else if (TextStyle == TEXT_FIELD_FLASH)
{
Value = Abs(Sin(GetPlayer().WorldInfo.TimeSeconds * 0.9) * 1);
HSV = class'KFColorHelper'.static.RGBToHSV(ColorToLinearColor(MainColor));
HSV.V = Value;
return class'KFColorHelper'.static.LinearColorToColor(class'KFColorHelper'.static.HSVToRGB(HSV));
}
return MainColor;
2020-01-10 13:14:11 +00:00
}
function bool CaptureMouse()
{
return (bShowScrollbar ? Super.CaptureMouse() : false); // Nope.
2020-01-10 13:14:11 +00:00
}
2021-06-13 02:53:33 +00:00
function ScrollMouseWheel( bool bUp)
2020-01-10 13:14:11 +00:00
{
2021-06-13 02:53:33 +00:00
if (bShowScrollbar)
ScrollBar.ScrollMouseWheel(bUp);
2020-01-10 13:14:11 +00:00
}
function SetVisibility(bool Visible)
{
Super.SetVisibility(Visible);
2021-06-13 02:53:33 +00:00
if (ScrollBar != None)
{
ScrollBar.SetVisibility(Visible);
}
2020-01-10 13:14:11 +00:00
}
defaultproperties
{
bNoReset=false
LineSplitter="|"
FontScale=1
MaxHistory=0
OutlineSize=1
Text="TextField"
TextColor=(R=255,G=255,B=255,A=255)
TextFontInfo=(bClipText=true,bEnableShadow=true)
bCanFocus=false
bClickable=false
bUseOutlineText=false
2020-01-10 13:14:11 +00:00
}