Better Progress Bars

This commit is contained in:
JacobTech 2025-03-12 11:23:20 -04:00
parent 77f23b0690
commit 6b1ea7ac3b
Signed by: JacobTech
GPG Key ID: ABCA7CDF59CE5FFE
7 changed files with 148 additions and 47 deletions

View File

@ -1,14 +1,9 @@
using System.Numerics;
namespace Luski.Classes.Attribs;
[AttributeUsage(AttributeTargets.Property)]
public class NumberSelectorAttribute : Attribute
public class NumberSelectorAttribute(Type PropertyType, bool Percentage = false, string Suffix = "") : Attribute
{
public NumberSelectorAttribute(Type propertyType)
{
Kind = propertyType;
}
public Type Kind { get; init; }
public bool Percentage { get; init; } = Percentage;
public string Suffix { get; init; } = Suffix;
public Type Kind { get; init; } = PropertyType;
}

View File

@ -17,7 +17,7 @@ public class Settings
[SettingInfo(SettingGroup.AppSettings, SettingsPage.Appearance)]
[Shared.GlobalAttributes.DisplayName("App Scale")]
[Description("Sets the scale for the app. If disabled, the default system scale will be used.")]
[NumberSelector(typeof(double?))]
[NumberSelector(typeof(double?), true)]
[NumberMin<double>(0.25)]
[NumberDefault<double>(1)]
[NumberMax<double>(2)]
@ -110,10 +110,10 @@ public class Settings
[SettingInfo(SettingGroup.AppSettings, SettingsPage.Appearance)]
[Shared.GlobalAttributes.DisplayName("Top Time Font Size")]
[Description("Sets the px value for the top time font size")]
[NumberSelector(typeof(uint))]
[NumberSelector(typeof(uint), Suffix: "px")]
[NumberMin<uint>(8)]
[NumberDefault<uint>(12)]
[NumberMax<uint>(20)]
[NumberMax<uint>(18)]
public uint TopTimeFontPX { get; set; } = 12;
[JsonInclude]
[JsonPropertyName("role_settings_font_px")]
@ -124,7 +124,7 @@ public class Settings
[SettingInfo(SettingGroup.AppSettings, SettingsPage.Appearance)]
[Shared.GlobalAttributes.DisplayName("Message Font Size")]
[Description("Sets the px value for the message font size")]
[NumberSelector(typeof(uint))]
[NumberSelector(typeof(uint), Suffix: "px")]
[NumberMin<uint>(12)]
[NumberDefault<uint>(17)]
[NumberMax<uint>(24)]

View File

