Compare commits

...

30 Commits

Author SHA1 Message Date
JacobTech f7abb6e993 Merge pull request 'dev' (#17) from dev into main
Reviewed-on: #17
2024-04-11 15:50:13 -04:00
JacobTech 452009675e Coordinates & Switches
• The client now uses the new coordinate system.
• Added a new control for a toggle switch.
2024-04-11 15:44:12 -04:00
JacobTech 149c893d3b More Time Settings 2024-04-06 22:42:31 -04:00
JacobTech 6748e7548d Progress 2024-04-03 22:57:32 -04:00
JacobTech 64a22b5358 Current 2024-04-01 10:12:49 -04:00
JacobTech d685737e1e OpenGL Version 2024-03-27 20:52:27 -04:00
JacobTech abf1e7fb74 Framework Update
A few changes, mostly to update the .NET framework version.

Started work on the settings menu by adding experiments.
2023-12-22 11:14:28 -05:00
JacobTech 9fcb4883e3 README 2023-11-18 12:37:21 -05:00
JacobTech 580d576e76 Update 2023-11-18 12:33:05 -05:00
JacobTech a6fc28e2ab Alternate servers.
Now, using the new alternate servers.
2023-08-25 12:13:06 -04:00
JacobTech c178ec62cf Public Servers.
Added a bunch of controls to use in public servers.
2023-08-21 10:55:03 -04:00
JacobTech d8657d103d Client Example.
This commit moves the client to the new main server layout. Once the Luski library has more code in the public server area, we can start to test the app.
2023-07-10 07:37:58 -04:00
JacobTech bdb1e350f6 Upkeeping
This push is just to prevent a merge conflict for myself.
2023-07-03 23:26:16 -04:00
JacobTech c6a194710a Added missing texture 2023-02-18 23:13:30 -05:00
JacobTech ac830c6578 Scaling Fixes 2023-02-18 22:48:06 -05:00
JacobTech 910b7f43e7 What am I doing 2023-01-29 21:06:01 -05:00
JacobTech df9b68c440 Got my code back 2023-01-24 09:27:44 -05:00
JacobTech aec8055491 Beta Time
Fixes #2
2023-01-08 01:41:19 -05:00
JacobTech b2f0fdc64f Added friend request UI
fixes #10
2023-01-06 17:48:28 -05:00
JacobTech 9738e8366d Friends Pannel Feature
You can open a DM from the freinds pannel
2023-01-06 01:56:44 -05:00
JacobTech 04ccaec3bb Friend TabControl
resolves #7
2023-01-06 01:52:36 -05:00
JacobTech 049cbe6f5b Finished Chat to resolve #4 2023-01-05 12:19:30 -05:00
JacobTech 6f106dc49c Added a channel picker to resolve #11 2023-01-03 10:04:47 -05:00
JacobTech 086e5d157c Friend control to resolve #8 2023-01-02 23:13:03 -05:00
JacobTech 3389495a98 Group UI to reslove #9 2023-01-02 23:03:29 -05:00
JacobTech f7e557344d New GUI layout to resolve #3 2023-01-02 20:39:35 -05:00
JacobTech 46fdd869da Added contenet embed to ChatMessage.cs 2023-01-02 12:48:35 -05:00
JacobTech d617e84f4c ContentEmbed control to resolve #6 2023-01-02 12:48:02 -05:00
JacobTech b82677bb64 ChatMessage control to resolve #5 2023-01-02 11:55:59 -05:00
JacobTech dc96ec3874 Login Page
Basic design for the login page
2023-01-01 23:34:33 -05:00
76 changed files with 6338 additions and 0 deletions

14
.gitignore vendored
View File

@ -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/

16
Luski.sln Normal file
View File

@ -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

View File

@ -0,0 +1,9 @@
namespace Luski.Classes;
public class ExperimentInfo
{
public string DisplayName { get; set; } = default!;
public string Name { get; set; } = default!;
public List<ExperimentSelectorInfo> Options { get; set; } = default!;
public int? Selected { get; set; } = null;
}

View File

@ -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!;
}

View File

@ -0,0 +1,14 @@
namespace Luski.Classes;
public class ExperimentSelectorInfo
{
public event Func<bool,Task>? 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);
}
}

View File

@ -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<ThemeStart> LuskiThemeList = new()
{
Light,
Dark,
Amoled
};
}

View File

@ -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;
}

View File

@ -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<ServerInfo>();
}
[JsonSerializable(typeof(ServerList))]
[JsonSourceGenerationOptions(
GenerationMode = JsonSourceGenerationMode.Default,
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
internal partial class ServerListContext : JsonSerializerContext
{
}

129
Luski/Classes/Settings.cs Normal file
View File

@ -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<ExperimentJson> Experiments { get; set; } = Array.Empty<ExperimentJson>().ToList();
[JsonInclude]
[JsonPropertyName("default_display")]
public int Display { get; set; } = 0;
/// <summary>
/// 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.
/// </summary>
[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<Task>? DayTimeChanged;
}
[JsonSerializable(typeof(Settings))]
[JsonSourceGenerationOptions(
GenerationMode = JsonSourceGenerationMode.Default,
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
internal partial class SettingsContext : JsonSerializerContext
{
}

View File

@ -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<ServerTheme>();
}
[JsonSerializable(typeof(ThemeStart))]
[JsonSourceGenerationOptions(
GenerationMode = JsonSourceGenerationMode.Default,
PropertyNamingPolicy = JsonKnownNamingPolicy.Unspecified,
WriteIndented = true,
DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
internal partial class ThemeStartContext : JsonSerializerContext
{
}

View File

@ -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();
}

View File

@ -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");
}

View File

@ -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
{
}

21
Luski/ConsoleLog.cs Normal file
View File

@ -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
}

View File

@ -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<Channel> AddChannel(SocketChannel chan);
public Task<Category> AddCategory(SocketCategory Cat, DateTime? dt = null);
}

View File

@ -0,0 +1,8 @@
using Luski.net.Structures.Main;
namespace Luski.GUI.MainScreen.Interfaces;
public interface IChannelPick
{
public MainSocketTextChannel Channel { get; }
}

View File

@ -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);
}
}
}

View File

@ -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());
}
}

View File

@ -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<VersionDropButton> 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<VersionDropButton>(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<PublicServer> ss = new ServerIcon<PublicServer>(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;
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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<TSelection> : 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<bool, Task>? 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<TSelection, Task>? 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;
}
}

View File

@ -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;
}

View File

@ -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<long, UserView> uuu = new();
public List<SocketUser> 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;
}
}

View File

@ -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<KeyboardKeyEventArgs, Task>? 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<Task>? OnNewLine;
public event Func<Task>? 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();
}
}

View File

@ -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<ToggleSwitch, Task>? 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;
}

View File

@ -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<UserView> Make(SocketUser u, Role r, bool offline)
{
UserView m = new(await u.MakeRct(new(32.ScaleInt()), true), u, r, offline);
return m;
}
}

View File

@ -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;
};
}
}

View File

@ -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();
}
}

View File

@ -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<Category> cc = new();
private List<Channel> cl = new();
private Label ee;
private ChannelSelector CS;
public event Func<int, Task>? AddY;
private Label Name;
public UserControl tmp;
public static Task<Category> 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<Category, Task>? ClickCon;
public async Task<Category> 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<Channel> 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;
}
}

View File

@ -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<SocketMessage> 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<Channel> 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<Channel, Task>? ClickCon;
}

View File

@ -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<Category> cc = new();
private readonly List<Channel> LoadedChannels = new();
public Channel? Selected;
private ChannelSelector(SocketCategory Cat)
{
CurrentCategory = Cat;
Cat.Server.MessageReceived += ServerOnMessageReceived;
}
public static async Task<ChannelSelector> 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<SocketCategory> 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<Channel> 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<Category> 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;
}
}

View File

@ -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<IRenderObject> MessageObjs = new();
private Label FirstL;
public readonly double HorPadding = 12.ScaleDouble(),
VerticalPadding = 0.ScaleDouble();
private static Dictionary<MainSocketRemoteUser, List<ChatMessage>> Messages = new();
public static async Task<ChatMessage> 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<Label> Labels = new();
private async Task NewLabel_MouseLeave(IRenderObject sender)
{
if (sender is not Label label) return;
if (label.Tag is not SocketMessage Message) return;
DateTime time = (await Message.GetParent(CancellationToken.None)).Epoch.AddMilliseconds(Message.TimeStamp).ToLocalTime();
string b;
if (!Globals.Settings.DayTime) b = time.ToString("h:mm tt");
else b = time.ToString("HH:mm");
Globals.Settings.DayTimeChanged += () =>
{
if (!Globals.Settings.DayTime) b = time.ToString("h:mm tt");
else b = time.ToString("HH:mm");
return Task.CompletedTask;
};
Label[] l = Labels.Where(s => s.Text == b).ToArray();
if (l.Any())
{
Controls.Remove(l.First());
Labels.Remove(l.First());
}
Window!.TryDraw();
}
private async Task NewLabel_MouseEnter(IRenderObject sender)
{
if (sender is not Label label) return;
if (label.Tag is not SocketMessage Message) return;
DateTime time = (await Message.GetParent(CancellationToken.None)).Epoch.AddMilliseconds(Message.TimeStamp).ToLocalTime();
Label m;
if (!Globals.Settings.DayTime) m = new( Globals.SmallTimeFont)
{
Text = time.ToString("h:mm tt"),
};
else m = new( Globals.SmallTimeFont)
{
Text = time.ToString("HH:mm"),
};
Globals.Settings.DayTimeChanged += () =>
{
if (!Globals.Settings.DayTime) m.Text = time.ToString("h:mm tt");
else m.Text = time.ToString("HH:mm");
return Task.CompletedTask;
};
m.Location = new(
label.Location.X - m.Size.X - 5.ScaleInt(),
(int)(label.Location.Y + label.Font.PixelHeight - Globals.SmallTimeFont.PixelHeight),
0);
Controls.Add(m);
Labels.Add(m);
Window!.TryDraw();
}
}

View File

