From a51ce22d28aa8da557cf81205d67551534c394e1 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Sun, 22 Oct 2023 17:12:44 +0200 Subject: [PATCH] fix offset for transfer bar at the bottom, use async collections, clear filter on tab change + add button to clear, require ctrl for align syncshells --- MareSynchronos/Interop/IpcManager.cs | 25 +++++----- MareSynchronos/MareSynchronos.csproj | 2 +- MareSynchronos/UI/CompactUI.cs | 3 +- MareSynchronos/UI/SettingsUi.cs | 14 +++--- MareSynchronos/UI/TopTabMenu.cs | 73 ++++++++++++++++++++-------- 5 files changed, 76 insertions(+), 41 deletions(-) diff --git a/MareSynchronos/Interop/IpcManager.cs b/MareSynchronos/Interop/IpcManager.cs index 64dd28c..6ecd660 100644 --- a/MareSynchronos/Interop/IpcManager.cs +++ b/MareSynchronos/Interop/IpcManager.cs @@ -22,6 +22,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase private readonly ICallGateSubscriber _customizePlusOnScaleUpdate; private readonly ICallGateSubscriber _customizePlusRevertCharacter; private readonly ICallGateSubscriber _customizePlusSetBodyScaleToCharacter; + private readonly DalamudPluginInterface _pi; private readonly DalamudUtilService _dalamudUtil; private readonly ICallGateSubscriber<(int, int)> _glamourerApiVersions; private readonly ICallGateSubscriber? _glamourerApplyAll; @@ -47,7 +48,6 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase private readonly ICallGateSubscriber _palettePlusRemoveCharaPalette; private readonly ICallGateSubscriber _palettePlusSetCharaPalette; private readonly FuncSubscriber, string, int, PenumbraApiEc> _penumbraAddTemporaryMod; - private readonly FuncSubscriber<(int, int)> _penumbraApiVersion; private readonly FuncSubscriber _penumbraAssignTemporaryCollection; private readonly FuncSubscriber _penumbraConvertTextureFile; private readonly FuncSubscriber _penumbraCreateNamedTemporaryCollection; @@ -64,7 +64,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase private readonly FuncSubscriber _penumbraRemoveTemporaryCollection; private readonly FuncSubscriber _penumbraRemoveTemporaryMod; private readonly FuncSubscriber _penumbraResolveModDir; - private readonly FuncSubscriber _penumbraResolvePaths; + private readonly FuncSubscriber> _penumbraResolvePaths; private readonly ParamsFuncSubscriber?[]> _penumbraResourcePaths; private readonly SemaphoreSlim _redrawSemaphore = new(2); private readonly uint LockCode = 0x6D617265; @@ -80,6 +80,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase public IpcManager(ILogger logger, DalamudPluginInterface pi, DalamudUtilService dalamudUtil, MareMediator mediator) : base(logger, mediator) { + _pi = pi; _dalamudUtil = dalamudUtil; _penumbraInit = Penumbra.Api.Ipc.Initialized.Subscriber(pi, PenumbraInit); @@ -87,7 +88,6 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase _penumbraResolveModDir = Penumbra.Api.Ipc.GetModDirectory.Subscriber(pi); _penumbraRedraw = Penumbra.Api.Ipc.RedrawObjectByName.Subscriber(pi); _penumbraRedrawObject = Penumbra.Api.Ipc.RedrawObject.Subscriber(pi); - _penumbraApiVersion = Penumbra.Api.Ipc.ApiVersions.Subscriber(pi); _penumbraObjectIsRedrawn = Penumbra.Api.Ipc.GameObjectRedrawn.Subscriber(pi, RedrawEvent); _penumbraGetMetaManipulations = Penumbra.Api.Ipc.GetPlayerMetaManipulations.Subscriber(pi); _penumbraRemoveTemporaryMod = Penumbra.Api.Ipc.RemoveTemporaryMod.Subscriber(pi); @@ -95,7 +95,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase _penumbraCreateNamedTemporaryCollection = Penumbra.Api.Ipc.CreateNamedTemporaryCollection.Subscriber(pi); _penumbraRemoveTemporaryCollection = Penumbra.Api.Ipc.RemoveTemporaryCollectionByName.Subscriber(pi); _penumbraAssignTemporaryCollection = Penumbra.Api.Ipc.AssignTemporaryCollection.Subscriber(pi); - _penumbraResolvePaths = Penumbra.Api.Ipc.ResolvePlayerPaths.Subscriber(pi); + _penumbraResolvePaths = Penumbra.Api.Ipc.ResolvePlayerPathsAsync.Subscriber(pi); _penumbraEnabled = Penumbra.Api.Ipc.GetEnabledState.Subscriber(pi); _penumbraModSettingChanged = Penumbra.Api.Ipc.ModSettingChanged.Subscriber(pi, (change, arg1, arg, b) => { @@ -569,7 +569,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase public async Task<(string[] forward, string[][] reverse)> PenumbraResolvePathsAsync(string[] forward, string[] reverse) { - return await _dalamudUtil.RunOnFrameworkThread(() => _penumbraResolvePaths.Invoke(forward, reverse)).ConfigureAwait(false); + return await _penumbraResolvePaths.Invoke(forward, reverse).ConfigureAwait(false); } public async Task PenumbraSetManipulationDataAsync(ILogger logger, Guid applicationId, string collName, string manipulationData) @@ -700,20 +700,23 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase private bool CheckPenumbraApiInternal() { - bool apiAvailable = false; + bool penumbraAvailable = false; try { - apiAvailable = _penumbraApiVersion.Invoke() is { Item1: 4, Item2: >= 21 } && _penumbraEnabled.Invoke(); - _shownPenumbraUnavailable = _shownPenumbraUnavailable && !apiAvailable; - return apiAvailable; + penumbraAvailable = (_pi.InstalledPlugins + .FirstOrDefault(p => string.Equals(p.InternalName, "Penumbra", StringComparison.OrdinalIgnoreCase)) + ?.Version ?? new Version(0, 0, 0, 0)) >= new Version(0, 8, 1, 6); + penumbraAvailable &= _penumbraEnabled.Invoke(); + _shownPenumbraUnavailable = _shownPenumbraUnavailable && !penumbraAvailable; + return penumbraAvailable; } catch { - return apiAvailable; + return penumbraAvailable; } finally { - if (!apiAvailable && !_shownPenumbraUnavailable) + if (!penumbraAvailable && !_shownPenumbraUnavailable) { _shownPenumbraUnavailable = true; Mediator.Publish(new NotificationMessage("Penumbra inactive", "Your Penumbra installation is not active or out of date. Update Penumbra and/or the Enable Mods setting in Penumbra to continue to use Mare.", NotificationType.Error)); diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index a378a2d..6d2c8e5 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -39,7 +39,7 @@ - + diff --git a/MareSynchronos/UI/CompactUI.cs b/MareSynchronos/UI/CompactUI.cs index e6715f1..4e8f0cb 100644 --- a/MareSynchronos/UI/CompactUI.cs +++ b/MareSynchronos/UI/CompactUI.cs @@ -183,7 +183,8 @@ public class CompactUi : WindowMediatorSubscriberBase { var ySize = TransferPartHeight == 0 ? 1 - : (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y) - TransferPartHeight - ImGui.GetCursorPosY(); + : (ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y + + ImGui.GetTextLineHeight() - ImGui.GetStyle().WindowBorderSize) - TransferPartHeight - ImGui.GetCursorPosY(); ImGui.BeginChild("list", new Vector2(WindowContentWidth, ySize), border: false); diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs index d45fbcc..3f68028 100644 --- a/MareSynchronos/UI/SettingsUi.cs +++ b/MareSynchronos/UI/SettingsUi.cs @@ -678,13 +678,6 @@ public class SettingsUi : WindowMediatorSubscriberBase Mediator.Publish(new CompactUiChange(Vector2.Zero, Vector2.Zero)); } UiSharedService.DrawHelpText("Will show profiles on the right side of the main UI"); - if (ImGui.Checkbox("Show profiles marked as NSFW", ref showNsfwProfiles)) - { - Mediator.Publish(new ClearProfileDataMessage()); - _configService.Current.ProfilesAllowNsfw = showNsfwProfiles; - _configService.Save(); - } - UiSharedService.DrawHelpText("Will show profiles that have the NSFW tag enabled"); if (ImGui.SliderFloat("Hover Delay", ref profileDelay, 1, 10)) { _configService.Current.ProfileDelay = profileDelay; @@ -693,6 +686,13 @@ public class SettingsUi : WindowMediatorSubscriberBase UiSharedService.DrawHelpText("Delay until the profile should be displayed"); if (!showProfiles) ImGui.EndDisabled(); ImGui.Unindent(); + if (ImGui.Checkbox("Show profiles marked as NSFW", ref showNsfwProfiles)) + { + Mediator.Publish(new ClearProfileDataMessage()); + _configService.Current.ProfilesAllowNsfw = showNsfwProfiles; + _configService.Save(); + } + UiSharedService.DrawHelpText("Will show profiles that have the NSFW tag enabled"); ImGui.Separator(); diff --git a/MareSynchronos/UI/TopTabMenu.cs b/MareSynchronos/UI/TopTabMenu.cs index 97fac2d..8042de6 100644 --- a/MareSynchronos/UI/TopTabMenu.cs +++ b/MareSynchronos/UI/TopTabMenu.cs @@ -20,12 +20,12 @@ public class TopTabMenu private readonly PairManager _pairManager; + private string _filter = string.Empty; private int _globalControlCountdown = 0; private string _pairToAdd = string.Empty; private SelectedTab _selectedTab = SelectedTab.None; - public TopTabMenu(MareMediator mareMediator, ApiController apiController, PairManager pairManager) { _mareMediator = mareMediator; @@ -41,8 +41,32 @@ public class TopTabMenu Filter, UserConfig } - public string Filter { get; private set; } = string.Empty; + public string Filter + { + get => _filter; + private set + { + if (!string.Equals(_filter, value, StringComparison.OrdinalIgnoreCase)) + { + _mareMediator.Publish(new RefreshUiMessage()); + } + + _filter = value; + } + } + private SelectedTab TabSelection + { + get => _selectedTab; set + { + if (_selectedTab == SelectedTab.Filter && value != SelectedTab.Filter) + { + Filter = string.Empty; + } + + _selectedTab = value; + } + } public void Draw() { var availableWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; @@ -61,11 +85,11 @@ public class TopTabMenu var x = ImGui.GetCursorScreenPos(); if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), buttonSize)) { - _selectedTab = _selectedTab == SelectedTab.Individual ? SelectedTab.None : SelectedTab.Individual; + TabSelection = TabSelection == SelectedTab.Individual ? SelectedTab.None : SelectedTab.Individual; } ImGui.SameLine(); var xAfter = ImGui.GetCursorScreenPos(); - if (_selectedTab == SelectedTab.Individual) + if (TabSelection == SelectedTab.Individual) drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y }, xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X }, underlineColor, 2); @@ -77,11 +101,11 @@ public class TopTabMenu var x = ImGui.GetCursorScreenPos(); if (ImGui.Button(FontAwesomeIcon.Users.ToIconString(), buttonSize)) { - _selectedTab = _selectedTab == SelectedTab.Syncshell ? SelectedTab.None : SelectedTab.Syncshell; + TabSelection = TabSelection == SelectedTab.Syncshell ? SelectedTab.None : SelectedTab.Syncshell; } ImGui.SameLine(); var xAfter = ImGui.GetCursorScreenPos(); - if (_selectedTab == SelectedTab.Syncshell) + if (TabSelection == SelectedTab.Syncshell) drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y }, xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X }, underlineColor, 2); @@ -94,12 +118,12 @@ public class TopTabMenu var x = ImGui.GetCursorScreenPos(); if (ImGui.Button(FontAwesomeIcon.Filter.ToIconString(), buttonSize)) { - _selectedTab = _selectedTab == SelectedTab.Filter ? SelectedTab.None : SelectedTab.Filter; + TabSelection = TabSelection == SelectedTab.Filter ? SelectedTab.None : SelectedTab.Filter; } ImGui.SameLine(); var xAfter = ImGui.GetCursorScreenPos(); - if (_selectedTab == SelectedTab.Filter) + if (TabSelection == SelectedTab.Filter) drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y }, xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X }, underlineColor, 2); @@ -112,12 +136,12 @@ public class TopTabMenu var x = ImGui.GetCursorScreenPos(); if (ImGui.Button(FontAwesomeIcon.UserCog.ToIconString(), buttonSize)) { - _selectedTab = _selectedTab == SelectedTab.UserConfig ? SelectedTab.None : SelectedTab.UserConfig; + TabSelection = TabSelection == SelectedTab.UserConfig ? SelectedTab.None : SelectedTab.UserConfig; } ImGui.SameLine(); var xAfter = ImGui.GetCursorScreenPos(); - if (_selectedTab == SelectedTab.UserConfig) + if (TabSelection == SelectedTab.UserConfig) drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y }, xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X }, underlineColor, 2); @@ -129,26 +153,26 @@ public class TopTabMenu ImGuiHelpers.ScaledDummy(spacing); - if (_selectedTab == SelectedTab.Individual) + if (TabSelection == SelectedTab.Individual) { DrawAddPair(availableWidth, spacing.X); DrawGlobalIndividualButtons(availableWidth, spacing.X); } - else if (_selectedTab == SelectedTab.Syncshell) + else if (TabSelection == SelectedTab.Syncshell) { DrawSyncshellMenu(availableWidth, spacing.X); DrawGlobalSyncshellButtons(availableWidth, spacing.X); } - else if (_selectedTab == SelectedTab.Filter) + else if (TabSelection == SelectedTab.Filter) { - DrawFilter(availableWidth); + DrawFilter(availableWidth, spacing.X); } - else if (_selectedTab == SelectedTab.UserConfig) + else if (TabSelection == SelectedTab.UserConfig) { DrawUserConfig(availableWidth, spacing.X); } - if (_selectedTab != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f); + if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f); ImGui.Separator(); ImGuiHelpers.ScaledDummy(1f); } @@ -171,14 +195,20 @@ public class TopTabMenu UiSharedService.AttachToolTip("Pair with " + (_pairToAdd.IsNullOrEmpty() ? "other user" : _pairToAdd)); } - private void DrawFilter(float availableWidth) + private void DrawFilter(float availableWidth, float spacingX) { - ImGui.SetNextItemWidth(availableWidth); + var buttonSize = UiSharedService.GetIconTextButtonSize(FontAwesomeIcon.Ban, "Clear"); + ImGui.SetNextItemWidth(availableWidth - buttonSize.X - spacingX); string filter = Filter; if (ImGui.InputTextWithHint("##filter", "Filter for UID/notes", ref filter, 255)) { Filter = filter; - _mareMediator.Publish(new RefreshUiMessage()); + } + ImGui.SameLine(); + using var disabled = ImRaii.Disabled(string.IsNullOrEmpty(Filter)); + if (UiSharedService.IconTextButton(FontAwesomeIcon.Ban, "Clear")) + { + Filter = string.Empty; } } @@ -404,7 +434,7 @@ public class TopTabMenu ImGui.SameLine(); using (ImRaii.PushFont(UiBuilder.IconFont)) { - using var disabled = ImRaii.Disabled(_globalControlCountdown > 0); + using var disabled = ImRaii.Disabled(_globalControlCountdown > 0 || !UiSharedService.CtrlPressed()); if (ImGui.Button(FontAwesomeIcon.Check.ToIconString(), buttonSize)) { @@ -425,7 +455,8 @@ public class TopTabMenu UiSharedService.AttachToolTip("Globally align syncshell permissions to suggested syncshell permissions." + UiSharedService.TooltipSeparator + "Note: This will not affect users with preferred permissions in syncshells." + Environment.NewLine + "Note: If multiple users share one syncshell the permissions to that user will be set to " + Environment.NewLine - + "the ones of the last applied syncshell in alphabetical order." + + "the ones of the last applied syncshell in alphabetical order." + UiSharedService.TooltipSeparator + + "Hold CTRL to enable this button" + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty)); }