- [GUI] AssetBrowser improvments

This commit is contained in:
Razmoth
2023-11-25 13:13:41 +04:00
parent 485da98499
commit 89a3543f18
3 changed files with 169 additions and 32 deletions

View File

@@ -1,4 +1,5 @@
using System.Windows.Forms; using System.Configuration;
using System.Windows.Forms;
namespace AssetStudio.GUI namespace AssetStudio.GUI
{ {
@@ -30,37 +31,42 @@ namespace AssetStudio.GUI
/// </summary> /// </summary>
private void InitializeComponent() private void InitializeComponent()
{ {
assetListView = new DataGridView(); assetDataGridView = new DataGridView();
tableLayoutPanel1 = new TableLayoutPanel(); tableLayoutPanel1 = new TableLayoutPanel();
tableLayoutPanel2 = new TableLayoutPanel(); tableLayoutPanel2 = new TableLayoutPanel();
loadAssetMap = new Button(); loadAssetMap = new Button();
clear = new Button(); clear = new Button();
loadSelected = new Button(); loadSelected = new Button();
searchTextBox = new TextBox(); searchTextBox = new TextBox();
((System.ComponentModel.ISupportInitialize)assetListView).BeginInit(); ((System.ComponentModel.ISupportInitialize)assetDataGridView).BeginInit();
tableLayoutPanel1.SuspendLayout(); tableLayoutPanel1.SuspendLayout();
tableLayoutPanel2.SuspendLayout(); tableLayoutPanel2.SuspendLayout();
FormClosing += AssetBrowser_FormClosing;
SuspendLayout(); SuspendLayout();
// //
// assetListView // assetDataGridView
// //
assetListView.AllowUserToAddRows = false; assetDataGridView.AllowUserToAddRows = false;
assetListView.AllowUserToDeleteRows = false; assetDataGridView.AllowUserToDeleteRows = false;
assetListView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; assetDataGridView.AllowUserToResizeRows = false;
assetListView.Dock = DockStyle.Fill; assetDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
assetListView.Location = new System.Drawing.Point(3, 38); assetDataGridView.Dock = DockStyle.Fill;
assetListView.Name = "assetListView"; assetDataGridView.Location = new System.Drawing.Point(3, 38);
assetListView.ReadOnly = true; assetDataGridView.Name = "assetDataGridView";
assetListView.RowTemplate.Height = 25; assetDataGridView.ReadOnly = true;
assetListView.Size = new System.Drawing.Size(518, 250); assetDataGridView.RowTemplate.Height = 25;
assetListView.TabIndex = 2; assetDataGridView.Size = new System.Drawing.Size(518, 250);
assetDataGridView.TabIndex = 2;
assetDataGridView.VirtualMode = true;
assetDataGridView.CellValueNeeded += AssetDataGridView_CellValueNeeded;
assetDataGridView.ColumnHeaderMouseClick += AssetListView_ColumnHeaderMouseClick;
// //
// tableLayoutPanel1 // tableLayoutPanel1
// //
tableLayoutPanel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; tableLayoutPanel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
tableLayoutPanel1.ColumnCount = 1; tableLayoutPanel1.ColumnCount = 1;
tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F)); tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
tableLayoutPanel1.Controls.Add(assetListView, 0, 1); tableLayoutPanel1.Controls.Add(assetDataGridView, 0, 1);
tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 0); tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 0);
tableLayoutPanel1.Location = new System.Drawing.Point(12, 12); tableLayoutPanel1.Location = new System.Drawing.Point(12, 12);
tableLayoutPanel1.Name = "tableLayoutPanel1"; tableLayoutPanel1.Name = "tableLayoutPanel1";
@@ -142,7 +148,7 @@ namespace AssetStudio.GUI
ShowIcon = false; ShowIcon = false;
StartPosition = FormStartPosition.CenterScreen; StartPosition = FormStartPosition.CenterScreen;
Text = "Asset Browser"; Text = "Asset Browser";
((System.ComponentModel.ISupportInitialize)assetListView).EndInit(); ((System.ComponentModel.ISupportInitialize)assetDataGridView).EndInit();
tableLayoutPanel1.ResumeLayout(false); tableLayoutPanel1.ResumeLayout(false);
tableLayoutPanel2.ResumeLayout(false); tableLayoutPanel2.ResumeLayout(false);
tableLayoutPanel2.PerformLayout(); tableLayoutPanel2.PerformLayout();
@@ -152,7 +158,7 @@ namespace AssetStudio.GUI
#endregion #endregion
private System.Windows.Forms.DataGridView assetListView; private System.Windows.Forms.DataGridView assetDataGridView;
private TableLayoutPanel tableLayoutPanel1; private TableLayoutPanel tableLayoutPanel1;
private TableLayoutPanel tableLayoutPanel2; private TableLayoutPanel tableLayoutPanel2;
private Button loadAssetMap; private Button loadAssetMap;