@ -0,0 +1,129 @@
using System.Reflection;
using GraphicsManager;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.net.Structures.Public;
using OpenTK.Windowing.Common.Input;
using Rectangle = GraphicsManager.Objects.Rectangle;
namespace Luski.GUI.MainScreen.UI.PublicServers;
public class ContentEmbed : UserControl
{
readonly SocketFile file;
public static Texture? t = null;
public static Texture? DownloadIcon = null;
long channel;
private static bool isopen;
public static async Task<IRenderObject> GetEmbed(ChatMessage m, SocketFile file, long channel)
{
if (file.Name.ToLower().EndsWith(".png") || file.Name.ToLower().EndsWith(".jpg"))
{
Stream data = await file.GetCache(CancellationToken.None);
Texture t = Globals.ms.TextureManager.AddTexture(data);
data.Dispose();
Rectangle r;
double s = 322.ScaleDouble();
double scale = s / t.RawSize!.Value.X;
m.Controls.Add(r = new Rectangle(t)
{
Size = new((int)s, (int)(scale * t.RawSize.Value.Y)),
Shader = Texture.TextureShader[Globals.ms.Context],
HoverMouse = MouseCursor.Hand,
Tag = m.pc
});
r.Clicked += ROnClicked;
return r;
}
else
{
ContentEmbed c;
m.Controls.Add(c = new ContentEmbed(file, channel));
return c;
}
}
private static Task ROnClicked(IRenderObject arg)
{
if (isopen) return Task.CompletedTask;
isopen = true;
FullScreenMedia r;
Globals.ms.Controls.Add(r = FullScreenMedia.GetDisplay(((Rectangle)arg).Textures[0]));
if (arg.Tag is PublicChat pc)
{
pc.MessageFlow.AllowHoverFromBehind = false;
r.Tag = pc;
}
r.Clicked += RrOnClicked;
Globals.ms.DrawFrame();
return Task.CompletedTask;
}
private static Task RrOnClicked(IRenderObject arg)
{
isopen = false;
Globals.ms.Controls.Remove(arg);
Globals.ms.DrawFrame();
FullScreenMedia fsm = (arg as FullScreenMedia)!;
fsm.Clicked -= RrOnClicked;
if (fsm.Tag is PublicChat pc)
{
pc.MessageFlow.AllowHoverFromBehind = true;
}
fsm.Clean();
fsm = null!;
return Task.CompletedTask;
}
public ContentEmbed(SocketFile file, long channel)
{
Label fileNameLabel, fileSizeLabel;
this.channel = channel;
this.file = file;
string fst = "";
ulong size = (ulong)file.Size;
if (size < 1000)
fst = size + " bytes";
else if (size < 1000000)
fst = Math.Round(size / (double)1000, 2) + " KB";
else if (size < 1000000000)
fst = Math.Round(size / (double)1000000, 2) + " MB";
else if (size < 1000000000000) fst = Math.Round(size / (double)1000000000, 2) + " GB";
base.Size = new(333, 66);
BackgroundColor = new(40, 40, 40, 255);
Controls.Add(fileSizeLabel = new Label(Globals.DefaultFont) { Text = fst, Location = new(64, 39, 0) });
Controls.Add(fileNameLabel = new Label(Globals.DefaultFont)
{
Color = new(102 / (float)255, 227 / (float)255, 170 / (float)255, 1), Text = file.Name,
Location = new(64, 6, 0)
});
fileNameLabel.Clicked += FileNameLabelOnClicked;
if (DownloadIcon is null)
{
Stream tempp =
Tools.GetResourceStream(Assembly.GetExecutingAssembly(), "Luski.Resources.Textures.Download.png");
DownloadIcon = Globals.ms.TextureManager.AddTexture(tempp);
tempp.Dispose();
}
Controls.Add(new Rectangle(DownloadIcon)
{ Location = new(8, 6, 0), Size = new(50, 50) });
int temp = fileNameLabel.Size.X + fileNameLabel.Location.X;
int temp2 = fileSizeLabel.Size.X + fileSizeLabel.Location.X;
//if (temp >= temp2) Size = new(temp + 4, Size.Y);
//else Size = new(temp2 + 4, Size.Y);
}
private Task FileNameLabelOnClicked(IRenderObject arg)
{
string dir = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Downloads", "LuskiDownloads");
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
//Thread t = new(() => file.DownloadBytes(Path.Join(dir, file.Name), channel, CancellationToken.None));
//t.Start();
return Task.CompletedTask;
}
}

View File

