From 02cd6d3c1026574385dd98208107e293371c95e8 Mon Sep 17 00:00:00 2001 From: "N. Lo." Date: Mon, 13 Jan 2025 21:50:06 +0100 Subject: [PATCH] Use InputText/Combo hybrids for MCDO ACLs (#81) * Use InputText/Combo hybrids for MCDO ACLs * Hybrid combo factoring, filtering, ordering, caching --- MareSynchronos/UI/CharaDataHubUi.McdOnline.cs | 50 +++++++++++++++++-- MareSynchronos/UI/CharaDataHubUi.cs | 17 ++++++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs b/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs index 958a5d3..e85f270 100644 --- a/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs +++ b/MareSynchronos/UI/CharaDataHubUi.McdOnline.cs @@ -709,8 +709,8 @@ internal sealed partial class CharaDataHubUi { using (ImRaii.Group()) { - ImGui.SetNextItemWidth(200); - ImGui.InputText("##AliasToAdd", ref _specificIndividualAdd, 20); + InputComboHybrid("##AliasToAdd", "##AliasToAddPicker", ref _specificIndividualAdd, _pairManager.PairsWithGroups.Keys, + static pair => (pair.UserData.UID, pair.UserData.Alias, pair.UserData.AliasOrUID, pair.GetNote())); ImGui.SameLine(); using (ImRaii.Disabled(string.IsNullOrEmpty(_specificIndividualAdd) || updateDto.UserList.Any(f => string.Equals(f.UID, _specificIndividualAdd, StringComparison.Ordinal) || string.Equals(f.Alias, _specificIndividualAdd, StringComparison.Ordinal)))) @@ -756,8 +756,8 @@ internal sealed partial class CharaDataHubUi { using (ImRaii.Group()) { - ImGui.SetNextItemWidth(200); - ImGui.InputText("##GroupAliasToAdd", ref _specificGroupAdd, 20); + InputComboHybrid("##GroupAliasToAdd", "##GroupAliasToAddPicker", ref _specificGroupAdd, _pairManager.Groups.Keys, + group => (group.GID, group.Alias, group.AliasOrGID, _serverConfigurationManager.GetNoteForGid(group.GID))); ImGui.SameLine(); using (ImRaii.Disabled(string.IsNullOrEmpty(_specificGroupAdd) || updateDto.GroupList.Any(f => string.Equals(f.GID, _specificGroupAdd, StringComparison.Ordinal) || string.Equals(f.Alias, _specificGroupAdd, StringComparison.Ordinal)))) @@ -800,4 +800,46 @@ internal sealed partial class CharaDataHubUi ImGuiHelpers.ScaledDummy(5); }); } + + private void InputComboHybrid(string inputId, string comboId, ref string value, IEnumerable comboEntries, + Func parseEntry) + { + const float ComponentWidth = 200; + ImGui.SetNextItemWidth(ComponentWidth - ImGui.GetFrameHeight()); + ImGui.InputText(inputId, ref value, 20); + ImGui.SameLine(0.0f, 0.0f); + + using var combo = ImRaii.Combo(comboId, string.Empty, ImGuiComboFlags.NoPreview | ImGuiComboFlags.PopupAlignLeft); + if (!combo) + { + return; + } + + if (_openComboHybridEntries is null || !string.Equals(_openComboHybridId, comboId, StringComparison.Ordinal)) + { + var valueSnapshot = value; + _openComboHybridEntries = comboEntries + .Select(parseEntry) + .Where(entry => entry.Id.Contains(valueSnapshot, StringComparison.OrdinalIgnoreCase) + || (entry.Alias is not null && entry.Alias.Contains(valueSnapshot, StringComparison.OrdinalIgnoreCase)) + || (entry.Note is not null && entry.Note.Contains(valueSnapshot, StringComparison.OrdinalIgnoreCase))) + .OrderBy(entry => entry.Note is null ? entry.AliasOrId : $"{entry.Note} ({entry.AliasOrId})", StringComparer.OrdinalIgnoreCase) + .ToArray(); + _openComboHybridId = comboId; + } + _comboHybridUsedLastFrame = true; + + // Is there a better way to handle this? + var width = ComponentWidth - 2 * ImGui.GetStyle().FramePadding.X - (_openComboHybridEntries.Length > 8 ? ImGui.GetStyle().ScrollbarSize : 0); + foreach (var (id, alias, aliasOrId, note) in _openComboHybridEntries) + { + var selected = !string.IsNullOrEmpty(value) + && (string.Equals(id, value, StringComparison.Ordinal) || string.Equals(alias, value, StringComparison.Ordinal)); + using var font = ImRaii.PushFont(UiBuilder.MonoFont, note is null); + if (ImGui.Selectable(note is null ? aliasOrId : $"{note} ({aliasOrId})", selected, ImGuiSelectableFlags.None, new(width, 0))) + { + value = aliasOrId; + } + } + } } \ No newline at end of file diff --git a/MareSynchronos/UI/CharaDataHubUi.cs b/MareSynchronos/UI/CharaDataHubUi.cs index ab449f0..a169c78 100644 --- a/MareSynchronos/UI/CharaDataHubUi.cs +++ b/MareSynchronos/UI/CharaDataHubUi.cs @@ -7,6 +7,7 @@ using ImGuiNET; using MareSynchronos.API.Dto.CharaData; using MareSynchronos.MareConfiguration; using MareSynchronos.MareConfiguration.Models; +using MareSynchronos.PlayerData.Pairs; using MareSynchronos.Services; using MareSynchronos.Services.CharaData.Models; using MareSynchronos.Services.Mediator; @@ -24,6 +25,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase private readonly CharaDataConfigService _configService; private readonly DalamudUtilService _dalamudUtilService; private readonly FileDialogManager _fileDialogManager; + private readonly PairManager _pairManager; private readonly ServerConfigurationManager _serverConfigurationManager; private readonly UiSharedService _uiSharedService; private CancellationTokenSource _closalCts = new(); @@ -53,11 +55,14 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase private string _specificIndividualAdd = string.Empty; private string _specificGroupAdd = string.Empty; private bool _abbreviateCharaName = false; + private string? _openComboHybridId = null; + private (string Id, string? Alias, string AliasOrId, string? Note)[]? _openComboHybridEntries = null; + private bool _comboHybridUsedLastFrame = false; public CharaDataHubUi(ILogger logger, MareMediator mediator, PerformanceCollectorService performanceCollectorService, CharaDataManager charaDataManager, CharaDataNearbyManager charaDataNearbyManager, CharaDataConfigService configService, UiSharedService uiSharedService, ServerConfigurationManager serverConfigurationManager, - DalamudUtilService dalamudUtilService, FileDialogManager fileDialogManager) + DalamudUtilService dalamudUtilService, FileDialogManager fileDialogManager, PairManager pairManager) : base(logger, mediator, "Mare Synchronos Character Data Hub###MareSynchronosCharaDataUI", performanceCollectorService) { SetWindowSizeConstraints(); @@ -69,6 +74,7 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase _serverConfigurationManager = serverConfigurationManager; _dalamudUtilService = dalamudUtilService; _fileDialogManager = fileDialogManager; + _pairManager = pairManager; Mediator.Subscribe(this, (_) => IsOpen |= _configService.Current.OpenMareHubOnGposeStart); } @@ -97,6 +103,8 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase _sharedWithYouOwnerFilter = string.Empty; _importCode = string.Empty; _charaDataNearbyManager.ComputeNearbyData = false; + _openComboHybridId = null; + _openComboHybridEntries = null; } public override void OnOpen() @@ -117,6 +125,13 @@ internal sealed partial class CharaDataHubUi : WindowMediatorSubscriberBase protected override void DrawInternal() { + if (!_comboHybridUsedLastFrame) + { + _openComboHybridId = null; + _openComboHybridEntries = null; + } + _comboHybridUsedLastFrame = false; + _disableUI = !(_charaDataManager.UiBlockingComputation?.IsCompleted ?? true); if (DateTime.UtcNow.Subtract(_lastFavoriteUpdateTime).TotalSeconds > 2) {