Skip to content

Commit 4a0ec65

Browse files
committed
rework file tree
1 parent a09fc03 commit 4a0ec65

File tree

3 files changed

+225
-151
lines changed

3 files changed

+225
-151
lines changed

GUI/App.xaml.cs

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
using System.Globalization;
22
using System.IO;
33
using System.Windows;
4-
54
using FEZRepacker.Core.FileSystem;
6-
using FEZRepacker.GUI.Windows;
75

86
namespace FEZRepacker.GUI
97
{
108
public partial class App : Application
119
{
1210
public string CurrentPackageName = "";
13-
public List<FileBundle> FileBundleList = new();
14-
public bool BundleDirty = false;
11+
public PakPackage CurrentPackage = new();
12+
public bool PackageDirty = false;
13+
14+
public Main MainAppWindow => (Main)MainWindow;
1515

1616
protected override void OnStartup(StartupEventArgs e)
1717
{
@@ -21,50 +21,28 @@ protected override void OnStartup(StartupEventArgs e)
2121
CreateEmptyPackage();
2222
}
2323

24-
2524
public void CreateEmptyPackage()
2625
{
27-
FileBundleList = new();
26+
CurrentPackage = new PakPackage();
2827
CurrentPackageName = "untitled.pak";
29-
BundleDirty = false;
30-
31-
(MainWindow as Main)?.Refresh();
28+
PackageDirty = false;
29+
RefreshMainWindow();
3230
}
3331

3432
public void OpenPackage(string path)
3533
{
36-
var status = new ProgressStatus("Opening package");
34+
using var pakStream = File.OpenRead(path);
35+
CurrentPackage = new PakPackage(pakStream);
36+
PackageDirty = false;
37+
RefreshMainWindow();
38+
}
3739

38-
status.Task += () =>
40+
void RefreshMainWindow()
41+
{
42+
if (MainWindow is Main mainWindow)
3943
{
40-
status.SetStageCount(1);
41-
status.SetStageName("Unpacking package (1/4)");
42-
43-
FileBundleList = new();
44-
45-
using var pakStream = File.OpenRead(path);
46-
using var pakReader = new PakReader(pakStream);
47-
48-
int filesProcessed = 0;
49-
foreach (var pakFile in pakReader.ReadFiles())
50-
{
51-
status.SetStageText($"{pakFile.Path}");
52-
status.SetStageCompletion(filesProcessed / (float)pakReader.FileCount);
53-
54-
var bundle = FileBundle.Single(new MemoryStream(pakFile.Payload), ".xnb");
55-
bundle.BundlePath = pakFile.Path;
56-
FileBundleList.Add(bundle);
57-
58-
filesProcessed++;
59-
}
60-
61-
CurrentPackageName = Path.GetFileName(path);
62-
BundleDirty = false;
63-
};
64-
65-
status.OnComplete += () => (MainWindow as Main)?.Refresh();
66-
67-
status.Run();
44+
mainWindow.Refresh();
45+
}
6846
}
6947
}
7048
}