@ -6,6 +6,7 @@ using GraphicsManager.Objects.Core;
using Luski.Enums;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.GraphicsLibraryFramework;
namespace Luski.GUI.MainScreen.UI.LuskiControls;
@ -40,11 +41,15 @@ public class NumberSelector<TNumber> : UserControl where TNumber : INumber<TNumb
set
{
_Min = value;
L1.Text = value.ToString() + Suffix;
if (Percent) L1.Text = (value * TNumber.CreateChecked(100))+ "%" + Suffix;
else L1.Text = value + Suffix;
int x = GetX(value);
L1.SetLocation(x - (L1.Size.X/2) + space, L1.Location.Y);
L1.ForceDistanceUpdate(this);
MinLine.SetLocation(x + space, MinLine.Location.Y);
x = GetX(_Default);
L2Default.SetLocation(x - (L2Default.Size.X/2) + space, L2Default.Location.Y);
L2Default.ForceDistanceUpdate(this);
Max = Max;
Value = Value;
}
@ -59,49 +64,99 @@ public class NumberSelector<TNumber> : UserControl where TNumber : INumber<TNumb
set
{
progressBar.MaxProgressValue = value - Min;
L3.Text = value.ToString() + Suffix;
if (Percent) L3.Text = (value * TNumber.CreateChecked(100))+ "%" + Suffix;
else L3.Text = value + Suffix;
int x = GetX(value);
L3.SetLocation(x - (L3.Size.X/2) + space, L3.Location.Y);
L3.ForceDistanceUpdate(this);
MaxLine.SetLocation(x + space, MaxLine.Location.Y);
MaxLine.ForceDistanceUpdate(this);
x = GetX(_Default);
L2Default.SetLocation(x - (L2Default.Size.X/2) + space, L2Default.Location.Y);
L2Default.ForceDistanceUpdate(this);
DefaltLine.SetLocation(x - (DefaltLine.Size.X/2) + space, DefaltLine.Location.Y);
DefaltLine.ForceDistanceUpdate(this);
progressBar.UpdateProgress();
}
}
private int GetX(TNumber number)
{
if (number >= Max) return progressBar.GetParentLocation(Max - Min, IgnoreEnd: true);
if (number <= Min) return progressBar.GetParentLocation(TNumber.Zero, IgnoreEnd: true);
return progressBar.GetParentLocation(number - Min, IgnoreEnd: true);
}
public TNumber Default { get; set; } = TNumber.Zero;
private TNumber Extra = TNumber.Zero;
public TNumber Default
{
get => _Default;
set
{
if (_Default == value) return;
_Default = value;
if (Percent) L2Default.Text = (value * TNumber.CreateChecked(100))+ "%" + Suffix;
else L2Default.Text = value + Suffix;
int x = GetX(value);
L2Default.SetLocation(x - (L2Default.Size.X/2) + space, L2Default.Location.Y);
DefaltLine.SetLocation(x - (DefaltLine.Size.X/2) + space, DefaltLine.Location.Y);
DefaltLine.ForceDistanceUpdate(this);
L2Default.ForceDistanceUpdate(this);
}
}
public TNumber Value
{
get
{
return progressBar.ProgressValue + Min;
return progressBar.ProgressValue + Min - Extra;
}
set
{
int i = 0;
TNumber tmp = value - Min;
if (progressBar.ProgressValue == tmp) return;
AddBlockDraw();
progressBar.ProgressValue = tmp;
Type tt = typeof(TNumber);
if (tt == typeof(double))
L2Cursor.Text = Math.Round((double)(object)value, 2) + Suffix;
else if (tt == typeof(float))
L2Cursor.Text = Math.Round((float)(object)value, 2) + Suffix;
if (value < Min)
{
Extra = Min - value;
progressBar.ProgressValue = TNumber.Zero;
}
else
L2Cursor.Text = value.ToString() + Suffix;
{
Extra = TNumber.Zero;
progressBar.ProgressValue = tmp;
}
Type tt = typeof(TNumber);
if (Percent)
{
if (tt == typeof(double))
L2Cursor.Text = Math.Round((double)(object)(value * TNumber.CreateChecked(100)), 0) + "%" + Suffix;
else if (tt == typeof(float))
L2Cursor.Text = Math.Round((float)(object)(value * TNumber.CreateChecked(100)), 0) + "%" + Suffix;
else
L2Cursor.Text = (value * TNumber.CreateChecked(100)) + "%" + Suffix;
}
else
{
if (tt == typeof(double))
L2Cursor.Text = Math.Round((double)(object)value, 2) + Suffix;
else if (tt == typeof(float))
L2Cursor.Text = Math.Round((float)(object)value, 2) + Suffix;
else
L2Cursor.Text = value.ToString() + Suffix;
}
int x = GetX(value);
if (value > Max || value < Min) L2Cursor.Color = Color4.Gold;
else L2Cursor.Color = Color4.White;
L2Cursor.SetLocation(x - (L2Cursor.Size.X/2) + space, L2Cursor.Location.Y);
Cursor.SetLocation(x - (Cursor.Size.X/2) + space, MaxLine.Location.Y);
Cursor.ForceDistanceUpdate(this);
L3.Visible = L2Cursor.Location.X + L2Cursor.Size.X < L3.Location.X;
L1.Visible = L2Cursor.Location.X > L1.Location.X + L1.Size.X;
L2Default.Visible = value != Default;
L2Cursor.Visible = value != Default;
RemoveBlockDraw();
progressBar.UpdateProgress();
if (Loaded && BlockEvents == 0 && ValueChanged is not null) ValueChanged.Invoke(this);
@ -112,15 +167,25 @@ public class NumberSelector<TNumber> : UserControl where TNumber : INumber<TNumb
private ProgressBar<TNumber> progressBar = new();
private Rectangle Cursor = new(), MinLine = new(), MaxLine = new();
private List<TNumber> ExtraPoints = new();
private Rectangle Cursor = new(), MinLine = new(), MaxLine = new(), DefaltLine = new();
private List<(TNumber, Rectangle)> ExtraPoints = new();
private int space = 5;
private TNumber _Min = TNumber.Zero, _Default = TNumber.Zero;
public Label
L1 = new(Globals.DefaultFont),
L2Default = new(Globals.DefaultFont),
L2Cursor = new(Globals.DefaultFont),
L3 = new(Globals.DefaultFont);
L1 = new(Globals.SliderFont),
L2Default = new(Globals.SliderFont),
L2Cursor = new(Globals.SliderFont),
L3 = new(Globals.SliderFont);
public bool Percent { get; set; }
public override void KeyEventChain(KeyboardKeyEventArgs KeyArgs)
{
base.KeyEventChain(KeyArgs);
if (Disabled) return;
if (KeyArgs.Key == Keys.Left && (Value > Min || KeyArgs.Control)) Value--;
else if (KeyArgs.Key == Keys.Right && (Value < Max || KeyArgs.Control)) Value++;
}
public NumberSelector()
{
@ -151,31 +216,45 @@ public class NumberSelector<TNumber> : UserControl where TNumber : INumber<TNumb
MinLine.SetLocation(0, Cursor.Location.Y);
MaxLine.SetSize(MinLine.Size.X, Cursor.Size.Y);
MaxLine.SetLocation(0, Cursor.Location.Y);
DefaltLine.SetSize(MinLine.Size.X, Cursor.Size.Y);
DefaltLine.SetLocation(0, Cursor.Location.Y);
L1.Text = Min.ToString() + Suffix;
L1.Anchor = ObjectAnchor.Top | ObjectAnchor.Left;
L2Default.Text = Default.ToString() + Suffix;
L2Cursor.Text = Value.ToString() + Suffix;
L3.Text = Max.ToString() + Suffix;
L3.Anchor = ObjectAnchor.Top | ObjectAnchor.Right;
L1.Location = new(0, MaxLine.Location.Y - L1.Size.Y - 5.ScaleInt());
L2Default.Location = new(0, L1.Location.Y);
L2Default.Color = Color4.Cyan;
L2Cursor.Location = new(0, L1.Location.Y);
L3.Location = new(0, L1.Location.Y);
MaxLine.Anchor = L3.Anchor;
DefaltLine.Anchor = Cursor.Anchor;
Controls.Add(progressBar);
MaxLine.BackgroundColor = Color4.Cyan;
MinLine.BackgroundColor = MaxLine.BackgroundColor;
DefaltLine.BackgroundColor = MaxLine.BackgroundColor;
StopNextHover = true;
L1.IgnoreHover = true;
L2Default.IgnoreHover = true;
L2Cursor.IgnoreHover = true;
L3.IgnoreHover = true;
Controls.Add(MinLine);
Controls.Add(L1);
Controls.Add(L3);
Controls.Add(L2Cursor);
Controls.Add(L2Default);
Controls.Add(MaxLine);
Controls.Add(DefaltLine);
Controls.Add(Cursor);
Cursor.ForceDistanceUpdate(this);
real_x = Cursor.Location.X;
progressBar.ForceDistanceUpdate(this);
//AllowHoverFromBehind = true;
WindowLoaded += OnWindowLoaded;
}
private Color4 FillColorL = Globals.DodgerBlue, BackColorL = Color4.DarkRed, CursorColorL = Color4.White, DisabledCursorColorL = new(128, 128, 128, 255), DisabledFillColorL = new(15, 72, 128, 255), DisabledBackColorL = new(70, 0, 0, 255);
private Color4 FillColorL = Globals.DodgerBlue, BackColorL = new(60, 60, 60, 255), CursorColorL = Color4.White, DisabledCursorColorL = new(128, 128, 128, 255), DisabledFillColorL = new(15, 72, 128, 255), DisabledBackColorL = new(40, 40, 40, 255);
private bool LocalDisabled;
public bool Disabled
@ -292,7 +371,15 @@ public class NumberSelector<TNumber> : UserControl where TNumber : INumber<TNumb
public void AddPoint(TNumber value)
{
if (value < _Min || value > Max) return;
ExtraPoints.Add(value);
Rectangle r = new();
r.Size = MinLine.Size;
r.Location = new(GetX(value) + space - (r.Size.X / 2), MinLine.Location.Y);
r.Anchor = ObjectAnchor.PreventWidthChange;
r.BackgroundColor = MinLine.BackgroundColor;
r.IgnoreHover = true;
r.ForceDistanceUpdate(this);
ExtraPoints.Add(new(value, r));
Controls.Insert(Controls.IndexOf(MinLine), r);
}
private byte BlockEvents = 0;
@ -308,6 +395,11 @@ public class NumberSelector<TNumber> : UserControl where TNumber : INumber<TNumb
BlockEvents++;
Value--;
Value++;
foreach ((TNumber, Rectangle) Point in ExtraPoints)
{
Point.Item2.Location = new(GetX(Point.Item1) + space - (Point.Item2.Size.X / 2), MinLine.Location.Y);
Point.Item2.ForceDistanceUpdate(this);
}
BlockEvents--;
progressBar.UpdateProgress();
}
@ -330,6 +422,8 @@ public class NumberSelector<TNumber> : UserControl where TNumber : INumber<TNumb
if (Disabled) return;
if (!Draging) return;
real_x += (int)obj.DeltaX;
TNumber n = progressBar.GetValueFromX(real_x) + Min;
if (n == Value) return;
Value = progressBar.GetValueFromX(real_x) + Min;
}

