mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
ResourceTree: Add name/path filter
This commit is contained in:
parent
f4bdbcac53
commit
c7046ec006
3 changed files with 60 additions and 19 deletions
|
|
@ -10,7 +10,6 @@ public class ResourceNode : ICloneable
|
|||
public string? Name;
|
||||
public string? FallbackName;
|
||||
public ChangedItemIcon Icon;
|
||||
public ChangedItemIcon DescendentIcons;
|
||||
public readonly ResourceType Type;
|
||||
public readonly nint ObjectAddress;
|
||||
public readonly nint ResourceHandle;
|
||||
|
|
@ -53,7 +52,6 @@ public class ResourceNode : ICloneable
|
|||
Name = other.Name;
|
||||
FallbackName = other.FallbackName;
|
||||
Icon = other.Icon;
|
||||
DescendentIcons = other.DescendentIcons;
|
||||
Type = other.Type;
|
||||
ObjectAddress = other.ObjectAddress;
|
||||
ResourceHandle = other.ResourceHandle;
|
||||
|
|
|
|||
|
|
@ -116,9 +116,6 @@ public class ResourceTreeFactory(
|
|||
{
|
||||
if (node.Name == parent?.Name)
|
||||
node.Name = null;
|
||||
|
||||
if (parent != null)
|
||||
parent.DescendentIcons |= node.Icon | node.DescendentIcons;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,9 +24,12 @@ public class ResourceTreeViewer
|
|||
private readonly Action<ResourceNode, Vector2> _drawActions;
|
||||
private readonly HashSet<nint> _unfolded;
|
||||
|
||||
private readonly Dictionary<nint, NodeVisibility> _filterCache;
|
||||
|
||||
private TreeCategory _categoryFilter;
|
||||
private ChangedItemDrawer.ChangedItemIcon _typeFilter;
|
||||
private string _nameFilter;
|
||||
private string _nodeFilter;
|
||||
|
||||
private Task<ResourceTree[]>? _task;
|
||||
|
||||
|
|
@ -40,11 +43,14 @@ public class ResourceTreeViewer
|
|||
_actionCapacity = actionCapacity;
|
||||
_onRefresh = onRefresh;
|
||||
_drawActions = drawActions;
|
||||
_unfolded = new HashSet<nint>();
|
||||
_unfolded = [];
|
||||
|
||||
_filterCache = [];
|
||||
|
||||
_categoryFilter = AllCategories;
|
||||
_typeFilter = ChangedItemDrawer.AllFlags;
|
||||
_nameFilter = string.Empty;
|
||||
_nodeFilter = string.Empty;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
|
|
@ -107,7 +113,7 @@ public class ResourceTreeViewer
|
|||
(_actionCapacity - 1) * 3 * ImGuiHelpers.GlobalScale + _actionCapacity * ImGui.GetFrameHeight());
|
||||
ImGui.TableHeadersRow();
|
||||
|
||||
DrawNodes(tree.Nodes, 0, unchecked(tree.DrawObjectAddress * 31));
|
||||
DrawNodes(tree.Nodes, 0, unchecked(tree.DrawObjectAddress * 31), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -140,14 +146,22 @@ public class ResourceTreeViewer
|
|||
|
||||
ImGui.SameLine(0, checkPadding);
|
||||
|
||||
var filterChanged = false;
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - yOffset);
|
||||
using (ImRaii.Child("##typeFilter", new Vector2(ImGui.GetContentRegionAvail().X, ChangedItemDrawer.TypeFilterIconSize.Y)))
|
||||
_changedItemDrawer.DrawTypeFilter(ref _typeFilter);
|
||||
filterChanged |= _changedItemDrawer.DrawTypeFilter(ref _typeFilter);
|
||||
|
||||
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X - checkSpacing - ImGui.GetFrameHeightWithSpacing());
|
||||
ImGui.InputTextWithHint("##TreeNameFilter", "Filter by Character/Entity Name...", ref _nameFilter, 128);
|
||||
var fieldWidth = (ImGui.GetContentRegionAvail().X - checkSpacing * 2.0f - ImGui.GetFrameHeightWithSpacing()) / 2.0f;
|
||||
ImGui.SetNextItemWidth(fieldWidth);
|
||||
filterChanged |= ImGui.InputTextWithHint("##TreeNameFilter", "Filter by Character/Entity Name...", ref _nameFilter, 128);
|
||||
ImGui.SameLine(0, checkSpacing);
|
||||
ImGui.SetNextItemWidth(fieldWidth);
|
||||
filterChanged |= ImGui.InputTextWithHint("##NodeFilter", "Filter by Item/Part Name or Path...", ref _nodeFilter, 128);
|
||||
ImGui.SameLine(0, checkSpacing);
|
||||
_incognito.DrawToggle();
|
||||
|
||||
if (filterChanged)
|
||||
_filterCache.Clear();
|
||||
}
|
||||
|
||||
private Task<ResourceTree[]> RefreshCharacterList()
|
||||
|
|
@ -161,36 +175,68 @@ public class ResourceTreeViewer
|
|||
}
|
||||
finally
|
||||
{
|
||||
_filterCache.Clear();
|
||||
_unfolded.Clear();
|
||||
_onRefresh();
|
||||
}
|
||||
});
|
||||
|
||||
private void DrawNodes(IEnumerable<ResourceNode> resourceNodes, int level, nint pathHash)
|
||||
private void DrawNodes(IEnumerable<ResourceNode> resourceNodes, int level, nint pathHash, ChangedItemDrawer.ChangedItemIcon parentFilterIcon)
|
||||
{
|
||||
var debugMode = _config.DebugMode;
|
||||
var frameHeight = ImGui.GetFrameHeight();
|
||||
var cellHeight = _actionCapacity > 0 ? frameHeight : 0.0f;
|
||||
|
||||
NodeVisibility GetNodeVisibility(ResourceNode node)
|
||||
bool MatchesFilter(ResourceNode node, ChangedItemDrawer.ChangedItemIcon filterIcon)
|
||||
{
|
||||
if (!_typeFilter.HasFlag(filterIcon))
|
||||
return false;
|
||||
|
||||
if (_nodeFilter.Length == 0)
|
||||
return true;
|
||||
|
||||
return node.Name != null && node.Name.Contains(_nodeFilter, StringComparison.OrdinalIgnoreCase)
|
||||
|| node.FullPath.FullName.Contains(_nodeFilter, StringComparison.OrdinalIgnoreCase)
|
||||
|| node.FullPath.InternalName.ToString().Contains(_nodeFilter, StringComparison.OrdinalIgnoreCase)
|
||||
|| Array.Exists(node.PossibleGamePaths, path => path.Path.ToString().Contains(_nodeFilter, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
NodeVisibility CalculateNodeVisibility(nint nodePathHash, ResourceNode node, ChangedItemDrawer.ChangedItemIcon parentFilterIcon)
|
||||
{
|
||||
if (node.Internal && !debugMode)
|
||||
return NodeVisibility.Hidden;
|
||||
|
||||
if (_typeFilter.HasFlag(node.Icon))
|
||||
var filterIcon = node.Icon != 0 ? node.Icon : parentFilterIcon;
|
||||
if (MatchesFilter(node, filterIcon))
|
||||
return NodeVisibility.Visible;
|
||||
if ((_typeFilter & node.DescendentIcons) != 0)
|
||||
return NodeVisibility.DescendentsOnly;
|
||||
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
if (GetNodeVisibility(unchecked(nodePathHash * 31 + child.ResourceHandle), child, filterIcon) != NodeVisibility.Hidden)
|
||||
return NodeVisibility.DescendentsOnly;
|
||||
}
|
||||
|
||||
return NodeVisibility.Hidden;
|
||||
}
|
||||
|
||||
NodeVisibility GetNodeVisibility(nint nodePathHash, ResourceNode node, ChangedItemDrawer.ChangedItemIcon parentFilterIcon)
|
||||
{
|
||||
if (!_filterCache.TryGetValue(nodePathHash, out var visibility))
|
||||
{
|
||||
visibility = CalculateNodeVisibility(nodePathHash, node, parentFilterIcon);
|
||||
_filterCache.Add(nodePathHash, visibility);
|
||||
}
|
||||
return visibility;
|
||||
}
|
||||
|
||||
string GetAdditionalDataSuffix(ByteString data)
|
||||
=> !debugMode || data.IsEmpty ? string.Empty : $"\n\nAdditional Data: {data}";
|
||||
|
||||
foreach (var (resourceNode, index) in resourceNodes.WithIndex())
|
||||
{
|
||||
var visibility = GetNodeVisibility(resourceNode);
|
||||
var nodePathHash = unchecked(pathHash + resourceNode.ResourceHandle);
|
||||
|
||||
var visibility = GetNodeVisibility(nodePathHash, resourceNode, parentFilterIcon);
|
||||
if (visibility == NodeVisibility.Hidden)
|
||||
continue;
|
||||
|
||||
|
|
@ -199,14 +245,14 @@ public class ResourceTreeViewer
|
|||
|
||||
using var mutedColor = ImRaii.PushColor(ImGuiCol.Text, textColorInternal, resourceNode.Internal);
|
||||
|
||||
var nodePathHash = unchecked(pathHash + resourceNode.ResourceHandle);
|
||||
var filterIcon = resourceNode.Icon != 0 ? resourceNode.Icon : parentFilterIcon;
|
||||
|
||||
using var id = ImRaii.PushId(index);
|
||||
ImGui.TableNextColumn();
|
||||
var unfolded = _unfolded.Contains(nodePathHash);
|
||||
using (var indent = ImRaii.PushIndent(level))
|
||||
{
|
||||
var hasVisibleChildren = resourceNode.Children.Any(child => GetNodeVisibility(child) != NodeVisibility.Hidden);
|
||||
var hasVisibleChildren = resourceNode.Children.Any(child => GetNodeVisibility(unchecked(nodePathHash * 31 + child.ResourceHandle), child, filterIcon) != NodeVisibility.Hidden);
|
||||
var unfoldable = hasVisibleChildren && visibility != NodeVisibility.DescendentsOnly;
|
||||
if (unfoldable)
|
||||
{
|
||||
|
|
@ -291,7 +337,7 @@ public class ResourceTreeViewer
|
|||
}
|
||||
|
||||
if (unfolded)
|
||||
DrawNodes(resourceNode.Children, level + 1, unchecked(nodePathHash * 31));
|
||||
DrawNodes(resourceNode.Children, level + 1, unchecked(nodePathHash * 31), filterIcon);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue