JacobTech 2dee38084e Categories And Scissor
The scissor code should now properly cut all controls from going past the parent.
2024-08-27 10:55:36 -04:00

741 lines
22 KiB
C#

using System.Diagnostics;
using System.Text;
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using GraphicsManager.Structs;
using Luski.Enums;
using Luski.net.Structures.Public;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common.Input;
namespace Luski.GUI.MainScreen.UI.LuskiControls;
public class LuskiLabel : LabelBase
{
public LuskiLabel() : this(Globals.DefaultFont) { }
public LuskiLabel(FontInteraction fi) : base(fi) { }
public Color4 DefaultColor { get; set; } = Color4.White;
public override void LoadToParent(IParent window, IWindow win)
{
if (Loaded) return;
if (Shader is null) Shader = Globals.GradientShader[win.Context];
base.LoadToParent(window, win);
}
protected virtual (Color4,Color4) getGradcols(int Start, int charter, int End, int StartLine, int Line, int EndLine, GradType GT, Color4[] Colors)
{
Vector2i cl = GetCharLocation(charter);
Vector2i cs = GetSizeOfChar(charter);
Vector2i cls = GetCharLocation(Start);
Vector2i cle = GetCharLocation(End);
Vector2i cse = GetSizeOfChar(End);
if (GT == GradType.Line && StartLine != EndLine)
{
for (int i = StartLine; i < EndLine; i++)
{
Vector2i dis = new(MaxLineSizes[i].Item1.X, 0);
if (i == StartLine) dis -= new Vector2i(cls.X, 0);
cle += dis;
if (i < Line) cl += dis;
}
}
else if (GT == GradType.Block && StartLine != EndLine)
{
cls = new(0, cl.Y);
int longest = MaxLineSizes[StartLine].Item1.X;
for (int i = StartLine+1; i <= EndLine; i++)
{
if (MaxLineSizes[i].Item1.X > longest) longest = MaxLineSizes[i].Item1.X;
}
cse = new(0);
cle = new(longest, cle.X);
}
return new(getGradcol(cls.X, cl.X, cle.X + cse.X, Colors), getGradcol(cls.X, cl.X + cs.X, cle.X + cse.X, Colors));
}
protected virtual Color4 getGradcol(int Start, int pos, int End, Color4[] Colors)
{
pos -= Start;
End -= Start;
float travel = (float)End/(Colors.Length - 1);
int i = 1;
while (travel * i < pos)
{
i++;
}
i--;
float t = Math.Clamp((pos-(travel*i))/travel, 0, 1);
Color4 LeftColor, RightColor;
try
{
LeftColor = Colors[i];
RightColor = Colors[i + 1];
}
catch (Exception e)
{
LeftColor = Color4.DarkRed;
RightColor = Color4.DarkRed;
}
float r = LeftColor.R + (RightColor.R - LeftColor.R) * t;
float g = LeftColor.G + (RightColor.G - LeftColor.G) * t;
float b = LeftColor.B + (RightColor.B - LeftColor.B) * t;
float a = LeftColor.A + (RightColor.A - LeftColor.A) * t;
return new Color4(r, g, b, a);
}
List<Tuple<TextCode, int, int, object?>> Commands = new();
public string PlainText { get; protected set; } = string.Empty;
private List<(Vector2i, FontInteraction)> MaxLineSizes = new();
public override string Text
{
get => base.Text;
set
{
if (value is null) value = string.Empty;
text = value;
text_Calculated = string.Empty;
PlainText = string.Empty;
MaxLineSizes.Clear();
float max_x = 0, lines = 1, char_x = 0F;
int len = Text.Length;
bool use_slash = true, usebrac = true;
List<int> Rainbow_End = new();
List<int> Gradient_End = new();
List<int> Color_End = new();
List<int> Font_Starts = new();
List<int> Link_Starts = new();
Commands.Clear();
List<(GradType, int)> RainGrad = new();
List<(Color4[], GradType, int)> Grad = new();
List<Color4> ccccc = new();
List<bool> Itilacs = new();
List<FontSize> Fonts = new();
List<uint> Sizes = new();
List<string> Links = new();
FontInteraction Current = Font;
FontInteraction? Largest = null;
int LastFontEnd = 0;
StringBuilder sb = new();
uint lh = 0;
float lw = 0;
uint max_lh = 0;
for (int i = 0; i < len; i++)
{
char c;
if (PasswordChar is null)
c = Text[i];
else
c = PasswordChar.Value;
bool n = (c == '\n');
if (Text[i] == '\\' && use_slash)
{
if (i + 1 < len)
{
char tm = Text[i + 1];
if (tm == '\\')
{
use_slash = false;
continue;
}
if (tm == '[')
{
usebrac = false;
continue;
}
}
}
try
{
if (usebrac && Text[i] == '[')
{
int brack = Text.IndexOf(']', i);
string com = Text[(i + 1)..(brack )].Replace("\" ", "\"");
while (com.Contains(" "))
{
com = com.Replace(" ", " ");
}
string[] args = com.Split('=', '"', ' ');
FontInteraction tmp;
if (args[0][0] != '/')
{
switch (args[0])
{
case "rainbow":
Rainbow_End.Add(sb.Length);
GradType rgt = GradType.Line;
for (int j = 1; j < args.Length-2; j+=3)
{
switch (args[j])
{
case "type":
rgt = (GradType)byte.Parse(args[j + 2]);
break;
}
}
RainGrad.Add(new(rgt, (int)lines-1));
i = brack;
continue;
case "gradient":
List<Color> cols = new();
Gradient_End.Add(sb.Length);
GradType gt = GradType.Line;
for (int j = 1; j < args.Length-2; j+=3)
{
Console.WriteLine(args[j]);
switch (args[j])
{
case "colors":
for (int w = 0; w < args[j+2].Length - 7; w+=8)
{
cols.Add(new(args[j+2][w..(w+8)]));
}
break;
case "type":
gt = (GradType)byte.Parse(args[j + 2]);
break;
}
}
Grad.Add(new(cols.ToArray().ToColor4Array(), gt, (int)lines-1));
i = brack;
continue;
case "color":
i = brack;
Color_End.Add(sb.Length);
Color col = new(args[2].Replace("#", ""));
ccccc.Add(col.ToColor4());
i = brack;
continue;
case "fontsize":
FontSize fs = (FontSize)int.Parse(args[2]);
tmp = Current.Clone();
tmp.FontSize = fs;
if (Fonts.Count != 0 || Itilacs.Count != 0 || Sizes.Count != 0)
{
int pos = Font_Starts.Count - 1;
int last_Start = Font_Starts[pos];
int end = sb.Length - 1;
if (end != -1 && last_Start != end)
Commands.Add(new(TextCode.Font, last_Start, end, Current));
Font_Starts.RemoveAt(pos);
}
Fonts.Add(fs);
Font_Starts.Add(sb.Length);
Current = tmp;
i = brack;
continue;
case "px":
uint ph = uint.Parse(args[2]);
tmp = Current.Clone();
tmp.PixelHeight = ph;
if (Fonts.Count != 0 || Itilacs.Count != 0 || Sizes.Count != 0)
{
int pos = Font_Starts.Count - 1;
int last_Start = Font_Starts[pos];
int end = sb.Length - 1;
if (end != -1 && last_Start != end)
Commands.Add(new(TextCode.Font, last_Start, end, Current));
Font_Starts.RemoveAt(pos);
}
i = brack;
Sizes.Add(ph);
Font_Starts.Add(sb.Length);
Current = tmp;
i = brack;
continue;
case "url":
Link_Starts.Add(i);
Links.Add(args[2]);
i = brack;
continue;
case "i":
tmp = Current.Clone();
tmp.Italic = true;
if (Fonts.Count != 0 || Itilacs.Count != 0 || Sizes.Count != 0)
{
int pos = Font_Starts.Count - 1;
int last_Start = Font_Starts[pos];
int end = sb.Length - 1;
if (end != -1 && last_Start != end)
Commands.Add(new(TextCode.Font, last_Start, end, Current));
Font_Starts.RemoveAt(pos);
}
Itilacs.Add(true);
Font_Starts.Add(sb.Length);
Current = tmp;
i = brack;
continue;
}
}
else
{
if (com == "/rainbow")
{
if (Rainbow_End.Count == 0)
{
i = brack;
continue;
}
(GradType, int) cc = RainGrad[RainGrad.Count - 1];
Commands.Add(new(TextCode.Rainbow, Rainbow_End[Rainbow_End.Count-1], sb.Length-1, new Tuple<GradType, int, int>(cc.Item1, cc.Item2, (int)lines-1)));
Rainbow_End.RemoveAt(Rainbow_End.Count-1);
i = brack;
continue;
}
if (com == "/gradient")
{
if (Gradient_End.Count == 0)
{
i = brack;
continue;
}
var cc = Grad[Grad.Count - 1];
Commands.Add(new(TextCode.Gradient, Gradient_End[Gradient_End.Count-1], sb.Length-1, new Tuple<Color4[], GradType, int, int>(cc.Item1, cc.Item2, cc.Item3, (int)lines-1)));
Gradient_End.RemoveAt(Gradient_End.Count-1);
Grad.RemoveAt(Grad.Count-1);
i = brack;
continue;
}
if (com == "/color")
{
if (ccccc.Count == 0)
{
i = brack;
continue;
}
Commands.Add(new(TextCode.Color, Color_End[Color_End.Count-1], sb.Length-1, ccccc[ccccc.Count-1]));
Color_End.RemoveAt(Color_End.Count-1);
ccccc.RemoveAt(ccccc.Count-1);
i = brack;
continue;
}
if (com == "/url")
{
Commands.Add(new(TextCode.url, Link_Starts[Link_Starts.Count-1], sb.Length-1, Links[Links.Count-1]));
Link_Starts.RemoveAt(Link_Starts.Count-1);
Links.RemoveAt(Links.Count-1);
i = brack;
continue;
}
if (com == "/fontsize" || com == "/i" || com == "/px")
{
int pos = Font_Starts.Count - 1;
if (pos == -1)
{
i = brack;
continue;
}
if (pos >= 0)
{
int last_Start = Font_Starts[pos];
Font_Starts.RemoveAt(pos);
if (LastFontEnd != sb.Length - 1)
{
LastFontEnd = sb.Length - 1;
Commands.Add(new(TextCode.Font, last_Start, LastFontEnd, Current));
}
}
}
if (com == "/fontsize")
{
Fonts.RemoveAt(Fonts.Count - 1);
if (Fonts.Count != 0)
{
Current = Current.Clone();
Current.FontSize = Fonts[Fonts.Count - 1];
Font_Starts.Add(sb.Length-1);
}
else
{
if (Sizes.Count == 0 && Itilacs.Count == 0)
Current = Font;
else
{
Current = Current.Clone();
Current.FontSize = Font.FontSize;
Font_Starts.Add(sb.Length-1);
}
}
i = brack;
continue;
}
if (com == "/i")
{
Itilacs.RemoveAt(Itilacs.Count - 1);
if (Itilacs.Count != 0)
{
Current = Current.Clone();
Current.Italic = Itilacs[Itilacs.Count - 1];
Font_Starts.Add(sb.Length-1);
}
else
{
if (Sizes.Count == 0 && Fonts.Count == 0)
Current = Font;
else
{
Current = Current.Clone();
Current.Italic = Font.Italic;
Font_Starts.Add(sb.Length-1);
}
}
i = brack;
continue;
}
if (com == "/px")
{
if (Sizes.Count == 0)
{
i = brack;
continue;
}
Sizes.RemoveAt(Sizes.Count - 1);
if (Sizes.Count != 0)
{
Current = Current.Clone();
Current.PixelHeight = Sizes[Sizes.Count - 1];
Font_Starts.Add(sb.Length-1);
}
else
{
if (Itilacs.Count == 0 && Fonts.Count == 0)
Current = Font;
else
{
Current = Current.Clone();
Current.PixelHeight = Font.PixelHeight;
Font_Starts.Add(sb.Length-1);
}
}
i = brack;
continue;
}
}
}
}
catch (Exception e)
{
Console.WriteLine(value);
Console.WriteLine(e);
//ignore
}
use_slash = true;
usebrac = true;
if (Largest is null || Current.PixelHeight > Largest.PixelHeight)
{
lh = Current.PixelHeight;
Largest = Current;
}
if (n)
{
lines++;
char_x = 0f;
max_lh += lh;
MaxLineSizes.Add(new(new((int)lw,(int)lh), Largest));
max_lh += (uint) ((double) lh * ((double) Largest.CurrentFonts[0].Face.Height / (double) Largest.CurrentFonts[0].Face.UnitsPerEM) * (double) this.Scale);
Largest = null;
lw = 0;
lh = 0;
sb.Append(c);
}
else
{
Character ch;
if (Window is not null) ch = Texture.GetChar(Font, c, Window.Context);
else ch = Texture.GetChar(Font, c);
if (MaxSize is not null && i > 0 && text[i-1] == ' ')
{
int addc = 0;
float word_char_x = char_x;
while (true)
{
if (addc + i == Text.Length) break;
if (text[addc + i] == ' ') break;
Character ch2;
if (Window is not null) ch2 = Texture.GetChar(Font, text[addc + i], Window.Context);
else ch2 = Texture.GetChar(Font, c);
word_char_x += (ch2.Advance >> 6) * Scale;
if (word_char_x > MaxSize.Value.X)
{
char_x = 0f;
lines++;
sb.Append('\n');
break;
}
addc++;
}
}
sb.Append(c);
float w = ch.Size.X * Scale;
float xrel = char_x + ch.Bearing.X * Scale;
char_x += (ch.Advance >> 6) * Scale;
if ((xrel + w) >= max_x) max_x = (xrel + w);
if ((xrel + w) >= lw) lw = (xrel + w);
}
}
MaxLineSizes.Add(new(new((int)lw,(int)lh), Largest));
max_lh += (uint) ((double) lh * ((double) Largest.CurrentFonts[0].Face.Height / (double) Largest.CurrentFonts[0].Face.UnitsPerEM) * (double) this.Scale);
Largest = null;
PlainText = sb.ToString();
text_Calculated = sb.ToString();
Commands.Sort((x, y) => x.Item2.CompareTo(y.Item2));
Size = new((int)max_x, (int)(max_lh) + (int)(lines * Font.ExtraLinePixels));
if (Loaded)
{
if (Window is not null && Window.CanControleUpdate)
{
if (!Window.Context.IsCurrent)
{
try
{
Window.Context.MakeCurrent();
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
if (Window.Context.IsCurrent)
{
Parent!.TryDraw();
}
}
}
}
}
public static Color4[] Rainbow = new[]
{
Color4.Red,
new(255,154,0,255),
new(208, 222, 33, 255),
new(79, 220, 74, 255),
new(63, 218, 216, 255),
new(47, 201, 226, 255),
new(28, 127, 238, 255),
new(95, 21, 242, 255),
new(186, 12, 248, 255),
new(251, 7, 217, 255)
};
public static Color4 LinkColor = Color4.Cyan;
private List<SubHitBox> Links = new();
public override void Draw(int x, int y, int sx, int sy, int sw, int sh)
{
if (Visible && Loaded)
{
if (!Window!.Context.IsCurrent) Window.Context.MakeCurrent();
Shader.Use();
GL.Enable(EnableCap.Blend);
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
GL.BlendFunc(0, BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
Shader.SetMatrixF4("projection", Window.WindowSizeMatrix);
GL.BindVertexArray(VAO);
float angle_rad = (float)Math.Atan2(DIR.Y, DIR.X);
Matrix4 rotateM = Matrix4.CreateRotationZ(angle_rad);
Matrix4 transOriginM = Matrix4.CreateTranslation(new Vector3(loc_.X + Parent!.IntToWindow(0), loc_.Y + (MaxLineSizes[0].Item1.Y * Scale) + Parent!.IntToWindow(0, true), 0f));
float char_x = 0.0f;
GL.PixelStore(PixelStoreParameter.UnpackAlignment, 1);
float hhh = 0;
int NextCommand = 0;
List<int> Active_Grads = new();
List<int> Active_Fonts = new();
List<Vector2i> Active_Links = new();
Dictionary<int, FontSize> Olds = new();
int line = 0;
int count = 0;
for (int i = 0; i < text_Calculated.Length; i++)
{
FontInteraction charfont = Font;
while (Commands.Count != 0 && NextCommand < Commands.Count && i == Commands[NextCommand].Item2)
{
switch (Commands[NextCommand].Item1)
{
case TextCode.Gradient or TextCode.Rainbow or TextCode.Color:
Active_Grads.Add(NextCommand);
break;
case TextCode.Font:
Active_Fonts.Add(NextCommand);
break;
case TextCode.url:
Active_Grads.Add(NextCommand);
Active_Links.Add(new((int)char_x, (int)hhh));
break;
}
NextCommand++;
}
if (Active_Fonts.Count != 0)
{
int g = Active_Fonts[Active_Fonts.Count - 1];
Tuple<TextCode, int, int ,object?> com = Commands[g];
if (com.Item1 == TextCode.Font)
{
charfont = (FontInteraction)com.Item4!;
}
if (com.Item3 <= i)
{
Active_Fonts.RemoveAt(Active_Fonts.Count-1);
}
}
if (Active_Grads.Count != 0)
{
Tuple<TextCode, int, int ,object?> com = Commands[Active_Grads[Active_Grads.Count - 1]];
(Color4, Color4) col;
if (com.Item1 == TextCode.Rainbow)
{
Tuple<GradType, int, int> item4 = (Tuple<GradType, int, int>)com.Item4!;
col = getGradcols(com.Item2, i, com.Item3, 0,line, item4.Item3, item4.Item1, Rainbow);
}
else if (com.Item1 == TextCode.Color)
{
col = new((Color4)com.Item4!, (Color4)com.Item4!);
}
else if (com.Item1 == TextCode.url)
{
col = new(LinkColor, LinkColor);
}
else
{
Tuple<Color4[], GradType, int, int> item4 = (Tuple<Color4[], GradType, int, int>)com.Item4!;
col = getGradcols(com.Item2, i, com.Item3, item4.Item3, line, item4.Item4, item4.Item2, item4.Item1);
}
GL.Uniform4(Shader.GetUniformLocation("textColor"), col.Item1);
GL.Uniform4(Shader.GetUniformLocation("rightColor"), col.Item2);
if (com.Item3 == i)
{
if (com.Item1 == TextCode.url)
{
int index = Active_Links.Count - 1;
Vector2i now = new((int)char_x, (int)hhh);
Vector2i lc = Active_Links[index];
Vector2i sz = new(now.X - Active_Links[Active_Links.Count - 1].X,
MaxLineSizes[line].Item1.Y);
if (Links.Count <= index || Links[index].Location != Active_Links[index] || Links[index].Size != sz)
{
if (Links.Count > count)Links.RemoveAt(count);
SubHitBox hb = new()
{
Location = lc,
Size = sz,
HoverMouse = MouseCursor.Hand
};
hb.Clicked += _ =>
{
try
{
if (OperatingSystem.IsWindows())
Process.Start((string)com.Item4!);
else if (OperatingSystem.IsLinux())
{
Process.Start("xdg-open", (string)com.Item4!);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
return Task.CompletedTask;
};
Links.Insert(count, hb);
SubHitBoxes.Add(hb);
count++;
}
Active_Links.RemoveAt(Active_Links.Count-1);
}
Active_Grads.RemoveAt(Active_Grads.Count-1);
}
}
else
{
GL.Uniform4(Shader.GetUniformLocation("textColor"), DefaultColor);
GL.Uniform4(Shader.GetUniformLocation("rightColor"), DefaultColor);
}
char c;
if (PasswordChar is null)
c = text_Calculated[i];
else
c = PasswordChar.Value;
bool n = (c == '\n');
if ((!_characters[Window!.Context].ContainsKey(charfont) || !_characters[Window!.Context][charfont].ContainsKey(c) ) && !n)
{
_ = Texture.TextureForChar(Window!.Context, charfont, c, Shader);
}
if (n)
{
hhh += ((float)MaxLineSizes[line].Item1.Y *
((float)MaxLineSizes[line].Item2.CurrentFonts[0].Face.Height /
(float)MaxLineSizes[line].Item2.CurrentFonts[0].Face.UnitsPerEM) * (float)this.Scale);
hhh += Font.ExtraLinePixels;
char_x = 0f;
line++;
}
else
{
if (!_characters[Window!.Context][charfont].ContainsKey(c)) continue;
Character ch = _characters[Window!.Context][charfont][c];
float w = ch.Size.X * Scale;
float h = ch.Size.Y * Scale;
float xrel = char_x + ch.Bearing.X * Scale;
float yrel = (ch.Size.Y - ch.Bearing.Y) * Scale;
yrel += hhh;
char_x += (ch.Advance >> 6) * Scale;
Matrix4 scaleM = Matrix4.CreateScale(new Vector3(w, h, 1.0f));
Matrix4 transRelM = Matrix4.CreateTranslation(new Vector3(xrel, yrel, 0.0f));
Matrix4 modelM = scaleM * transRelM * rotateM * transOriginM;
GL.UniformMatrix4(Shader.GetUniformLocation("model"), false, ref modelM);
ch.Texture.Use();
GL.DrawArrays(PrimitiveType.Triangles, 0, 6);
}
}
}
}
}