View File

@@ -1,22 +1,28 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using AssetStudio;
namespace AssetStudio.GUI namespace AssetStudio.GUI
{ {
partial class AssetBrowser : Form partial class AssetBrowser : Form
{ {
private readonly MainForm _parent; private readonly MainForm _parent;
private SortOrder _sortOrder;
private DataGridViewColumn _sortedColumn;
private List<AssetEntry> _assetEntries;
private List<string> _columnNames;
public AssetBrowser(MainForm form) public AssetBrowser(MainForm form)
{ {
InitializeComponent(); InitializeComponent();
_parent = form; _parent = form;
FormClosing += AssetBrowser_FormClosing;
} }
private async void loadAssetMap_Click(object sender, EventArgs e) private async void loadAssetMap_Click(object sender, EventArgs e)
@@ -29,8 +35,18 @@ namespace AssetStudio.GUI
var path = openFileDialog.FileName; var path = openFileDialog.FileName;
Logger.Info($"Loading AssetMap..."); Logger.Info($"Loading AssetMap...");
await Task.Run(() => ResourceMap.FromFile(path)); await Task.Run(() => ResourceMap.FromFile(path));
assetListView.DataSource = ResourceMap.GetEntries();
assetListView.Columns.GetLastColumn(DataGridViewElementStates.None, DataGridViewElementStates.None).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; _sortedColumn = null;
_columnNames = typeof(AssetEntry).GetProperties().Select(x => x.Name).ToList();
_assetEntries = ResourceMap.GetEntries();
assetDataGridView.Columns.Clear();
assetDataGridView.Columns.AddRange(_columnNames.Select(x => new DataGridViewTextBoxColumn() { Name = x, HeaderText = x, SortMode = DataGridViewColumnSortMode.Programmatic }).ToArray());
assetDataGridView.Columns.GetLastColumn(DataGridViewElementStates.None, DataGridViewElementStates.None).AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
assetDataGridView.Rows.Clear();
assetDataGridView.RowCount = _assetEntries.Count;
assetDataGridView.Refresh();
} }
loadAssetMap.Enabled = true; loadAssetMap.Enabled = true;
} }
@@ -39,9 +55,9 @@ namespace AssetStudio.GUI
Clear(); Clear();
Logger.Info($"Cleared !!"); Logger.Info($"Cleared !!");
} }
private async void loadSelected_Click(object sender, EventArgs e) private void loadSelected_Click(object sender, EventArgs e)
{ {
var files = assetListView.SelectedRows.Cast<DataGridViewRow>().Select(x => x.DataBoundItem as AssetEntry).Select(x => x.Source).ToHashSet(); var files = assetDataGridView.SelectedRows.Cast<DataGridViewRow>().Select(x => x.DataBoundItem as AssetEntry).Select(x => x.Source).ToHashSet();
var missingFiles = files.Where(x => !File.Exists(x)); var missingFiles = files.Where(x => !File.Exists(x));
foreach (var file in missingFiles) foreach (var file in missingFiles)
{ {
@@ -59,7 +75,6 @@ namespace AssetStudio.GUI
if (e.KeyChar == (char)Keys.Enter) if (e.KeyChar == (char)Keys.Enter)
{ {
var filters = new Dictionary<string, Regex>(); var filters = new Dictionary<string, Regex>();
var names = typeof(AssetEntry).GetProperties().Select(x => x.Name).ToList();
var value = searchTextBox.Text; var value = searchTextBox.Text;
var options = value.Split(' '); var options = value.Split(' ');
@@ -73,7 +88,7 @@ namespace AssetStudio.GUI
continue; continue;
} }
var (name, regex) = (arguments[0], arguments[1]); var (name, regex) = (arguments[0], arguments[1]);
if (!names.Contains(name, StringComparer.OrdinalIgnoreCase)) if (!_columnNames.Contains(name, StringComparer.OrdinalIgnoreCase))
{ {
Logger.Error($"Unknonw argument {name}"); Logger.Error($"Unknonw argument {name}");
continue; continue;
@@ -81,17 +96,73 @@ namespace AssetStudio.GUI
filters[name] = new Regex(regex, RegexOptions.IgnoreCase); filters[name] = new Regex(regex, RegexOptions.IgnoreCase);
} }
var assets = ResourceMap.GetEntries(); _assetEntries = ResourceMap.GetEntries().FindAll(x => x.Matches(filters));
if (assets.Count != 0)
assetDataGridView.Rows.Clear();
assetDataGridView.RowCount = _assetEntries.Count;
assetDataGridView.Refresh();
}
}
private void AssetDataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{ {
var regex = new Regex(value, RegexOptions.IgnoreCase); if (e.RowIndex <= _assetEntries.Count)
assetListView.DataSource = assets.FindAll(x => x.Matches(filters)); {
var assetEntry = _assetEntries[e.RowIndex];
e.Value = e.ColumnIndex switch
{
0 => assetEntry.Name,
1 => assetEntry.Container,
2 => assetEntry.PathID,
3 => assetEntry.Source,
4 => assetEntry.Type,
_ => ""
};
}
}
private void AssetListView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex <= assetDataGridView.Columns.Count)
{
ListSortDirection direction;
var column = assetDataGridView.Columns[e.ColumnIndex];
if (_sortedColumn != null)
{
if (_sortedColumn != column)
{
direction = ListSortDirection.Ascending;
_sortedColumn.HeaderCell.SortGlyphDirection = SortOrder.None;
_sortedColumn = column;
} }
else else
{ {
assetListView.DataSource = assets; direction = _sortOrder == SortOrder.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
} }
} }
else
{
direction = ListSortDirection.Ascending;
_sortedColumn = column;
}
_sortedColumn.HeaderCell.SortGlyphDirection = _sortOrder = direction == ListSortDirection.Ascending ? SortOrder.Ascending : SortOrder.Descending;
Func<AssetEntry, object> keySelector = e.ColumnIndex switch
{
0 => x => x.Name,
1 => x => x.Container,
2 => x => x.PathID,
3 => x => x.Source,
4 => x => x.Type,
_ => x => ""
};
_assetEntries = direction == ListSortDirection.Ascending ? _assetEntries.OrderBy(keySelector).ToList() : _assetEntries.OrderByDescending(keySelector).ToList();
assetDataGridView.Rows.Clear();
assetDataGridView.RowCount = _assetEntries.Count;
assetDataGridView.Refresh();
}
} }
private void AssetBrowser_FormClosing(object sender, FormClosingEventArgs e) private void AssetBrowser_FormClosing(object sender, FormClosingEventArgs e)
{ {
@@ -101,7 +172,7 @@ namespace AssetStudio.GUI
public void Clear() public void Clear()
{ {
ResourceMap.Clear(); ResourceMap.Clear();
assetListView.DataSource = Array.Empty<AssetEntry>(); assetDataGridView.Rows.Clear();
} }
} }
} }

View File

@@ -1,4 +1,64 @@
<root> <?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">