diff --git a/.gitignore b/.gitignore index 57940fd..3e662a0 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,17 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser + Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + diff --git a/Luski.sln b/Luski.sln new file mode 100644 index 0000000..2944c7e --- /dev/null +++ b/Luski.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Luski", "Luski\Luski.csproj", "{02A83482-752B-4EB8-A952-51961D6EE684}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {02A83482-752B-4EB8-A952-51961D6EE684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02A83482-752B-4EB8-A952-51961D6EE684}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02A83482-752B-4EB8-A952-51961D6EE684}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02A83482-752B-4EB8-A952-51961D6EE684}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/Luski/Classes/ExperimentInfo.cs b/Luski/Classes/ExperimentInfo.cs new file mode 100644 index 0000000..7522679 --- /dev/null +++ b/Luski/Classes/ExperimentInfo.cs @@ -0,0 +1,9 @@ +namespace Luski.Classes; + +public class ExperimentInfo +{ + public string DisplayName { get; set; } = default!; + public string Name { get; set; } = default!; + public List Options { get; set; } = default!; + public int? Selected { get; set; } = null; +} \ No newline at end of file diff --git a/Luski/Classes/ExperimentJson.cs b/Luski/Classes/ExperimentJson.cs new file mode 100644 index 0000000..64f3af8 --- /dev/null +++ b/Luski/Classes/ExperimentJson.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; + +namespace Luski.Classes; + +public class ExperimentJson +{ + [JsonInclude] + [JsonPropertyName("name")] + public string Name { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("selected")] + public int Selected { get; set; } = default!; +} \ No newline at end of file diff --git a/Luski/Classes/ExperimentSelectorInfo.cs b/Luski/Classes/ExperimentSelectorInfo.cs new file mode 100644 index 0000000..40581ed --- /dev/null +++ b/Luski/Classes/ExperimentSelectorInfo.cs @@ -0,0 +1,14 @@ +namespace Luski.Classes; + +public class ExperimentSelectorInfo +{ + public event Func? EventToggled; + public string Name { get; set; } = default!; + public string Description { get; set; } = default!; + public bool RequiresRestart { get; set; } = false; + + internal void SendTog(bool b) + { + if (EventToggled is not null) EventToggled.Invoke(b); + } +} \ No newline at end of file diff --git a/Luski/Classes/LuskiThemes.cs b/Luski/Classes/LuskiThemes.cs new file mode 100644 index 0000000..e5a071e --- /dev/null +++ b/Luski/Classes/LuskiThemes.cs @@ -0,0 +1,48 @@ +using System.IO.Compression; + +namespace Luski.Classes; + +public static class LuskiThemes +{ + public static void LoadThemeFromDir(string dir) + { + ThemeStart ts = Globals.GetSettings(Path.Combine(dir, "theme.json"), ThemeStartContext.Default.ThemeStart); + LuskiThemes.LuskiThemeList.Add(ts); + } + + public static void LoadThemeFromZip(string ZIP) + { + ZipArchive zf = ZipFile.OpenRead(ZIP); + ZipArchiveEntry? json = zf.GetEntry("theme.json"); + ThemeStart ts = Globals.GetSettings(json?.Open()!, ThemeStartContext.Default.ThemeStart); + LuskiThemes.LuskiThemeList.Add(ts); + } + + + public readonly static ThemeStart Dark = new() + { + Name = "Dark", + Description = "A dark theme but still a bit lit." + }; + public static ThemeStart Amoled = new() + { + Name = "Amoled", + Description = "A dark theme that is truly dark." + }; + public static ThemeStart Light = new() + { + Name = "Light", + Description = "A light theme for the insane.", + GlobalServerTemplate = new() + { + SelectionColor = new("000000") + } + }; + + public static List LuskiThemeList = new() + { + Light, + Dark, + Amoled + }; +} \ No newline at end of file diff --git a/Luski/Classes/ServerInfo.cs b/Luski/Classes/ServerInfo.cs new file mode 100644 index 0000000..fc4f124 --- /dev/null +++ b/Luski/Classes/ServerInfo.cs @@ -0,0 +1,25 @@ +using System.Text.Json.Serialization; + +namespace Luski.Classes; + +public class ServerInfo +{ + [JsonInclude] + [JsonPropertyName("domain")] + public string Domain { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("version")] + public string Version { get; set; } = "v1"; + [JsonInclude] + [JsonPropertyName("is_main")] + public bool Main { get; set; } = false; + [JsonInclude] + [JsonPropertyName("is_secure")] + public bool Secure { get; set; } = true; + [JsonInclude] + [JsonPropertyName("pre_encrypt")] + public bool PreGenEncryption { get; set; } = true; + [JsonInclude] + [JsonPropertyName("show_server_messages")] + public bool ShowMessage { get; set; } = false; +} \ No newline at end of file diff --git a/Luski/Classes/ServerList.cs b/Luski/Classes/ServerList.cs new file mode 100644 index 0000000..1935945 --- /dev/null +++ b/Luski/Classes/ServerList.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +namespace Luski.Classes; + +public class ServerList +{ + [JsonInclude] + [JsonPropertyName("servers")] + public ServerInfo[] Servers { get; set; } = Array.Empty(); +} + +[JsonSerializable(typeof(ServerList))] +[JsonSourceGenerationOptions( + GenerationMode = JsonSourceGenerationMode.Default, + PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified, + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.Never)] +internal partial class ServerListContext : JsonSerializerContext +{ + +} \ No newline at end of file diff --git a/Luski/Classes/Settings.cs b/Luski/Classes/Settings.cs new file mode 100644 index 0000000..24d95b1 --- /dev/null +++ b/Luski/Classes/Settings.cs @@ -0,0 +1,129 @@ +using System.ComponentModel; +using System.Text.Json.Serialization; +using GraphicsManager.Objects; + +namespace Luski.Classes; + +public class Settings +{ + [JsonInclude] + [JsonPropertyName("scale")] + public double? Scale { get; set; } = null; + [JsonInclude] + [JsonPropertyName("perscrollpixels")] + public uint PerScrollPixels { get; set; } = 20; + [JsonInclude] + [JsonPropertyName("multithreadpercent")] + public uint MultiThreadPercent { get; set; } = 50; + [JsonInclude] + [JsonPropertyName("loadperchannel")] + public int LoadPerChannel { get; set; } = 50; + [JsonInclude] + [JsonPropertyName("theme")] + public string Theme { get; set; } = "Dark"; + [JsonInclude] + [JsonPropertyName("experiments")] + public List Experiments { get; set; } = Array.Empty().ToList(); + [JsonInclude] + [JsonPropertyName("default_display")] + public int Display { get; set; } = 0; + /// + /// Sets the log value for the console. Default value of -25 to enable all logs by default except for DrawFrames and InfoOpenGL even if new ones are added. + /// + [JsonInclude] + [Description("Console Logs")] + [JsonPropertyName("log")] + public ConsoleLog Logs + { + get + { + return _Logs; + } + set + { + _Logs = value; + if (Globals.ms is not null) + { + Globals.ms.LogFrames = (_Logs & ConsoleLog.DrawFrames) == ConsoleLog.DrawFrames; + Globals.ms.ShowMissingChar = (_Logs & ConsoleLog.ShowMissingChar) == ConsoleLog.ShowMissingChar; + } + } + } + + [JsonInclude] + [Description("Scale Fonts")] + [JsonPropertyName("scale_fonts")] + public bool ScaleFonts + { + get + { + return _ScaleFonts; + } + set + { + _ScaleFonts = value; + if (Globals.ms is not null) + { + Globals.DefaultFont.PixelHeight = Globals.Settings.DefaultFontPX.ScaleFont(); + Globals.MessageFont.PixelHeight = Globals.Settings.MessageFontPX.ScaleFont(); + Globals.TopTimeFont.PixelHeight = Globals.Settings.TopTimeFonttPX.ScaleFont(); + Globals.SmallTimeFont.PixelHeight = ((uint)11).ScaleFont(); + Label._characters[Globals.ms.Context][Globals.DefaultFont].Clear(); + Label._characters[Globals.ms.Context][Globals.MessageFont].Clear(); + Label._characters[Globals.ms.Context][Globals.TopTimeFont].Clear(); + Label._characters[Globals.ms.Context][Globals.SmallTimeFont].Clear(); + + Globals.ms.ForceUpdate(new(Globals.ms.ClientSize)); + Globals.ms.DrawFrame(); + } + } + } + [JsonInclude] + [JsonPropertyName("default_font_px")] + public uint DefaultFontPX { get; set; } = 20; + [JsonInclude] + [JsonPropertyName("top_time_font_px")] + public uint TopTimeFonttPX { get; set; } = 12; + [JsonInclude] + [JsonPropertyName("message_font_px")] + public uint MessageFontPX { get; set; } = 17; + [JsonInclude] + [JsonPropertyName("message_font_line_space_px")] + public uint MessageFontLineSpacePX { get; set; } = 5; + + [JsonInclude] + [Description("24 Hour Time")] + [JsonPropertyName("24hour_time")] + public bool DayTime + { + get + { + return _DayTime; + } + set + { + _DayTime = value; + if (DayTimeChanged is not null) DayTimeChanged.Invoke(); + } + } + + [JsonIgnore] + private bool _ScaleFonts = true; + [JsonIgnore] + private ConsoleLog _Logs = (ConsoleLog)(-25); + [JsonIgnore] + private bool _DayTime = false; + public event Func? DayTimeChanged; + +} + +[JsonSerializable(typeof(Settings))] +[JsonSourceGenerationOptions( + GenerationMode = JsonSourceGenerationMode.Default, + PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified, + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.Never)] +internal partial class SettingsContext : JsonSerializerContext +{ + +} \ No newline at end of file diff --git a/Luski/Classes/ThemeStart.cs b/Luski/Classes/ThemeStart.cs new file mode 100644 index 0000000..cf7db30 --- /dev/null +++ b/Luski/Classes/ThemeStart.cs @@ -0,0 +1,32 @@ +using System.Text.Json.Serialization; +using Luski.Classes.ThemeSub; + +namespace Luski.Classes; + +public class ThemeStart +{ + [JsonInclude] + [JsonPropertyName("name")] + public string Name { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("description")] + public string Description { get; set; } = default!; + [JsonInclude] + [JsonPropertyName("global_server_template")] + public ServerThemeProperties GlobalServerTemplate { get; set; } = new(); + [JsonInclude] + [JsonPropertyName("server_overrides")] + public ServerTheme[] ServerOverrides { get; set; } = Array.Empty(); +} + + +[JsonSerializable(typeof(ThemeStart))] +[JsonSourceGenerationOptions( + GenerationMode = JsonSourceGenerationMode.Default, + PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified, + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.Never)] +internal partial class ThemeStartContext : JsonSerializerContext +{ + +} \ No newline at end of file diff --git a/Luski/Classes/ThemeSub/ServerTheme.cs b/Luski/Classes/ThemeSub/ServerTheme.cs new file mode 100644 index 0000000..a1d175e --- /dev/null +++ b/Luski/Classes/ThemeSub/ServerTheme.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace Luski.Classes.ThemeSub; + +public class ServerTheme +{ + [JsonInclude] + [JsonPropertyName("address")] + public string Address { get; set; } = default!; + + [JsonInclude] + [JsonPropertyName("properties")] + public ServerThemeProperties Properties { get; set; } = new(); +} \ No newline at end of file diff --git a/Luski/Classes/ThemeSub/ServerThemeProperties.cs b/Luski/Classes/ThemeSub/ServerThemeProperties.cs new file mode 100644 index 0000000..69aa150 --- /dev/null +++ b/Luski/Classes/ThemeSub/ServerThemeProperties.cs @@ -0,0 +1,11 @@ +using System.Text.Json.Serialization; +using Luski.net.Structures.Public; + +namespace Luski.Classes.ThemeSub; + +public class ServerThemeProperties +{ + [JsonInclude] + [JsonPropertyName("selection_color")] + public Color SelectionColor { get; set; } = new("FFFFFF"); +} \ No newline at end of file diff --git a/Luski/Classes/UpdaterSettings.cs b/Luski/Classes/UpdaterSettings.cs new file mode 100644 index 0000000..63c467b --- /dev/null +++ b/Luski/Classes/UpdaterSettings.cs @@ -0,0 +1,46 @@ +using System.ComponentModel; +using System.Text.Json.Serialization; +using Luski.net.Enums; + +namespace Luski.Classes; + +public class UpdaterSettings +{ + [JsonInclude] + [Description("Self Contained")] + [JsonPropertyName("self_contained")] + public bool SelfContained { get; set; } = false; + + [JsonInclude] + [JsonPropertyName("updater")] + public string? Updater { get; set; } = null; + + [JsonInclude] + [JsonPropertyName("platform")] + public string Platform { get; set; } = "linux-x64"; + + [JsonInclude] + [Description("Auto Launch")] + [JsonPropertyName("auto_launch")] + public bool AutoLaunch { get; set; } = true; + [JsonInclude] + [Description("Auto Update")] + [JsonPropertyName("auto_update")] + public bool AutoUpdate { get; set; } = false; + + [JsonInclude] + [Description("Check For Updates")] + [JsonPropertyName("update_check")] + public bool AutoUpdateCheck { get; set; } = true; +} + +[JsonSerializable(typeof(UpdaterSettings))] +[JsonSourceGenerationOptions( + GenerationMode = JsonSourceGenerationMode.Default, + PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified, + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.Never)] +internal partial class UpdaterSettingsContext : JsonSerializerContext +{ + +} diff --git a/Luski/ConsoleLog.cs b/Luski/ConsoleLog.cs new file mode 100644 index 0000000..8ea1ed6 --- /dev/null +++ b/Luski/ConsoleLog.cs @@ -0,0 +1,21 @@ +using System.ComponentModel; + +namespace Luski; + +[Flags] +public enum ConsoleLog : long +{ + None = 0, + [Description("Show OpenGL Major Errors")] + BigErrosForOpenGL = 1, + [Description("Show OpenGL Medium Errors")] + MediumErrosForOpenGL = 2, + [Description("Show OpenGL Small Errors")] + LowErrosForOpenGL = 4, + [Description("Show OpenGL Info")] + InfoForOpenGL = 8, + [Description("Show Draw Frams")] + DrawFrames = 16, + [Description("Show Missing Charters")] + ShowMissingChar = 32 +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/Interfaces/IChannelAdder.cs b/Luski/GUI/MainScreen/Interfaces/IChannelAdder.cs new file mode 100644 index 0000000..68a3ea4 --- /dev/null +++ b/Luski/GUI/MainScreen/Interfaces/IChannelAdder.cs @@ -0,0 +1,12 @@ +using Luski.GUI.MainScreen.UI.PublicServers; +using Luski.net.Structures.Public; + +namespace Luski.GUI.MainScreen.Interfaces; + +public interface IChannelAdder +{ + public bool Extended { get; set; } + public SocketCategory CurrentCategory { get; } + public Task AddChannel(SocketChannel chan); + public Task AddCategory(SocketCategory Cat, DateTime? dt = null); +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/Interfaces/IChannelPick.cs b/Luski/GUI/MainScreen/Interfaces/IChannelPick.cs new file mode 100644 index 0000000..ff782af --- /dev/null +++ b/Luski/GUI/MainScreen/Interfaces/IChannelPick.cs @@ -0,0 +1,8 @@ +using Luski.net.Structures.Main; + +namespace Luski.GUI.MainScreen.Interfaces; + +public interface IChannelPick +{ + public MainSocketTextChannel Channel { get; } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/AccountButton.cs b/Luski/GUI/MainScreen/UI/AccountButton.cs new file mode 100644 index 0000000..1723302 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/AccountButton.cs @@ -0,0 +1,95 @@ +using GraphicsManager.Enums; +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using GraphicsManager.Objects.Core; +using Luski.Interfaces; +using OpenTK.Mathematics; + +namespace Luski.GUI.MainScreen.UI; + +public class AccountButton : UserControl +{ + private IServerOverlay SM; + public Label l; + public required Action OnPageLoad; + + public AccountButton(string Text, IServerOverlay SM) + :base(Globals.ms.TextureManager.GetTextureResource("RoundedRectangle.png")) + { + this.SM = SM; + base.Size = new(297.ScaleInt(), 40.ScaleInt()); + TextureDisplay = TextureDisplay.HorizontalCenter; + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context]; + l = new Label(Globals.DefaultFont) + { + Text = Text, + Color = Color4.Gray, + IgnoreHover = true, + }; + l.Location = new((base.Size.X / 2) - (l.Size.X / 2), + ((base.Size.Y - l.Size.Y) / 2) + , 0); + Controls.Add(l); + base.BackgroundColor = new(0, 0, 0, 0); + Clicked += OnClicked; + MouseEnter += o => + { + if (!Selected) + { + BackgroundColor = new(141, 151, 165, 30); + } + return Task.CompletedTask; + }; + MouseLeave += o => + { + if (!Selected) + { + BackgroundColor = new(0,0,0,0); + } + return Task.CompletedTask; + }; + } + + private async Task OnClicked(IRenderObject arg) + { + if (!Selected) await ToggleSelected(); + } + + public bool Selected { get; private set; } + + public async Task ToggleSelected() + { + try + { + Color4 bc = new(141,151,165,51), f= Color4.White; + if (Selected) + { + bc = new (0,0,0,0); + f = Color4.Gray; + } + + BlockDraw = true; + Selected = !Selected; + + if (SM.Selected is not null && SM.Selected != this) + { + await SM.Selected.ToggleSelected(); + } + BackgroundColor = bc; + l.Color = f; + if (Selected) + { + SM.Selected = this; + SM.page.Controls.Clear(); + OnPageLoad.Invoke(); + } + + BlockDraw = false; + TryDraw(); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/AddServerIcon.cs b/Luski/GUI/MainScreen/UI/AddServerIcon.cs new file mode 100644 index 0000000..4d93c1a --- /dev/null +++ b/Luski/GUI/MainScreen/UI/AddServerIcon.cs @@ -0,0 +1,23 @@ +using GraphicsManager.Objects; +using OpenTK.Mathematics; + +namespace Luski.GUI.MainScreen.UI; + +public class AddServerIcon : UserControl +{ + public Rectangle Button; + public AddServerIcon() + { + Button = new(Globals.ms.TextureManager.GetTextureResource("add.png")) + { + Location = new(18.ScaleInt(), 8.ScaleInt(), 0), + Size = new(32.ScaleInt()), + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context], + BackgroundColor = Color4.White, + IgnoreHover = true + }; + Controls.Add(Button); + base.BackgroundColor = new(26, 26, 26, 255); + base.Size = new(68.ScaleInt(), 48.ScaleInt()); + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/AddServerOverlay.cs b/Luski/GUI/MainScreen/UI/AddServerOverlay.cs new file mode 100644 index 0000000..05967f3 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/AddServerOverlay.cs @@ -0,0 +1,606 @@ +using GraphicsManager.Enums; +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using GraphicsManager.Objects.Core; +using Luski.Classes; +using Luski.GUI.MainScreen.UI.LuskiControls; +using Luski.Interfaces; +using Luski.net; +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; +using OpenTK.Windowing.GraphicsLibraryFramework; +using Rectangle = GraphicsManager.Objects.Rectangle; + +namespace Luski.GUI.MainScreen.UI; + +public class AddServerOverlay : UserControl, IServerOverlay +{ + private UserControl Form, btn; + private DropDown version; + + public AccountButton? Selected { get; set; } + public UserControl page { get; set; } + private TextBox? UserName, Password, DisplayName, tb; + + private Rectangle? rec; + + public AddServerOverlay() + { + base.Size = Globals.ms.ClientSize; + BackgroundColor = new(0, 0, 0, 130); + Anchor = ObjectAnchor.All; + + + + Form = new(Globals.ms.TextureManager.GetTextureResource("RoundedRectangle.png")) + { + Size = new(350.ScaleInt(), 347.ScaleInt()), + BackgroundColor = new(32,32,32,255), + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context], + TextureDisplay = TextureDisplay.Center + }; + Label t; + Form.Controls.Add(t=new Label(Globals.DefaultFont) { Scale = 1.6f, Text = "Add Server", Color = Globals.DodgerBlue }); + t.Location = new((Form.Size.X / 2) - (t.Size.X / 2), t.Location.Y, 0); + + #region Server Loc + Label? ll = new Label(Globals.DefaultFont) + { + Text = net.API.DefaultVersion, + Color = Color4.DarkGray, + IgnoreHover = true + }; + Vector2i s =new((int)(ll.Size.X * 1.6f),27.ScaleInt()); + ll = null; + + Rectangle line = new Rectangle() + { + Size = new Vector2i(1.ScaleInt()), + BackgroundColor = Globals.DodgerBlue + }; + + tb = new() + { + Location = new(10.ScaleInt(),50.ScaleInt(), 0), + Size = s, + WatermarkText = "Server Address", + TextLocation = TextLocation.LineCenter, + AllowMultiLine = false + }; + tb.Textures[0] = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + tb.KeyPress += args => + { + Texture t; + Texture good = Globals.ms.TextureManager.GetTextureResource("Textbox.png"); + if ((args.Key == Keys.Backspace || args.Key == Keys.Delete) && string.IsNullOrWhiteSpace(tb.Text)) + { + t = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + } + else + { + t = good; + } + + if (tb.Textures[0].handel != t.handel) + { + tb.Textures[0] = t; + if (t.handel == good.handel && + UserName!.Textures[0].handel == good.handel && + Password!.Textures[0].handel == good.handel && + (rec is null || rec.Textures.Count > 1) && + btn!.Textures[0].handel != good.handel && + tb.Textures[0].handel == good.handel) + { + if (Selected!.l.Text != "Login") + { + if (DisplayName!.Textures[0].handel == good.handel) btn.Textures[0] = good; + } + else btn.Textures[0] = good; + } + else if (t.handel != good.handel && + (UserName!.Textures[0].handel != good.handel || + Password!.Textures[0].handel != good.handel || + (rec is not null && rec!.Textures.Count == 1) || + btn!.Textures[0].handel == good.handel || + tb.Textures[0].handel != good.handel || + (DisplayName is not null && DisplayName.Textures[0].handel != good.handel))) + { + btn!.Textures[0] = t; + } + Globals.ms.TryDraw(); + } + + return Task.CompletedTask; + }; + tb.Size = new(Form.Size.X - tb.Location.X - tb.Location.X - tb.Location.X - s.X, tb.Size.Y); + + Form.Controls.Add(tb); + + version = new DropDown(Form.Textures[0], line) + { + DropDownParentOverride = Form, + Size = s, + BackgroundColor = new(255,20,20,255), + TextureDisplay = TextureDisplay.HorizontalCenter, + Shader = Form.Shader, + Location = new(tb.Location.X + tb.Size.X + tb.Location.X, tb.Location.Y, 0) + }; + foreach (string v in Globals.Luski.SupportedVersions) + { + VersionDropButton option = new VersionDropButton(s, v) + { + LoadDisplay = () => + { + try + { + Label ll2 = new Label(Globals.DefaultFont) + { + Text = v, + Color = Color4.DarkGray, + IgnoreHover = true, + + }; + ll2.Location = new((version.Size.X / 2) - (ll2.Size.X / 2), + ((version.Size.Y - ll2.Size.Y) / 2) + , 0); + version.Controls.Add(ll2); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + }; + version.AddOption(option); + if (v == net.API.DefaultVersion) + { + version.SetSelected(option); + } + } + + version.OpenStatusChanged += VersionOnOpenStatusChanged; + version.OptionSelected += VersionOnOptionSelected; + + + version.DropDownContainer.Textures.Add(Globals.ms.TextureManager.GetTextureResource("RoundedRectangleBottom.png")); + version.DropDownContainer.TextureDisplay = TextureDisplay.Center; + version.DropDownContainer.Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context]; + version.DropDownContainer.BackgroundColor = version.BackgroundColor; + version.OpenStatusChanged += b => + { + BlockDraw = true; + if (b) + { + version.Textures[0] = Globals.ms.TextureManager.GetTextureResource("RoundedRectangleTop.png"); + } + else + { + version.Textures[0] = Globals.ms.TextureManager.GetTextureResource("RoundedRectangle.png"); + } + + BlockDraw = false; + return Task.CompletedTask; + }; + + + #endregion + + #region Buttons + + AccountButton ca = new AccountButton("Create Account", this) + { + Location = new(tb.Location.X, tb.Location.Y + tb.Location.X + tb.Size.Y, 0), + OnPageLoad = () => + { + btn.Textures[0] = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + page!.Controls.Add(UserName = new() + { + Location = new(0, 10.ScaleInt(), 0), + Size = new(page.Size.X, 30.ScaleInt()), + WatermarkText = "Username", + TextLocation = TextLocation.LineCenter, + AllowMultiLine = false + }); + UserName.Textures[0] = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + UserName.KeyPress += args => + { + Texture t; + Texture good = Globals.ms.TextureManager.GetTextureResource("Textbox.png"); + if ((args.Key == Keys.Backspace || args.Key == Keys.Delete || args.Alt || args.Shift || args.Control || args.Key == Keys.Enter || args.Key == Keys.KeyPadEnter || args.Key== Keys.Space) && string.IsNullOrWhiteSpace(UserName.Text)) + { + t = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + } + else + { + t = good; + } + + if (UserName.Textures[0].handel != t.handel) + { + UserName.Textures[0] = t; + if (t.handel == good.handel && + Password!.Textures[0].handel == good.handel && + DisplayName!.Textures[0].handel == good.handel && + rec!.Textures.Count > 1 && + btn!.Textures[0].handel != good.handel && + tb.Textures[0].handel == good.handel) + { + btn.Textures[0] = good; + } + else if (t.handel != good.handel && + (Password!.Textures[0].handel != good.handel || + DisplayName!.Textures[0].handel != good.handel || + rec!.Textures.Count == 1 || + btn!.Textures[0].handel == good.handel || tb.Textures[0].handel != good.handel)) + { + btn!.Textures[0] = t; + } + Globals.ms.TryDraw(); + } + + return Task.CompletedTask; + }; + + page.Controls.Add(Password = new() + { + Location = new(0, UserName.Location.Y + UserName.Size.Y + UserName.Location.Y + UserName.Location.Y, 0), + Size = new(page.Size.X, UserName.Size.Y), + WatermarkText = "Password", + TextLocation = TextLocation.LineCenter, + AllowMultiLine = false, + PasswordChar = '●' + }); + Password.Textures[0] = UserName.Textures[0]; + Password.KeyPress += args => + { + Texture t; + Texture good = Globals.ms.TextureManager.GetTextureResource("Textbox.png"); + if ((args.Key == Keys.Backspace || args.Key == Keys.Delete || args.Alt || args.Shift || args.Control || args.Key == Keys.Enter || args.Key == Keys.KeyPadEnter || args.Key== Keys.Space) && string.IsNullOrWhiteSpace(Password.Text)) + { + t = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + } + else + { + t = good; + } + + if (Password.Textures[0].handel != t.handel) + { + Password.Textures[0] = t; + if (t.handel == good.handel && UserName!.Textures[0].handel == good.handel && DisplayName!.Textures[0].handel == good.handel && rec!.Textures.Count > 1 && btn!.Textures[0].handel != good.handel && tb.Textures[0].handel == good.handel) + { + btn.Textures[0] = good; + } + else if (t.handel != good.handel && (UserName!.Textures[0].handel != good.handel || DisplayName!.Textures[0].handel != good.handel || rec!.Textures.Count == 1 || btn!.Textures[0].handel == good.handel || tb.Textures[0].handel != good.handel)) + { + btn!.Textures[0] = t; + } + Globals.ms.TryDraw(); + } + + return Task.CompletedTask; + }; + + page.Controls.Add(rec = new(Globals.ms.TextureManager.GetAlphaCircle()) + { + Size = new(50.ScaleInt()), + BackgroundColor = Color4.Red, + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context], + IgnoreHover = false + }); + rec.Location = new(page.Size.X - rec.Size.X, page.Size.Y - rec.Size.Y, 0); + + page.Controls.Add(DisplayName = new() + { + Location = new(0, Password.Location.Y + Password.Size.Y + UserName.Location.Y + UserName.Location.Y, 0), + Size = new(page.Size.X- tb.Location.X - rec.Size.X, Password.Size.Y ), + WatermarkText = "Display Name", + TextLocation = TextLocation.LineCenter, + AllowMultiLine = false + }); + DisplayName.KeyPress += args => + { + Texture t; + Texture good = Globals.ms.TextureManager.GetTextureResource("Textbox.png"); + if ((args.Key == Keys.Backspace || args.Key == Keys.Delete || args.Alt || args.Shift || args.Control || args.Key == Keys.Enter || args.Key == Keys.KeyPadEnter || args.Key== Keys.Space) && + string.IsNullOrWhiteSpace(UserName.Text)) + { + t = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + } + else + { + t = good; + } + + if (DisplayName.Textures[0].handel != t.handel) + { + DisplayName.Textures[0] = t; + if (t.handel == good.handel && UserName!.Textures[0].handel == good.handel && + Password!.Textures[0].handel == good.handel && rec!.Textures.Count > 1 && + btn!.Textures[0].handel != good.handel && tb.Textures[0].handel == good.handel) + { + btn.Textures[0] = good; + } + else if (t.handel != good.handel && (UserName!.Textures[0].handel != good.handel || + Password!.Textures[0].handel != good.handel || + rec!.Textures.Count == 1 || + btn!.Textures[0].handel == good.handel || tb.Textures[0].handel != good.handel)) + { + btn!.Textures[0] = t; + } + + Globals.ms.TryDraw(); + } + return Task.CompletedTask; + }; + rec.FilesDroped += RecOnFilesDroped; + DisplayName.Textures[0] = UserName.Textures[0]; + rec.ForceDistanceUpdate(page); + Globals.ms.TryDraw(); + Globals.ms.ForceUpdate(new(Size)); + } + }; + ca.Size = new((Form.Size.X - tb.Location.X - tb.Location.X - (tb.Location.X / 2)) / 2, ca.Size.Y); + ca.l.Location = new((ca.Size.X - ca.l.Size.X) / 2, + ((ca.Size.Y - ca.l.Size.Y) / 2) + , 0); + ca.l.ForceDistanceUpdate(ca); + Form.Controls.Add(ca); + + AccountButton lo = new AccountButton("Login", this) + { + Location = new(ca.Location.X + ca.Size.X + (tb.Location.X / 2),ca.Location.Y, 0), + OnPageLoad = () => + { + btn!.Textures[0] = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + page!.Controls.Add(UserName = new() + { + Location = new(0, 22.ScaleInt(), 0), + Size = new(page.Size.X, 31.ScaleInt()), + WatermarkText = "Username", + TextLocation = TextLocation.LineCenter, + AllowMultiLine = false + }); + UserName.Textures[0] = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + UserName.KeyPress += args => + { + Texture t; + Texture good = Globals.ms.TextureManager.GetTextureResource("Textbox.png"); + if ((args.Key == Keys.Backspace || args.Key == Keys.Delete || args.Alt || args.Shift || args.Control || args.Key == Keys.Enter || args.Key == Keys.KeyPadEnter || args.Key== Keys.Space) && string.IsNullOrWhiteSpace(UserName.Text)) + { + t = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + } + else + { + t = good; + } + + if (UserName.Textures[0].handel != t.handel) + { + UserName.Textures[0] = t; + if (t.handel == good.handel && + Password!.Textures[0].handel == good.handel && + btn!.Textures[0].handel != good.handel && + tb.Textures[0].handel == good.handel) + { + btn.Textures[0] = good; + } + else if (t.handel != good.handel && + (Password!.Textures[0].handel != good.handel || + btn!.Textures[0].handel == good.handel || tb.Textures[0].handel != good.handel)) + { + btn!.Textures[0] = t; + } + Globals.ms.TryDraw(); + } + + return Task.CompletedTask; + }; + + page.Controls.Add(Password = new() + { + Location = new(0, UserName.Location.Y + UserName.Size.Y + UserName.Location.Y + UserName.Location.Y, 0), + Size = new(page.Size.X, UserName.Size.Y), + WatermarkText = "Password", + TextLocation = TextLocation.LineCenter, + AllowMultiLine = false, + PasswordChar = '●' + }); + Password.Textures[0] = UserName.Textures[0]; + Password.KeyPress += args => + { + Texture t; + Texture good = Globals.ms.TextureManager.GetTextureResource("Textbox.png"); + if ((args.Key == Keys.Backspace || args.Key == Keys.Delete || args.Alt || args.Shift || args.Control || args.Key == Keys.Enter || args.Key == Keys.KeyPadEnter || args.Key== Keys.Space) && + string.IsNullOrWhiteSpace(Password.Text)) + { + t = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + } + else + { + t = good; + } + + if (Password.Textures[0].handel != t.handel) + { + Password.Textures[0] = t; + if (t.handel == good.handel && + UserName!.Textures[0].handel == good.handel && + btn!.Textures[0].handel != good.handel && + tb.Textures[0].handel == good.handel) + { + btn.Textures[0] = good; + } + else if (t.handel != good.handel && + (UserName!.Textures[0].handel != good.handel || + btn!.Textures[0].handel == good.handel || tb.Textures[0].handel != good.handel)) + { + btn!.Textures[0] = t; + } + + Globals.ms.TryDraw(); + } + + return Task.CompletedTask; + }; + DisplayName = null!; + rec = null!; + } + }; + lo.Size = ca.Size; + lo.l.Location = new((lo.Size.X / 2) - (lo.l.Size.X / 2), + ((lo.Size.Y - lo.l.Size.Y) / 2) + , 0); + lo.l.ForceDistanceUpdate(lo); + Form.Controls.Add(lo); + + + #endregion + + Form.Controls.Add(version); + + page = new() + { + Location = new(tb.Location.X, ca.Location.Y + ca.Size.Y + tb.Location.X, 0), + BackgroundColor = Form.BackgroundColor + }; + page.Size = new(Form.Size.X - tb.Location.X - tb.Location.X, Form.Size.Y - tb.Location.X - page.Location.Y - ca.Size.Y - tb.Location.X); + Console.Write(page.Size.Y - tb.Location.X - tb.Location.X - (50*2*3)); + Console.WriteLine(page.Size); + Form.Controls.Add(page); + + btn = new(Globals.ms.TextureManager.GetTextureResource("BadTextbox.png")) + { + Location = new(page.Location.X, page.Location.Y + page.Size.Y + tb.Location.X, 0), + Size = new(page.Size.X, ca.Size.Y), + TextureDisplay = TextureDisplay.Center + }; + _ = ca.ToggleSelected(); + Label sub = new(Globals.DefaultFont) + { + Text = "Submit", + IgnoreHover = true + }; + sub.Location = new((btn.Size.X / 2) - (sub.Size.X / 2), + ((btn.Size.Y - sub.Size.Y) / 2) + , 0); + sub.ForceDistanceUpdate(btn); + btn.Controls.Add(sub); + Form.Controls.Add(btn); + + Form.Location = new((base.Size.X - Form.Size.X) / 2, (base.Size.Y - Form.Size.Y) / 2, 0); + Controls.Add(Form); + btn.Clicked += BtnOnClicked; + } + + private async Task BtnOnClicked(IRenderObject arg) + { + if (btn.Textures[0].handel == Globals.ms.TextureManager.GetTextureResource("BadTextbox.png").handel) + return; + bool s = true; + string d = tb!.Text; + if (d.Contains("://")) + { + string[] a = d.Split("://"); + d = a[1]; + if (a[0] == "http") s = false; + } + ServerInfo si = new() + { + Domain = d, + Version = version.SelectedOption.l.Text, + Main = false, + Secure = s + }; + bool g = await Globals.Luski.TryGetPublicServer(out PublicServer ps, si.Domain, si.Version, si.Secure); + + if (!g) + { + Texture b = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + tb!.Textures[0] = b; + btn.Textures[0] = b; + Globals.ms.TryDraw(); + return; + } + + if (g && !ps.IsLogedIn) + { + if (DisplayName is null) + { + g = await ps.Login(UserName!.Text, Password!.Text, CancellationToken.None); + } + else + { + g = await ps.CreateAccount(UserName!.Text, Password!.Text, DisplayName.Text, pfp, + CancellationToken.None); + } + } + + if (!g) + { + Texture b = Globals.ms.TextureManager.GetTextureResource("BadTextbox.png"); + UserName!.Textures[0] = b; + Password!.Textures[0] = b; + btn.Textures[0] = b; + Globals.ms.TryDraw(); + return; + } + + var l = Globals.ServerList.Servers.ToList(); + l.Add(si); + Globals.ServerList.Servers = l.ToArray(); + Globals.ServerList.SaveSettings(Path.Combine(Globals.LuskiPath, "Servers.json"), ServerListContext.Default.ServerList); + ServerIcon ss = new ServerIcon(ps); + Globals.ms.ser.Controls.Insert(Globals.ms.ser.Controls.Length - 1, ss); + await ss.LoadServer(); + Globals.ms.Controls.Remove(this); + Globals.ms.ForceUpdate(new(Size)); + Globals.ms.TryDraw(); + } + + private Task VersionOnOptionSelected(VersionDropButton arg) + { + return Task.CompletedTask; + } + + private Task VersionOnOpenStatusChanged(bool arg) + { + return Task.CompletedTask; + } + + private string pfp = ""; + + private Task RecOnFilesDroped(string[] arg) + { + Console.WriteLine(arg[0]); + if (!arg[0].ToLower().EndsWith("png")) return Task.CompletedTask; + + pfp = arg[0]; + if (rec!.Textures.Count() ==1 ) + { + Texture good = Globals.ms.TextureManager.GetTextureResource("Textbox.png"); + if (UserName!.Textures[0].handel == good.handel && + Password!.Textures[0].handel == good.handel && + btn!.Textures[0].handel != good.handel && tb.Textures[0].handel == good.handel) + { + if (DisplayName is not null) + { + if (Password!.Textures[0].handel == good.handel) btn.Textures[0] = good; + } + else btn.Textures[0] = good; + } + Texture tex = Globals.ms.TextureManager.AddTexture(File.OpenRead(arg[0])); + tex.Unit = TextureUnit.Texture1; + rec.Shader = Rectangle.DefaultAlphaTextureShader[Globals.ms.Context]; + rec.Textures.Add(tex); + } + else + { + rec.Textures[1] = Globals.ms.TextureManager.AddTexture(File.OpenRead(arg[0])); + rec.Textures[1].Unit = TextureUnit.Texture1; + } + + Window!.TryDraw(); + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/FullScreenMedia.cs b/Luski/GUI/MainScreen/UI/FullScreenMedia.cs new file mode 100644 index 0000000..64f1d0c --- /dev/null +++ b/Luski/GUI/MainScreen/UI/FullScreenMedia.cs @@ -0,0 +1,30 @@ +using GraphicsManager.Enums; +using GraphicsManager.Objects; +using GraphicsManager.Objects.Core; + +namespace Luski.GUI.MainScreen.UI; + +public class FullScreenMedia : UserControl +{ + public Rectangle IMG; + + public FullScreenMedia(Texture t) + { + base.Size = Globals.ms.ClientSize; + IMG = new(t) + { + Size = t.RawSize!.Value, + Location = new((base.Size.X - t.RawSize!.Value.X) / 2, (base.Size.Y - t.RawSize!.Value.Y) / 2, 0), + Anchor = ObjectAnchor.All + }; + BackgroundColor = new(0, 0, 0, 130); + Controls.Add(IMG); + IMG.ForceDistanceUpdate(this); + Anchor = ObjectAnchor.All; + } + + public static FullScreenMedia GetDisplay(Texture t) + { + return new FullScreenMedia(t); + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/LuskiContextMenu.cs b/Luski/GUI/MainScreen/UI/LuskiContextMenu.cs new file mode 100644 index 0000000..70d57fc --- /dev/null +++ b/Luski/GUI/MainScreen/UI/LuskiContextMenu.cs @@ -0,0 +1,52 @@ +using GraphicsManager.Enums; +using GraphicsManager.Objects; +using GraphicsManager.Objects.Core; +using OpenTK.Graphics.ES20; +using OpenTK.Mathematics; + +namespace Luski.GUI.MainScreen.UI; + +public class LuskiContextMenu : BetterContextMenu +{ + public LuskiContextMenu() + :base(Globals.ms.TextureManager.GetTextureResource("Context.png")) + { + Margins = new(5.ScaleInt()); + TextureDisplay = TextureDisplay.Center; + SpaceBetweenObjects = 8.ScaleInt(); + } + + public Label AddLabel(string text, Color4 color) + { + return AddLabel(Globals.DefaultFont, text, color); + } + + public Label AddLabel(string text) + { + Label l = AddLabel(Globals.DefaultFont, text, Color4.Gray); + l.Clicked += o => + { + HideContext(Window!); + TryDraw(); + return Task.CompletedTask; + }; + l.MouseEnter += o => + { + l.Color = Color4.White; + TryDraw(); + return Task.CompletedTask; + }; + l.MouseLeave += o => + { + l.Color = Color4.Gray; + TryDraw(); + return Task.CompletedTask; + }; + return l; + } + + public new void AddLine() + { + AddLine(Color4.White, 1.ScaleInt()); + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/LuskiControls/DropDown.cs b/Luski/GUI/MainScreen/UI/LuskiControls/DropDown.cs new file mode 100644 index 0000000..6d9bdfe --- /dev/null +++ b/Luski/GUI/MainScreen/UI/LuskiControls/DropDown.cs @@ -0,0 +1,192 @@ +using GraphicsManager.Enums; +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using GraphicsManager.Objects.Core; +using OpenTK.Mathematics; +using OpenTK.Windowing.Common; + +namespace Luski.GUI.MainScreen.UI.LuskiControls; + +public class DropDown : UserControl where TSelection : DropDownOption +{ + public readonly FlowLayout DropDownContainer; + + private IParent ip; + + public required IParent DropDownParentOverride + { + get + { + return ip; + } + set + { + ip = value; + DropDownContainer.TransferOwners(Globals.ms, value); + } + } + private bool IsOpen; + public event Func? OpenStatusChanged; + + public DropDown(TSelection defaultOption) + { + ip = this; + DropDownContainer = new() + { + Visible = false + }; + Clicked += OnClicked; + WindowLoaded += OnWindowLoaded; + AddOption(defaultOption); + SelectedOption = defaultOption; + } + + public DropDown(Texture t, TSelection defaultOption) + :base(t) + { + ip = this; + TextureDisplay = TextureDisplay.HorizontalCenter; + DropDownContainer = new() + { + Visible = false, + Anchor = ObjectAnchor.Left | ObjectAnchor.Top | ObjectAnchor.Right + }; + Clicked += OnClicked; + WindowLoaded += OnWindowLoaded; + DropDownContainer.Size = new(base.Size.X, DropDownContainer.Size.Y + defaultOption.Size.Y); + DropDownContainer.Controls.Add(defaultOption); + defaultOption.Clicked += OptionOnClicked; + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context]; + SelectedOption = defaultOption; + } + + public void SetSelected(TSelection obj) + { + SelectedOption = obj; + Controls.Clear(); + obj.LoadDisplay.Invoke(); + } + + public DropDown(Texture t, IRenderObject spacer, TSelection defaultOption) + :base(t) + { + ip = this; + TextureDisplay = TextureDisplay.HorizontalCenter; + DropDownContainer = new() + { + Visible = false, + Anchor = ObjectAnchor.Left | ObjectAnchor.Top | ObjectAnchor.Right + }; + Clicked += OnClicked; + WindowLoaded += OnWindowLoaded; + DropDownContainer.Size = new(base.Size.X, DropDownContainer.Size.Y + spacer.Size.Y); + DropDownContainer.Controls.Add(spacer); + DropDownContainer.Size = new(base.Size.X, DropDownContainer.Size.Y + defaultOption.Size.Y); + DropDownContainer.Controls.Add(defaultOption); + defaultOption.Clicked += OptionOnClicked; + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context]; + SelectedOption = defaultOption; + } + + public DropDown(Texture t, IRenderObject spacer) + :base(t) + { + ip = this; + TextureDisplay = TextureDisplay.HorizontalCenter; + DropDownContainer = new() + { + Visible = false, + Anchor = ObjectAnchor.Left | ObjectAnchor.Top | ObjectAnchor.Right + }; + Clicked += OnClicked; + WindowLoaded += OnWindowLoaded; + DropDownContainer.Size = new(base.Size.X, DropDownContainer.Size.Y + spacer.Size.Y); + DropDownContainer.Controls.Add(spacer); + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context]; + } + + public TSelection SelectedOption { get; private set; } + + private Task OnWindowLoaded(IRenderObject arg) + { + SelectedOption.LoadDisplay.Invoke(); + Window!.MouseDown += WindowOnMouseDown; + return Task.CompletedTask; + } + + private void WindowOnMouseDown(MouseButtonEventArgs obj) + { + if (IsOpen && !MouseInside) + { + IsOpen = false; + DropDownContainer.Visible = IsOpen; + if (OpenStatusChanged is not null) OpenStatusChanged.Invoke(IsOpen); + TryDraw(); + } + } + + private Task OnClicked(IRenderObject arg) + { + BlockDraw = true; + if (IsOpen) + { + IsOpen = false; + DropDownContainer.Visible = IsOpen; + if (OpenStatusChanged is not null) OpenStatusChanged.Invoke(IsOpen); + BlockDraw = false; + TryDraw(); + return Task.CompletedTask; + } + + DropDownContainer.Location = this.GetParentLocation(DropDownParentOverride)+ new Vector3i(0, Size.Y, 0); + DropDownParentOverride.Controls.Add(DropDownContainer); + DropDownContainer.Size = new(Size.X, DropDownContainer.Size.Y); + DropDownContainer.ForceDistanceUpdate(DropDownParentOverride); + IsOpen = true; + DropDownContainer.Visible = IsOpen; + DropDownParentOverride.Controls.MoveControlToEnd(DropDownContainer); + if (OpenStatusChanged is not null) OpenStatusChanged.Invoke(IsOpen); + BlockDraw = false; + TryDraw(); + return Task.CompletedTask; + } + + public void AddOption(TSelection Option) + { + DropDownContainer.Size = new(Size.X, DropDownContainer.Size.Y + Option.Size.Y); + DropDownContainer.Controls.Add(Option); + Option.Clicked += OptionOnClicked; + } + + public event Func? OptionSelected; + + private Task OptionOnClicked(IRenderObject arg) + { + try + { + TSelection but =(arg as TSelection)!; + if (but == SelectedOption) + { + IsOpen = false; + DropDownContainer.Visible = IsOpen; + if (OpenStatusChanged is not null) OpenStatusChanged.Invoke(IsOpen); + TryDraw(); + return Task.CompletedTask; + } + SelectedOption = but; + Controls.Clear(); + SelectedOption.LoadDisplay.Invoke(); + IsOpen = false; + DropDownContainer.Visible = IsOpen; + if (OpenStatusChanged is not null) OpenStatusChanged.Invoke(IsOpen); + if (OptionSelected is not null) OptionSelected.Invoke(SelectedOption); + TryDraw(); + } + catch (Exception e) + { + Console.WriteLine(e); + } + + return Task.CompletedTask; + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/LuskiControls/DropDownOption.cs b/Luski/GUI/MainScreen/UI/LuskiControls/DropDownOption.cs new file mode 100644 index 0000000..5767ab2 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/LuskiControls/DropDownOption.cs @@ -0,0 +1,19 @@ +using GraphicsManager.Objects; +using GraphicsManager.Objects.Core; +using OpenTK.Mathematics; + +namespace Luski.GUI.MainScreen.UI.LuskiControls; + +public class DropDownOption : UserControl +{ + public DropDownOption() + { + } + + + public DropDownOption(Texture t) : base(t) + { + } + + public required Action LoadDisplay; +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/LuskiControls/RoleView.cs b/Luski/GUI/MainScreen/UI/LuskiControls/RoleView.cs new file mode 100644 index 0000000..e5505f0 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/LuskiControls/RoleView.cs @@ -0,0 +1,70 @@ +using GraphicsManager.Objects; +using Luski.net.Structures.Public; +using OpenTK.Mathematics; + +namespace Luski.GUI.MainScreen.UI.LuskiControls; + +public class RoleView : FlowLayout +{ + private Label l; + private string n = "Offline"; + public int i = 0; + public Role? r; + public RoleView(Role? r = null) + { + this.r = r; + if (r is not null) n = r.DisplayName; + l = new(Globals.DefaultFont) + { + Text = " " + n + " — " + i, + }; + base.Size = new(0, 30.ScaleInt()); + base.BackgroundColor = new(34, 34, 34, 255); + Controls.Add(l); + } + + private Dictionary uuu = new(); + public List Users = new(); + + public async Task AddUser(SocketUser user, Role TopRole) + { + UserView f = await UserView.Make(user, TopRole, r is null); + uuu.Add(user.Id, f); + bool ff = false; + for (int j = 0; j < Users.Count; j++) + { + if (string.Compare(Users[j].DisplayName, user.DisplayName) > 0) + { + Users.Insert(j, user); + Controls.Insert(j+1, f); + ff = true; + break; + } + } + + if (!ff) + { + Users.Add(user); + Controls.Add(f); + } + + Size = new(Size.X, Size.Y + f.Size.Y); + i++; + l.Text = " " + n + " — " + i; + } + + public void RemoveUser(long id) + { + Vector2i Sizes = new(Size.X, Size.Y - uuu[id].Size.Y); + i--; + l.Text = " " + n + " — " + i; + Users.Remove(uuu[id].User); + Controls.Remove(uuu[id]); + uuu.Remove(id); + for (int j = 0; j < Controls.Length; j++) + { + ReportSizeUpdate(Controls[j]); + } + Size = Sizes; + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/LuskiControls/TextBox.cs b/Luski/GUI/MainScreen/UI/LuskiControls/TextBox.cs new file mode 100644 index 0000000..f4083e3 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/LuskiControls/TextBox.cs @@ -0,0 +1,334 @@ +using System.Timers; +using GraphicsManager.Enums; +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using GraphicsManager.Objects.Core; +using OpenTK.Mathematics; +using OpenTK.Windowing.Common; +using OpenTK.Windowing.Common.Input; +using OpenTK.Windowing.GraphicsLibraryFramework; +using Timer = System.Timers.Timer; + +namespace Luski.GUI.MainScreen.UI.LuskiControls; + +public class TextBox : UserControl +{ + private Label _watermark, _label; + private bool use; + private Rectangle Pointer; + private Timer t; + + public int CursorLocation { get; set; } = 0; + + public TextBox() + :base(Globals.ms.TextureManager.GetTextureResource("Textbox.png")) + { + t = new(500); + t.Elapsed += TOnElapsed; + TextureDisplay = TextureDisplay.Center; + _label = new Label(Globals.DefaultFont) + { + HoverMouse = MouseCursor.IBeam, + IgnoreHover = true + }; + _watermark = new(_label.Font) + { + Text = "Text Box", + Color = new(128, 128, 128, 255), + HoverMouse = MouseCursor.IBeam, + IgnoreHover = true + }; + Pointer = new() + { + Size = new(1.ScaleInt(), + (int)_label.LineHeight ), + Location = _watermark.Location, + BackgroundColor = Color4.White, + Visible = false + }; + Controls.Add(Pointer); + + Controls.Add(_label); + Controls.Add(_watermark); + } + + private void TOnElapsed(object? sender, ElapsedEventArgs e) + { + Globals.ms.Invoke(new Action(() => + { + Pointer.Visible = !Pointer.Visible; + })); + } + + public event Func? KeyPress; + + public override void UnFocus() + { + use = false; + t.Stop(); + Pointer.Visible = false; + if (Window is not null && Window.focused == this) + Window.focused = null; + + } + public override void Focus() + { + if (Window is not null) + { + if (Window.focused is not null) + { + Window.focused.UnFocus(); + } + t.Start(); + + Window.focused = this; + use = true; + } + } + + public override void LoadToParent(IParent parent, IWindow window) + { + if (Loaded) return; + window.MouseDown += Window_MouseDown; + window.KeyDown += Window_KeyDown; + window.TextInput += WindowOnTextInput; + if (!window.Context.IsCurrent) window.Context.MakeCurrent(); + base.LoadToParent(parent, window); + Pointer.Location = _watermark.Location; + } + + private void WindowOnTextInput(TextInputEventArgs obj) + { + if (!use) return; + Text = Text.Insert((int)CursorLocation, obj.AsString); + CursorLocation += obj.AsString.Length; + var f = _label.GetCharLocation((int)CursorLocation); + Pointer.Location = _label.Location + new Vector3i(f.X, f.Y, 0); + Pointer.Visible = true; + } + + + public char? PasswordChar { get => _label.PasswordChar; set => _label.PasswordChar = value; } + + private TextLocation tl = TextLocation.TopLeft; + + public TextLocation TextLocation + { + get => tl; + set + { + tl = value; + if (!string.IsNullOrWhiteSpace(Text)) + { + _label.Location = value switch + { + TextLocation.LineCenter => new(10.ScaleInt(), + ((Size.Y - _label.Size.Y) / 2), Location.Z), + _ => _label.Location + }; + _watermark.Location = _label.Location; + } + else + { + _watermark.Location = value switch + { + TextLocation.LineCenter => new(10.ScaleInt(), + ((Size.Y - _watermark.Size.Y) / 2), Location.Z), + _ => _watermark.Location + }; + _label.Location = _watermark.Location; + } + } + } + + public override bool Visible + { + get => base.Visible; + set + { + if (value == base.Visible) return; + if (value) + { + if (!string.IsNullOrEmpty(_label.Text)) + { + _label.Visible = true; + _watermark.Visible = false; + } + else + { + _label.Visible = false; + _watermark.Visible = true; + } + } + else + { + _label.Visible = value; + _watermark.Visible = value; + } + + base.Visible = value; + } + } + + public FontInteraction Font { get => _label.Font; } + public FontInteraction WatermarkFont { get => _watermark.Font; } + + public Color4 TextColor { get => _label.Color; set => _label.Color = value; } + public Color4 WatermarkColor { get => _watermark.Color; set => _watermark.Color = value; } + + public bool AllowMultiLine { get; set; } = true; + + public string Text + { + get => _label.Text; + set + { + int old = _label.Size.Y; + _label.Text = value; + if (!string.IsNullOrEmpty(value)) + { + bool f = false; + if (!_label.Visible) + { + f = true; + _label.Visible = true; + _label.Location = TextLocation switch + { + TextLocation.LineCenter => new(10.ScaleInt(), ((Size.Y - _label.Size.Y) / 2), Location.Z), + _ => _label.Location + }; + /* + _label.Location = TextLocation switch + { + TextLocation.TrueCenterLeft => new(Location.X + 5, Location.Y + ((Size.Y - _label.TrueHeight) / 2) - (_label.Size.Y - _label.TrueHeight), Location.Z), + TextLocation.PostiveTureCenterLeft => new(Location.X + 5, Location.Y + ((Size.Y - _label.PostiveTrueHeight) / 2) - _label.Size.Y + _label.TrueHeight, Location.Z), + TextLocation.PxLeft => new(Location.X + 5, Location.Y + ((Size.Y - _label.Size.Y) / 2), Location.Z), + _ => new(Location.X + 5, Location.Y + 5, Location.Z) + };*/ + _watermark.Location = _label.Location; + } + if (_watermark.Visible) _watermark.Visible = false; + if (!f && TextLocation == TextLocation.LineCenter && old != _label.Size.Y) + { + //_label.Location = new(Location.X + 5, Location.Y + ((Size.Y - _label.TrueHeight) / 2) - (_label.Size.Y - _label.TrueHeight), Location.Z); + _watermark.Location = _label.Location; + } + } + else + { + if (_label.Visible) _label.Visible = false; + if (!_watermark.Visible) + { + _watermark.Visible = true; + _watermark.Location = TextLocation switch + { + TextLocation.LineCenter => new(10.ScaleInt(), ((Size.Y - _watermark.Size.Y) / 2), Location.Z), + _ => _watermark.Location + }; + /* + _watermark.Location = TextLocation switch + { + TextLocation.TrueCenterLeft => new(Location.X + 5, Location.Y + ((Size.Y - _watermark.TrueHeight) / 2) - (_watermark.Size.Y - _watermark.TrueHeight), Location.Z), + TextLocation.PostiveTureCenterLeft => new(Location.X + 5, Location.Y + ((Size.Y - _label.PostiveTrueHeight) / 2) - _label.Size.Y + _label.TrueHeight, Location.Z), + TextLocation.PxLeft => new(Location.X + 5, Location.Y + ((Size.Y - _watermark.Size.Y) / 2), Location.Z), + _ => new(Location.X + 5, Location.Y + 5, Location.Z) + };*/ + _label.Location = _label.Location; + } + } + } + } + public string WatermarkText + { + get + { + return _watermark.Text; + } + set + { + _watermark.Text = value; + } + } + + public event Func? OnNewLine; + public event Func? OnRemoveLine; + + private void Window_KeyDown(KeyboardKeyEventArgs obj) + { + if (!use) return; + if (obj.Key == Keys.Left) + { + CursorLocation--; + var f = _label.GetCharLocation((int)CursorLocation); + Pointer.Location = _label.Location + new Vector3i(f.X, f.Y, 0); + Pointer.Visible = true; + } + if (obj.Key == Keys.Right) + { + if (CursorLocation != Text.Length) + { + CursorLocation++; + var f = _label.GetCharLocation((int)CursorLocation); + Pointer.Location = _label.Location + new Vector3i(f.X, f.Y, 0); + Pointer.Visible = true; + } + + } + if (obj.Key == Keys.CapsLock || obj.Key == Keys.Menu || obj.Key == Keys.LeftSuper || obj.Key == Keys.RightSuper || obj.Key == Keys.End || obj.Key == Keys.Home || obj.Key == Keys.PageDown || obj.Key == Keys.PageUp || obj.Key == Keys.Insert || obj.Key == Keys.Up || obj.Key == Keys.Down || obj.Key == Keys.Left || obj.Key == Keys.Right) return; + if (obj.Key == Keys.Backspace) + { + if (!(Text.Length > 0)) return; + if (Text[CursorLocation- 1] == '\n') + { + Size = new(Size.X, Size.Y - (int)_label.Font.PixelHeight); + if (OnRemoveLine is not null) OnRemoveLine.Invoke(); + } + Text = Text.Remove(CursorLocation - 1, 1); + CursorLocation--; + var f = _label.GetCharLocation(CursorLocation); + Pointer.Location = _label.Location + new Vector3i(f.X, f.Y, 0); + Pointer.Visible = true; + } + if (obj.Key == Keys.Delete) + { + if (CursorLocation == Text.Length) return; + if (Text[CursorLocation] == '\n') + { + Size = new(Size.X, Size.Y - (int)_label.Font.PixelHeight); + if (OnRemoveLine is not null) OnRemoveLine.Invoke(); + } + Text = Text.Remove(CursorLocation, 1); + } + + if (obj.Key == Keys.Enter) + { + if (AllowMultiLine && obj.Shift) + { + BlockDraw = true; + Size = new(Size.X, Size.Y + (int)_label.Font.PixelHeight); + if (OnNewLine is not null) OnNewLine.Invoke().Wait(); + BlockDraw = false; + Text += '\n'; + } + else + { + + } + } + + + + if (obj.Key == Keys.V && obj.Control && Window is not null) Text += Window.ClipboardString; + if (KeyPress is not null) _ = KeyPress.Invoke(obj); + } + + private void Window_MouseDown(MouseButtonEventArgs e) + { + if (MouseInside && e.Button == MouseButton.Button1) + { + use = true; + Focus(); + } + else UnFocus(); + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/LuskiControls/ToggleSwitch.cs b/Luski/GUI/MainScreen/UI/LuskiControls/ToggleSwitch.cs new file mode 100644 index 0000000..7e7ab67 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/LuskiControls/ToggleSwitch.cs @@ -0,0 +1,52 @@ +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using OpenTK.Mathematics; + +namespace Luski.GUI.MainScreen.UI.LuskiControls; + +public class ToggleSwitch : UserControl +{ + public ToggleSwitch() + :base(Globals.ms.TextureManager.GetTextureResource("Toggle.png")) + { + base.Size = new(40.ScaleInt(), 24.ScaleInt()); + base.BackgroundColor = OffBackgroundColor; + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context]; + Clicked += o => + { + Value = !Value; + return Task.CompletedTask; + }; + } + + public event Func? ValueChanged; + + public override void LoadToParent(IParent Parent, IWindow Window) + { + Value = !Value; + Value = !Value; + base.LoadToParent(Parent, Window); + } + + public new Vector2i Size + { + get => base.Size; + private set => base.Size = value; + } + + public bool Value + { + get => val; + set + { + if (value) BackgroundColor = OnBackgroundColor; + else BackgroundColor = OffBackgroundColor; + val = value; + if (Loaded && ValueChanged is not null) ValueChanged.Invoke(this); + } + } + + public Color4 OnBackgroundColor { get; set; }= new(35, 165, 90, 255); + public Color4 OffBackgroundColor { get; set; } = new(128, 132, 142, 255); + private bool val = true; +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/LuskiControls/UserView.cs b/Luski/GUI/MainScreen/UI/LuskiControls/UserView.cs new file mode 100644 index 0000000..d5f7795 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/LuskiControls/UserView.cs @@ -0,0 +1,36 @@ +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using Luski.net.Structures.Public; +using OpenTK.Mathematics; + +namespace Luski.GUI.MainScreen.UI.LuskiControls; + +public class UserView : UserControl +{ + public SocketUser User { get; set; } + + private UserView(IRenderObject user, SocketUser u, Role r, bool offline) + { + this.User = u; + base.Size = new(244.ScaleInt(), 44.ScaleInt()); + base.BackgroundColor = new(34, 34, 34, 255); + user.Location = new(8.ScaleInt(), 6.ScaleInt(), 0); + user.ForceDistanceUpdate(this); + Label uname = new(Globals.DefaultFont) + { + Text = u.DisplayName, + Color = r.Color.ToColor4() + }; + if (offline) uname.Color = new(uname.Color.R, uname.Color.G, uname.Color.B, uname.Color.A * 0.6f); + uname.Location = new(user.Location.X + user.Size.X + 8.ScaleInt(), + (user.Location.Y + (user.Size.Y / 2) - (uname.Size.Y / 2)), 0); + Controls.Add(uname); + Controls.Add(user); + } + + public static async Task Make(SocketUser u, Role r, bool offline) + { + UserView m = new(await u.MakeRct(new(32.ScaleInt()), true), u, r, offline); + return m; + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/LuskiControls/VersionDropButton.cs b/Luski/GUI/MainScreen/UI/LuskiControls/VersionDropButton.cs new file mode 100644 index 0000000..71455ae --- /dev/null +++ b/Luski/GUI/MainScreen/UI/LuskiControls/VersionDropButton.cs @@ -0,0 +1,39 @@ +using GraphicsManager.Enums; +using GraphicsManager.Objects; +using OpenTK.Mathematics; + +namespace Luski.GUI.MainScreen.UI.LuskiControls; + +public class VersionDropButton : DropDownOption +{ + public Label l; + + public VersionDropButton(Vector2i size, string v) + :base(Globals.ms.TextureManager.GetTextureResource("RoundedRectangle.png")) + { + base.Size = size; + TextureDisplay = TextureDisplay.HorizontalCenter; + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context]; + l = new Label(Globals.DefaultFont) + { + Text = v, + Color = Color4.DarkGray, + IgnoreHover = true + }; + l.Location = new((base.Size.X / 2) - (l.Size.X / 2), + ((base.Size.Y - l.Size.Y) / 2) + , 0); + Controls.Add(l); + BackgroundColor = new(0, 0, 0, 0); + MouseEnter += o => + { + BackgroundColor = new(141, 151, 165, 30); + return Task.CompletedTask; + }; + MouseLeave += o => + { + BackgroundColor = new(0,0,0,0); + return Task.CompletedTask; + }; + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/PublicServers/AddChannel.cs b/Luski/GUI/MainScreen/UI/PublicServers/AddChannel.cs new file mode 100644 index 0000000..7542718 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/PublicServers/AddChannel.cs @@ -0,0 +1,78 @@ +using GraphicsManager.Enums; +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using Luski.GUI.MainScreen.Interfaces; +using Luski.GUI.MainScreen.UI.LuskiControls; +using Luski.net.Structures.Public; + +namespace Luski.GUI.MainScreen.UI.PublicServers; + +public class AddChannel : UserControl +{ + private TextBox cn, cd; + private UserControl btn; + private SocketCategory Cat; + private IChannelAdder CA; + + public AddChannel(IChannelAdder CA, SocketCategory cat) + { + this.CA = CA; + Cat = cat; + base.Size = Globals.ms.ClientSize; + base.BackgroundColor = new(0, 0, 0, 130); + Anchor = ObjectAnchor.All; + FlowLayout fl = new() + { + SpaceBetweenObjects = 5.ScaleInt(), + Size = new(350.ScaleInt(), 220.ScaleInt()), + BackgroundColor = new(32,32,32,255), + //Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context], + //TextureDisplay = TextureDisplay.Center + }; + fl.Location = new((base.Size.X - fl.Size.X) / 2, (base.Size.Y - fl.Size.Y) / 2, 0); + fl.Controls.Add(new Label(Globals.DefaultFont) {Text = "Channel Name"}); + fl.Controls.Add(cn =new TextBox() + { + WatermarkText = "Channel Name", + Size = new(34.ScaleInt()), + Anchor = ObjectAnchor.Bottom | ObjectAnchor.Left | ObjectAnchor.Right, + TextLocation = TextLocation.LineCenter + }); + fl.Controls.Add(new Label(Globals.DefaultFont) {Text = "Channel Description"}); + fl.Controls.Add(cd =new TextBox() + { + WatermarkText = "Channel Description", + Size = cn.Size, + Anchor = ObjectAnchor.Bottom | ObjectAnchor.Left | ObjectAnchor.Right, + TextLocation = TextLocation.LineCenter + }); + fl.Controls.Add(new Label(Globals.DefaultFont) {Text = "\n "}); + fl.Controls.Add(btn = new(Globals.ms.TextureManager.GetTextureResource("Textbox.png")) + { + Size = new(40.ScaleInt()), + TextureDisplay = TextureDisplay.Center + }); + Label sub = new(Globals.DefaultFont) + { + Text = "Submit", + IgnoreHover = true + }; + sub.Location = new((btn.Size.X / 2) - (sub.Size.X / 2), + ((btn.Size.Y - sub.Size.Y) / 2) + , 0); + btn.Clicked += BtnOnClicked; + sub.ForceDistanceUpdate(btn); + btn.Controls.Add(sub); + fl.ForceDistanceUpdate(this); + Controls.Add(fl); + Anchor = ObjectAnchor.All; + } + + private async Task BtnOnClicked(IRenderObject arg) + { + SocketChannel chan = await Cat.Server.MakeChannel(Cat, cn.Text, cd.Text); + await CA.AddChannel(chan); + Globals.ms.Controls.Remove(this); + Globals.ms.DrawFrame(); + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/PublicServers/Category.cs b/Luski/GUI/MainScreen/UI/PublicServers/Category.cs new file mode 100644 index 0000000..ad85f8f --- /dev/null +++ b/Luski/GUI/MainScreen/UI/PublicServers/Category.cs @@ -0,0 +1,206 @@ +using GraphicsManager.Enums; +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using Luski.GUI.MainScreen.Interfaces; +using Luski.net.Structures.Public; +using OpenTK.Windowing.Common.Input; + +namespace Luski.GUI.MainScreen.UI.PublicServers; + +public class Category : UserControl, IChannelAdder +{ + public FlowLayout Members; + public SocketCategory CurrentCategory { get; set; } + private List cc = new(); + private List cl = new(); + private Label ee; + private ChannelSelector CS; + + public event Func? AddY; + + private Label Name; + public UserControl tmp; + + public static Task MakeCat(SocketCategory cat, ChannelSelector cs) + { + Category c = new(); + c.CurrentCategory = cat; + c.CS = cs; + c.Anchor = ObjectAnchor.All; + c.Size = new(307.ScaleInt(), 40.ScaleInt()); + c.tmp = new() + { + Size = c.Size, + Anchor = ObjectAnchor.Top | ObjectAnchor.Left, + IgnoreHover = true + }; + c.tmp.Clicked += c.TmpOnClicked; + c.tmp.HoverMouse = MouseCursor.Hand; + c.Controls.Add(c.tmp); + c.tmp.Controls.Add(c.ee = new(Globals.DefaultFont) + { + Text = ">", + Location = new(5.ScaleInt()), + Color = cat.Color.ToColor4(), + DIR = new(1,0), + IgnoreHover = true + }); + c.tmp.Controls.Add(c.Name = new Label(Globals.DefaultFont) + { + Text = cat.Name, + Color = c.ee.Color, + IgnoreHover = true + }); + c.Clicked += c.AllOnClicked; + c.Name.Location = new(26.ScaleInt(), (((c.Size.Y - c.Name.Size.Y)/2)), 0); + c.Members = new() + { + Anchor = ObjectAnchor.All, + Location = new(20.ScaleInt(), c.Size.Y, 0), + IgnoreHover = true + }; + c.ee.Location = new(c.ee.Location.X, c.Name.Location.Y, 0); + c.Members.Size = new(c.Size.X - c.Members.Location.X, 0); + c.Controls.Add(c.Members); + c.Members.ForceDistanceUpdate(c); + c.tmp.HoverMouse = MouseCursor.Hand; + return Task.FromResult(c); + } + + private Category() + { + } + private async Task TmpOnClicked(IRenderObject arg) + { + BlockDraw = true; + if (!Extended) + { + DateTime dt = DateTime.UtcNow; + SocketChannel[] Channels = await CurrentCategory.GetChannels(); + Console.WriteLine(DateTime.UtcNow - dt); + foreach (SocketChannel v in Channels) + { + Channel c = await AddChannel(v); + c.LoadToParent(Members, Window!); + _ = CatOnAddY(c.Size.Y); + } + Console.WriteLine(DateTime.UtcNow - dt); + + SocketCategory[] cats = await CurrentCategory.GetCategories(); + Console.WriteLine(DateTime.UtcNow - dt); + foreach (SocketCategory v in cats) + { + var c = await AddCategory(v, dt); + c.LoadToParent(Members, Window!); + _ = CatOnAddY(c.Size.Y); + } + Console.WriteLine(DateTime.UtcNow - dt); + } + else + { + if (AddY is not null) await AddY.Invoke(-Members.Size.Y); + this.Size = new(this.Size.X, this.Size.Y -Members.Size.Y); + Members.Size = new(Members.Size.X, 0); + //Members.Controls.Clear(false); + } + + BlockDraw = false; + + Extended = !Extended; + + // Window!.ForceUpdate(new(Window.Size)); + } + + private bool e; + public bool Extended + { + get => e; + set + { + if (value) + { + ee.DIR = new(0,1); + ee.Location = new(ee.Location.X, (ee.Location.Y - ee.Size.Y), 0); + } + else + { + ee.DIR = new(1,0); + ee.Location = new(ee.Location.X, (ee.Location.Y + ee.Size.Y), 0); + } + e = value; + } + } + + private Task AllOnClicked(IRenderObject arg) + { + if (ClickCon is not null) _ = ClickCon.Invoke(this); + return Task.CompletedTask; + } + + public event Func? ClickCon; + + public async Task AddCategory(SocketCategory Cat, DateTime? dt = null) + { + if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt); + Category[] tc = cc.Where(s => s.CurrentCategory.ID == Cat.ID).ToArray(); + if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt); + if (tc.Length > 0) + { + if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt); + var cat2 = tc[0]; + if (!Members.Controls.Contains(cat2)) + { + if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt); + Members.Controls.Add(cat2); + if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt); + //Size = new(Size.X, Size.Y + cat2.Size.Y); + _ = CatOnAddY(cat2.Size.Y); + if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt); + if (AddY is not null) _ = AddY.Invoke(cat2.Size.Y); + if (dt is not null) Console.WriteLine("c: {0}",DateTime.UtcNow - dt); + } + + return cat2; + } + var cat = await Category.MakeCat(Cat, CS); + cc.Add(cat); + Members.Controls.Add(cat); + cat.Size = new(this.Size.X, cat.Size.Y); + cat.Members.BackgroundColor = BackgroundColor; + cat.BackgroundColor = BackgroundColor; + cat.tmp.BackgroundColor = BackgroundColor; + Size = new(Size.X, Size.Y + cat.Size.Y); + cat.AddY += CatOnAddY; + if (AddY is not null) await AddY.Invoke(cat.Size.Y); + return cat; + } + + private async Task CatOnAddY(int arg) + { + this.Size = new(Size.X, Size.Y + arg); + } + + public async Task AddChannel(SocketChannel chan) + { + Channel[] tc = cl.Where(s => s.CurrentChannel.ID == chan.ID).ToArray(); + if (tc.Length > 0) + { + Channel cat2 = tc[0]; + if (!Members.Controls.Contains(cat2)) + { + Members.Controls.Add(cat2); + Size = new(Size.X, Size.Y + cat2.Size.Y); + if (AddY is not null) _ = AddY.Invoke(cat2.Size.Y); + } + + return cat2; + } + Channel cat = await Channel.MakeChannel(chan, CS); + cl.Add(cat); + cat.BackgroundColor = BackgroundColor; + Size = new(Size.X, Size.Y + cat.Size.Y); + Members.Controls.Add(cat); + if (AddY is not null) await AddY.Invoke(cat.Size.Y); + return cat; + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/PublicServers/Channel.cs b/Luski/GUI/MainScreen/UI/PublicServers/Channel.cs new file mode 100644 index 0000000..e8528a2 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/PublicServers/Channel.cs @@ -0,0 +1,160 @@ +using GraphicsManager.Enums; +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using GraphicsManager.Objects.Core; +using Luski.net.Enums; +using Luski.net.Structures.Public; +using Luski.Shared.PublicServers.V1.Enums; +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; +using OpenTK.Windowing.Common.Input; + +namespace Luski.GUI.MainScreen.UI.PublicServers; + +public class Channel : UserControl +{ + private ChannelSelector CS; + public SocketChannel CurrentChannel { get; set; } + + private Channel(Stream UserIcon, ChannelSelector cs, SocketChannel chan) + : base(Globals.ms.TextureManager.GetTextureResource("RoundedRectangle.png")) + { + CS = cs; + CurrentChannel = chan; + base.Size = new(307.ScaleInt(), 34.ScaleInt()); + + TextureDisplay = TextureDisplay.HorizontalCenter; + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context]; + int i = 4.ScaleInt(); + r = new Rectangle(Globals.ms.TextureManager.GetAlphaCircle()) + { + Location = new(i,i,0), + Size = new (32.ScaleInt()), + IgnoreHover = true + }; + Texture tex; + tex = Globals.ms.TextureManager.AddTexture(UserIcon); + GC.Collect(); + UserIcon.Dispose(); + tex.Unit = TextureUnit.Texture1; + r.Textures.Add(tex); + r.Shader = Rectangle.DefaultAlphaTextureShader[Globals.ms.Context]; + Controls.Add(r); + ChannelName = new Label(Globals.DefaultFont) + { + Text = chan.Name, + Color = chan.Color.ToColor4(), + IgnoreHover = true + }; + Controls.Add(ChannelName); + Clicked += AllOnClicked; + ChannelName.Location = new(40.ScaleInt(), + ((base.Size.Y - ChannelName.Size.Y) / 2) + , 0); + base.HoverMouse = MouseCursor.Hand; + } + + private Channel(ChannelSelector cs, SocketChannel chan) + : base(Globals.ms.TextureManager.GetTextureResource("RoundedRectangle.png")) + { + CS = cs; + CurrentChannel = chan; + base.Size = new(307.ScaleInt(), 34.ScaleInt()); + + TextureDisplay = TextureDisplay.HorizontalCenter; + Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context]; + int i = 4.ScaleInt(); + GC.Collect(); + ChannelName = new Label(Globals.DefaultFont) + { + Text = chan.Name, + Color = chan.Color.ToColor4(), + IgnoreHover = true + }; + Controls.Add(ChannelName); + Clicked += AllOnClicked; + ChannelName.Location = new(i, + ((base.Size.Y - ChannelName.Size.Y) / 2) + , 0); + base.HoverMouse = MouseCursor.Hand; + } + + public bool Selected { get; private set; } + + public async Task ToggleSelected() + { + try + { + Color4 bc = new(141,151,165,51); + if (Selected) + { + bc = CS.BackgroundColor; + } + + BlockDraw = true; + Selected = !Selected; + + if (CS.Selected is not null && CS.Selected != this) + { + await CS.Selected.ToggleSelected(); + } + BackgroundColor = bc; + Task? mm = null; + if (Selected) + { + CS.Selected = this; + IReadOnlyList m; + m = await CurrentChannel.GetMessages(CancellationToken.None, Globals.Settings.LoadPerChannel); + Globals.ms.pc.ClearChat(); + await Globals.ms.pc.LoadChannel(CurrentChannel); + mm = Globals.ms.pc.AddMessages(m); + } + + if (mm is not null) + { + Console.WriteLine("Waiting"); + Task.WaitAll(mm); + Globals.ms.pc.MessageFlow.ForceScrollUpdate(); + Globals.ms.pc.MessageFlow.ScrollToBottom(); + Console.WriteLine("Done"); + } + BlockDraw = false; + TryDraw(); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + public Label ChannelName; + public Rectangle r; + + public static async Task MakeChannel(SocketChannel chan, ChannelSelector cs) + { + Channel c; + if (chan.PictureType == PictureType.none) c = new(cs, chan); + else c = new(await chan.GetPicture(CancellationToken.None), cs, chan); + return c; + } + + private Task EditChannelButtonOnClicked(IRenderObject arg) + { + arg.ContextMenu!.HideContext(Window!); + return Task.CompletedTask; + } + + private Task ExportKeysButtonOnClicked(IRenderObject arg) + { + //_ = CurrentChannel.SendKeysToUsers(CancellationToken.None); + ContextMenu!.HideContext(Window!); + return Task.CompletedTask; + } + + private async Task AllOnClicked(IRenderObject arg) + { + if (!Selected) await ToggleSelected(); + //if (ClickCon is not null) _ = ClickCon.Invoke(this); + } + + //public event Func? ClickCon; +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/PublicServers/ChannelSelector.cs b/Luski/GUI/MainScreen/UI/PublicServers/ChannelSelector.cs new file mode 100644 index 0000000..05301a9 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/PublicServers/ChannelSelector.cs @@ -0,0 +1,138 @@ +using System.Runtime.CompilerServices; +using GraphicsManager.Enums; +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using Luski.GUI.MainScreen.Interfaces; +using Luski.net.Structures.Public; +using Luski.Shared.PublicServers.V1.Enums; +using OpenTK.Mathematics; + +namespace Luski.GUI.MainScreen.UI.PublicServers; + +public class ChannelSelector : FlowLayout, IChannelAdder +{ + public SocketCategory CurrentCategory { get; } + private readonly List cc = new(); + private readonly List LoadedChannels = new(); + public Channel? Selected; + + private ChannelSelector(SocketCategory Cat) + { + CurrentCategory = Cat; + Cat.Server.MessageReceived += ServerOnMessageReceived; + } + + public static async Task MakeSelector(SocketCategory Cat) + { + ChannelSelector cs = new(Cat); + if (await Cat.Server.User.HasAccessToCategory(Cat, ServerPermission.CreateChannels)) + { + LuskiContextMenu lcm = new(); + Label l = lcm.AddLabel("Create Channel"); + l.Clicked += cs.LOnClicked; + cs.ContextMenu = lcm; + } + + return cs; + } + + private async Task LOnClicked(IRenderObject arg) + { + Globals.ms.Controls.Add(new AddChannel(this, CurrentCategory)); + TryDraw(); + } + + private async Task ServerOnMessageReceived(SocketMessage arg) + { + if (Selected is null || arg.ChannelID != Selected.CurrentChannel.ID) return; + bool u = Globals.ms.pc.MessageFlow.MaxScrollValue == Globals.ms.pc.MessageFlow.ScrollValue; + await Globals.ms.pc.AddMessage(arg, u); + + } + + public async Task Load(SocketChannel currentchannel, List parents) + { + IChannelAdder b = this; + SocketChannel[] chanspp = await b.CurrentCategory.GetChannels(); + foreach (SocketChannel v in chanspp) + { + Channel f = await b.AddChannel(v); + if (v.ID == currentchannel.ID) + { + await f.ToggleSelected(); + } + } + SocketCategory[] cats = await b.CurrentCategory.GetCategories(); + foreach (SocketCategory v in cats) + { + await b.AddCategory(v); + Globals.ms.DrawFrame(); + } + foreach (SocketCategory par in parents) + { + b.Extended = true; + b = await b.AddCategory(par); + Globals.ms.DrawFrame(); + chanspp = await par.GetChannels(); + foreach (SocketChannel v in chanspp) + { + Channel f = await b.AddChannel(v); + if (v.ID == currentchannel.ID) + { + await f.ToggleSelected(); + } + } + cats = await par.GetCategories(); + foreach (SocketCategory v in cats) + { + await b.AddCategory(v); + Globals.ms.DrawFrame(); + } + } + + } + + public async Task AddChannel(SocketChannel chan) + { + Channel[] tc = LoadedChannels.Where(s => s.CurrentChannel.ID == chan.ID).ToArray(); + if (tc.Length > 0) + { + Channel cat23 = tc[0]; + if (!Controls.Contains(cat23)) + { + Controls.Add(cat23); + } + + return cat23; + } + Channel cat2 = await Channel.MakeChannel(chan, this); + LoadedChannels.Add(cat2); + cat2.BackgroundColor = BackgroundColor; + Controls.Add(cat2); + return cat2; + } + + public bool Extended { get; set; } = true; + + public async Task AddCategory(SocketCategory Cat, DateTime? dt = null) + { + Category[] tc = cc.Where(s => s.CurrentCategory.ID == Cat.ID).ToArray(); + if (tc.Length > 0) + { + Category cat23 = tc[0]; + if (!Controls.Contains(cat23)) + { + Controls.Add(cat23); + } + + return cat23; + } + Category cat = await Category.MakeCat(Cat, this); + cc.Add(cat); + cat.BackgroundColor = BackgroundColor; + cat.tmp.BackgroundColor = BackgroundColor; + cat.Members.BackgroundColor = BackgroundColor; + Controls.Add(cat); + return cat; + } +} \ No newline at end of file diff --git a/Luski/GUI/MainScreen/UI/PublicServers/ChatMessage.cs b/Luski/GUI/MainScreen/UI/PublicServers/ChatMessage.cs new file mode 100644 index 0000000..405f9c8 --- /dev/null +++ b/Luski/GUI/MainScreen/UI/PublicServers/ChatMessage.cs @@ -0,0 +1,304 @@ +using System.Diagnostics; +using GraphicsManager.Enums; +using GraphicsManager.Interfaces; +using GraphicsManager.Objects; +using Luski.net.Interfaces; +using Luski.net.Structures.Main; +using Luski.net.Structures.Public; +using OpenTK.Mathematics; +using OpenTK.Windowing.Common.Input; +using Label = GraphicsManager.Objects.Label; + +namespace Luski.GUI.MainScreen.UI.PublicServers; + +public class ChatMessage : UserControl +{ + private SocketMessage Msg { get; } + private SocketChannel ch { get; } + + public PublicChat pc; + + private IRenderObject LastObject; + public List MessageObjs = new(); + private Label FirstL; + + public readonly double HorPadding = 12.ScaleDouble(), + VerticalPadding = 0.ScaleDouble(); + + private static Dictionary> Messages = new(); + + public static async Task MakeChatMessage(PublicChat p, SocketMessage message) + { + IUser auth = await message.GetAuthor(CancellationToken.None); + Color c = await auth.GetColor(); + Color4 c4 = new(c.R, c.G, c.B, c.A); + return new ChatMessage(p, message, await message.GetParent(CancellationToken.None), auth, await auth.MakeRct(new(40.ScaleInt()), message.IsProfile), c4); + } + + + private ChatMessage(PublicChat p, SocketMessage message, SocketChannel chan, IUser Author, IRenderObject UserIcon, Color4 UserNameColor) + { + pc = p; + Label label1; + base.Size = new(723.5.ScaleInt(), 37.ScaleInt()); + ch = chan; + base.BackgroundColor = new(40, 40, 40, 255); + Msg = message; + Anchor = ObjectAnchor.Left | ObjectAnchor.Right; + + DateTime time = chan.Epoch.AddMilliseconds(Msg.TimeStamp).ToLocalTime(); + + string time_str; + if (Globals.Settings.DayTime) + { + if (time.Date == DateTime.Now.ToLocalTime().Date) + { + time_str = $"Today at {time:HH:mm}"; + } + else if (time.Date == DateTime.Now.ToLocalTime().AddDays(-1).Date) + { + time_str = $"Yesterday at {time:HH:mm}"; + } + else + { + time_str = $"{time:M/dd/yyyy HH:mm}"; + } + } + else + { + if (time.Date == DateTime.Now.ToLocalTime().Date) + { + time_str = $"Today at {time.ToShortTimeString().Replace('\u202f', ' ')}"; + } + else if (time.Date == DateTime.Now.ToLocalTime().AddDays(-1).Date) + { + time_str = $"Yesterday at {time.ToShortTimeString().Replace('\u202f', ' ')}"; + } + else + { + time_str = $"{time:M/dd/yyyy h:mm tt}"; + } + } + + UserIcon.Location = new(10.ScaleInt(), 2.ScaleInt(), 0); + Controls.Add(UserIcon); + Controls.Add(label1 = new Label(Globals.DefaultFont) { Color = UserNameColor, Text = Author.DisplayName }); + label1.Location = new( + 54.ScaleInt(), + //(int)(UserIcon.Location.Y + (UserIcon.Size.Y / 2) - (label1.Font.CurrentFonts[0].Face.Size.Metrics.NominalHeight / 2) - label1.Size.Y + label1.Font.PixelHeight), + UserIcon.Location.Y, + 0); + Label label2; + LastObject = label1; + FirstL = label1; + Controls.Add(label2 = new Label(Globals.TopTimeFont) { Location = new(label1.Location.X + label1.Size.X + 8.ScaleInt(), (int)(label1.Location.Y + label1.Font.PixelHeight - Globals.TopTimeFont.PixelHeight), 0), Text = time_str}); + if (!string.IsNullOrWhiteSpace(Msg.Context)) + { + Label l; + Controls.Add(l = new Label(Globals.MessageFont) { Location = new(LastObject.Location.X, (int)(UserIcon.Location.Y + UserIcon.Size.Y - Globals.MessageFont.PixelHeight), 0), Text = message.Context}); + LastObject = l; + MessageObjs.Add(l); + } + Globals.Settings.DayTimeChanged += () => + { + if (Globals.Settings.DayTime) + { + if (time.Date == DateTime.Now.ToLocalTime().Date) + { + time_str = $"Today at {time:HH:mm}"; + } + else if (time.Date == DateTime.Now.ToLocalTime().AddDays(-1).Date) + { + time_str = $"Yesterday at {time:HH:mm}"; + } + else + { + time_str = $"{time:M/dd/yyyy HH:mm}"; + } + } + else + { + if (time.Date == DateTime.Now.ToLocalTime().Date) + { + time_str = $"Today at {time.ToShortTimeString().Replace('\u202f', ' ')}"; + } + else if (time.Date == DateTime.Now.ToLocalTime().AddDays(-1).Date) + { + time_str = $"Yesterday at {time.ToShortTimeString().Replace('\u202f', ' ')}"; + } + else + { + time_str = $"{time:M/dd/yyyy h:mm tt}"; + } + } + + label2.Text = time_str; + return Task.CompletedTask; + }; + + if (Msg.Files.Count > 0) + { + int row = 1; + int files_on_row = 0; + for (int i = 0; i < Msg.Files.Count; i++) + { + double lx = (HorPadding * files_on_row) + LastObject.Location.X + (333 * (files_on_row + 1)); + if (lx > base.Size.X) + { + row++; + files_on_row = 0; + lx = (HorPadding * files_on_row) + LastObject.Location.X + (333 * (files_on_row + 1)); + } + + files_on_row++; + IRenderObject cem = ContentEmbed.GetEmbed(this, Msg.Files[i], Msg.ChannelID).Result; + cem.Location = new((int)(lx - 333), (int)(LastObject.Location.Y + 2 + LastObject.Size.Y + (HorPadding * row) + (66 * (row - 1))), 0); + LastObject = cem; + Controls.Add(cem); + } + } + + if (LastObject is Label ll) base.Size = new(base.Size.X, (int)(ll.Location.Y + ll.Size.Y + VerticalPadding)); + else base.Size = new(base.Size.X ,(int)(LastObject.Location.Y + LastObject.Size.Y + VerticalPadding)); + } + + + public async Task AddMessage(SocketMessage msg) + { + BlockDraw = true; + Label newLabel; + if (!string.IsNullOrWhiteSpace(msg.Context)) + { + newLabel = new(Globals.MessageFont) + { + Text = msg.Context, + Tag = msg + }; + if (LastObject is Label l) + { + newLabel.Location = new(FirstL.Location.X, (int)(l.Location.Y + l.Size.Y + VerticalPadding), 0); + } + else + { + newLabel.Location = new(FirstL.Location.X, Size.Y, 0); + } + bool result = Uri.TryCreate(newLabel.Text, UriKind.Absolute, out Uri? uriResult) + && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); + if (result) + { + newLabel.HoverMouse = MouseCursor.Hand; + newLabel.Color = Color4.Aqua; + newLabel.Clicked += NewLabelOnClicked; + } + + newLabel.MouseEnter += NewLabel_MouseEnter; + newLabel.MouseLeave += NewLabel_MouseLeave; + Controls.Add(newLabel); + MessageObjs.Add(newLabel); + LastObject = newLabel; + } + + + if (msg.Files.Count > 0) + { + int row = 1; + int filesonrow = 0; + for (int i = 0; i < msg.Files.Count; i++) + { + double lx = (HorPadding * filesonrow) + LastObject.Location.X + (333 * (filesonrow + 1)); + if (lx > Size.X) + { + row++; + filesonrow = 0; + lx = (HorPadding * filesonrow) + LastObject.Location.X + (333 * (filesonrow + 1)); + } + + filesonrow++; + IRenderObject cem = await ContentEmbed.GetEmbed(this, msg.Files[i], msg.ChannelID); + cem.Location = new((int)(lx - 333), (int)(LastObject.Location.Y + 2 + LastObject.Size.Y + (HorPadding * row) + (66 * (row - 1))), 0); + LastObject = cem; + Controls.Add(cem); + } + } + if (LastObject is Label ll) Size = new(Size.X, (int)(ll.Location.Y + ll.Size.Y + VerticalPadding)); + else Size = new(Size.X ,(int)(LastObject.Location.Y + LastObject.Size.Y + VerticalPadding)); + BlockDraw = false; + //if (Parent is not null) Globals.ms.pc.MessageFlow.ReportSizeUpdate(this); + TryDraw(); + } + + private Task NewLabelOnClicked(IRenderObject arg) + { + try + { + Label m = (arg as Label)!; + if (OperatingSystem.IsWindows()) + Process.Start(m.Text); + else if (OperatingSystem.IsLinux()) + { + if (m.Tag is string s) Process.Start("xdg-open", s); + else Process.Start("xdg-open", m.Text); + } + } + catch (Exception e) + { + Console.WriteLine(e); + } + return Task.CompletedTask; + } + + readonly List