@ -0,0 +1,544 @@
using System.Reflection;
using GraphicsManager;
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using Luski.GUI.MainScreen.UI.LuskiControls;
using Luski.net.Structures.Public;
using Luski.Shared.PublicServers.V1.Enums;
using OpenTK.Graphics.ES11;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Common.Input;
using OpenTK.Windowing.GraphicsLibraryFramework;
using MatrixMode = OpenTK.Graphics.OpenGL.MatrixMode;
namespace Luski.GUI.MainScreen.UI.PublicServers;
public class PublicChat : UserControl
{
public FlowLayout MessageFlow;
private Label title, desc;
private TextBox tb;
private SocketChannel? Channel;
UserControl titlecon;
private Rectangle? UserCon;
private SocketMessage? first;
private FlowLayout? memberflow = null;
public PublicChat()
{
base.Size = new(980.ScaleInt(), 866.ScaleInt());
base.BackgroundColor = new(40,40,40,255);
Anchor = ObjectAnchor.All;
Controls.Add(MessageFlow = new()
{
Size = new(base.Size.X, 785.ScaleInt()),
Location = new(0, 52.ScaleInt(), 0),
BackgroundColor = new(40,40,40,255),
Anchor = ObjectAnchor.All,
HScrollPixels = Globals.Settings.PerScrollPixels,
});
MessageFlow.FlowUpdate += MessageFlowOnFlowUpdate;
if (LuskiExperiments.GUI.MessageLiveSize.IsEnabled()) MessageFlow.SizeChanged += OnSizeChanged;
LuskiExperiments.GUI.MessageLiveSize.EventToggled += MessageLiveSizeOnEventToggled;
Task MessageLiveSizeOnEventToggled(bool arg)
{
if (arg) MessageFlow.SizeChanged += OnSizeChanged;
else MessageFlow.SizeChanged -= OnSizeChanged;
return Task.CompletedTask;
}
Controls.Add(titlecon = new UserControl()
{
Anchor = ObjectAnchor.Left | ObjectAnchor.Top | ObjectAnchor.Right,
Size = new(980.ScaleInt(), 48.ScaleInt()),
BackgroundColor = new(50,50,50,255),
});
UserCon =
new(Globals.ms.TextureManager.GetTextureResource("person.png"))
{
Size = new(24.ScaleInt()),
Location = new(944.ScaleInt(), 12.ScaleInt(),0),
Anchor = ObjectAnchor.Right | ObjectAnchor.Top,
Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
BackgroundColor = Color4.LightGray
};
UserCon.MouseEnter += o => { UserCon.BackgroundColor = Color4.White; return Task.CompletedTask; };
UserCon.MouseLeave += o => { UserCon.BackgroundColor = Color4.LightGray; return Task.CompletedTask; };
UserCon.Clicked += UserConOnClicked;
titlecon.Controls.Add(UserCon);
titlecon.ForceDistanceUpdate(this);
titlecon.Controls.Add(title = new Label(Globals.DefaultFont)
{
//Location = new(
});
titlecon.Controls.Add(desc = new Label(Globals.DefaultFont)
{
Color = new(161,161,161,255),
Location = new(title.Location.X + title.Size.X + 5, title.Location.Y, 0)
});
Controls.Add(tb = new()
{
// InsideColor = new(28, 28, 28, 255),
//BorderColor = Color4.DarkCyan,
Location = new(10.ScaleInt(), 824.ScaleInt(), 0),
Size = new(960.ScaleInt(), 34.ScaleInt()),
Anchor = ObjectAnchor.Bottom | ObjectAnchor.Left | ObjectAnchor.Right,
HoverMouse = MouseCursor.IBeam,
//Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
//Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
BackgroundColor = Color4.Red,
TextLocation = TextLocation.LineCenter
});
tb.KeyPress += TbOnKeyPress;
tb.OnRemoveLine += TbOnOnRemoveLine;
tb.OnNewLine += TbOnOnNewLine;
tb.ForceDistanceUpdate(this);
//tb.KeyPress += TbOnKeyPress;
//Globals.Luski.MainServer.MessageReceived += LuskiOnMessageReceived;
}
private bool ssss = false;
private Task OnSizeChanged(IRenderObject arg)
{
if (ssss) return Task.CompletedTask;
ssss = true;
BlockDraw = true;
bool off = false;
for (int j = 0; j < MessageFlow.Controls.Length; j++)
{
if (MessageFlow.Controls[j] is ChatMessage cm && cm.Controls.Length != 0 && cm.Location.Y + cm.Size.Y >= 0 && !off)
{
if (cm.MessageObjs[0] is Label First)
{
First.MaxSize = new(MessageFlow.Size.X - First.Location.X - 10.ScaleInt(), Int32.MaxValue);
First.ForceDistanceUpdate(cm);
}
for (int i = 1; i < cm.MessageObjs.Count; i++)
{
cm.MessageObjs[i].Location = new(cm.MessageObjs[i].Location.X,
cm.MessageObjs[i - 1].Location.Y + cm.MessageObjs[i - 1].Size.Y,
cm.MessageObjs[i].Location.Z);
cm.MessageObjs[i].ForceDistanceUpdate(cm);
if (cm.MessageObjs[i] is Label l)
{
l.MaxSize = new(MessageFlow.Size.X - l.Location.X - 10.ScaleInt(), Int32.MaxValue);
}
}
int ny = cm.MessageObjs.Last().Size.Y + cm.MessageObjs.Last().Location.Y + (int)cm.VerticalPadding;
if (cm.Location.Y + ny > MessageFlow.Size.Y) off = true;
if (cm.Size.Y != ny)
{
cm.Size = new(Size.X, ny);
MessageFlow.ReportSizeUpdate(cm);
}
ssss = false;
}
}
BlockDraw = false;
return Task.CompletedTask;
}
private async Task MessageFlowOnFlowUpdate(bool arg1, uint arg2, uint arg3)
{
if (!loadingm && arg1 && arg3 == 0 && (arg2 != 0 || MessageFlow.MaxScrollValue == 0))
{
loadingm = true;
var messages = await Channel!.GetMessages(CancellationToken.None, first!, Globals.Settings.LoadPerChannel);
if (messages.Count == 0) return;
index = 0;
fakeIndex = false;
lastmIndex = null;
lastUserIndex = null;
LastChatMessageIndex = null;
await AddMessagesIndex(messages);
MessageFlow.ForceScrollUpdate();
first = messages.Last();
if (Globals.Settings.LoadPerChannel == messages.Count)loadingm = false;
}
}
private async Task TbOnKeyPress(KeyboardKeyEventArgs arg)
{
//var t = Matrix4.Identity * Matrix4.CreateScale(2 / (float)Size.X, 2 / (float)Size.Y, 1) * Matrix4.CreateTranslation(-1.0f, -1.0f, 0.0f);
//var tt = Matrix4.CreateOrthographicOffCenter(0.0f, Size.X, 0.0f, Size.Y, 1, -1);
if (arg.Key == Keys.Enter && !arg.Shift)
{
await Channel!.SendMessage(tb.Text);
tb.Text = string.Empty;
tb.CursorLocation = 0;
}
}
private Task TbOnOnRemoveLine()
{
BlockDraw = true;
tb.Location = new(tb.Location.X, tb.Location.Y + (int)tb.Font.PixelHeight, 0);
MessageFlow.Size = new(MessageFlow.Size.X, MessageFlow.Size.Y + (int)tb.Font.PixelHeight);
BlockDraw = false;
return Task.CompletedTask;
}
private Task TbOnOnNewLine()
{
BlockDraw = true;
tb.Location = new(tb.Location.X, tb.Location.Y - (int)tb.Font.PixelHeight, 0);
MessageFlow.Size = new(MessageFlow.Size.X, MessageFlow.Size.Y - (int)tb.Font.PixelHeight);
BlockDraw = false;
return Task.CompletedTask;
}
private bool um_open = false;
private bool SeperateOffline = true;
private async Task UserConOnClicked(IRenderObject arg)
{
um_open = !um_open;
if (um_open)
{
if (memberflow is null)
{
int x = 232.ScaleInt();
memberflow = new()
{
BackgroundColor = new(34, 34, 34, 255),
Size = new(x, Size.Y - titlecon.Size.Y),
Location = new(Size.X - x, titlecon.Size.Y, 0),
Anchor = ObjectAnchor.Top | ObjectAnchor.Right | ObjectAnchor.Bottom
};
memberflow.ForceDistanceUpdate(this);
Controls.Add(memberflow);
}
if (memberflow.Controls.Length == 0)
{
Dictionary<long, RoleView> Roles = new();
RoleView? Offline = null;
Dictionary<long, RoleView> Users = new();
foreach (var m in (await Channel!.GetMembers()))
{
Role top_role = (await m.GetRoles())[0];
if (m.Status == UserStatus.Offline && SeperateOffline)
{
if (Offline is null)
{
Offline = new();
memberflow.Controls.Add(Offline);
}
await Offline.AddUser(m, top_role);
Users.Add(m.Id, Offline);
memberflow.ReportSizeUpdate(Offline);
}
else
{
if (!Roles.ContainsKey(top_role.ID))
{
Roles.Add(top_role.ID, new(top_role));
int _index_ = 0;
for (int index_ = memberflow.Controls.Length-1; index_ >= 0; index_--)
{
RoleView r = ((RoleView)memberflow.Controls[index_]);
if (r.r is null) continue;
if (r.r.Index > top_role.Index)
{
_index_ = index_ + 1;
break;
}
}
memberflow.Controls.Insert(_index_, Roles[top_role.ID]);
}
await Roles[top_role.ID].AddUser(m, top_role);
Users.Add(m.Id, Roles[top_role.ID]);
memberflow.ReportSizeUpdate(Roles[top_role.ID]);
}
}
async Task OnServerOnStatusUpdate(UserStatus status, SocketUser user)
{
if (!SeperateOffline && !Users.ContainsKey(user.Id)) return;
Role top_role2 = (await user.GetRoles())[0];
Globals.ms.Invoke(async () =>
{
BlockDraw = true;
if (status == UserStatus.Offline && user.Status != UserStatus.Offline)
{
Offline!.RemoveUser(user.Id);
if (Offline.i == 0)
{
memberflow.Controls.Remove(Offline);
}
if (!Roles.ContainsKey(top_role2.ID))
{
Roles.Add(top_role2.ID, new(top_role2));
int _index_ = 0;
for (int index_ = memberflow.Controls.Length - 1; index_ >= 0; index_--)
{
RoleView r = ((RoleView)memberflow.Controls[index_]);
if (r.r is null) continue;
if (r.r.Index > top_role2.Index)
{
_index_ = index_ + 1;
break;
}
}
memberflow.Controls.Insert(_index_, Roles[top_role2.ID]);
}
await Roles[top_role2.ID].AddUser(user, top_role2);
memberflow.ReportSizeUpdate(Roles[top_role2.ID]);
if (Offline is not null) memberflow.ReportSizeUpdate(Offline);
Users[user.Id] = Roles[top_role2.ID];
}
if (status != UserStatus.Offline && user.Status == UserStatus.Offline)
{
Users[user.Id].RemoveUser(user.Id);
bool g = true;
if (Users[user.Id].i == 0)
{
if (Roles.ContainsKey(top_role2.ID)) Roles.Remove(top_role2.ID);
g = false;
memberflow.Controls.Remove(Users[user.Id]);
}
if (Offline is null)
{
Offline = new();
memberflow.Controls.Add(Offline);
}
await Offline.AddUser(user, top_role2);
memberflow.ReportSizeUpdate(Offline);
if (g) memberflow.ReportSizeUpdate(Users[user.Id]);
Users[user.Id] = Offline;
}
BlockDraw = false;
Globals.ms.DrawFrame();
});
}
Channel!.Server.StatusUpdate += OnServerOnStatusUpdate;
}
TryDraw();
memberflow.Visible = true;
MessageFlow.Size = new(MessageFlow.Size.X - memberflow.Size.X, MessageFlow.Size.Y);
MessageFlow.ForceDistanceUpdate(this);
tb.Size = new(tb.Size.X - memberflow.Size.X, tb.Size.Y);
tb.ForceDistanceUpdate();
}
else
{
memberflow!.Visible = false;
MessageFlow.Size = new(MessageFlow.Size.X + memberflow.Size.X, MessageFlow.Size.Y);
MessageFlow.ForceDistanceUpdate(this);
tb.Size = new(tb.Size.X + memberflow.Size.X, tb.Size.Y);
tb.ForceDistanceUpdate();
}
}
private SocketMessage? lastm;
private long? lastUser;
private bool fake = false;
public ChatMessage? LastChatMessage;
private SocketMessage? lastmIndex;
private long? lastUserIndex;
private bool fakeIndex = false;
public ChatMessage? LastChatMessageIndex;
private bool loadingm = false;
public async Task LoadChannel(SocketChannel channel)
{
Channel = channel;
BlockDraw = true;
Globals.ms.BlockDraw = true;
if (memberflow is not null)
{
await UserConOnClicked(UserCon!);
memberflow.Controls.Clear();
await UserConOnClicked(UserCon!);
}
title.Text = channel.Name;
var five = 5.ScaleInt();
title.Location = new(five + five,
(titlecon.Size.Y - ((int)(title.Font.PixelHeight * ((float)title.Font.CurrentFonts[0].Face.Height /
title.Font.CurrentFonts[0].Face.UnitsPerEM)))) / 2,
title.Location.Z);
desc.Text = channel.Description;
desc.Location = new((int)(title.Location.X + title.Size.X + five),
(titlecon.Size.Y - ((int)(desc.Font.PixelHeight * ((float)desc.Font.CurrentFonts[0].Face.Height /
desc.Font.CurrentFonts[0].Face.UnitsPerEM)))) / 2,
desc.Location.Z);
if (Window is not null)
{
Window.Title = $"{channel.Name} | {channel.Server.Name} - Luski";
}
tb.WatermarkText = $"Message {channel.Name}";
tb.Text = "";
tb.CursorLocation = 0;
tb.Focus();
Globals.ms.BlockDraw = false;
BlockDraw = false;
TryDraw();
}
public void ClearChat()
{
MessageFlow.Controls.Clear();
MessageFlow.ScrollUpdatesInterval = 33;
lastm = null;
lastUser = null;
LastChatMessage = null;
first = null;
}
public async Task AddMessages(IEnumerable<SocketMessage> messages, bool reverse = true)
{
MessageFlow.BlockDraw = true;
if (reverse)
{
foreach (SocketMessage message in messages.Reverse())
{
await AddMessage(message);
}
}
else
{
foreach (SocketMessage message in messages)
{
await AddMessage(message);
}
}
MessageFlow.BlockDraw = false;
}
public async Task AddMessagesIndex(IEnumerable<SocketMessage> messages)
{
MessageFlow.BlockDraw = true;
index = 0;
foreach (SocketMessage message in messages.Reverse())
{
await AddMessageIndex(message);
}
MessageFlow.BlockDraw = false;
}
public async Task AddMessage(SocketMessage Message, bool scrool = false)
{
if (first is null) first = Message;
bool hasbeentenmin = false;
if (lastm is not null)
{
DateTime chan = Channel!.Epoch.AddMilliseconds(lastm.ID >> 22).ToLocalTime();
hasbeentenmin =
Channel!.Epoch.AddMilliseconds(lastm.ID >> 22).ToLocalTime().AddMinutes(10) <
Channel!.Epoch.AddMilliseconds(Message.ID >> 22).ToLocalTime();
}
lastm = Message;
if (lastUser is null || lastUser != Message.AuthorID || hasbeentenmin || fake != Message.IsProfile)
{
if (Window is null || !Globals.ms.InvokeRequired)
{
MessageFlow.Controls.Add(LastChatMessage = await ChatMessage.MakeChatMessage(this, Message));
if (scrool) MessageFlow.ScrollToBottom();
}
else
{
Globals.ms.Invoke(async () =>
{
LastChatMessage = await ChatMessage.MakeChatMessage(this, Message);
MessageFlow.Controls.Add(LastChatMessage);
if (scrool) MessageFlow.ScrollToBottom();
Window.TryDraw();
});
}
}
else
{
if (Window is null || !Globals.ms.InvokeRequired)
{
await LastChatMessage!.AddMessage(Message);
if (scrool) MessageFlow.ScrollToBottom();
}
else
{
Globals.ms.Invoke(() =>
{
LastChatMessage!.AddMessage(Message);
if (scrool) MessageFlow.ScrollToBottom();
Window!.TryDraw();
});
}
}
fake = Message.IsProfile;
lastUser = Message.AuthorID;
}
private int index = 0;
public async Task AddMessageIndex(SocketMessage Message)
{
bool hasbeentenmin = false;
if (lastmIndex is not null)
hasbeentenmin =
Channel!.Epoch.AddMilliseconds(lastmIndex.ID >> 22).ToLocalTime().AddMinutes(10) <
Channel!.Epoch.AddMilliseconds(Message.ID >> 22).ToLocalTime();
lastmIndex = Message;
if (lastUserIndex is null || lastUserIndex != Message.AuthorID || hasbeentenmin || fake != Message.IsProfile)
{
if (Window is null || !Globals.ms.InvokeRequired)
{
MessageFlow.Controls.Insert(index, LastChatMessageIndex = await ChatMessage.MakeChatMessage(this, Message));
LastChatMessageIndex.LoadToParent(MessageFlow, Globals.ms);
index++;
}
else
{
LastChatMessageIndex = await ChatMessage.MakeChatMessage(this, Message);
Globals.ms.Invoke(() =>
{
MessageFlow.Controls.Insert(index, LastChatMessageIndex);
LastChatMessageIndex.LoadToParent(MessageFlow, Globals.ms);
index++;
Window.TryDraw();
});
}
}
else
{
if (Window is null || !Globals.ms.InvokeRequired)
{
await LastChatMessageIndex!.AddMessage(Message);
}
else
{
Globals.ms.Invoke(() =>
{
LastChatMessageIndex!.AddMessage(Message);
Window!.TryDraw();
});
}
}
fakeIndex = Message.IsProfile;
lastUserIndex = Message.AuthorID;
}
}

