From 5b81caf5a84ebe52e2b9b2db70b1dac83ce442f5 Mon Sep 17 00:00:00 2001 From: choco Date: Tue, 23 Dec 2025 17:16:51 +0100 Subject: [PATCH] compact menu redesign with new animated particle header, enable particles toggle added in UI settings --- .../Configurations/LightlessConfig.cs | 1 + LightlessSync/UI/CompactUI.cs | 189 ++++++++---------- LightlessSync/UI/SettingsUi.cs | 9 +- LightlessSync/UI/Style/AnimatedHeader.cs | 4 +- LightlessSync/UI/UpdateNotesUi.cs | 4 +- 5 files changed, 102 insertions(+), 105 deletions(-) diff --git a/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs b/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs index 9b4055b..4987cc1 100644 --- a/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs +++ b/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs @@ -154,4 +154,5 @@ public class LightlessConfig : ILightlessConfiguration public bool SyncshellFinderEnabled { get; set; } = false; public string? SelectedFinderSyncshell { get; set; } = null; public string LastSeenVersion { get; set; } = string.Empty; + public bool EnableParticleEffects { get; set; } = true; } diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index 2c9e112..ec2ff0d 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -68,7 +68,7 @@ public class CompactUi : WindowMediatorSubscriberBase private bool _wasOpen; private float _windowContentWidth; private readonly SeluneBrush _seluneBrush = new(); - private readonly AnimatedHeader _animatedHeader = new() { Height = 120f, EnableBottomGradient = false }; + private readonly AnimatedHeader _animatedHeader = new(); private const float _connectButtonHighlightThickness = 14f; private Pair? _focusedPair; private Pair? _pendingFocusPair; @@ -128,6 +128,11 @@ public class CompactUi : WindowMediatorSubscriberBase .Apply(); _drawFolders = [.. DrawFolders]; + + _animatedHeader.Height = 120f; + _animatedHeader.EnableBottomGradient = true; + _animatedHeader.GradientHeight = 250f; + _animatedHeader.EnableParticles = _configService.Current.EnableParticleEffects; #if DEBUG string dev = "Dev Build"; @@ -218,17 +223,11 @@ public class CompactUi : WindowMediatorSubscriberBase } using (ImRaii.PushId("header")) DrawUIDHeader(); - _uiSharedService.RoundedSeparator(UIColors.Get("LightlessPurple"), 2.5f, 1f, 12f); - using (ImRaii.PushId("serverstatus")) - { - DrawServerStatus(); - } selune.DrawHighlightOnly(ImGui.GetIO().DeltaTime); var style = ImGui.GetStyle(); var contentMinY = windowPos.Y + ImGui.GetWindowContentRegionMin().Y; var gradientInset = 4f * ImGuiHelpers.GlobalScale; var gradientTop = MathF.Max(contentMinY, ImGui.GetCursorScreenPos().Y - style.ItemSpacing.Y + gradientInset); - ImGui.Separator(); if (_apiController.ServerState is ServerState.Connected) { @@ -236,7 +235,6 @@ public class CompactUi : WindowMediatorSubscriberBase using (ImRaii.PushId("global-topmenu")) _tabMenu.Draw(pairSnapshot); using (ImRaii.PushId("pairlist")) DrawPairs(); - ImGui.Separator(); var transfersTop = ImGui.GetCursorScreenPos().Y; var gradientBottom = MathF.Max(gradientTop, transfersTop - style.ItemSpacing.Y - gradientInset); selune.DrawGradient(gradientTop, gradientBottom, ImGui.GetIO().DeltaTime); @@ -317,95 +315,6 @@ public class CompactUi : WindowMediatorSubscriberBase ImGui.EndChild(); } - private void DrawServerStatus() - { - var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Link); - var userCount = _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture); - var userSize = ImGui.CalcTextSize(userCount); - var textSize = ImGui.CalcTextSize("Users Online"); -#if DEBUG - string shardConnection = $"Shard: {_apiController.ServerInfo.ShardName}"; -#else - string shardConnection = string.Equals(_apiController.ServerInfo.ShardName, "Main", StringComparison.OrdinalIgnoreCase) ? string.Empty : $"Shard: {_apiController.ServerInfo.ShardName}"; -#endif - var shardTextSize = ImGui.CalcTextSize(shardConnection); - var printShard = !string.IsNullOrEmpty(_apiController.ServerInfo.ShardName) && shardConnection != string.Empty; - - if (_apiController.ServerState is ServerState.Connected) - { - ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - (userSize.X + textSize.X) / 2 - ImGui.GetStyle().ItemSpacing.X / 2); - if (!printShard) ImGui.AlignTextToFramePadding(); - ImGui.TextColored(UIColors.Get("LightlessPurple"), userCount); - ImGui.SameLine(); - if (!printShard) ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted("Users Online"); - } - else - { - ImGui.AlignTextToFramePadding(); - ImGui.TextColored(UIColors.Get("DimRed"), "Not connected to any server"); - } - - if (printShard) - { - ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().ItemSpacing.Y); - ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth()) / 2 - shardTextSize.X / 2); - ImGui.TextUnformatted(shardConnection); - } - - ImGui.SameLine(); - if (printShard) - { - ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2); - } - bool isConnectingOrConnected = _apiController.ServerState is ServerState.Connected or ServerState.Connecting or ServerState.Reconnecting; - var color = UiSharedService.GetBoolColor(!isConnectingOrConnected); - var connectedIcon = isConnectingOrConnected ? FontAwesomeIcon.Unlink : FontAwesomeIcon.Link; - - ImGui.SameLine(ImGui.GetWindowContentRegionMin().X + UiSharedService.GetWindowContentRegionWidth() - buttonSize.X); - if (printShard) - { - ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ((userSize.Y + textSize.Y) / 2 + shardTextSize.Y) / 2 - ImGui.GetStyle().ItemSpacing.Y + buttonSize.Y / 2); - } - - if (_apiController.ServerState is not (ServerState.Reconnecting or ServerState.Disconnecting)) - { - using (ImRaii.PushColor(ImGuiCol.Text, color)) - { - if (_uiSharedService.IconButton(connectedIcon)) - { - if (isConnectingOrConnected && !_serverManager.CurrentServer.FullPause) - { - _serverManager.CurrentServer.FullPause = true; - _serverManager.Save(); - } - else if (!isConnectingOrConnected && _serverManager.CurrentServer.FullPause) - { - _serverManager.CurrentServer.FullPause = false; - _serverManager.Save(); - } - - _ = _apiController.CreateConnectionsAsync(); - } - } - - if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) - { - Selune.RegisterHighlight( - ImGui.GetItemRectMin(), - ImGui.GetItemRectMax(), - SeluneHighlightMode.Both, - borderOnly: true, - borderThicknessOverride: _connectButtonHighlightThickness, - exactSize: true, - clipToElement: true, - roundingOverride: ImGui.GetStyle().FrameRounding); - } - - UiSharedService.AttachToolTip(isConnectingOrConnected ? "Disconnect from " + _serverManager.CurrentServer.ServerName : "Connect to " + _serverManager.CurrentServer.ServerName); - } - } - private void DrawTransfers() { var currentUploads = _fileTransferManager.GetCurrentUploadsSnapshot(); @@ -541,8 +450,7 @@ public class CompactUi : WindowMediatorSubscriberBase using (_uiSharedService.IconFont.Push()) iconSize = ImGui.CalcTextSize(FontAwesomeIcon.PersonCirclePlus.ToIconString()); - float contentWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; - float uidStartX = (contentWidth - uidTextSize.X) / 2f; + float uidStartX = 25f; float cursorY = ImGui.GetCursorPosY(); if (_configService.Current.BroadcastEnabled && _apiController.IsConnected) @@ -671,6 +579,12 @@ public class CompactUi : WindowMediatorSubscriberBase UiSharedService.AttachToolTip("Click to copy"); + // Connect/Disconnect button next to big UID + DrawConnectButton(cursorY, uidTextSize.Y); + + // Add spacing below the big UID + ImGuiHelpers.ScaledDummy(5f); + if (_apiController.ServerState is ServerState.Connected && analysisSummary.HasData) { var objectSummary = analysisSummary.Objects.Values.FirstOrDefault(summary => summary.HasEntries); @@ -717,10 +631,12 @@ public class CompactUi : WindowMediatorSubscriberBase ImGui.SetClipboardText(_apiController.DisplayName); } - if (!string.Equals(_apiController.DisplayName, _apiController.UID, StringComparison.Ordinal)) + // Only show smaller UID line if DisplayName differs from UID (custom vanity name) + bool hasCustomName = !string.Equals(_apiController.DisplayName, _apiController.UID, StringComparison.OrdinalIgnoreCase); + + if (hasCustomName) { - var origTextSize = ImGui.CalcTextSize(_apiController.UID); - ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X) / 2 - (origTextSize.X / 2)); + ImGui.SetCursorPosX(uidStartX); if (useVanityColors) { @@ -755,14 +671,83 @@ public class CompactUi : WindowMediatorSubscriberBase { ImGui.SetClipboardText(_apiController.UID); } + + // Users Online on same line as smaller UID (with separator) + ImGui.SameLine(); + ImGui.AlignTextToFramePadding(); + ImGui.TextUnformatted("|"); + ImGui.SameLine(); + ImGui.TextColored(UIColors.Get("LightlessGreen"), _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture)); + ImGui.SameLine(); + ImGui.TextUnformatted("Users Online"); + } + else + { + // No custom name - just show Users Online aligned to uidStartX + ImGui.SetCursorPosX(uidStartX); + ImGui.TextColored(UIColors.Get("LightlessGreen"), _apiController.OnlineUsers.ToString(CultureInfo.InvariantCulture)); + ImGui.SameLine(); + ImGui.TextUnformatted("Users Online"); } } else { + ImGui.SetCursorPosX(uidStartX); UiSharedService.ColorTextWrapped(_apiController.ServerState.GetServerError(_apiController.AuthFailureMessage), uidColor); } } + private void DrawConnectButton(float cursorY, float buttonHeight) + { + var buttonSize = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Link); + bool isConnectingOrConnected = _apiController.ServerState is ServerState.Connected or ServerState.Connecting or ServerState.Reconnecting; + var color = UiSharedService.GetBoolColor(!isConnectingOrConnected); + var connectedIcon = isConnectingOrConnected ? FontAwesomeIcon.Unlink : FontAwesomeIcon.Link; + + // Position next to big UID on the right side + + if (_apiController.ServerState is not (ServerState.Reconnecting or ServerState.Disconnecting)) + { + ImGui.SetCursorPosX(UiSharedService.GetWindowContentRegionWidth() - buttonSize.X - 13f); + ImGui.SetCursorPosY(buttonHeight); + + using (ImRaii.PushColor(ImGuiCol.Text, color)) + using (ImRaii.PushColor(ImGuiCol.Button, ImGui.ColorConvertFloat4ToU32(new(0, 0, 0, 0)))) + { + if (_uiSharedService.IconButton(connectedIcon, buttonSize.Y)) + { + if (isConnectingOrConnected && !_serverManager.CurrentServer.FullPause) + { + _serverManager.CurrentServer.FullPause = true; + _serverManager.Save(); + } + else if (!isConnectingOrConnected && _serverManager.CurrentServer.FullPause) + { + _serverManager.CurrentServer.FullPause = false; + _serverManager.Save(); + } + + _ = _apiController.CreateConnectionsAsync(); + } + } + + if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive()) + { + Selune.RegisterHighlight( + ImGui.GetItemRectMin(), + ImGui.GetItemRectMax(), + SeluneHighlightMode.Both, + borderOnly: true, + borderThicknessOverride: _connectButtonHighlightThickness, + exactSize: true, + clipToElement: true, + roundingOverride: ImGui.GetStyle().FrameRounding); + } + + UiSharedService.AttachToolTip(isConnectingOrConnected ? "Disconnect from " + _serverManager.CurrentServer.ServerName : "Connect to " + _serverManager.CurrentServer.ServerName); + } + } + private IEnumerable DrawFolders { get diff --git a/LightlessSync/UI/SettingsUi.cs b/LightlessSync/UI/SettingsUi.cs index 548fc75..580849e 100644 --- a/LightlessSync/UI/SettingsUi.cs +++ b/LightlessSync/UI/SettingsUi.cs @@ -2082,7 +2082,7 @@ public class SettingsUi : WindowMediatorSubscriberBase ImGui.Separator(); var openPopupOnAddition = _configService.Current.OpenPopupOnAdd; - + using (var popupTree = BeginGeneralTree("Popup & Auto Fill", UIColors.Get("LightlessPurple"))) { if (popupTree.Visible) @@ -2139,11 +2139,18 @@ public class SettingsUi : WindowMediatorSubscriberBase var groupInVisible = _configService.Current.ShowSyncshellUsersInVisible; var syncshellOfflineSeparate = _configService.Current.ShowSyncshellOfflineUsersSeparately; var greenVisiblePair = _configService.Current.ShowVisiblePairsGreenEye; + var enableParticleEffects = _configService.Current.EnableParticleEffects; using (var behaviorTree = BeginGeneralTree("Behavior", UIColors.Get("LightlessPurple"))) { if (behaviorTree.Visible) { + if (ImGui.Checkbox("Enable Particle Effects", ref enableParticleEffects)) + { + _configService.Current.EnableParticleEffects = enableParticleEffects; + _configService.Save(); + } + if (ImGui.Checkbox("Enable Game Right Click Menu Entries", ref enableRightClickMenu)) { _configService.Current.EnableRightClickMenus = enableRightClickMenu; diff --git a/LightlessSync/UI/Style/AnimatedHeader.cs b/LightlessSync/UI/Style/AnimatedHeader.cs index 15488ac..839c704 100644 --- a/LightlessSync/UI/Style/AnimatedHeader.cs +++ b/LightlessSync/UI/Style/AnimatedHeader.cs @@ -47,6 +47,8 @@ public class AnimatedHeader public Vector4 BottomColor { get; set; } = new(0.12f, 0.08f, 0.20f, 1.0f); public bool EnableParticles { get; set; } = true; public bool EnableBottomGradient { get; set; } = true; + + public float GradientHeight { get; set; } = 60f; /// /// Draws the animated header with some customizable content @@ -171,7 +173,7 @@ public class AnimatedHeader private void DrawBottomGradient(Vector2 headerStart, Vector2 headerEnd, float width) { var drawList = ImGui.GetWindowDrawList(); - var gradientHeight = 60f; + var gradientHeight = GradientHeight; for (int i = 0; i < gradientHeight; i++) { diff --git a/LightlessSync/UI/UpdateNotesUi.cs b/LightlessSync/UI/UpdateNotesUi.cs index e1b3ab3..d27e87c 100644 --- a/LightlessSync/UI/UpdateNotesUi.cs +++ b/LightlessSync/UI/UpdateNotesUi.cs @@ -40,6 +40,7 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase logger.LogInformation("UpdateNotesUi constructor called"); _uiShared = uiShared; _configService = configService; + _animatedHeader.EnableParticles = _configService.Current.EnableParticleEffects; RespectCloseHotkey = true; ShowCloseButton = true; @@ -48,7 +49,8 @@ public class UpdateNotesUi : WindowMediatorSubscriberBase ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoMove; PositionCondition = ImGuiCond.Always; - + + WindowBuilder.For(this) .AllowPinning(false) .AllowClickthrough(false)