193 lines
8.8 KiB
C#
193 lines
8.8 KiB
C#
using System.Text.Json.Serialization;
|
|
|
|
namespace Lumi.Companion.Overlay;
|
|
|
|
public enum OverlayVisibilityMode { Off, WhenLive, On }
|
|
public enum OverlayLayoutMode { Unified, DividedHorizontal, DividedVertical, Separate }
|
|
public enum OverlayAnchor { TopLeft, Top, TopRight, Left, Right, BottomLeft, Bottom, BottomRight }
|
|
public enum OverlayHorizontalAlignment { Left, Middle, Right }
|
|
public enum OverlayVerticalAlignment { Top, Middle, Bottom }
|
|
public enum OverlayNewestDirection { Start, End }
|
|
public enum OverlayAnimation { None, Fade, Slide, FadeSlide, ScaleFade }
|
|
|
|
public sealed class OverlaySourceSetting
|
|
{
|
|
public string Id { get; set; } = "";
|
|
public string Platform { get; set; } = "";
|
|
public string Label { get; set; } = "";
|
|
public bool Selected { get; set; }
|
|
}
|
|
|
|
public sealed class OverlayContainerSettings
|
|
{
|
|
public OverlayAnchor Anchor { get; set; } = OverlayAnchor.BottomLeft;
|
|
public int PaddingTop { get; set; } = 24;
|
|
public int PaddingRight { get; set; } = 24;
|
|
public int PaddingBottom { get; set; } = 24;
|
|
public int PaddingLeft { get; set; } = 24;
|
|
public int Width { get; set; } = 700;
|
|
public int Height { get; set; } = 600;
|
|
public OverlayHorizontalAlignment HorizontalAlignment { get; set; } = OverlayHorizontalAlignment.Left;
|
|
public OverlayVerticalAlignment VerticalAlignment { get; set; } = OverlayVerticalAlignment.Bottom;
|
|
public OverlayNewestDirection NewestDirection { get; set; } = OverlayNewestDirection.End;
|
|
public string CardBackground { get; set; } = "#12121266";
|
|
public string TextColor { get; set; } = "#bbbbbb";
|
|
public string FontFamily { get; set; } = "Segoe UI";
|
|
public double FontSize { get; set; } = 22;
|
|
public string TextShadow { get; set; } = "#000000aa";
|
|
public int ShadowX { get; set; } = 1;
|
|
public int ShadowY { get; set; } = 2;
|
|
public int ShadowBlur { get; set; } = 3;
|
|
public bool ShowAvatar { get; set; } = true;
|
|
public bool ShowUsername { get; set; } = true;
|
|
public bool ShowPlatform { get; set; } = true;
|
|
public OverlayAnimation EntryAnimation { get; set; } = OverlayAnimation.FadeSlide;
|
|
public OverlayAnimation ExitAnimation { get; set; } = OverlayAnimation.FadeSlide;
|
|
public int EntryDurationMs { get; set; } = 260;
|
|
public int ExitDurationMs { get; set; } = 220;
|
|
public string Easing { get; set; } = "cubic-out";
|
|
public int SlideDistance { get; set; } = 24;
|
|
public double ScaleAmount { get; set; } = 0.92;
|
|
public int LifetimeMs { get; set; } = 12000;
|
|
public int QueueLimit { get; set; } = 12;
|
|
|
|
public OverlayContainerSettings CreateCopy() => new()
|
|
{
|
|
Anchor = Anchor,
|
|
PaddingTop = PaddingTop,
|
|
PaddingRight = PaddingRight,
|
|
PaddingBottom = PaddingBottom,
|
|
PaddingLeft = PaddingLeft,
|
|
Width = Width,
|
|
Height = Height,
|
|
HorizontalAlignment = HorizontalAlignment,
|
|
VerticalAlignment = VerticalAlignment,
|
|
NewestDirection = NewestDirection,
|
|
CardBackground = CardBackground,
|
|
TextColor = TextColor,
|
|
FontFamily = FontFamily,
|
|
FontSize = FontSize,
|
|
TextShadow = TextShadow,
|
|
ShadowX = ShadowX,
|
|
ShadowY = ShadowY,
|
|
ShadowBlur = ShadowBlur,
|
|
ShowAvatar = ShowAvatar,
|
|
ShowUsername = ShowUsername,
|
|
ShowPlatform = ShowPlatform,
|
|
EntryAnimation = EntryAnimation,
|
|
ExitAnimation = ExitAnimation,
|
|
EntryDurationMs = EntryDurationMs,
|
|
ExitDurationMs = ExitDurationMs,
|
|
Easing = Easing,
|
|
SlideDistance = SlideDistance,
|
|
ScaleAmount = ScaleAmount,
|
|
LifetimeMs = LifetimeMs,
|
|
QueueLimit = QueueLimit
|
|
};
|
|
}
|
|
|
|
public sealed class LumiOverlaySettings
|
|
{
|
|
public int SchemaVersion { get; set; } = 1;
|
|
public string ActiveProfileId { get; set; } = "default";
|
|
public bool Enabled { get; set; } = true;
|
|
public OverlayVisibilityMode Visibility { get; set; } = OverlayVisibilityMode.On;
|
|
public string? MonitorId { get; set; }
|
|
public List<OverlaySourceSetting> Sources { get; set; } = [];
|
|
public HashSet<string> EventTypes { get; set; } = [];
|
|
public OverlayLayoutMode Layout { get; set; } = OverlayLayoutMode.Unified;
|
|
public int ChatPercentage { get; set; } = 70;
|
|
public OverlayContainerSettings Unified { get; set; } = new();
|
|
public OverlayContainerSettings Chat { get; set; } = new();
|
|
public OverlayContainerSettings Events { get; set; } = new() { Anchor = OverlayAnchor.TopRight, Width = 520, Height = 420 };
|
|
public string ToggleVisibilityHotkey { get; set; } = "Ctrl+Alt+L";
|
|
public string TogglePreviewHotkey { get; set; } = "Ctrl+Alt+P";
|
|
|
|
[JsonIgnore]
|
|
public IEnumerable<string> SelectedSourceIds => Sources.Where(source => source.Selected).Select(source => source.Id);
|
|
|
|
public LumiOverlaySettings CreateCopy() => new()
|
|
{
|
|
SchemaVersion = SchemaVersion,
|
|
ActiveProfileId = ActiveProfileId,
|
|
Enabled = Enabled,
|
|
Visibility = Visibility,
|
|
MonitorId = MonitorId,
|
|
Sources = Sources.Select(source => new OverlaySourceSetting
|
|
{
|
|
Id = source.Id,
|
|
Platform = source.Platform,
|
|
Label = source.Label,
|
|
Selected = source.Selected
|
|
}).ToList(),
|
|
EventTypes = EventTypes.ToHashSet(StringComparer.Ordinal),
|
|
Layout = Layout,
|
|
ChatPercentage = ChatPercentage,
|
|
Unified = Unified.CreateCopy(),
|
|
Chat = Chat.CreateCopy(),
|
|
Events = Events.CreateCopy(),
|
|
ToggleVisibilityHotkey = ToggleVisibilityHotkey,
|
|
TogglePreviewHotkey = TogglePreviewHotkey
|
|
};
|
|
|
|
public void Normalize()
|
|
{
|
|
SchemaVersion = 1;
|
|
ActiveProfileId = Clean(ActiveProfileId, 80, "default");
|
|
MonitorId = string.IsNullOrWhiteSpace(MonitorId) ? null : MonitorId.Trim()[..Math.Min(MonitorId.Trim().Length, 300)];
|
|
Sources = Sources.Where(source => !string.IsNullOrWhiteSpace(source.Id))
|
|
.GroupBy(source => source.Id, StringComparer.Ordinal).Select(group => group.First()).Take(250).ToList();
|
|
foreach (var source in Sources)
|
|
{
|
|
source.Id = Clean(source.Id, 300, "");
|
|
source.Platform = Clean(source.Platform, 24, "");
|
|
source.Label = Clean(source.Label, 300, source.Id);
|
|
}
|
|
EventTypes = EventTypes.Where(value => !string.IsNullOrWhiteSpace(value)).Select(value => Clean(value, 120, "")).Take(100).ToHashSet();
|
|
ChatPercentage = Math.Clamp(ChatPercentage, 10, 90);
|
|
NormalizeContainer(Unified);
|
|
NormalizeContainer(Chat);
|
|
NormalizeContainer(Events);
|
|
ToggleVisibilityHotkey = Clean(ToggleVisibilityHotkey, 80, "Ctrl+Alt+L");
|
|
TogglePreviewHotkey = Clean(TogglePreviewHotkey, 80, "Ctrl+Alt+P");
|
|
}
|
|
|
|
private static void NormalizeContainer(OverlayContainerSettings value)
|
|
{
|
|
value.Width = Math.Clamp(value.Width, 160, 16000);
|
|
value.Height = Math.Clamp(value.Height, 100, 16000);
|
|
value.PaddingTop = Math.Clamp(value.PaddingTop, 0, 4000);
|
|
value.PaddingRight = Math.Clamp(value.PaddingRight, 0, 4000);
|
|
value.PaddingBottom = Math.Clamp(value.PaddingBottom, 0, 4000);
|
|
value.PaddingLeft = Math.Clamp(value.PaddingLeft, 0, 4000);
|
|
AnchorLayout.ClampPadding(value);
|
|
value.CardBackground = ColorValue(value.CardBackground, true, "#12121266");
|
|
value.TextColor = ColorValue(value.TextColor, false, "#bbbbbb");
|
|
value.TextShadow = ColorValue(value.TextShadow, true, "#000000aa");
|
|
value.FontFamily = Clean(value.FontFamily, 120, "Segoe UI");
|
|
value.FontSize = Math.Clamp(value.FontSize, 8, 120);
|
|
value.ShadowX = Math.Clamp(value.ShadowX, -40, 40);
|
|
value.ShadowY = Math.Clamp(value.ShadowY, -40, 40);
|
|
value.ShadowBlur = Math.Clamp(value.ShadowBlur, 0, 40);
|
|
value.EntryDurationMs = Math.Clamp(value.EntryDurationMs, 0, 5000);
|
|
value.ExitDurationMs = Math.Clamp(value.ExitDurationMs, 0, 5000);
|
|
value.SlideDistance = Math.Clamp(value.SlideDistance, 0, 1000);
|
|
value.ScaleAmount = Math.Clamp(value.ScaleAmount, 0.1, 2);
|
|
value.LifetimeMs = Math.Clamp(value.LifetimeMs, 1000, 300000);
|
|
value.QueueLimit = Math.Clamp(value.QueueLimit, 1, 100);
|
|
value.Easing = Clean(value.Easing, 40, "cubic-out");
|
|
}
|
|
|
|
private static string Clean(string? value, int max, string fallback)
|
|
{
|
|
var clean = (value ?? "").Trim();
|
|
return clean.Length == 0 ? fallback : clean[..Math.Min(clean.Length, max)];
|
|
}
|
|
|
|
private static string ColorValue(string? value, bool alpha, string fallback) =>
|
|
System.Text.RegularExpressions.Regex.IsMatch(value ?? "", alpha ? "^#[0-9a-fA-F]{8}$" : "^#[0-9a-fA-F]{6}$") ? value! : fallback;
|
|
}
|
|
|
|
public sealed record OverlaySource(string Id, string Platform, string Label, bool? Live, bool Available, string Status);
|
|
public sealed record OverlayEventType(string Id, string Label, string Platform);
|