View File

@ -0,0 +1,87 @@
using System.Reflection;
using GraphicsManager;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.net;
using OpenTK.Graphics.OpenGL4;
namespace Luski.GUI.MainScreen.UI;
public class ServerIcon<TServer> : UserControl where TServer : Server
{
private Rectangle SelectedRect;
private static ServerIcon<MainServer>? ser1;
private static ServerIcon<PublicServer>? ser2;
public async Task LoadServer()
{
if (ser1 is not null)
{
ser1.SelectedRect.BackgroundColor = new(26, 26, 26, 255);
ser1 = null;
}
if (ser2 is not null)
{
ser2.SelectedRect.BackgroundColor = new(26, 26, 26, 255);
ser2 = null;
}
SelectedRect.BackgroundColor = new(255, 255, 255, 255);
Globals.UserTextureMap.Clear();
if (typeof(TServer).FullName == typeof(PublicServer).FullName)
{
ser2 = this as ServerIcon<PublicServer>;
await Globals.ms.LoadPublicServer(ser2!.Server);
}
else
{
ser1 = this as ServerIcon<MainServer>;
await Globals.ms.LoadMainServer(ser1!.Server);
}
}
public ServerIcon(TServer Server)
{
Rectangle r = new(Globals.ms.TextureManager.GetTextureResource("rc.png"))
{
Location = new(18.ScaleInt(), 8.ScaleInt(), 0),
Size = new(32.ScaleInt()),
Shader = Rectangle.DefaultAlphaTextureShader[Globals.ms.Context],
IgnoreHover = true
};
Rectangle rr = new(r.Textures[0])
{
Location = new(17.ScaleInt(), 7.ScaleInt(), 0),
Size = new(34.ScaleInt()),
Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
BackgroundColor = new(26, 26, 26, 255),
IgnoreHover = true
};
SelectedRect = new(r.Textures[0])
{
Location = new(14.ScaleInt(), 4.ScaleInt(), 0),
Size = new(40.ScaleInt()),
Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
BackgroundColor = new(26, 26, 26, 255),
IgnoreHover = true
};
this.Server = Server;
Texture t = Globals.ms.TextureManager.AddTexture(Server.GetAvatar(CancellationToken.None).Result);
t.Unit = TextureUnit.Texture1;
r.Textures.Add(t);
Controls.Add(SelectedRect);
Controls.Add(rr);
Controls.Add(r);
base.BackgroundColor = new(26, 26, 26, 255);
this.Clicked += OnClicked;
base.Size = new(68.ScaleInt(), 48.ScaleInt());
}
private async Task OnClicked(IRenderObject arg)
{
await LoadServer();
}
public TServer Server { get; }
}

View File

@ -0,0 +1,592 @@
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 ServerLoginOverlay : UserControl, IServerOverlay
{
private UserControl Form, btn;
private DropDown<VersionDropButton> version;
public AccountButton? Selected { get; set; }
public UserControl page { get; set; }
private TextBox? UserName, Password, DisplayName, tb;
private Rectangle? rec;
public ServerLoginOverlay(string address)
{
base.Size = Globals.ms.ClientSize;
base.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 = "Server Login", 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,
Text = address,
WatermarkText = "Server Address",
TextLocation = TextLocation.LineCenter,
AllowMultiLine = false
};
tb.Textures[0] = Globals.ms.TextureManager.GetTextureResource("Textbox.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<VersionDropButton>(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);
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
};
_ = lo.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
};
IEnumerable<PublicServer> sers = Globals.Luski.LoadedServers.Where(s => s.Domain == tb.Text);
if (sers.Any())
{
bool g;
PublicServer ps = sers.First();
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.LoadPublicServer(ps);
Globals.ms.TryDraw();
return;
}
}
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;
}
}

View File