GUI/Views/PakFileTreeView.cs

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
using System.Windows;
2+
using System.Windows.Controls;
3+
using System.Windows.Media;
4+
5+
using FEZRepacker.Core.FileSystem;
6+
7+
namespace FEZRepacker.GUI.Views
8+
{
9+
internal class PakFileTreeView
10+
{
11+
private class TreeNode
12+
{
13+
public readonly TreeNode? Parent;
14+
public readonly string Name = "";
15+
public readonly int Depth;
16+
17+
public readonly List<TreeNode> Entries = new();
18+
19+
public WeakReference<PakFileRecord>? LinkedFile;
20+
public bool Expanded = false;
21+
22+
public TreeNode(TreeNode? parent, string name)
23+
{
24+
Parent = parent;
25+
Depth = parent?.Depth + 1 ?? 0;
26+
Name = name;
27+
}
28+
29+
public TreeNode GetOrCreateEntry(string name)
30+
{
31+
var node = Entries.Find(n => n.Name == name);
32+
if (node == null)
33+
{
34+
node = new TreeNode(this, name);
35+
Entries.Add(node);
36+
}
37+
return node;
38+
}
39+
}
40+
41+
private struct TreeNodeView
42+
{
43+
public TreeNode Model;
44+
45+
public StackPanel MainView;
46+
public Button Button;
47+
public StackPanel EntriesGroup;
48+
}
49+
50+
private readonly StackPanel FileListPanel;
51+
52+
private readonly Style baseFileButtonStyle;
53+
private readonly Style openFileButtonStyle;
54+
private readonly Style closedFileButtonStyle;
55+
56+
private TreeNode rootNode = new(null, "");
57+
private TreeNode? selectedNode = null;
58+
59+
private readonly Dictionary<TreeNode, TreeNodeView> nodeViews = new();
60+
61+
public PakFileTreeView(StackPanel fileListPanel)
62+
{
63+
FileListPanel = fileListPanel;
64+
65+
baseFileButtonStyle = (Style)FileListPanel.FindResource("FileButton");
66+
openFileButtonStyle = (Style)FileListPanel.FindResource("OpenDirectoryFileButton");
67+
closedFileButtonStyle = (Style)FileListPanel.FindResource("DirectoryFileButton");
68+
}
69+
70+
public void Refresh(PakPackage pakPackage, string pakName)
71+
{
72+
RecreateTree(pakPackage, pakName);
73+
RefreshTreeView();
74+
}
75+
76+
private void RecreateTree(PakPackage pakPackage, string pakName)
77+
{
78+
rootNode = new TreeNode(null, pakName);
79+
if(pakPackage.Entries.Count > 0)
80+
{
81+
rootNode.Expanded = true;
82+
}
83+
84+
foreach (var entry in pakPackage.Entries)
85+
{
86+
CreateBranchForFile(entry);
87+
}
88+
}
89+
90+
private void CreateBranchForFile(PakFileRecord record)
91+
{
92+
var dirs = record.Path.Split("\\");
93+
var currentNode = rootNode;
94+
foreach (var dir in dirs)
95+
{
96+
currentNode = currentNode.GetOrCreateEntry(dir);
97+
}
98+
currentNode.LinkedFile = new(record);
99+
}
100+
101+
private void RefreshTreeView()
102+
{
103+
FileListPanel.Children.Clear();
104+
RefreshNodeBranch(rootNode);
105+
}
106+
107+
private void RefreshNodeBranch(TreeNode node)
108+
{
109+
if (!nodeViews.ContainsKey(node))
110+
{
111+
CreateNodeView(node);
112+
}
113+
114+
UpdateNodeView(node);
115+
116+
if (node.Expanded)
117+
{
118+
foreach (var childNode in node.Entries)
119+
{
120+
RefreshNodeBranch(childNode);
121+
}
122+
}
123+
}
124+
125+
private void CreateNodeView(TreeNode node)
126+
{
127+
var button = new Button();
128+
button.Content = node.Name;
129+
button.Click += (sender, e) => OnFileViewClicked(node);
130+
131+
var nodeView = new StackPanel();
132+
var entriesGroup = new StackPanel();
133+
134+
nodeView.Children.Add(button);
135+
nodeView.Children.Add(entriesGroup);
136+
137+
if(node.Parent == null)
138+
{
139+
FileListPanel.Children.Add(nodeView);
140+
}
141+
else
142+
{
143+
var parentEntriesGroup = nodeViews[node.Parent].EntriesGroup;
144+
var insertIndex = node.Parent.Entries.IndexOf(node);
145+
parentEntriesGroup.Children.Insert(insertIndex, nodeView);
146+
}
147+
148+
nodeViews.Add(node, new()
149+
{
150+
Model = node,
151+
MainView = nodeView,
152+
Button = button,
153+
EntriesGroup = entriesGroup,
154+
});
155+
}
156+
157+
private void UpdateNodeView(TreeNode node)
158+
{
159+
if (!nodeViews.TryGetValue(node, out var view))
160+
{
161+
return;
162+
}
163+
164+
view.Button.Padding = new Thickness(node.Depth * 10, 0, 0, 0);
165+
166+
view.Button.Style = node switch
167+
{
168+
{ LinkedFile: not null } => baseFileButtonStyle,
169+
{ Expanded: true } => openFileButtonStyle,
170+
{ Expanded: false } => closedFileButtonStyle,
171+
};
172+
173+
if (node == selectedNode)
174+
{
175+
view.Button.Background = new SolidColorBrush(new Color() { R = 255, G = 255, B = 255, A = 64 });
176+
}
177+
else
178+
{
179+
view.Button.ClearValue(Button.BackgroundProperty);
180+
}
181+
182+
view.EntriesGroup.Visibility = node.Expanded switch
183+
{
184+
true => Visibility.Visible,
185+
false => Visibility.Collapsed
186+
};
187+
}
188+
189+
void OnFileViewClicked(TreeNode node)
190+
{
191+
node.Expanded = !node.Expanded;
192+
var oldSelectedNode = selectedNode;
193+
selectedNode = node;
194+
if(oldSelectedNode != null && oldSelectedNode != node)
195+
{
196+
UpdateNodeView(oldSelectedNode);
197+
}
198+
199+
RefreshNodeBranch(node);
200+
}
201+
}
202+
}

0 commit comments

Comments
 (0)