From 656de5936d624a75ccdb74bdc288932f25b07ab0 Mon Sep 17 00:00:00 2001 From: deMathias <47175867+deMathias@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:30:57 +0200 Subject: [PATCH 1/2] single panel & folders --- HighlightedItems.cs | 336 +++++++++++++++++++++++++++------------- HighlightedItems.csproj | 70 ++++----- SavedFilter.cs | 8 + Settings.cs | 6 +- 4 files changed, 278 insertions(+), 142 deletions(-) create mode 100644 SavedFilter.cs diff --git a/HighlightedItems.cs b/HighlightedItems.cs index ea001e2..d5f9d60 100644 --- a/HighlightedItems.cs +++ b/HighlightedItems.cs @@ -1,4 +1,4 @@ -using System.Windows.Forms; +using System.Windows.Forms; using HighlightedItems.Utils; using ExileCore; using ExileCore.PoEMemory.Elements.InventoryElements; @@ -25,8 +25,14 @@ namespace HighlightedItems; public class HighlightedItems : BaseSettingsPlugin { private SyncTask _currentOperation; - private string _customStashFilter = ""; - private string _customInventoryFilter = ""; + private string _customItemFilter = ""; + private int? _editFilterIndex; + private string _editQuery = ""; + private string _editName = ""; + private string _editFolder = ""; + private string _newQuery = ""; + private string _newName = ""; + private string _newFolder = ""; private record QueryOrException(ItemQuery Query, Exception Exception); @@ -38,6 +44,7 @@ private record QueryOrException(ItemQuery Query, Exception Exception); public override bool Initialise() { + MigrateLegacySavedFilters(); Graphics.InitImage(Path.Combine(DirectoryFullName, "images\\pick.png").Replace('\\', '/'), false); Graphics.InitImage(Path.Combine(DirectoryFullName, "images\\pickL.png").Replace('\\', '/'), false); @@ -55,130 +62,253 @@ public override void DrawSettings() DrawIgnoredCellsSettings(); } - private Predicate GetPredicate(string windowTitle, ref string filterText, Vector2 defaultPosition) + private void MigrateLegacySavedFilters() { - if (!Settings.ShowCustomFilterWindow) return null; Settings.SavedFilters ??= []; + Settings.SavedFilterEntries ??= []; + if (Settings.SavedFilters.Count == 0) + return; + foreach (var q in Settings.SavedFilters) + { + if (string.IsNullOrEmpty(q)) + continue; + if (Settings.SavedFilterEntries.Any(e => e.Query == q)) + continue; + var name = q.Length > 48 ? q.Substring(0, 45) + "…" : q; + Settings.SavedFilterEntries.Add(new SavedFilter { DisplayName = name, Query = q, Folder = "" }); + } + Settings.SavedFilters.Clear(); + } + + private bool TryGetFilterAnchor(out Vector2 anchor) + { + anchor = default; + var ui = InGameState.IngameUi; + if (ui.StashElement is { IsVisible: true, VisibleStash: { InventoryUIElement: { } inv } }) + { + anchor = inv.GetClientRectCache.BottomLeft.ToVector2Num(); + return true; + } + if (ui.GuildStashElement is { IsVisible: true, VisibleStash: { InventoryUIElement: { } inv2 } }) + { + anchor = inv2.GetClientRectCache.BottomLeft.ToVector2Num(); + return true; + } + if (ui.InventoryPanel.IsVisible) + { + anchor = ui.InventoryPanel[2].GetClientRectCache.BottomLeft.ToVector2Num(); + return true; + } + if (ui.TradeWindow is { IsVisible: true }) + { + anchor = ui.TradeWindow.GetClientRectCache.BottomLeft.ToVector2Num(); + return true; + } + if (ui.SellWindow is { IsVisible: true }) + { + anchor = ui.SellWindow.GetClientRectCache.BottomLeft.ToVector2Num(); + return true; + } + return false; + } + + private Predicate GetPredicate(ref string filterText, Vector2 defaultPosition) + { + if (!Settings.ShowCustomFilterWindow) + return null; + Settings.SavedFilters ??= []; + Settings.SavedFilterEntries ??= []; ImGui.SetNextWindowPos(defaultPosition, ImGuiCond.FirstUseEver); - if (ImGui.Begin(windowTitle, ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.AlwaysAutoResize)) + if (!ImGui.Begin("Custom filter", ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.AlwaysAutoResize)) + return null; + MigrateLegacySavedFilters(); + ImGui.TextUnformatted("Active IFL filter"); + ImGui.InputTextMultiline("##input", ref filterText, 8000, new Vector2(320, 128)); + Predicate returnValue = null; + if (ImGui.Button("Clear")) + filterText = ""; + var trimmed = filterText.Trim(); + if (!string.IsNullOrEmpty(trimmed) && !Settings.SavedFilterEntries.Any(x => x.Query == trimmed)) { - ImGui.InputTextWithHint("##input", "Filter using IFL syntax", ref filterText, 2000); - Predicate returnValue = null; - if (!string.IsNullOrWhiteSpace(filterText)) + ImGui.SameLine(); + if (ImGui.Button("Save")) { - ImGui.SameLine(); - if (ImGui.Button("Clear")) + Settings.SavedFilterEntries.Add(new SavedFilter { - filterText = ""; - return null; + DisplayName = trimmed.Length > 48 ? trimmed.Substring(0, 45) + "…" : trimmed, + Query = trimmed, + Folder = "" + }); + } + } + if (!string.IsNullOrEmpty(trimmed)) + { + var (query, exception) = _queries.GetValue(trimmed, s => + { + try + { + var itemQuery = ItemQuery.Load(s); + if (itemQuery.FailedToCompile) + return new QueryOrException(null, new Exception(itemQuery.Error)); + return new QueryOrException(itemQuery, null); } - - if (!Settings.SavedFilters.Contains(filterText)) + catch (Exception ex) { - ImGui.SameLine(); - if (ImGui.Button("Save")) - { - Settings.SavedFilters.Add(filterText); - } + return new QueryOrException(null, ex); } - - var (query, exception) = _queries.GetValue(filterText, s => + })!; + if (exception != null) + ImGui.TextUnformatted($"{exception.Message}"); + else + returnValue = s => { try { - var itemQuery = ItemQuery.Load(s); - if (itemQuery.FailedToCompile) - { - return new QueryOrException(null, new Exception(itemQuery.Error)); - } - - return new QueryOrException(itemQuery, null); + return query.CompiledQuery(new ItemData(s, GameController)); } catch (Exception ex) { - return new QueryOrException(null, ex); + DebugWindow.LogError($"Failed to match item: {ex}"); + return false; } - })!; - - if (exception != null) - { - ImGui.TextUnformatted($"{exception.Message}"); - } + }; + } + if (Settings.UsePopupForFilterSelector) + { + if (ImGui.Button("Open Saved Filters")) + ImGui.OpenPopup("saved_filter_popup"); + if (ImGui.BeginPopup("saved_filter_popup")) + { + if (!Settings.SavedFilterEntries.Any()) + ImGui.TextUnformatted("No saved filters yet."); else - { - returnValue = s => - { - try - { - return query.CompiledQuery(new ItemData(s, GameController)); - } - catch (Exception ex) - { - DebugWindow.LogError($"Failed to match item: {ex}"); - return false; - } - }; - } + DrawSavedFilterRows(ref filterText); + ImGui.EndPopup(); } + } + // ReSharper disable once AssignmentInConditionalExpression + else if (Settings.OpenSavedFilterList = ImGui.TreeNodeEx("Saved filters", + Settings.OpenSavedFilterList + ? ImGuiTreeNodeFlags.DefaultOpen | ImGuiTreeNodeFlags.NoTreePushOnOpen + : ImGuiTreeNodeFlags.NoTreePushOnOpen)) + { + if (!Settings.SavedFilterEntries.Any()) + ImGui.TextUnformatted("No saved filters yet."); + else + DrawSavedFilterRows(ref filterText); + ImGui.TreePop(); + } + if (ImGui.TreeNodeEx("Add new IFL Filter")) + { + ImGui.TextUnformatted("Display name"); + ImGui.InputTextWithHint("##addname", "Short name", ref _newName, 128); + ImGui.TextUnformatted("Folder"); + ImGui.InputTextWithHint("##addfolder", "Optional", ref _newFolder, 64); + ImGui.TextUnformatted("IFL query"); + ImGui.InputTextMultiline("##addquery", ref _newQuery, 8000, new Vector2(320, 128)); + if (ImGui.Button("Add") && !string.IsNullOrWhiteSpace(_newQuery)) + { + var q = _newQuery.Trim(); + var dn = string.IsNullOrWhiteSpace(_newName) ? (q.Length > 48 ? q.Substring(0, 45) + "…" : q) : _newName; + Settings.SavedFilterEntries.Add(new SavedFilter { DisplayName = dn, Query = q, Folder = _newFolder ?? "" }); + _newQuery = ""; + _newName = ""; + _newFolder = ""; + } + ImGui.TreePop(); + } + ImGui.End(); + return returnValue; + } - // ReSharper disable once AssignmentInConditionalExpression - if (Settings.SavedFilters.Any() && Settings.UsePopupForFilterSelector - ? Settings.OpenSavedFilterList = ImGui.BeginPopupContextItem("saved_filter_popup") - : Settings.OpenSavedFilterList = ImGui.TreeNodeEx("Saved filters", - Settings.OpenSavedFilterList - ? ImGuiTreeNodeFlags.DefaultOpen | ImGuiTreeNodeFlags.NoTreePushOnOpen - : ImGuiTreeNodeFlags.NoTreePushOnOpen)) + private void DrawSavedFilterRows(ref string filterText) + { + var list = Settings.SavedFilterEntries; + foreach (var folderGroup in list.Select((f, i) => (f, i)).GroupBy(t => t.f.Folder ?? "").OrderBy(g => g.Key)) + { + var label = string.IsNullOrEmpty(folderGroup.Key) ? "General" : folderGroup.Key; + ImGui.PushID($"fld_{label}"); + if (ImGui.TreeNodeEx(label, ImGuiTreeNodeFlags.DefaultOpen)) { - foreach (var (savedFilter, index) in Settings.SavedFilters.Select((x, i) => (x, i)).ToList()) + foreach (var (savedFilter, index) in folderGroup.OrderBy(x => x.i)) { ImGui.PushID($"saved{index}"); + ImGui.Button("≡"); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Drag to reorder"); + if (ImGui.BeginDragDropSource(ImGuiDragDropFlags.None)) + { + ImGuiHelpers.SetDragDropPayload("HI_FILTER_ITEM", index); + ImGui.EndDragDropSource(); + } + if (ImGui.BeginDragDropTarget()) + { + var payload = ImGuiHelpers.AcceptDragDropPayload("HI_FILTER_ITEM"); + if (payload.HasValue) + { + var srcIndex = payload.Value; + if (srcIndex >= 0 && srcIndex < list.Count && srcIndex != index) + { + var item = list[srcIndex]; + list.RemoveAt(srcIndex); + var insertIndex = index; + if (insertIndex > srcIndex) + insertIndex--; + list.Insert(insertIndex, item); + } + } + ImGui.EndDragDropTarget(); + } + ImGui.SameLine(); if (ImGui.Button("Load")) + filterText = savedFilter.Query; + ImGui.SameLine(); + if (ImGui.Button("Edit")) { - filterText = savedFilter; + _editFilterIndex = index; + _editQuery = savedFilter.Query; + _editName = savedFilter.DisplayName; + _editFolder = savedFilter.Folder ?? ""; + ImGui.OpenPopup($"hi_edit_{index}"); } - + if (ImGui.BeginPopup($"hi_edit_{index}")) + { + ImGui.TextUnformatted("Display name"); + ImGui.InputTextWithHint("##editname", "Short name", ref _editName, 128); + ImGui.TextUnformatted("Folder"); + ImGui.InputTextWithHint("##editfolder", "Optional", ref _editFolder, 64); + ImGui.TextUnformatted("IFL query"); + ImGui.InputTextMultiline("##editquery", ref _editQuery, 8000, new Vector2(320, 128)); + if (ImGui.Button("Save")) + { + savedFilter.Query = _editQuery.Trim(); + savedFilter.DisplayName = _editName; + savedFilter.Folder = _editFolder ?? ""; + ImGui.CloseCurrentPopup(); + _editFilterIndex = null; + } + ImGui.EndPopup(); + } + else if (_editFilterIndex == index) + _editFilterIndex = null; ImGui.SameLine(); if (ImGui.Button("Delete")) { if (ImGui.IsKeyDown(ImGuiKey.ModShift)) - { - Settings.SavedFilters.Remove(savedFilter); - } + list.Remove(savedFilter); } else if (ImGui.IsItemHovered()) - { ImGui.SetTooltip("Hold Shift"); - } - ImGui.SameLine(); - ImGui.TextUnformatted(savedFilter); - + ImGui.TextUnformatted(string.IsNullOrEmpty(savedFilter.DisplayName) ? savedFilter.Query : savedFilter.DisplayName); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip(savedFilter.Query); ImGui.PopID(); } - - if (Settings.UsePopupForFilterSelector) - { - ImGui.EndPopup(); - } - else - { - ImGui.TreePop(); - } - } - - if (Settings.UsePopupForFilterSelector) - { - if (ImGui.Button("Open Saved Filters")) - { - ImGui.OpenPopup("saved_filter_popup"); - } + ImGui.TreePop(); } - - ImGui.End(); - return returnValue; + ImGui.PopID(); } - - return null; } public override void Render() @@ -200,6 +330,14 @@ public override void Render() if (!Settings.Enable) return; + var panelsOpen = TryGetFilterAnchor(out var filterAnchor); + if (Settings.ResetCustomFilterOnPanelClose && !panelsOpen) + _customItemFilter = ""; + + Predicate entityPredicate = null; + if (panelsOpen && Settings.ShowCustomFilterWindow) + entityPredicate = GetPredicate(ref _customItemFilter, filterAnchor); + var (inventory, rectElement) = (InGameState.IngameUi.StashElement, InGameState.IngameUi.GuildStashElement) switch { ({ IsVisible: true, VisibleStash: { InventoryUIElement: { } invRect } visibleStash }, _) => (visibleStash, invRect), @@ -212,7 +350,7 @@ public override void Render() if (inventory != null) { var stashRect = rectElement.GetClientRectCache; - var (itemFilter, isCustomFilter) = GetPredicate("Custom stash filter", ref _customStashFilter, stashRect.BottomLeft.ToVector2Num()) is { } customPredicate + var (itemFilter, isCustomFilter) = entityPredicate is { } customPredicate ? ((Predicate)(s => customPredicate(s.Item)), true) : (s => s.isHighlighted != Settings.InvertSelection.Value, false); @@ -264,20 +402,13 @@ public override void Render() _currentOperation = MoveItemsToInventory(orderedItems); } } - else - { - if (Settings.ResetCustomFilterOnPanelClose) - { - _customStashFilter = ""; - } - } var inventoryPanel = InGameState.IngameUi.InventoryPanel; if (inventoryPanel.IsVisible) { var inventoryRect = inventoryPanel[2].GetClientRectCache; - var (itemFilter, isCustomFilter) = GetPredicate("Custom inventory filter", ref _customInventoryFilter, inventoryRect.BottomLeft.ToVector2Num()) is { } customPredicate + var (itemFilter, isCustomFilter) = entityPredicate is { } customPredicate ? (customPredicate, true) : (_ => true, false); @@ -323,13 +454,6 @@ public override void Render() } } } - else - { - if (Settings.ResetCustomFilterOnPanelClose) - { - _customInventoryFilter = ""; - } - } } private async SyncTask MoveItemsCommonPreamble() diff --git a/HighlightedItems.csproj b/HighlightedItems.csproj index b9c21b8..5d938a5 100644 --- a/HighlightedItems.csproj +++ b/HighlightedItems.csproj @@ -1,35 +1,35 @@ - - - net10.0-windows - Library - true - x64 - true - latest - embedded - $(MSBuildProjectDirectory)=$(MSBuildProjectName) - true - $(ExApiPluginOutputPath)$(MSBuildProjectName) - - - - - - - PreserveNewest - - - - - $(exapiPackage)\ExileCore.dll - False - - - $(exapiPackage)\ItemFilterLibrary.dll - - - - - - - + + + net10.0-windows + Library + true + x64 + true + latest + embedded + $(MSBuildProjectDirectory)=$(MSBuildProjectName) + true + $(ExApiPluginOutputPath)$(MSBuildProjectName) + + + + + + + PreserveNewest + + + + + $(exapiPackage)\ExileCore.dll + False + + + $(exapiPackage)\ItemFilterLibrary.dll + + + + + + + diff --git a/SavedFilter.cs b/SavedFilter.cs new file mode 100644 index 0000000..27314c7 --- /dev/null +++ b/SavedFilter.cs @@ -0,0 +1,8 @@ +namespace HighlightedItems; + +public class SavedFilter +{ + public string DisplayName { get; set; } = ""; + public string Query { get; set; } = ""; + public string Folder { get; set; } = ""; +} diff --git a/Settings.cs b/Settings.cs index 5b5cb2d..56ad049 100644 --- a/Settings.cs +++ b/Settings.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Windows.Forms; using ExileCore.Shared.Attributes; using ExileCore.Shared.Interfaces; @@ -62,6 +62,10 @@ public class Settings : ISettings [IgnoreMenu] public List SavedFilters { get; set; } = []; + [IgnoreMenu] + public List SavedFilterEntries { get; set; } = []; + [IgnoreMenu] public bool OpenSavedFilterList { get; set; } = true; + } \ No newline at end of file From af43b752822eba430b7436ba4aac419f45400eb0 Mon Sep 17 00:00:00 2001 From: deMathias <47175867+deMathias@users.noreply.github.com> Date: Thu, 2 Apr 2026 13:57:00 +0200 Subject: [PATCH 2/2] Update HighlightedItems.cs --- HighlightedItems.cs | 137 +++++++++++++++++++++++++++++++++----------- 1 file changed, 105 insertions(+), 32 deletions(-) diff --git a/HighlightedItems.cs b/HighlightedItems.cs index d5f9d60..02f8592 100644 --- a/HighlightedItems.cs +++ b/HighlightedItems.cs @@ -30,9 +30,12 @@ public class HighlightedItems : BaseSettingsPlugin private string _editQuery = ""; private string _editName = ""; private string _editFolder = ""; - private string _newQuery = ""; - private string _newName = ""; - private string _newFolder = ""; + private string _saveAsQuerySnapshot = ""; + private string _saveAsName = ""; + private string _saveAsFolder = ""; + private string _folderDeleteKey; + private string _folderDeleteLabel; + private bool _openFolderDeleteConfirm; private record QueryOrException(ItemQuery Query, Exception Exception); @@ -112,34 +115,71 @@ private bool TryGetFilterAnchor(out Vector2 anchor) return false; } + private static string TruncateUi(string text, int maxLen) + { + if (string.IsNullOrEmpty(text)) return ""; + return text.Length <= maxLen ? text : text.Substring(0, maxLen - 1) + "…"; + } + + private static string LineLabel(SavedFilter f) => + string.IsNullOrEmpty(f.DisplayName) ? TruncateUi(f.Query, 36) : TruncateUi(f.DisplayName, 44); + + private void RemoveFiltersInFolder(string folderKey) + { + var key = folderKey ?? ""; + Settings.SavedFilterEntries.RemoveAll(x => (x.Folder ?? "") == key); + } + private Predicate GetPredicate(ref string filterText, Vector2 defaultPosition) { if (!Settings.ShowCustomFilterWindow) return null; Settings.SavedFilters ??= []; Settings.SavedFilterEntries ??= []; + ImGui.SetNextWindowSizeConstraints(new Vector2(340, 200), new Vector2(900, 1200)); + ImGui.SetNextWindowSize(new Vector2(440, 560), ImGuiCond.FirstUseEver); ImGui.SetNextWindowPos(defaultPosition, ImGuiCond.FirstUseEver); - if (!ImGui.Begin("Custom filter", ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.AlwaysAutoResize)) + if (!ImGui.Begin("Custom filter", ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoCollapse)) return null; + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(8, 7)); + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(8, 5)); MigrateLegacySavedFilters(); ImGui.TextUnformatted("Active IFL filter"); - ImGui.InputTextMultiline("##input", ref filterText, 8000, new Vector2(320, 128)); + ImGui.InputTextMultiline("##input", ref filterText, 8000, new Vector2(-1, 150)); Predicate returnValue = null; if (ImGui.Button("Clear")) filterText = ""; + ImGui.SameLine(); var trimmed = filterText.Trim(); - if (!string.IsNullOrEmpty(trimmed) && !Settings.SavedFilterEntries.Any(x => x.Query == trimmed)) + ImGui.BeginDisabled(string.IsNullOrWhiteSpace(trimmed)); + if (ImGui.Button("Save")) { - ImGui.SameLine(); + _saveAsQuerySnapshot = trimmed; + _saveAsName = trimmed.Length > 48 ? trimmed.Substring(0, 45) + "…" : trimmed; + _saveAsFolder = ""; + ImGui.OpenPopup("hi_save_active_filter"); + } + ImGui.EndDisabled(); + if (ImGui.BeginPopup("hi_save_active_filter")) + { + ImGui.TextUnformatted("Name"); + ImGui.InputTextWithHint("##saveasname", "Name", ref _saveAsName, 128); + ImGui.TextUnformatted("Group"); + ImGui.InputTextWithHint("##saveasfolder", "Group", ref _saveAsFolder, 64); if (ImGui.Button("Save")) { - Settings.SavedFilterEntries.Add(new SavedFilter + var q = _saveAsQuerySnapshot; + if (!string.IsNullOrWhiteSpace(q)) { - DisplayName = trimmed.Length > 48 ? trimmed.Substring(0, 45) + "…" : trimmed, - Query = trimmed, - Folder = "" - }); + var dn = string.IsNullOrWhiteSpace(_saveAsName.Trim()) ? TruncateUi(q, 48) : _saveAsName.Trim(); + Settings.SavedFilterEntries.Add(new SavedFilter { DisplayName = dn, Query = q.Trim(), Folder = _saveAsFolder ?? "" }); + } + ImGui.CloseCurrentPopup(); } + ImGui.SameLine(); + if (ImGui.Button("Cancel")) + ImGui.CloseCurrentPopup(); + ImGui.EndPopup(); } if (!string.IsNullOrEmpty(trimmed)) { @@ -173,6 +213,7 @@ private Predicate GetPredicate(ref string filterText, Vector2 defaultPos } }; } + ImGui.Separator(); if (Settings.UsePopupForFilterSelector) { if (ImGui.Button("Open Saved Filters")) @@ -195,41 +236,66 @@ private Predicate GetPredicate(ref string filterText, Vector2 defaultPos if (!Settings.SavedFilterEntries.Any()) ImGui.TextUnformatted("No saved filters yet."); else + { + var savedH = Math.Max(120f, ImGui.GetContentRegionAvail().Y); + ImGui.BeginChild("##saved_scroll", new Vector2(0, savedH), ImGuiChildFlags.Border, ImGuiWindowFlags.HorizontalScrollbar); DrawSavedFilterRows(ref filterText); + ImGui.EndChild(); + } ImGui.TreePop(); } - if (ImGui.TreeNodeEx("Add new IFL Filter")) + if (_openFolderDeleteConfirm) + { + ImGui.OpenPopup("hi_confirm_folder_delete"); + _openFolderDeleteConfirm = false; + } + if (ImGui.BeginPopup("hi_confirm_folder_delete")) { - ImGui.TextUnformatted("Display name"); - ImGui.InputTextWithHint("##addname", "Short name", ref _newName, 128); - ImGui.TextUnformatted("Folder"); - ImGui.InputTextWithHint("##addfolder", "Optional", ref _newFolder, 64); - ImGui.TextUnformatted("IFL query"); - ImGui.InputTextMultiline("##addquery", ref _newQuery, 8000, new Vector2(320, 128)); - if (ImGui.Button("Add") && !string.IsNullOrWhiteSpace(_newQuery)) + ImGui.TextUnformatted($"Remove all filters in \"{_folderDeleteLabel}\"?"); + if (ImGui.Button("Remove all")) { - var q = _newQuery.Trim(); - var dn = string.IsNullOrWhiteSpace(_newName) ? (q.Length > 48 ? q.Substring(0, 45) + "…" : q) : _newName; - Settings.SavedFilterEntries.Add(new SavedFilter { DisplayName = dn, Query = q, Folder = _newFolder ?? "" }); - _newQuery = ""; - _newName = ""; - _newFolder = ""; + RemoveFiltersInFolder(_folderDeleteKey); + ImGui.CloseCurrentPopup(); } - ImGui.TreePop(); + ImGui.SameLine(); + if (ImGui.Button("Cancel")) + ImGui.CloseCurrentPopup(); + ImGui.EndPopup(); } + ImGui.PopStyleVar(2); ImGui.End(); return returnValue; } private void DrawSavedFilterRows(ref string filterText) { + ImGui.TextDisabled("Hover a name for full IFL; hold Shift and click Delete to remove a filter."); + ImGui.Spacing(); + ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(9, 5)); + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, new Vector2(8, 6)); var list = Settings.SavedFilterEntries; foreach (var folderGroup in list.Select((f, i) => (f, i)).GroupBy(t => t.f.Folder ?? "").OrderBy(g => g.Key)) { var label = string.IsNullOrEmpty(folderGroup.Key) ? "General" : folderGroup.Key; ImGui.PushID($"fld_{label}"); - if (ImGui.TreeNodeEx(label, ImGuiTreeNodeFlags.DefaultOpen)) + var folderId = $"##fld_{folderGroup.Key.GetHashCode():X8}"; + var treeOpen = ImGui.TreeNodeEx(folderId, ImGuiTreeNodeFlags.DefaultOpen); + ImGui.SameLine(); + ImGui.TextUnformatted(label); + ImGui.SameLine(0, 8f); + ImGui.PushID("foldtools"); + if (ImGui.Button("Delete group")) + { + _folderDeleteKey = folderGroup.Key; + _folderDeleteLabel = label; + _openFolderDeleteConfirm = true; + } + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Remove every filter in this folder"); + ImGui.PopID(); + if (treeOpen) { + ImGui.Separator(); foreach (var (savedFilter, index) in folderGroup.OrderBy(x => x.i)) { ImGui.PushID($"saved{index}"); @@ -276,9 +342,9 @@ private void DrawSavedFilterRows(ref string filterText) ImGui.TextUnformatted("Display name"); ImGui.InputTextWithHint("##editname", "Short name", ref _editName, 128); ImGui.TextUnformatted("Folder"); - ImGui.InputTextWithHint("##editfolder", "Optional", ref _editFolder, 64); + ImGui.InputTextWithHint("##editfolder", "Optional group", ref _editFolder, 64); ImGui.TextUnformatted("IFL query"); - ImGui.InputTextMultiline("##editquery", ref _editQuery, 8000, new Vector2(320, 128)); + ImGui.InputTextMultiline("##editquery", ref _editQuery, 8000, new Vector2(-1, 150)); if (ImGui.Button("Save")) { savedFilter.Query = _editQuery.Trim(); @@ -300,15 +366,22 @@ private void DrawSavedFilterRows(ref string filterText) else if (ImGui.IsItemHovered()) ImGui.SetTooltip("Hold Shift"); ImGui.SameLine(); - ImGui.TextUnformatted(string.IsNullOrEmpty(savedFilter.DisplayName) ? savedFilter.Query : savedFilter.DisplayName); + ImGui.TextUnformatted(LineLabel(savedFilter)); if (ImGui.IsItemHovered()) - ImGui.SetTooltip(savedFilter.Query); + { + ImGui.BeginTooltip(); + ImGui.PushTextWrapPos(ImGui.GetFontSize() * 42); + ImGui.TextUnformatted(savedFilter.Query); + ImGui.PopTextWrapPos(); + ImGui.EndTooltip(); + } ImGui.PopID(); } ImGui.TreePop(); } ImGui.PopID(); } + ImGui.PopStyleVar(2); } public override void Render()