@ -0,0 +1,452 @@
using System.ComponentModel;
using System.Reflection;
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.Classes;
using Luski.GUI.MainScreen.UI.LuskiControls;
using Luski.GUI.MainScreen.UI.SettingsPanel;
using OpenTK.Mathematics;
namespace Luski.GUI.MainScreen.UI;
public class SettingsMenu : UserControl
{
private string BehindName;
public FlowLayout page;
public CategoryButton? Selected, apper;
private FlowLayout fl;
private Category? AppSettings;
private FontInteraction f;
private DropDown<ThemeDropButton> ThemeDrop;
public SettingsMenu()
{
LuskiExperiments.Settings.Theme.EventToggled += ThemeOnEventToggled;
BehindName = Globals.ms.Title;
Globals.ms.Title = "Settings - Luski";
base.BackgroundColor = new(34, 34, 34, 255);
base.Size = Globals.ms.ClientSize;
Anchor = ObjectAnchor.All;
if (CategoryButton.seltec is null)
{
CategoryButton.seltec = Globals.ms.TextureManager.GetTextureResource("RoundedRectangle.png");
}
fl = new()
{
BackgroundColor = new(20, 20, 20, 255),
Size = new(307.ScaleInt(), base.Size.Y),
Anchor = ObjectAnchor.Top | ObjectAnchor.Left | ObjectAnchor.Bottom
};
f = Globals.DefaultFont.Clone();
f.FontSize = FontSize.Bold;
f.PixelHeight = (uint)(f.PixelHeight * 1.4f);
AppSettings = new("APP SETTINGS");
CategoryButton cb3 = new("General", this)
{
OnPageLoad = () =>
{
page!.Controls.Add(new Label(f)
{
Text = " \nGeneral\n "
});
foreach (PropertyInfo prop in typeof(Settings).GetProperties())
{
object PropVal = prop.GetValue(Globals.Settings)!;
Type PropType = prop.PropertyType;
if (PropType.IsEnum)
{
IEnumerable<Enum> values = Enum.GetValues(PropType).Cast<Enum>();
foreach (var val in values)
{
try
{
MemberInfo[] memberInfos =
PropType.GetMember(val.ToString());
MemberInfo? enumValueMemberInfo = memberInfos.FirstOrDefault(m =>
m.DeclaringType == PropType);
object[] valueAttributes =
enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (valueAttributes.Length == 0) continue;
string description = ((DescriptionAttribute)valueAttributes[0]).Description;
AddBool(description, ((Enum)PropVal).HasFlag(val), bb =>
{
long va = Convert.ToInt64(val);
long v = Convert.ToInt64(PropVal);
if (bb)
{
object e = Enum.Parse(PropType, (v + va).ToString());
PropVal = e;
prop.SetValue(Globals.Settings, e);
}
else
{
var e = Enum.Parse(PropType, (v - va).ToString());
PropVal = e;
prop.SetValue(Globals.Settings, e);
}
Globals.Settings.SaveSettings(Path.Combine(Globals.LuskiPath, "Settings.json"), SettingsContext.Default.Settings);
});
}
catch
{
//ignore
}
}
}
if (PropType.FullName == typeof(bool).FullName)
{
try
{
object[] valueAttributes =
prop.GetCustomAttributes(typeof(DescriptionAttribute), false);
string description = ((DescriptionAttribute)valueAttributes[0]).Description;
AddBool(description, (bool)PropVal, b =>
{
prop.SetValue(Globals.Settings, b);
Globals.Settings.SaveSettings(Path.Combine(Globals.LuskiPath, "Settings.json"), SettingsContext.Default.Settings);
});
}
catch
{
// ignored
}
}
}
}
};
AppSettings.AddButton(cb3);
fl.Controls.Add(AppSettings);
if (LuskiExperiments.Settings.Theme.IsEnabled())
{
Label Top = new(Globals.DefaultFont)
{
Location = new(5.ScaleInt(), 5.ScaleInt(), 0),
Text = LuskiThemes.Dark.Name
};
CategoryButton cb2 = new("Appearance", this)
{
OnPageLoad = () =>
{
page!.Controls.Add(new Label(f)
{
Text = " \nAppearance\n "
});
ThemeDropButton LightDD;
ThemeDrop = new(CategoryButton.seltec!,new Rectangle()
{
Size = new(base.Size.X - 2, 1.ScaleInt()),
BackgroundColor = Color4.Gray,
Location = new(1, base.Size.Y - 1.ScaleInt(), 0),
Anchor = ObjectAnchor.Left | ObjectAnchor.Right | ObjectAnchor.Bottom
}, LightDD = new(LuskiThemes.Light)
{
LoadDisplay = () =>
{
Label ll = new Label(Globals.DefaultFont)
{
Text = LuskiThemes.Light.Name,
Color = Color4.DarkGray,
IgnoreHover = true
};
ll.Location = new(10.ScaleInt(),
((ThemeDrop.Size.Y - ll.Size.Y) / 2)
, 0);
ThemeDrop.Controls.Add(ll);
},
Size = new(297.ScaleInt(), 40.ScaleInt()),
}){DropDownParentOverride = Globals.ms,Size = new(40.ScaleInt()),
Location = new(Top.Location.X, Top.Location.Y, 0),
BackgroundColor = new(40, 40, 40, 255),
Anchor = ObjectAnchor.Right | ObjectAnchor.Left,};
foreach (ThemeStart themeStart in LuskiThemes.LuskiThemeList)
{
if (themeStart.Name == LuskiThemes.Light.Name) continue;
ThemeDropButton tdb;
ThemeDrop.AddOption(tdb = new(themeStart)
{
LoadDisplay = () =>
{
Label ll = new Label(Globals.DefaultFont)
{
Text = themeStart.Name,
Color = Color4.DarkGray,
IgnoreHover = true
};
ll.Location = new(10.ScaleInt(),
((ThemeDrop.Size.Y - ll.Size.Y) / 2)
, 0);
ThemeDrop.Controls.Add(ll);
},
Size = new(297.ScaleInt(), 40.ScaleInt()),
});
if (themeStart.Name == Globals.Settings.Theme) ThemeDrop.SetSelected(tdb);
}
ThemeDrop.DropDownContainer.Textures.Add(Globals.ms.TextureManager.GetTextureResource("RoundedRectangleBottom.png"));
ThemeDrop.DropDownContainer.TextureDisplay = TextureDisplay.Center;
ThemeDrop.DropDownContainer.Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context];
ThemeDrop.DropDownContainer.BackgroundColor = ThemeDrop.BackgroundColor;
Rectangle line = new()
{
Size = new(base.Size.X - 2, 1.ScaleInt()),
BackgroundColor = Color4.Gray,
Location = new(1, base.Size.Y - 1.ScaleInt(), 0),
Anchor = ObjectAnchor.Left | ObjectAnchor.Right | ObjectAnchor.Bottom
};
ThemeDrop.OpenStatusChanged += b =>
{
BlockDraw = true;
Size = new(base.Size.X, base.Size.Y + ( b ? ThemeDrop.DropDownContainer.Size.Y : -1 * ThemeDrop.DropDownContainer.Size.Y));
line!.Location = new(line.Location.X,
line.Location.Y + (b ? ThemeDrop.DropDownContainer.Size.Y : -1 * ThemeDrop.DropDownContainer.Size.Y), 0);
if (b)
{
ThemeDrop.Textures[0] = Globals.ms.TextureManager.GetTextureResource("RoundedRectangleTop.png");
}
else
{
ThemeDrop.Textures[0] = CategoryButton.seltec!;
}
BlockDraw = false;
return Task.CompletedTask;
};
page!.Controls.Add(ThemeDrop);
}
};
AppSettings.AddButton(cb2);
fl.Controls.Insert(0, AppSettings);
fl.ScrollToBottom();
}
page = new()
{
BackgroundColor = this.BackgroundColor,
Location = new(fl.Size.X + 40.ScaleInt(), 0, 0),
Size = new(Globals.ms.ClientSize.X - fl.Size.X - 80.ScaleInt(), Globals.ms.Size.Y),
AllowHoverFromBehind = true,
Anchor = ObjectAnchor.All,
HScrollPixels = Globals.Settings.PerScrollPixels
};
Controls.Add(page);
void AddBool(string Name, bool s, Action<bool> a)
{
ToggleSwitch ts = new()
{
Value = s
};
UserControl tc = new()
{
Size = ts.Size,
BackgroundColor = page.BackgroundColor
};
Label l;
tc.Controls.Add(l =new Label(Globals.DefaultFont)
{
Text = Name + ": "
});
tc.Size = l.Size;
tc.Controls.Add(ts);
ts.Location = new(l.Size.X + 10.ScaleInt(), 0, 0);
ts.ValueChanged += @switch =>
{
a.Invoke(@switch .Value);
return Task.CompletedTask;
};
page.Controls.Add(tc);
}
page.ForceDistanceUpdate(this);
Category As = new("ADVANCED SETTINGS");
CategoryButton cb = new("Experiments", this)
{
OnPageLoad = () =>
{
page!.Controls.Add(new Label(f)
{
Text = " \nExperiments\n "
});
ExperimentGUI? g = null;
foreach (ExperimentInfo exp in Globals.Experiments)
{
g = new(exp);
page.Controls.Add(g);
}
if (g is not null)
{
g.line.WindowLoaded += _ =>
{
page.ParentResize(new(Globals.ms.ClientSize));
return Task.CompletedTask;
};
}
}
};
CategoryButton us = new("Updater Config", this)
{
OnPageLoad = () =>
{
page!.Controls.Add(new Label(f)
{
Text = " \nUpdater Config\n "
});
TextBox t;
page!.Controls.Add(t =new TextBox()
{
Text = Globals.UpdaterSettings.Updater!,
WatermarkText = "Updater File",
TextureDisplay = TextureDisplay.Center,
Size = new(page.Size.X, 34.ScaleInt()),
TextLocation = TextLocation.LineCenter,
AllowMultiLine = false
});
foreach (PropertyInfo prop in typeof(UpdaterSettings).GetProperties())
{
object PropVal = prop.GetValue(Globals.UpdaterSettings)!;
Type PropType = prop.PropertyType;
if (PropType.IsEnum)
{
IEnumerable<Enum> values = Enum.GetValues(PropType).Cast<Enum>();
foreach (var val in values)
{
try
{
MemberInfo[] memberInfos =
PropType.GetMember(val.ToString());
MemberInfo? enumValueMemberInfo = memberInfos.FirstOrDefault(m =>
m.DeclaringType == PropType);
object[] valueAttributes =
enumValueMemberInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (valueAttributes.Length == 0) continue;
string description = ((DescriptionAttribute)valueAttributes[0]).Description;
AddBool(description, ((Enum)PropVal).HasFlag(val), bb =>
{
long va = Convert.ToInt64(val);
long v = Convert.ToInt64(PropVal);
if (bb)
{
object e = Enum.Parse(PropType, (v + va).ToString());
PropVal = e;
prop.SetValue(Globals.Settings, e);
}
else
{
var e = Enum.Parse(PropType, (v - va).ToString());
PropVal = e;
prop.SetValue(Globals.Settings, e);
}
Globals.UpdaterSettings.SaveSettings(Path.Combine(Globals.LuskiPath, "UpdaterSettings.json"), UpdaterSettingsContext.Default.UpdaterSettings);
});
}
catch
{
//ignore
}
}
}
if (PropType.FullName == typeof(bool).FullName)
{
try
{
object[] valueAttributes =
prop.GetCustomAttributes(typeof(DescriptionAttribute), false);
string description = ((DescriptionAttribute)valueAttributes[0]).Description;
AddBool(description, (bool)PropVal, b =>
{
prop.SetValue(Globals.Settings, b);
Globals.UpdaterSettings.SaveSettings(Path.Combine(Globals.LuskiPath, "UpdaterSettings.json"), UpdaterSettingsContext.Default.UpdaterSettings);
});
}
catch
{
// ignored
}
}
}
t.ForceDistanceUpdate(page);
t.KeyPress += args =>
{
Globals.UpdaterSettings.Updater = t.Text;
Globals.UpdaterSettings.SaveSettings(Path.Combine(Globals.LuskiPath, "UpdaterSettings.json"), UpdaterSettingsContext.Default.UpdaterSettings);
return Task.CompletedTask;
};
Globals.ms.ForceUpdate(new(Globals.ms.ClientSize));
}
};
As.AddButton(cb);
As.AddButton(us);
fl.Controls.Add(As);
fl.ForceDistanceUpdate(this);
_ = cb3.ToggleSelected();
Rectangle closebtn = new(Globals.ms.TextureManager.GetTextureResource("close.png"))
{
Location = new(Globals.ms.ClientSize.X - 40.ScaleInt(), 8.ScaleInt(),0),
Size = new(32.ScaleInt()),
Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context],
BackgroundColor = Color4.Gray,
Anchor = ObjectAnchor.Top | ObjectAnchor.Right
};
closebtn.MouseEnter += _ =>
{
closebtn.BackgroundColor = Color4.White;
return Task.CompletedTask;
};
closebtn.MouseLeave += _ =>
{
closebtn.BackgroundColor = Color4.Gray;
return Task.CompletedTask;
};
closebtn.Clicked += ClosebtnOnClicked;
closebtn.ForceDistanceUpdate(this);
Controls.Add(closebtn);
Controls.Add(fl);
}
private Task ThemeOnEventToggled(bool arg)
{
if (arg)
{
apper = new("Appearance", this)
{
OnPageLoad = () =>
{
page.Controls.Add(new Label(f)
{
Text = " \nAppearance\n "
});
}
};
AppSettings!.AddButton(apper);
fl.ScrollToBottom();
}
else
{
AppSettings!.RemoveButton(apper);
}
return Task.CompletedTask;
}
private Task ClosebtnOnClicked(IRenderObject arg)
{
Globals.ms.Controls.Remove(this);
Globals.ms.Title = BehindName;
Globals.ms.DrawFrame();
return Task.CompletedTask;
}
}

View File

@ -0,0 +1,65 @@
using GraphicsManager.Enums;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using OpenTK.Mathematics;
namespace Luski.GUI.MainScreen.UI.SettingsPanel;
public class Category : UserControl
{
private Label Top;
private static FontInteraction? fi;
private Rectangle line;
public string Name
{
get => Top.Text;
}
public Category(string Name)
{
if (fi is null)
{
fi = Globals.DefaultFont.Clone();
fi.FontSize = FontSize.Bold;
}
Top = new(fi)
{
Location = new(5.ScaleInt(), 5.ScaleInt(), 0),
Text = Name
};
BackgroundColor = new(255, 255, 255, 0);
base.Size = new(307.ScaleInt(), 20.ScaleInt() + Top.Size.Y);
Top.Location = new((base.Size.X - Top.Size.X) / 2, Top.Location.Y, 0);
line = new()
{
Size = new(base.Size.X, 1.ScaleInt()),
BackgroundColor = Color4.Gray,
Location = new(0, base.Size.Y - 1.ScaleInt(), 0)
};
line.ForceDistanceUpdate(this);
Controls.Add(line);
Controls.Add(Top);
}
public void AddButton(CategoryButton cb)
{
Controls.Add(cb);
int f = 5.ScaleInt();
cb.Location = new (line.Location.X + f, line.Location.Y - f, 0);
line.Location = new(line.Location.X, line.Location.Y + cb.Size.Y + f, 0);
Size = new(Size.X, Size.Y + cb.Size.Y + f);
}
public void RemoveButton(CategoryButton cb)
{
int f = 5.ScaleInt();
line.Location = new(line.Location.X, line.Location.Y - cb.Size.Y - f, 0);
Controls.Remove(cb);
Size = new(Size.X, Size.Y - cb.Size.Y + f);
for (int i = 0; i < Controls.Length; i++)
{
ReportSizeUpdate(Controls[i]);
}
TryDraw();
}
}

View File

@ -0,0 +1,96 @@
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using OpenTK.Mathematics;
namespace Luski.GUI.MainScreen.UI.SettingsPanel;
public class CategoryButton : UserControl
{
public static Texture? seltec = null;
private SettingsMenu SM;
private Label l;
public required Action OnPageLoad;
public CategoryButton(string Text, SettingsMenu SM)
:base(seltec)
{
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(5.ScaleInt(),
((base.Size.Y - l.Size.Y) / 2)
, 0);
Controls.Add(l);
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;
Globals.ms.Title = $"Settings | {l.Text} - Luski";
SM.page.Controls.Clear();
OnPageLoad.Invoke();
}
BlockDraw = false;
TryDraw();
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}

View File

@ -0,0 +1,55 @@
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.Classes;
using Luski.GUI.MainScreen.UI.LuskiControls;
using OpenTK.Mathematics;
namespace Luski.GUI.MainScreen.UI.SettingsPanel;
public class ExperimentDropButton : DropDownOption
{
private Label l, d;
public ExperimentSelectorInfo ESI;
public ExperimentDropButton(ExperimentSelectorInfo esi)
:base(CategoryButton.seltec!)
{
ESI = esi;
base.Size = new(297.ScaleInt(), 40.ScaleInt());
TextureDisplay = TextureDisplay.HorizontalCenter;
Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context];
l = new Label(Globals.DefaultFont)
{
Text = esi.Name,
Color = Color4.DarkGray,
IgnoreHover = true
};
l.Location = new(10.ScaleInt(),
((base.Size.Y - l.Size.Y) / 2)
, 0);
d = new(Globals.MessageFont)
{
Text = esi.Description,
Color = Color4.Gray,
IgnoreHover = true
};
d.Location = new(l.Location.X + l.Size.X + l.Location.X,
l.Location.Y + (int)l.Font.PixelHeight - (int)d.Font.PixelHeight
, 0);
Controls.Add(d);
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;
};
}
}

