Luski/Luski/Globals.cs
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

634 lines
22 KiB
C#

using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using GraphicsManager;
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.Classes;
using Luski.Classes.ThemeSub;
using Luski.GUI;
using Luski.GUI.MainScreen.UI.LuskiControls;
using Luski.net;
using Luski.net.Enums;
using Luski.net.Interfaces;
using Luski.net.Structures.Public;
using Luski.Shared.PublicServers.V1.Enums;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common.Input;
using OpenTK.Windowing.Desktop;
namespace Luski;
public static class Globals
{
#pragma warning disable CS8618
public static List<Task<bool>> ServersLoading = new();
public static ServerList ServerList;
public static Dictionary<Window, List<IRenderObject>> AllowedBehindObjects = new();
public static ThemeStart Theme
{
get
{
return LuskiThemes.LuskiThemeList.Where(s => s.Name == Settings.Theme).First();
}
}
public static ServerThemeProperties GetTheme(this PublicServer ser)
{
IEnumerable<ServerTheme> l = Theme.ServerOverrides.Where(s => s.Address == ser.Domain);
ServerTheme[] serverThemes = l as ServerTheme[] ?? l.ToArray();
if (serverThemes.Any()) return serverThemes[0].Properties;
return Theme.GlobalServerTemplate;
}
private static List<ExperimentInfo> AddedExperiments = new();
private static List<ExperimentInfo> EnabledExperiments = new();
public static List<ExperimentJson> MissingExperiments = new();
private static Dictionary<ExperimentSelectorInfo, ExperimentInfo> ExperimentSelectorInfos = new();
public static IReadOnlyList<ExperimentInfo> Experiments => AddedExperiments.AsReadOnly();
private static int LastExpCount = 0;
public static Color4 DodgerBlue = new Color4(30, 144, 255, 255);
private static bool msc = true;
private static double mscale = -1;
public static double GetScale()
{
if (Settings.Scale is not null) return Settings.Scale.Value;
if (msc)
{
msc = false;
mscale = Monitors.GetMonitorFromWindow(ms).HorizontalScale;
}
return mscale;
}
public static int ScaleInt(this int i)
{
return (int)(GetScale() * i);
}
public static int ScaleInt(this double i)
{
return (int)(GetScale() * i);
}
public static double ScaleDouble(this int i)
{
return (GetScale() * i);
}
public static double ScaleDouble(this double i)
{
return (GetScale() * i);
}
public static uint ScaleFont(this uint i)
{
if (Globals.Settings.ScaleFonts) return (uint)(GetScale() * i);
return i;
}
public static void PrintParent(IParent par)
{
void PrintP(int index, IParent p, Vector3i l)
{
string sp = "";
for (int i = 0; i < index; i++)
{
sp += " ";
}
for (int i = 0; i < p.Controls.Length; i++)
{
if (p.Controls[i].IgnoreHover) continue;
Console.WriteLine(sp + p.Controls[i] + ": " + p.Controls[i].Location + " " + (p.Controls[i].Location + l) + " "+ p.Controls[i].Size);
if (p.Controls[i] is IParent pp) PrintP(index + 1, pp, l + pp.Position);
}
}
Console.WriteLine(par + ": " + par.Position + par.Size);
PrintP(1,par, par.Position);
}
public static void RegisterExperiment(ExperimentInfo exp)
{
IEnumerable<ExperimentJson> found = MissingExperiments.Where(e => e.Name == exp.Name);
ExperimentJson[] experimentInfos = found as ExperimentJson[] ?? found.ToArray();
if (experimentInfos.Length > 0)
{
MissingExperiments.Remove(experimentInfos[0]);
EnabledExperiments.Add(exp);
}
AddedExperiments.Add(exp);
foreach (ExperimentSelectorInfo esi in exp.Options)
{
ExperimentSelectorInfos.Add(esi, exp);
}
}
public static void Toggle(this ExperimentSelectorInfo exp)
{
if (!ExperimentSelectorInfos.TryGetValue(exp, out ExperimentInfo EI)) return;
if (Settings.Experiments.Any(e => e.Name == EI.Name))
{
ExperimentJson ej = Settings.Experiments.Where(e => e.Name == EI.Name).First();
if (EI.Selected == EI.Options.IndexOf(exp))
{
Settings.Experiments.Remove(ej);
EnabledExperiments.Remove(EI);
EI.Selected = null;
LastExpCount--;
exp.SendTog(false);
}
else
{
EI.Options[EI.Selected!.Value].SendTog(false);
ej.Selected = EI.Options.IndexOf(exp);
EI.Selected = ej.Selected;
exp.SendTog(true);
}
}
else
{
LastExpCount++;
ExperimentJson ej = new()
{
Name = EI.Name,
Selected = EI.Options.IndexOf(exp)
};
Settings.Experiments.Add(ej);
EI.Selected = ej.Selected;
if (!EnabledExperiments.Contains(EI)) EnabledExperiments.Add(EI);
exp.SendTog(true);
}
Settings.SaveSettings(Path.Combine(Globals.LuskiPath, "Settings.json"), SettingsContext.Default.Settings);
}
public static bool IsEnabled(this ExperimentSelectorInfo exp)
{
if (!ExperimentSelectorInfos.TryGetValue(exp, out ExperimentInfo EI)) return false;
if (LastExpCount != Settings.Experiments.Count)
{
//rescan
foreach (ExperimentJson experiment in Settings.Experiments)
{
IEnumerable<ExperimentInfo> found = AddedExperiments.Where(e => e.Name == experiment.Name);
ExperimentInfo[] experimentInfos = found as ExperimentInfo[] ?? found.ToArray();
if (experimentInfos.Count() > 0)
{
if (!EnabledExperiments.Contains(experimentInfos[0])) EnabledExperiments.Add(experimentInfos[0]);
experimentInfos[0].Selected = experiment.Selected;
}
else
{
MissingExperiments.Add(experiment);
}
}
LastExpCount = Settings.Experiments.Count;
}
//detect
return EnabledExperiments.Contains(EI) && EI.Selected.HasValue && EI.Options.Count > EI.Selected &&
EI.Options[EI.Selected.Value] == exp;
}
private static Dictionary<TextureManager, Dictionary<string, Texture>> TextureResources = new();
public static Texture GetTextureResource(this TextureManager tm, string File)
{
try
{
if (!TextureResources.ContainsKey(tm)) TextureResources.Add(tm, new());
if (TextureResources[tm].TryGetValue(File, out Texture? t)) return t;
t = tm.AddTexture(GetResource($"Textures.{File}"));
TextureResources[tm].Add(File,t);
return t;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public static Stream GetResource(string File)
{
return Tools.GetResourceStream(Assembly.GetExecutingAssembly(),
$"Luski.Resources.{File}");
}
public static void AddBehindObject(this Window w, IRenderObject obj)
{
if (!AllowedBehindObjects.ContainsKey(w)) AllowedBehindObjects.Add(w, new());
if (AllowedBehindObjects[w].Count > 0)
{
obj.AllowHoverFromBehind = AllowedBehindObjects[w][0].AllowHoverFromBehind;
}
w.Controls.Add(obj);
AllowedBehindObjects[w].Add(obj);
}
public static void ToggleBehindObjects(this Window w)
{
if (!AllowedBehindObjects.ContainsKey(w)) AllowedBehindObjects.Add(w, new());
if (AllowedBehindObjects[w].Count > 0)
{
bool new_val = !AllowedBehindObjects[w][0].AllowHoverFromBehind;
foreach (IRenderObject v in AllowedBehindObjects[w])
{
v.AllowHoverFromBehind = new_val;
}
}
}
public static void RemoveBehindObject(this Window w, IRenderObject obj, bool purge = true)
{
if (!AllowedBehindObjects.ContainsKey(w)) AllowedBehindObjects.Add(w, new());
AllowedBehindObjects[w].Remove(obj);
w.Controls.Remove(obj, purge);
obj.Clean();
obj = null!;
}
public static bool Download { get; set; } = false;
public static API Luski { get; } = new();
public static MainScreenWindow ms;
public static UserControl AddBool(IParent parent, string Name, string description, bool s, Action<bool> a, List<Label>? List = null)
{
ToggleSwitch ts = new()
{
Value = s,
Anchor = ObjectAnchor.Top | ObjectAnchor.Right
};
UserControl tc = new()
{
BackgroundColor = new(0,0,0,0)
};
Label l, ll;
int space = 5.ScaleInt();
tc.Controls.Add(ll =new Label(Globals.DefaultFont)
{
Location = new(0, space + space, 0),
Text = Name
});
tc.Controls.Add(l =new Label(Globals.DefaultFont)
{
Location = new(ll.Location.X, ll.Size.Y + space, 0),
Color = Color4.Gray,
MaxSize = parent.Size,
Text = description
});
if (List is not null) List.Add(l);
tc.Size = l.Size;
tc.Controls.Add(ts);
ts.Location = new(parent.Size.X - ts.Size.X - 5.ScaleInt(), ll.Location.Y, 0);
Rectangle TempLine = new()
{
Location = new(0, l.Location.Y + l.Size.Y + space, 0),
BackgroundColor = Color4.White,
Anchor = ObjectAnchor.Left | ObjectAnchor.Right | ObjectAnchor.Top
};
l.Tag = TempLine;
TempLine.Size = new(parent.Size.X - space - space, 2.ScaleInt());
tc.SetSize(parent.Size.X, TempLine.Location.Y + TempLine.Size.Y);
TempLine.ForceDistanceUpdate(tc);
tc.Controls.Add(TempLine);
//ts.ForceDistanceUpdate(tc);
ts.ValueChanged += @switch =>
{
a.Invoke(@switch.Value);
return Task.CompletedTask;
};
tc.ForceDistanceUpdate(parent);
parent.Controls.Add(tc);
return tc;
}
public static void AddBool<TEnum>(IParent parent, Type t, TEnum e, bool s, Action<bool> a, List<Label>? List = null) where TEnum : Enum
{
MemberInfo? enumValueMemberInfo = GetMemberInfo(t, e);
object[] valueAttributes =
enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (valueAttributes.Length == 0) return;
string description = ((DescriptionAttribute)valueAttributes[0]).Description;
object[] namevalueAttributes =
enumValueMemberInfo.GetCustomAttributes(typeof(Luski.Shared.GlobalAttributes.DisplayNameAttribute), false);
if (namevalueAttributes.Length == 0) return;
string Name = ((Luski.Shared.GlobalAttributes.DisplayNameAttribute)namevalueAttributes[0]).DisplayName;
AddBool(parent, Name, description,s,a,List);
}
public static void AddBool(IParent parent, PropertyInfo t, bool s, Action<bool> a, List<Label>? List = null)
{
object[] valueAttributes =
t.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (valueAttributes.Length == 0) return;
string description = ((DescriptionAttribute)valueAttributes[0]).Description;
object[] namevalueAttributes =
t.GetCustomAttributes(typeof(Luski.Shared.GlobalAttributes.DisplayNameAttribute), false);
if (namevalueAttributes.Length == 0) return;
string Name = ((Luski.Shared.GlobalAttributes.DisplayNameAttribute)namevalueAttributes[0]).DisplayName;
AddBool(parent, Name, description,s,a,List);
}
public static TAttribute GetAttribute<TAttribute, TEnum>(Type t, TEnum e) where TAttribute : Attribute where TEnum : Enum
{
MemberInfo? enumValueMemberInfo = GetMemberInfo(t, e);
object[] valueAttributes =
enumValueMemberInfo!.GetCustomAttributes(typeof(TAttribute), false);
return (TAttribute)valueAttributes[0];
}
public static TAttribute GetAttribute<TAttribute, TEnum>(MemberInfo enumValueMemberInfo, TEnum e) where TAttribute : Attribute where TEnum : Enum
{
object[] valueAttributes =
enumValueMemberInfo.GetCustomAttributes(typeof(TAttribute), false);
return (TAttribute)valueAttributes[0];
}
public static MemberInfo? GetMemberInfo<TEnum>(Type t, TEnum e) where TEnum : Enum
{
MemberInfo[] memberInfos =
t.GetMember(e.ToString());
MemberInfo? enumValueMemberInfo = memberInfos.FirstOrDefault(m =>
m.DeclaringType == t);
return enumValueMemberInfo;
}
public static Color4 ToColor4(this Color col)
{
return new(col.R, col.G, col.B, col.A);
}
public static Color4[] ToColor4Array(this Color[] col)
{
List<Color4> cols = new();
foreach (Color c in col)
{
cols.Add(new(c.R, c.G, c.B, c.A));
}
return cols.ToArray();
}
public static string ToDB(this Color[] col)
{
StringBuilder sb = new();
foreach (Color c in col)
{
sb.Append(Convert.ToHexString(new byte[] { c.R, c.G, c.B, c.A }));
}
return sb.ToString();
}
public static string ToDB(this Color4[] col)
{
StringBuilder sb = new();
foreach (Color4 c in col)
{
sb.Append(Convert.ToHexString(new byte[] { (byte)(c.R * byte.MaxValue), (byte)(c.G * byte.MaxValue), (byte)(c.B * byte.MaxValue), (byte)(c.A * byte.MaxValue) }));
}
return sb.ToString();
}
public static Color4 ToColor4(this Color? col)
{
return new(col!.Value.R, col.Value.G, col.Value.B, col.Value.A);
}
public static Color ToColor(this Color4 col)
{
return new((byte)(col.R*byte.MaxValue), (byte)(col.G*byte.MaxValue), (byte)(col.B*byte.MaxValue), (byte)(col.A*byte.MaxValue));
}
public static Texture GetAlphaCircle(this TextureManager tm)
{
return tm.GetTextureResource("Status.png");
}
public static Dictionary<long, Texture> UserTextureMap = new();
public static Dictionary<long, Texture> ProfileTextureMap = new();
public static readonly Dictionary<IGLFWGraphicsContext, Shader> GradientShader = new Dictionary<IGLFWGraphicsContext, Shader>();
public static ServerProfile? ServerProfile = null;
public static async Task<IRenderObject> MakeRct<TUser>(this ServerProfile Profile, TUser User, Vector2i Size) where TUser : SocketUser
{
Texture t = ms.TextureManager.GetTextureResource("Status.png");
if (Profile.PictureType == PictureType.none)
{
UserControl r = new(t);
r.Size = Size;
r.Shader = Rectangle.DefaultAlphaShader[ms.Context];
ColorType ct = await User.GetColorType();
Color[] c = await User.GetColors();
ColorType? cct = await Profile.GetColorType();
Color[]? cc = await Profile.GetColors();
if (cc is not null)
{
c = cc;
ct = cct!.Value;
}
r.BackgroundColor = new(25, 25, 25, 255);
if (ct == ColorType.Full)
{
Label l = new(DefaultFont)
{
Color = c[0].ToColor4()
};
l.Text = Profile.DisplayName[0].ToString();
Vector2i y = l.GetSizeOfChar(0),
yy = l.GetBearingOfChar(0);
l.Location = new((r.Size.X - l.Size.X)/2,
(int)(r.Size.Y - l.Font.PixelHeight + yy.Y - (r.Size.Y / 2) - (y.Y/2)),
0);
r.Controls.Add(l);
}
else
{
AdvancedGradientLabel l = new(DefaultFont)
{
Colors = c.ToColor4Array()
};
l.Text = Profile.DisplayName[0].ToString();
Vector2i y = l.GetSizeOfChar(0),
yy = l.GetBearingOfChar(0);
l.Location = new((r.Size.X - l.Size.X)/2,
(int)(r.Size.Y - l.Font.PixelHeight + yy.Y - (r.Size.Y / 2) - (y.Y/2)),
0);
r.Controls.Add(l);
}
return r;
}
else
{
Rectangle r = new(t);
r.Size = Size;
r.Shader = Rectangle.DefaultAlphaTextureShader[ms.Context];
r.Textures.Add(await Profile.GetIcon());
return r;
}
}
public static async Task<IRenderObject> MakeRct(this PublicServer Server, Vector2i Size)
{
Texture t = ms.TextureManager.GetTextureResource("rc.png");
if (Server.PictureType == PictureType.none)
{
UserControl r = new(t);
r.Size = Size;
r.Shader = Rectangle.DefaultAlphaShader[ms.Context];
r.BackgroundColor = new(25, 25, 25, 255);
Label l = new(DefaultFont)
{
Color = new(255,255,255,255),
IgnoreHover = true,
Text = Server.Name[0].ToString()
};
Vector2i y = l.GetSizeOfChar(0),
yy = l.GetBearingOfChar(0);
l.Location = new((r.Size.X - l.Size.X)/2,
(int)(r.Size.Y - l.Font.PixelHeight + yy.Y - (r.Size.Y / 2) - (y.Y/2)),
0);
r.Controls.Add(l);
return r;
}
else
{
Rectangle r = new(t);
r.Size = Size;
r.Shader = Rectangle.DefaultAlphaTextureShader[ms.Context];
r.Textures.Add(await Server.GetIcon());
return r;
}
}
private static async Task<Texture> GetIcon<TServer>(this TServer Server) where TServer : Server
{
Stream UserStream = await Server.GetAvatar(CancellationToken.None);
Texture t = Globals.ms.TextureManager.AddTexture(UserStream);
UserStream.Dispose();
t.Unit = TextureUnit.Texture1;
return t;
}
private static async Task<Texture> GetIcon(this ServerProfile User)
{
if (ProfileTextureMap.TryGetValue(User.ID, out Texture? t)) return t;
Stream UserStream = await User.GetAvatar(CancellationToken.None);
t = Globals.ms.TextureManager.AddTexture(UserStream);
ProfileTextureMap.Add(User.ID, t);
UserStream.Dispose();
t.Unit = TextureUnit.Texture1;
return t;
}
public static Settings Settings { get; set; }
public static FontFamily DefaultFontFamly { get; set; }
public static FontInteraction DefaultFont { get; set; }
public static FontInteraction ServerRoleFont { get; set; }
public static FontInteraction TopTimeFont { get; set; }
public static FontInteraction MessageFont { get; set; }
public static FontInteraction SmallTimeFont { get; set; }
public static PublicServer? GetCurentPublicServer()
{
if (Luski.LoadedServers.Count > 0)
return Luski.LoadedServers[0];
else
return null;
}
public static UpdaterSettings UpdaterSettings { get; set; }
public static Texture LuskiTexture;
public static TResult GetSettings<TResult>(string path, JsonTypeInfo<TResult> TypeInfo) where TResult : new()
{
TResult? @out;
if (!File.Exists(path))
{
@out = new();
File.WriteAllText(path, JsonSerializer.Serialize(@out, TypeInfo));
}
try
{
@out = JsonSerializer.Deserialize(File.ReadAllText(path), TypeInfo);
if (@out is null)
{
@out = new();
}
}
catch
{
@out = new();
}
File.WriteAllText(path, JsonSerializer.Serialize(@out, TypeInfo));
return @out;
}
public static TResult GetSettings<TResult>(Stream data, JsonTypeInfo<TResult> TypeInfo) where TResult : new()
{
TResult? @out;
try
{
@out = JsonSerializer.Deserialize(data, TypeInfo);
if (@out is null)
{
@out = new();
}
}
catch
{
@out = new();
}
return @out;
}
public static void SaveSettings<TResult>(this TResult json, string path, JsonTypeInfo<TResult> TypeInfo) where TResult : new()
{
File.WriteAllText(path, JsonSerializer.Serialize(json, TypeInfo));
}
public static string JT
{
get
{
string tmp = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "JacobTech");
if (OperatingSystem.IsLinux())
{
tmp = Path.Combine(Environment.GetEnvironmentVariable("HOME")!, ".config/");
tmp += "JacobTech";
}
if (!Directory.Exists(tmp)) Directory.CreateDirectory(tmp);
if (!Directory.Exists(Path.Combine(tmp, "Luski"))) Directory.CreateDirectory(Path.Combine(tmp, "Luski"));
return tmp;
}
}
public static WindowIcon Icon { get; set; }
public static string LuskiPath
{
get
{
return Path.Combine(JT, "Luski");
}
}
public static bool Empty(string? str)
{
return (string.IsNullOrEmpty(str) || string.IsNullOrWhiteSpace(str));
}
}
#pragma warning restore CS8618