View File

@ -72,7 +72,7 @@ public class Generic : PageFlow
{
if (typeinfo.Kind.FullName == typeof(uint).FullName)
{
Globals.AddNumberSlider(this, prop, (uint)PropVal, b =>
Globals.AddNumberSlider(this, prop, (uint)PropVal, typeinfo.Suffix, typeinfo.Percentage, b =>
{
prop.SetValue(Globals.Settings, b);
Globals.Settings.SaveSettings(Path.Combine(Globals.LuskiPath, "Settings.json"), SettingsContext.Default.Settings);
@ -82,7 +82,7 @@ public class Generic : PageFlow
if (typeinfo.Kind.FullName == typeof(double?).FullName)
{
double? pv = (double?)PropVal;
Globals.AddNullNumberSlider(this, prop, pv, b =>
Globals.AddNullNumberSlider(this, prop, pv, typeinfo.Suffix, typeinfo.Percentage, b =>
{
prop.SetValue(Globals.Settings, b);
Globals.Settings.SaveSettings(Path.Combine(Globals.LuskiPath, "Settings.json"), SettingsContext.Default.Settings);

View File

@ -299,18 +299,21 @@ public static class Globals
return tc;
}
public static UserControl AddNumberSlider<TNumber>(IParent parent, string Name, string description, TNumber defaul, TNumber min, TNumber val, TNumber max, Action<TNumber> a) where TNumber : INumber<TNumber>
public static UserControl AddNumberSlider<TNumber>(IParent parent, string Name, string description, string suffix, bool percent, TNumber defaul, TNumber min, TNumber val, TNumber max, Action<TNumber> a) where TNumber : INumber<TNumber>
{
NumberSelector<TNumber> NumberSelector = new()
{
Default = defaul,
Percent = percent,
Suffix = suffix,
Min = min,
Max = max,
Default = defaul,
Value = val,
Anchor = ObjectAnchor.Top | ObjectAnchor.Right | ObjectAnchor.Left,
BackgroundColor = new(0,0,0,0),
Space = 15.ScaleInt()
};
UserControl tc = new()
{
BackgroundColor = new(0,0,0,0)
@ -354,10 +357,14 @@ public static class Globals
};
tc.ForceDistanceUpdate(parent);
parent.Controls.Add(tc);
for (TNumber i = max; i > min; i--)
{
NumberSelector.AddPoint(i);
}
return tc;
}
public static UserControl AddNullNumberSlider<TNumber>(IParent parent, string Name, string description, TNumber defaul, TNumber min, TNumber? val, TNumber max, Action<TNumber?> a) where TNumber : struct, INumber<TNumber>
public static UserControl AddNullNumberSlider<TNumber>(IParent parent, string Name, string description, string suffix, bool percent, TNumber defaul, TNumber min, TNumber? val, TNumber max, Action<TNumber?> a) where TNumber : struct, INumber<TNumber>
{
TNumber v = defaul;
if (val is not null) v = val.Value;
@ -368,9 +375,11 @@ public static class Globals
};
NumberSelector<TNumber> NumberSelector = new()
{
Default = defaul,
Percent = percent,
Suffix = suffix,
Min = min,
Max = max,
Default = defaul,
Value = v,
Anchor = ObjectAnchor.Top | ObjectAnchor.Right | ObjectAnchor.Left,
BackgroundColor = new(0,0,0,0),
@ -468,7 +477,7 @@ public static class Globals
AddBool(parent, Name, description,s,a,List);
}
public static void AddNumberSlider<TNumber>(IParent parent, PropertyInfo t, TNumber s, Action<TNumber> a) where TNumber : INumber<TNumber>
public static void AddNumberSlider<TNumber>(IParent parent, PropertyInfo t, TNumber s, string suffix, bool percent, Action<TNumber> a) where TNumber : INumber<TNumber>
{
object[] valueAttributes =
t.GetCustomAttributes(typeof(DescriptionAttribute), false);
@ -478,10 +487,10 @@ public static class Globals
t.GetCustomAttributes(typeof(Luski.Shared.GlobalAttributes.DisplayNameAttribute), false);
if (namevalueAttributes.Length == 0) return;
string Name = ((Luski.Shared.GlobalAttributes.DisplayNameAttribute)namevalueAttributes[0]).DisplayName;
_ = AddNumberSlider(parent, Name, description, t.GetAnyAttribute<NumberDefault<TNumber>>().Default, t.GetAnyAttribute<NumberMin<TNumber>>().Min, s, t.GetAnyAttribute<NumberMax<TNumber>>().Max,a);
_ = AddNumberSlider(parent, Name, description, suffix, percent, t.GetAnyAttribute<NumberDefault<TNumber>>().Default, t.GetAnyAttribute<NumberMin<TNumber>>().Min, s, t.GetAnyAttribute<NumberMax<TNumber>>().Max,a);
}
public static void AddNullNumberSlider<TNumber>(IParent parent, PropertyInfo t, TNumber? s, Action<TNumber?> a) where TNumber : struct, INumber<TNumber>
public static void AddNullNumberSlider<TNumber>(IParent parent, PropertyInfo t, TNumber? s, string suffix, bool percent, Action<TNumber?> a) where TNumber : struct, INumber<TNumber>
{
object[] valueAttributes =
t.GetCustomAttributes(typeof(DescriptionAttribute), false);
@ -491,7 +500,7 @@ public static class Globals
t.GetCustomAttributes(typeof(Luski.Shared.GlobalAttributes.DisplayNameAttribute), false);
if (namevalueAttributes.Length == 0) return;
string Name = ((Luski.Shared.GlobalAttributes.DisplayNameAttribute)namevalueAttributes[0]).DisplayName;
_ = AddNullNumberSlider(parent, Name, description, t.GetAnyAttribute<NumberDefault<TNumber>>().Default, t.GetAnyAttribute<NumberMin<TNumber>>().Min, s, t.GetAnyAttribute<NumberMax<TNumber>>().Max,a);
_ = AddNullNumberSlider(parent, Name, description, suffix, percent, t.GetAnyAttribute<NumberDefault<TNumber>>().Default, t.GetAnyAttribute<NumberMin<TNumber>>().Min, s, t.GetAnyAttribute<NumberMax<TNumber>>().Max,a);
}
public static TAttribute GetAnyAttribute<TAttribute>(this PropertyInfo t)
@ -720,6 +729,7 @@ public static class Globals
public static FontFamily DefaultFontFamly { get; set; }
public static FontInteraction DefaultFont { get; set; }
public static FontInteraction SliderFont { get; set; }
public static FontInteraction ServerRoleFont { get; set; }
public static FontInteraction TopTimeFont { get; set; }
public static FontInteraction MessageFont { get; set; }

View File

@ -22,7 +22,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="GraphicsManager" Version="1.1.1-alpha60" />
<PackageReference Include="GraphicsManager" Version="1.1.1-alpha61" />
<PackageReference Include="Luski.net" Version="2.0.1-alpha18" />
<PackageReference Include="Updater" Version="1.0.0-alpha05" />
</ItemGroup>

View File

@ -87,6 +87,8 @@ public class RootWindow : Window
Globals.MessageFont.FontSize = FontSize.Regular;
Globals.SmallTimeFont = Globals.DefaultFont.Clone();
Globals.SmallTimeFont.PixelHeight = ((uint)11).ScaleFont();
Globals.SliderFont = Globals.DefaultFont.Clone();
Globals.SliderFont.PixelHeight = ((uint)14).ScaleFont();
Globals.LuskiTexture = TextureManager.GetTextureResource("Luski.png");
#endregion