View File

@ -0,0 +1,163 @@
using GraphicsManager.Enums;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.Classes;
using Luski.GUI.MainScreen.UI.LuskiControls;
using OpenTK.Mathematics;
namespace Luski.GUI.MainScreen.UI.SettingsPanel;
public class ExperimentGUI : UserControl
{
private Label Top;
public Rectangle line;
public DropDown<ExperimentDropButton> dd;
private static Texture? TopOpen, BottomOpen;
private ExperimentSelectorInfo? currentEnabled;
private static ExperimentSelectorInfo DisabledESI = new()
{
Name = "Disabled"
};
public string Name
{
get => Top.Text;
}
public ExperimentGUI(ExperimentInfo ei)
{
TextureDisplay = TextureDisplay.Center;
if (TopOpen is null)
{
TopOpen = Globals.ms.TextureManager.GetTextureResource("RoundedRectangleTop.png");
}
if (BottomOpen is null)
{
BottomOpen = Globals.ms.TextureManager.GetTextureResource("RoundedRectangleBottom.png");
}
Top = new(Globals.DefaultFont)
{
Location = new(5.ScaleInt(), 5.ScaleInt(), 0),
Text = ei.DisplayName
};
Label n = new(Globals.MessageFont)
{
Text = ei.Name,
Location = new(Top.Location.X, Top.Location.Y + Top.Size.Y + Top.Location.Y, 0),
Color = Color4.Gray
};
Controls.Add(n);
BackgroundColor = new(255, 255, 255, 0);
ExperimentDropButton Disabled = new(DisabledESI)
{
LoadDisplay = () =>
{
Label ll = new Label(Globals.DefaultFont)
{
Text = DisabledESI.Name,
Color = Color4.DarkGray,
IgnoreHover = true
};
ll.Location = new(10.ScaleInt(),
((dd!.Size.Y - ll.Size.Y) / 2)
, 0);
dd.Controls.Add(ll);
},
Size = new(297.ScaleInt(), 40.ScaleInt())
};
dd = new(CategoryButton.seltec!, new Rectangle()
{
Size = new(1.ScaleInt()),
BackgroundColor = Color4.Gray
}, Disabled)
{
Size = new(40.ScaleInt()),
Location = new(Top.Location.X, n.Location.Y + n.Size.Y + Top.Location.Y, 0),
BackgroundColor = new(40, 40, 40, 255),
Anchor = ObjectAnchor.Right | ObjectAnchor.Left,
DropDownParentOverride = this
};
dd.DropDownContainer.Textures.Add(BottomOpen);
dd.DropDownContainer.TextureDisplay = TextureDisplay.Center;
dd.DropDownContainer.Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context];
dd.DropDownContainer.BackgroundColor = dd.BackgroundColor;
dd.OpenStatusChanged += b =>
{
BlockDraw = true;
Size = new(base.Size.X, base.Size.Y + ( b ? dd.DropDownContainer.Size.Y : -1 * dd.DropDownContainer.Size.Y));
line!.Location = new(line.Location.X,
line.Location.Y + (b ? dd.DropDownContainer.Size.Y : -1 * dd.DropDownContainer.Size.Y), 0);
if (b)
{
dd.Textures[0] = TopOpen;
}
else
{
dd.Textures[0] = CategoryButton.seltec!;
}
BlockDraw = false;
return Task.CompletedTask;
};
int i = -1;
foreach (ExperimentSelectorInfo o in ei.Options)
{
i++;
ExperimentDropButton oo = new ExperimentDropButton(o)
{
Tag = i,
LoadDisplay = () =>
{
Label ll = new Label(Globals.DefaultFont)
{
Text = o.Name,
Color = Color4.DarkGray,
IgnoreHover = true
};
ll.Location = new(10.ScaleInt(),
((dd.Size.Y - ll.Size.Y) / 2)
, 0);
dd.Controls.Add(ll);
}
};
dd.AddOption(oo);
if (o.IsEnabled())
{
dd.SetSelected(oo);
currentEnabled = o;
}
}
dd.OptionSelected += DdOnOptionSelected;
Controls.Add(dd);
base.Size = new(Globals.ms.ClientSize.X - 307.ScaleInt() - 80.ScaleInt(), 15.ScaleInt() + dd.Size.Y + dd.Location.Y );
dd.Size = new(base.Size.X - Top.Location.X - Top.Location.X, dd.Size.Y);
dd.ForceDistanceUpdate(this);
line = new()
{
Size = new(base.Size.X - 2, 1.ScaleInt()),
BackgroundColor = Color4.Gray,
Location = new(1, base.Size.Y - 1.ScaleInt(), 0),
Anchor = ObjectAnchor.Left | ObjectAnchor.Right | ObjectAnchor.Bottom
};
line.ForceDistanceUpdate(this);
Controls.Add(line);
Controls.Add(Top);
}
private Task DdOnOptionSelected(ExperimentDropButton arg)
{
if (arg.ESI == DisabledESI)
{
currentEnabled!.Toggle();
currentEnabled = null;
}
else
{
currentEnabled = arg.ESI;
arg.ESI.Toggle();
}
return Task.CompletedTask;
}
}

View File

@ -0,0 +1,55 @@
using GraphicsManager.Enums;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.Classes;
using Luski.GUI.MainScreen.UI.LuskiControls;
using OpenTK.Mathematics;
namespace Luski.GUI.MainScreen.UI.SettingsPanel;
public class ThemeDropButton : DropDownOption
{
private Label l, d;
public ThemeStart ESI;
public ThemeDropButton(ThemeStart esi)
:base(CategoryButton.seltec!)
{
ESI = esi;
base.Size = new(297.ScaleInt(), 40.ScaleInt());
TextureDisplay = TextureDisplay.HorizontalCenter;
Shader = Rectangle.DefaultAlphaShader[Globals.ms.Context];
l = new Label(Globals.DefaultFont)
{
Text = esi.Name,
Color = Color4.DarkGray,
IgnoreHover = true
};
l.Location = new(10.ScaleInt(),
((base.Size.Y - l.Size.Y) / 2)
, 0);
d = new(Globals.MessageFont)
{
Text = esi.Description,
Color = Color4.Gray,
IgnoreHover = true
};
d.Location = new(l.Location.X + l.Size.X + l.Location.X,
l.Location.Y + (int)l.Font.PixelHeight - (int)d.Font.PixelHeight
, 0);
Controls.Add(d);
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;
};
}
}

View File

@ -0,0 +1,433 @@
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using GraphicsManager.Enums;
using GraphicsManager.Globals;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.GUI.MainScreen.UI;
using Luski.GUI.MainScreen.UI.PublicServers;
using Luski.net;
using Luski.net.Structures.Public;
using OpenTK.Graphics.GL;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
using DebugProc = OpenTK.Graphics.OpenGL4.DebugProc;
using DebugSeverity = OpenTK.Graphics.OpenGL4.DebugSeverity;
using DebugSource = OpenTK.Graphics.OpenGL4.DebugSource;
using DebugType = OpenTK.Graphics.OpenGL4.DebugType;
using Window = GraphicsManager.Window;
namespace Luski.GUI;
public class MainScreenWindow : Window
{
public static readonly NativeWindowSettings Settings = new()
{
Title = "Luski",
WindowBorder = WindowBorder.Resizable,
APIVersion = new Version(3, 2),
API = ContextAPI.OpenGL,
StartFocused = true,
Size = new Vector2i(624, 1090),
Icon = Globals.Icon,
SharedContext = null,
};
public TabControl? tc;
private FlowLayout? channelpicker, friends, friend_request;
private RoundedButton? FriendManagerBtn;
private static DebugProc DebugMessageDelegate = OnDebugMessage;
private static void OnDebugMessage(
DebugSource source, // Source of the debugging message.
DebugType type, // Type of the debugging message.
int id, // ID associated with the message.
DebugSeverity severity, // Severity of the message.
int length, // Length of the string in pMessage.
IntPtr pMessage, // Pointer to message string.
IntPtr pUserParam) // The pointer you gave to OpenGL, explained later.
{
string message = Marshal.PtrToStringAnsi(pMessage, length);
switch (severity)
{
case DebugSeverity.DebugSeverityHigh:
if ((Globals.Settings.Logs & ConsoleLog.BigErrosForOpenGL) == ConsoleLog.BigErrosForOpenGL)
{
Console.ForegroundColor = ConsoleColor.DarkRed;
Console.WriteLine("[{0} source={1} type={2} id={3}] {4}", severity, source, type, id, message);
Console.ResetColor();
}
break;
case DebugSeverity.DebugSeverityMedium:
if ((Globals.Settings.Logs & ConsoleLog.MediumErrosForOpenGL) == ConsoleLog.MediumErrosForOpenGL)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("[{0} source={1} type={2} id={3}] {4}", severity, source, type, id, message);
Console.ResetColor();
}
break;
case DebugSeverity.DebugSeverityLow:
if ((Globals.Settings.Logs & ConsoleLog.LowErrosForOpenGL) == ConsoleLog.LowErrosForOpenGL)
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine("[{0} source={1} type={2} id={3}] {4}", severity, source, type, id, message);
Console.ResetColor();
}
break;
default:
if ((Globals.Settings.Logs & ConsoleLog.InfoForOpenGL) == ConsoleLog.InfoForOpenGL)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(message);
Console.ResetColor();
}
break;
}
}
public MainScreenWindow() : base(Settings)
{
Globals.ms = this;
Size = new(1332.ScaleInt(), 866.ScaleInt());
ShowMissingChar = true;
LogFrames = ((Globals.Settings.Logs & ConsoleLog.DrawFrames) == ConsoleLog.DrawFrames);
VSync = VSyncMode.On;
GL.DebugMessageCallback(DebugMessageDelegate, IntPtr.Zero);
GL.Enable(EnableCap.DebugOutput);
try
{
Globals.DefaultFontFamly = FontFamily.LoadFontFamily(Globals.GetResource("Fonts.OpenSans.zip"), "OpenSans");
Globals.DefaultFont = FontInteraction.Load(Globals.DefaultFontFamly);
string fams = Path.Combine(Globals.LuskiPath, "FontFamilies");
if (!Directory.Exists(fams)) Directory.CreateDirectory(fams);
DirectoryInfo di = new DirectoryInfo(fams);
foreach (FileInfo fam in di.GetFiles())
{
try
{
if (fam.FullName.ToLower().EndsWith(".zip"))
Globals.DefaultFont.AddFamily(FontFamily.LoadFontFamily(File.Open(fam.FullName, FileMode.Open), fam.Name));
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
Globals.DefaultFont.PixelHeight = Globals.Settings.DefaultFontPX.ScaleFont();
Globals.DefaultFont.FontSize = FontSize.Regular;
Globals.TopTimeFont = Globals.DefaultFont.Clone();
Globals.TopTimeFont.PixelHeight = Globals.Settings.TopTimeFonttPX.ScaleFont();
Globals.TopTimeFont.FontSize = FontSize.Regular;
Globals.MessageFont = Globals.DefaultFont.Clone();
Globals.MessageFont.PixelHeight = Globals.Settings.MessageFontPX.ScaleFont();
Globals.MessageFont.ExtraLinePixels = Globals.Settings.MessageFontLineSpacePX.ScaleFont();
Globals.MessageFont.FontSize = FontSize.Regular;
Globals.SmallTimeFont = Globals.DefaultFont.Clone();
Globals.SmallTimeFont.PixelHeight = ((uint)11).ScaleFont();
Globals.LuskiTexture = TextureManager.GetTextureResource("Luski.png");
try
{
CenterWindow(Globals.Settings.Display);
}
catch (Exception e)
{
CenterWindow();
}
WindowLoaded += OnWindowLoaded;
}
private async Task OnWindowLoaded(Window arg)
{
if (Globals.UpdaterSettings.AutoUpdateCheck && new HttpClient()
.GetAsync(
$"https://www.jacobtech.com/Updater/GetProgramVersion?directory=Luski&branch=main&selfcontained={Globals.UpdaterSettings.SelfContained.ToString().ToLower()}&platform={Globals.UpdaterSettings.Platform}")
.Result.Content.ReadAsStringAsync().Result !=
FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion)
{
var update = new UpdateWindow();
var result = update.ShowDialogue(this);
if (result == UpdateWindow.DialogueResult.Yes)
{
Globals.Download = true;
Close();
}
}
await LoginOnChangeToApp();
}
public FlowLayout ser;
private UserControl? SerBox;
public PublicChat pc;
public async Task LoadPublicServer(PublicServer? Server)
{
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.Multisample);
GL.DepthFunc(DepthFunction.Always);
if (Server is null) return;
if (!Server.IsLogedIn)
{
ServerLoginOverlay SLO = new(Server.Domain);
Controls.Add(SLO);
ForceUpdate(new(ClientSize));
Globals.PrintParent(this);
return;
}
BlockDraw = true;
try
{
#region Box Init
if (SerBox is null)
{
SerBox = new()
{
Location = new(ser.Size.X, 0, 0),
Size = new(Size.X - ser.Size.X, ClientSize.Y),
Anchor = ObjectAnchor.All,
BackgroundColor = new(20, 20, 20, 255)
};
Controls.Add(SerBox);
SerBox.LoadToParent(this, this);
}
SerBox.Controls.Clear();
#endregion
#region Channel Selector Init
SocketChannel current_channel = await Server.User.GetSelectedChannel(CancellationToken.None);
List<SocketCategory> parents = new();
SocketCategory? cur = await current_channel.GetParent();
while (cur is not null)
{
parents.Add(cur);
cur = await cur.GetParent();
}
parents.Reverse();
ChannelSelector cs = await ChannelSelector.MakeSelector(parents[0]);
cs.BackgroundColor = new(34, 34, 34, 255);
cs.Size = new(307.ScaleInt(), SerBox.Size.Y - 54.ScaleInt());
cs.Anchor = ObjectAnchor.Top | ObjectAnchor.Left | ObjectAnchor.Bottom;
parents.RemoveAt(0);
SerBox.Controls.Add(cs);
cs.ForceDistanceUpdate(SerBox);
#endregion
#region Chat Init
pc = new()
{
Anchor = ObjectAnchor.All,
Location = new(cs.Size.X, 0, 0),
Size = new(SerBox.Size.X - cs.Size.X, SerBox.Size.Y),
};
SerBox.Controls.Add(pc);
pc.LoadToParent(SerBox, this);
pc.ForceDistanceUpdate();
pc.MessageFlow.ForceDistanceUpdate(pc);
#endregion
#region Channel Selector Loader
_ = cs.Load(current_channel, parents);
#endregion
#region User Icon
Role[] ra = await Server.User.GetRoles();
Color c = ra[0].Color;
Color4 c4 = new(c.R, c.G, c.B, c.A);
IRenderObject u = await Server.User.MakeRct(new(46.ScaleInt()), false);
int ii = 4.ScaleInt();
u.Location = new(ii, cs.Size.Y + ii, 0);
u.Anchor = ObjectAnchor.Bottom | ObjectAnchor.Left;
SerBox.Controls.Add(u);
u.LoadToParent(SerBox, this);
u.ForceDistanceUpdate();
Label ul = new Label(Globals.DefaultFont)
{
Anchor = u.Anchor,
Text = Server.User.DisplayName,
Color = c4
};
ul.Location = new(u.Location.X + u.Size.X + 5.ScaleInt(),
(u.Location.Y + ((u.Size.Y - ul.Size.Y) / 2)), 0);
SerBox.Controls.Add(ul);
Rectangle setting = new(TextureManager.GetTextureResource("settings.png"))
{
Location = new(cs.Size.X - 40.ScaleInt(), cs.Size.Y + 11.ScaleInt(),0),
Size = new(32.ScaleInt()),
Shader = Rectangle.DefaultAlphaShader[Context],
BackgroundColor = Color4.Gray,
Anchor = ObjectAnchor.Bottom | ObjectAnchor.Left
};
setting.MouseEnter += o =>
{
setting.BackgroundColor = Color4.White;
return Task.CompletedTask;
};
setting.MouseLeave += o =>
{
setting.BackgroundColor = Color4.Gray;
return Task.CompletedTask;
};
setting.Clicked += SettingOnClicked;
setting.ForceDistanceUpdate(SerBox);
SerBox.Controls.Add(setting);
ForceUpdate(new (Size));
TryDraw();
#endregion
}
catch (Exception e)
{
Console.WriteLine(e);
}
BlockDraw = false;
}
private Task SettingOnClicked(IRenderObject arg)
{
SettingsMenu sm = new();
Controls.Add(sm);
Globals.ms.DrawFrame();
return Task.CompletedTask;
}
public async Task LoadMainServer(MainServer Server)
{
if (SerBox is null)
SerBox = new()
{
Location = new(ser.Size.X, 0, 0),
Size = new(Size.X - ser.Size.X, Size.Y),
Anchor = ObjectAnchor.All
};
Controls.Add(SerBox);
SerBox.ForceDistanceUpdate();
SerBox.Controls.Clear();
}
private async Task<Task> LoginOnChangeToApp()
{
Controls.Clear();
BlockDraw = true;
Title = "Luski";
unsafe
{
GLFW.SetWindowSizeLimits(WindowPtr, 500.ScaleInt(), 250.ScaleInt(),GLFW.DontCare, GLFW.DontCare);
}
try
{
CenterWindow(Globals.Settings.Display);
}
catch (Exception e)
{
CenterWindow();
}
WindowBorder = WindowBorder.Resizable;
BackgroundColor = new Color4(20, 20, 20, 255);
Controls.Add(ser = new FlowLayout()
{
BackgroundColor = new(26, 26, 26, 255),
Size = new(68.ScaleInt(), ClientSize.Y),
Anchor = ObjectAnchor.Top | ObjectAnchor.Left | ObjectAnchor.Bottom,
Location = new(0,0,0)
});
ser.LoadToParent(this,this);
DrawFrame();
DateTime utcNow = DateTime.UtcNow;
Task.WhenAll(Globals.ServersLoading.ToArray()).Wait();
foreach (PublicServer pser in Globals.Luski.LoadedServers)
{
ServerIcon<PublicServer> si = new ServerIcon<PublicServer>(pser);
ser.Controls.Add(si);
si.LoadToParent(ser, this);
}
AddServerIcon asi = new();
asi.Clicked += AddButtonClicked;
ser.Controls.Add(asi);
if (ser.Controls.Length > 1) (ser.Controls[0] as ServerIcon<PublicServer>)!.LoadServer().Start();
DrawFrame();
MainShow += OnMainShow;
return Task.CompletedTask;
}
protected override void OnResize(ResizeEventArgs e)
{
base.OnResize(e);
}
private Task AddButtonClicked(IRenderObject arg)
{
AddServerOverlay aso = new();
aso.Clicked += AsoOnClicked;
Controls.Add(aso);
TryDraw();
OnResize(new(Size));
return Task.CompletedTask;
}
private Task AsoOnClicked(IRenderObject arg)
{
Globals.ms.Controls.Remove(arg);
Globals.ms.DrawFrame();
AddServerOverlay aso = (arg as AddServerOverlay)!;
aso.Clicked -= AsoOnClicked;
aso.Clean();
aso = null!;
return Task.CompletedTask;
}
private Task OnMainShow()
{
if (Globals.Luski.MainServer is not null && Globals.Luski.MainServer.IsLogedIn)
{
Globals.Luski.MainServer.OnError += LuskiOnOnError;
}
return Task.CompletedTask;
}
public event Func<Task>? MainShow;
private Task LuskiOnOnError(Exception arg)
{
Console.WriteLine(arg);
return Task.CompletedTask;
}
}

106
Luski/GUI/UpdateWindow.cs Normal file
View File

@ -0,0 +1,106 @@
using GraphicsManager;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using OpenTK.Mathematics;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.Common;
namespace Luski.GUI;
public class UpdateWindow : Window
{
private RoundedButton? yes, no;
private static readonly NativeWindowSettings Settings = new()
{
Title = "Update Available",
WindowBorder = WindowBorder.Fixed,
APIVersion = new Version(3, 2),
StartFocused = true,
Size = new Vector2i(481, 838),
Icon = Globals.Icon,
SharedContext = null
};
public enum DialogueResult
{
Yes,
No,
Closed
}
private DialogueResult Result = DialogueResult.Closed;
public UpdateWindow() : base(Settings)
{
Label t;
Controls.Add(t = new Label(Globals.DefaultFont) { Scale = 1.2f, Location = new(17.5.ScaleInt()), Text = "Luski has detected that your\nclient is on an older version\nfor your branch."});
if (!Globals.Empty(Globals.UpdaterSettings.Updater))
{
t.Text += "\n\nWould you like to update?";
Controls.Add(yes = new(Globals.LuskiTexture, Globals.DefaultFont)
{
Text = "Yes",
Location = new(t.Location.X, t.Location.Y + t.Size.Y + (int)(t.Scale * t.Font.PixelHeight), 0),
Size = new(t.Size.X, 33.5.ScaleInt())
});
Controls.Add(no = new(Globals.LuskiTexture, Globals.DefaultFont)
{
Text = "No", Location = new(t.Location.X, yes.Location.Y + yes.Size.Y + 20, 0),
Size = new(yes.Size.X, 35.5.ScaleInt())
});
Size = new(t.Location.X + t.Location.X + t.Size.X, no.Location.Y + no.Size.Y + t.Location.X);
yes.Clicked += YesOnClicked;
no.Clicked += NoOnClicked;
}
else
{
t.Text += "\n\nNo updater path was set\nSet a path for auto updates";
Controls.Add(no = new(Globals.LuskiTexture, Globals.DefaultFont)
{
Text = "Ok",
Location = new(t.Location.X, t.Location.Y + t.Size.Y + (int)(t.Scale * t.Font.PixelHeight), 0),
Size = new(t.Size.X, 35.5.ScaleInt()),
});
Size = new(t.Location.X + t.Location.X + t.Size.X, no.Location.Y + no.Size.Y + t.Location.X);
no.Clicked += NoOnClicked;
}
try
{
CenterWindow(Globals.Settings.Display);
}
catch (Exception e)
{
CenterWindow();
}
}
private Task NoOnClicked(IRenderObject arg)
{
Result = DialogueResult.No;
base.Close();
return Task.CompletedTask;
}
private Task YesOnClicked(IRenderObject arg)
{
Result = DialogueResult.Yes;
base.Close();
return Task.CompletedTask;
}
public DialogueResult ShowDialogue(Window? Parent = null)
{
try
{
if (Parent is not null) Parent.DrawFrame();
StartRender();
return Result;
}
finally
{
IsVisible = false;
//Dispose();
}
}
}

436
Luski/Globals.cs Normal file
View File

@ -0,0 +1,436 @@
using System.CodeDom.Compiler;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using GraphicsManager;
using GraphicsManager.Interfaces;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using Luski.Classes;
using Luski.Classes.ThemeSub;
using Luski.GUI;
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(EI)) 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)
{
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;
}
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 Color4 ToColor4(this Color col)
{
return new(col.R, col.G, col.B, col.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();
private static async Task<Texture> GetIcon(this SocketUser User)
{
if (UserTextureMap.TryGetValue(User.Id, out Texture? t)) return t;
Stream UserStream = await User.GetAvatar(CancellationToken.None);
t = Globals.ms.TextureManager.AddTexture(UserStream);
UserTextureMap.Add(User.Id, t);
UserStream.Dispose();
t.Unit = TextureUnit.Texture1;
return t;
}
public static async Task<IRenderObject> MakeRct<TUser>(this TUser User, Vector2i Size, bool IsProfile) where TUser : IUser
{
Texture t = ms.TextureManager.GetTextureResource("Status.png");
if (User.PictureType == PictureType.none)
{
UserControl r = new(t);
r.Size = Size;
r.Shader = Rectangle.DefaultAlphaShader[ms.Context];
Color c = await User.GetColor();
r.BackgroundColor = new(25, 25, 25, 255);
Label l = new(DefaultFont)
{
Color = c.ToColor4()
};
l.Text = User.DisplayName[0].ToString();
var y = l.GetSizeOfChar(0);
l.Location = new((r.Size.X - l.Size.X)/2,
(int)(r.Size.Y - (l.Font.PixelHeight - y.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 User.GetIcon(IsProfile));
return r;
}
}
private static async Task<Texture> GetIcon(this IUser User, bool IsProfile)
{
if (IsProfile)
{
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;
}
else
{
if (UserTextureMap.TryGetValue(User.Id, out Texture? t)) return t;
Stream UserStream = await User.GetAvatar(CancellationToken.None);
t = Globals.ms.TextureManager.AddTexture(UserStream);
UserTextureMap.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 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

View File

@ -0,0 +1,10 @@
using GraphicsManager.Objects;
using Luski.GUI.MainScreen.UI;
namespace Luski.Interfaces;
public interface IServerOverlay
{
public AccountButton? Selected { get; set; }
public UserControl page { get; set; }
}

View File

@ -0,0 +1,8 @@
using GraphicsManager.Interfaces;
namespace Luski.Interfaces;
public interface IThemeObject
{
public IRenderObject MakeObject(params object[] param);
}

41
Luski/Luski.csproj Normal file
View File

@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<FileVersion>0.0.0.1</FileVersion>
<Company>JacobTech, LLC</Company>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants />
<DebugType>none</DebugType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<NoWarn>1701;1702;IL2121;MSB3246</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GraphicsManager" Version="1.0.9-alpha72" />
<PackageReference Include="Luski.net" Version="2.0.0-alpha89" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources/**"></EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Folder Include="GUI\Windows\" />
</ItemGroup>
<PropertyGroup>
<ApplicationIcon>Luski.ico</ApplicationIcon>
</PropertyGroup>
</Project>

BIN
Luski/Luski.ico Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

78
Luski/LuskiExperiments.cs Normal file
View File

@ -0,0 +1,78 @@
using Luski.Classes;
namespace Luski;
public static class LuskiExperiments
{
public static List<ExperimentInfo> LuskiExperimentsList = new()
{
Parents.MainServer,
Parents.ThemeEdit,
new()
{
DisplayName = "Proper Message Label Size",
Name = "2024_04_label_size",
Options = new()
{
GUI.MessageLiveSize
}
}
};
public static class Parents
{
public static ExperimentInfo MainServer = new()
{
DisplayName = "Main Servers",
Name = "2023_12_main_servers",
Options = new()
{
MainServers.EnableLuskiMainServers,
MainServers.EnableMainServers,
}
};
public static ExperimentInfo ThemeEdit = new()
{
DisplayName = "Theme Editor",
Name = "2023_12_theme_edit",
Options = new()
{
Settings.Theme,
}
};
}
public static class Settings
{
public static readonly ExperimentSelectorInfo Theme = new()
{
Name = "Appearance Tab",
Description = "Adds a tab to edit the theme options.",
};
}
public static class MainServers
{
public static readonly ExperimentSelectorInfo EnableMainServers = new()
{
Name = "Enable Main Servers",
Description = "Will allow the Luski client to connect to all main servers.",
RequiresRestart = true,
};
public static readonly ExperimentSelectorInfo EnableLuskiMainServers = new()
{
Name = "Enable Luski Main Servers",
Description = "Will force the Luski client to connect to Luski main servers.",
RequiresRestart = true,
};
}
public static class GUI
{
public static readonly ExperimentSelectorInfo MessageLiveSize = new()
{
Name = "Proper Label Size",
Description = "Live updates messages to be the right length during resize.", RequiresRestart = false
};
}
}

120
Luski/Program.cs Normal file
View File

@ -0,0 +1,120 @@
using System.Diagnostics;
using Luski;
using Luski.Classes;
using Luski.GUI;
using OpenTK.Windowing.Common.Input;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using Image = OpenTK.Windowing.Common.Input.Image;
try
{
Globals.Settings = Globals.GetSettings(Path.Combine(Globals.LuskiPath, "Settings.json"), SettingsContext.Default.Settings);
foreach (ExperimentInfo le in LuskiExperiments.LuskiExperimentsList)
{
Globals.RegisterExperiment(le);
}
ServerList serverlist = Globals.GetSettings(Path.Combine(Globals.LuskiPath, "Servers.json"), ServerListContext.Default.ServerList);
Globals.ServerList = serverlist;
string themes = Path.Combine(Globals.LuskiPath, "Themes");
if (!Directory.Exists(themes)) Directory.CreateDirectory(themes);
DirectoryInfo di = new DirectoryInfo(themes);
foreach (DirectoryInfo Theme in di.GetDirectories())
{
try
{
LuskiThemes.LoadThemeFromDir(Theme.FullName);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
foreach (FileInfo Theme in di.GetFiles())
{
try
{
if (Theme.FullName.ToLower().EndsWith(".zip")) LuskiThemes.LoadThemeFromDir(Theme.FullName);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
if (serverlist.Servers.Length > 0)
{
foreach (ServerInfo server in serverlist.Servers)
{
switch (server.Main)
{
case false:
Globals.ServersLoading.Add(Task.Run(async () =>
{
return await Globals.Luski.TryGetPublicServer(out _, server.Domain, server.Version,
server.Secure, server.PreGenEncryption, server.ShowMessage);
}));
break;
case true:
if (LuskiExperiments.MainServers.EnableMainServers.IsEnabled()) Globals.Luski.GetMainServer(server.Domain, server.Version);
break;
}
}
}
Globals.UpdaterSettings = Globals.GetSettings(Path.Combine(Globals.LuskiPath, "UpdaterSettings.json"), UpdaterSettingsContext.Default.UpdaterSettings);
if (Globals.UpdaterSettings.Updater is null) Globals.UpdaterSettings.Updater = string.Empty;
Image<Rgba32> Logo = SixLabors.ImageSharp.Image.Load<Rgba32>(Globals.GetResource("Textures.Luski.png"));
Logo.DangerousTryGetSinglePixelMemory(out Memory<Rgba32> m);
byte[] pixels = new byte[4 * Logo.Width * Logo.Height];
Logo.CopyPixelDataTo(pixels);
Globals.Icon = new WindowIcon(new Image(Logo.Width, Logo.Height, pixels));
Logo.Dispose();
Globals.ms = new MainScreenWindow();
Globals.ms.CustomF11 = false;
Globals.ms.DrawFrame();
pixels = Array.Empty<byte>();
Globals.ms.StartRender();
Globals.ms.Dispose();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
if (Globals.Download)
{
Console.WriteLine("Auto Update Starting");
List<string> arguments = new List<string>
{
"--process",
Process.GetCurrentProcess().ProcessName,
"--remotedirectory",
"Luski",
"--localdirectory",
AppDomain.CurrentDomain.BaseDirectory,
"--branch",
"main",
"--selfcontained",
Globals.UpdaterSettings.SelfContained.ToString().ToLower(),
"--platform",
Globals.UpdaterSettings.Platform,
"--setconfig",
Path.Combine(Globals.LuskiPath, "UpdaterSettings.json")
};
if (Globals.UpdaterSettings.AutoLaunch)
{
arguments.Add("--dll");
arguments.Add(AppDomain.CurrentDomain.FriendlyName);
}
Process p = new();
p.StartInfo.FileName = Globals.UpdaterSettings.Updater;
p.StartInfo.UseShellExecute = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WorkingDirectory = new FileInfo(Globals.UpdaterSettings.Updater!).Directory!.FullName;
p.StartInfo.Arguments = $"\"{string.Join("\" \"", arguments)}\"";
p.Start();
Environment.Exit(0);
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

View File

@ -1,2 +1,3 @@
# Luski
A simple chat app that is in progress