diff --git a/BundleManager.sln b/BundleManager.sln index 2f45a98..553155e 100644 --- a/BundleManager.sln +++ b/BundleManager.sln @@ -5,12 +5,12 @@ VisualStudioVersion = 17.5.33627.172 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BundleManager", "BundleManager\BundleManager.csproj", "{F11A0DF0-A25C-4E94-AA54-D0DD51F15A8E}" ProjectSection(ProjectDependencies) = postProject - {754DDA1C-8F2F-4F6C-8BC0-D6553A9A7451} = {754DDA1C-8F2F-4F6C-8BC0-D6553A9A7451} - {7743D330-6A1A-496C-872B-E36C9EB38CE7} = {7743D330-6A1A-496C-872B-E36C9EB38CE7} {07E80234-B95F-42DC-99A3-A89A929DDDBF} = {07E80234-B95F-42DC-99A3-A89A929DDDBF} - {557FC08F-7ACD-44D7-AC1F-FB815A267A36} = {557FC08F-7ACD-44D7-AC1F-FB815A267A36} - {47381AB0-8EEC-49E2-AC2F-D8AD2AC0F2DC} = {47381AB0-8EEC-49E2-AC2F-D8AD2AC0F2DC} {20E7A1C4-AFCD-4B8A-8AEF-06B0C27E72B7} = {20E7A1C4-AFCD-4B8A-8AEF-06B0C27E72B7} + {47381AB0-8EEC-49E2-AC2F-D8AD2AC0F2DC} = {47381AB0-8EEC-49E2-AC2F-D8AD2AC0F2DC} + {557FC08F-7ACD-44D7-AC1F-FB815A267A36} = {557FC08F-7ACD-44D7-AC1F-FB815A267A36} + {754DDA1C-8F2F-4F6C-8BC0-D6553A9A7451} = {754DDA1C-8F2F-4F6C-8BC0-D6553A9A7451} + {7743D330-6A1A-496C-872B-E36C9EB38CE7} = {7743D330-6A1A-496C-872B-E36C9EB38CE7} EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BundleFormat", "BundleFormat\BundleFormat.csproj", "{49B81828-760C-42DB-9FAD-96755597C871}" @@ -55,6 +55,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WorldCollisionHandler", "Wo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuaList", "LuaList\LuaList.csproj", "{D1395FDE-6A64-4D9F-9DCA-60825BD0A43C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WheelList", "WheelList\WheelList.csproj", "{56CAC721-417D-445A-9031-DD365313C703}" + ProjectSection(ProjectDependencies) = postProject + {34471573-F236-4A7C-ABD9-C1FE4686B37E} = {34471573-F236-4A7C-ABD9-C1FE4686B37E} + {49B81828-760C-42DB-9FAD-96755597C871} = {49B81828-760C-42DB-9FAD-96755597C871} + {757F0204-F091-464D-AA42-FE8919FF73BB} = {757F0204-F091-464D-AA42-FE8919FF73BB} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -133,6 +140,10 @@ Global {D1395FDE-6A64-4D9F-9DCA-60825BD0A43C}.Debug|Any CPU.Build.0 = Debug|Any CPU {D1395FDE-6A64-4D9F-9DCA-60825BD0A43C}.Release|Any CPU.ActiveCfg = Release|Any CPU {D1395FDE-6A64-4D9F-9DCA-60825BD0A43C}.Release|Any CPU.Build.0 = Release|Any CPU + {56CAC721-417D-445A-9031-DD365313C703}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {56CAC721-417D-445A-9031-DD365313C703}.Debug|Any CPU.Build.0 = Debug|Any CPU + {56CAC721-417D-445A-9031-DD365313C703}.Release|Any CPU.ActiveCfg = Release|Any CPU + {56CAC721-417D-445A-9031-DD365313C703}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -156,6 +167,7 @@ Global {7743D330-6A1A-496C-872B-E36C9EB38CE7} = {60F98E02-807F-4EDC-8747-147C365606B1} {754DDA1C-8F2F-4F6C-8BC0-D6553A9A7451} = {60F98E02-807F-4EDC-8747-147C365606B1} {D1395FDE-6A64-4D9F-9DCA-60825BD0A43C} = {60F98E02-807F-4EDC-8747-147C365606B1} + {56CAC721-417D-445A-9031-DD365313C703} = {60F98E02-807F-4EDC-8747-147C365606B1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {566130B7-31A2-4407-A2E1-C22E60C85C2C} diff --git a/WheelList/Properties/Resources.Designer.cs b/WheelList/Properties/Resources.Designer.cs new file mode 100644 index 0000000..ffbe0b8 --- /dev/null +++ b/WheelList/Properties/Resources.Designer.cs @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace WheelList.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WheelList.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap AddTableHS { + get { + object obj = ResourceManager.GetObject("AddTableHS", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap CopyHS { + get { + object obj = ResourceManager.GetObject("CopyHS", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap EditTableHS { + get { + object obj = ResourceManager.GetObject("EditTableHS", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap remove_xform { + get { + object obj = ResourceManager.GetObject("remove_xform", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/WheelList/Properties/Resources.resx b/WheelList/Properties/Resources.resx new file mode 100644 index 0000000..bf2aafb --- /dev/null +++ b/WheelList/Properties/Resources.resx @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\AddTableHS.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\CopyHS.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\EditTableHS.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\remove_xform.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/WheelList/Resources/AddTableHS.png b/WheelList/Resources/AddTableHS.png new file mode 100644 index 0000000..71dd563 Binary files /dev/null and b/WheelList/Resources/AddTableHS.png differ diff --git a/WheelList/Resources/CopyHS.png b/WheelList/Resources/CopyHS.png new file mode 100644 index 0000000..cb3d871 Binary files /dev/null and b/WheelList/Resources/CopyHS.png differ diff --git a/WheelList/Resources/EditTableHS.png b/WheelList/Resources/EditTableHS.png new file mode 100644 index 0000000..6ebcdc5 Binary files /dev/null and b/WheelList/Resources/EditTableHS.png differ diff --git a/WheelList/Resources/remove_xform.png b/WheelList/Resources/remove_xform.png new file mode 100644 index 0000000..f2e38cd Binary files /dev/null and b/WheelList/Resources/remove_xform.png differ diff --git a/WheelList/WheelEditor.Designer.cs b/WheelList/WheelEditor.Designer.cs new file mode 100644 index 0000000..3a4b1c8 --- /dev/null +++ b/WheelList/WheelEditor.Designer.cs @@ -0,0 +1,139 @@ +namespace WheelList +{ + partial class WheelEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + btnOk = new Button(); + btnCancel = new Button(); + txtIndex = new TextBox(); + txtID = new TextBox(); + txtName = new TextBox(); + lblIndex = new Label(); + lblID = new Label(); + lblName = new Label(); + SuspendLayout(); + // + // btnOk + // + btnOk.Location = new Point(52, 117); + btnOk.Name = "btnOk"; + btnOk.Size = new Size(75, 23); + btnOk.TabIndex = 0; + btnOk.Text = "OK"; + btnOk.UseVisualStyleBackColor = true; + btnOk.Click += btnOk_Click; + // + // btnCancel + // + btnCancel.Location = new Point(133, 117); + btnCancel.Name = "btnCancel"; + btnCancel.Size = new Size(75, 23); + btnCancel.TabIndex = 1; + btnCancel.Text = "Cancel"; + btnCancel.UseVisualStyleBackColor = true; + btnCancel.Click += btnCancel_Click; + // + // txtIndex + // + txtIndex.Location = new Point(58, 23); + txtIndex.Name = "txtIndex"; + txtIndex.Size = new Size(150, 23); + txtIndex.TabIndex = 2; + // + // txtID + // + txtID.Location = new Point(58, 53); + txtID.Name = "txtID"; + txtID.Size = new Size(150, 23); + txtID.TabIndex = 3; + // + // txtName + // + txtName.Location = new Point(58, 83); + txtName.Name = "txtName"; + txtName.Size = new Size(150, 23); + txtName.TabIndex = 4; + // + // lblIndex + // + lblIndex.AutoSize = true; + lblIndex.Location = new Point(12, 27); + lblIndex.Name = "lblIndex"; + lblIndex.Size = new Size(39, 15); + lblIndex.TabIndex = 5; + lblIndex.Text = "Index:"; + // + // lblID + // + lblID.AutoSize = true; + lblID.Location = new Point(12, 57); + lblID.Name = "lblID"; + lblID.Size = new Size(21, 15); + lblID.TabIndex = 6; + lblID.Text = "ID:"; + // + // lblName + // + lblName.AutoSize = true; + lblName.Location = new Point(11, 86); + lblName.Name = "lblName"; + lblName.Size = new Size(42, 15); + lblName.TabIndex = 7; + lblName.Text = "Name:"; + // + // WheelEditor + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(234, 156); + Controls.Add(lblName); + Controls.Add(lblID); + Controls.Add(lblIndex); + Controls.Add(txtName); + Controls.Add(txtID); + Controls.Add(txtIndex); + Controls.Add(btnCancel); + Controls.Add(btnOk); + Name = "WheelEditor"; + Text = "WheelEditor"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Button btnOk; + private Button btnCancel; + private TextBox txtIndex; + private TextBox txtID; + private TextBox txtName; + private Label lblIndex; + private Label lblID; + private Label lblName; + } +} \ No newline at end of file diff --git a/WheelList/WheelEditor.cs b/WheelList/WheelEditor.cs new file mode 100644 index 0000000..5c9ac9f --- /dev/null +++ b/WheelList/WheelEditor.cs @@ -0,0 +1,122 @@ +using BundleUtilities; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Reflection.PortableExecutable; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Xml.Linq; + +namespace WheelList +{ + public partial class WheelEditor : Form + { + public delegate void Done(Wheel wheel); + public event Done OnDone; + private Wheel _wheel; + public Wheel Wheel + { + get + { + return _wheel; + } + set + { + _wheel = value; + UpdateDisplay(); + } + } + + public WheelEditor() + { + InitializeComponent(); + } + + private int maxIndex; + public WheelEditor(int max) + { + InitializeComponent(); + maxIndex = max; + } + + private void UpdateDisplay() + { + Text = "Edit Wheel: " + Wheel.Index; + + txtIndex.Text = Wheel.Index.ToString(); + txtID.Text = Wheel.ID.Value; + txtName.Text = Wheel.Name; + } + + private Wheel GetModifiedWheel() + { + Wheel result = new Wheel(Wheel); + + // Index + int index; + if (int.TryParse(txtIndex.Text, out index)) + { + if (index <= maxIndex) + result.Index = index; + else + { + MessageBox.Show(this, "Index out of bounds.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + } + else + { + MessageBox.Show(this, "Index is invalid.\nEnsure the value is a decimal integer.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + // Wheel ID + if (txtID.Text.Trim().Length == 0) + { + MessageBox.Show(this, "ID cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + try + { + EncryptedString ID = new EncryptedString(txtID.Text); + result.ID = ID; + } + catch (ArgumentException e) + { + MessageBox.Show(this, e.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + + // Vehicle name + result.Name = txtName.Text; + if (result.Name.Trim().Length == 0) + { + MessageBox.Show(this, "Car name cannot be left blank.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return null; + } + + return result; + } + + private void btnCancel_Click(object sender, EventArgs e) + { + Close(); + } + + private void btnOk_Click(object sender, EventArgs e) + { + Wheel retWheel = GetModifiedWheel(); + if (retWheel == null) + { + return; + } + + OnDone?.Invoke(retWheel); + + Close(); + } + } +} diff --git a/WheelList/WheelEditor.resx b/WheelList/WheelEditor.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/WheelList/WheelEditor.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/WheelList/WheelList.csproj b/WheelList/WheelList.csproj new file mode 100644 index 0000000..0635ab2 --- /dev/null +++ b/WheelList/WheelList.csproj @@ -0,0 +1,35 @@ + + + + net8.0-windows + enable + true + enable + + + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + diff --git a/WheelList/WheelListData.cs b/WheelList/WheelListData.cs new file mode 100644 index 0000000..b0f4f6a --- /dev/null +++ b/WheelList/WheelListData.cs @@ -0,0 +1,120 @@ +using BundleFormat; +using BundleUtilities; +using PluginAPI; +using System.Text; + +namespace WheelList +{ + public class WheelListData : IEntryData + { + public int NumWheels = 0; + public int EntriesPtr = 0; + public List Entries = []; + + public WheelListData() + { + + } + + public IEntryEditor GetEditor(BundleEntry entry) + { + WheelListForm wheelList = new WheelListForm(); + wheelList.List = this; + wheelList.Edit += () => + { + Write(entry); + }; + + return wheelList; + } + + public EntryType GetEntryType(BundleEntry entry) + { + return EntryType.WheelList; + } + + public bool Read(BundleEntry entry, ILoader loader = null) + { + Clear(); + + MemoryStream ms = new MemoryStream(entry.EntryBlocks[0].Data); + BinaryReader2 br = new BinaryReader2(ms); + br.BigEndian = entry.Console; + + NumWheels = br.ReadInt32(); + EntriesPtr = br.ReadInt32(); + br.BaseStream.Position = EntriesPtr; + + for (int i = 0; i < NumWheels; i++) + { + Wheel wheel = new(); + + wheel.Index = i; + wheel.ID = new EncryptedString(br.ReadUInt64()); + wheel.Name = Encoding.ASCII.GetString(br.ReadBytes(64)); + + Entries.Add(wheel); + } + + br.Close(); + + return true; + } + + public bool Write(BundleEntry entry) + { + MemoryStream ms = new MemoryStream(); + BinaryWriter2 bw = new BinaryWriter2(ms); + bw.BigEndian = entry.Console; + + bw.Write(Entries.Count); + bw.Write(EntriesPtr); + bw.BaseStream.Position = EntriesPtr; + + for (int i = 0; i < Entries.Count; i++) + { + Wheel wheel = Entries[i]; + + bw.Write(wheel.ID.Encrypted); + bw.WriteLenString(wheel.Name, 64); + } + + bw.Align(0x10); + + bw.Flush(); + byte[] data = ms.ToArray(); + bw.Close(); + + entry.EntryBlocks[0].Data = data; + entry.Dirty = true; + + return true; + } + + private void Clear() + { + NumWheels = default; + EntriesPtr = default; + Entries.Clear(); + } + } + + public class Wheel + { + public int Index = -1; + public EncryptedString ID = new(0); + public string Name = new(""); + + public Wheel() + { + + } + + public Wheel(Wheel copy) + { + Index = copy.Index; + ID = copy.ID; + Name = copy.Name; + } + } +} diff --git a/WheelList/WheelListForm.Designer.cs b/WheelList/WheelListForm.Designer.cs new file mode 100644 index 0000000..c001d28 --- /dev/null +++ b/WheelList/WheelListForm.Designer.cs @@ -0,0 +1,222 @@ +namespace WheelList +{ + partial class WheelListForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + menuStrip1 = new MenuStrip(); + itemsToolStripMenuItem = new ToolStripMenuItem(); + addItemToolStripMenuItem = new ToolStripMenuItem(); + copyItemToolStripMenuItem = new ToolStripMenuItem(); + deleteItemToolStripMenuItem = new ToolStripMenuItem(); + toolStrip1 = new ToolStrip(); + tsbAddItem = new ToolStripButton(); + tsbCopyItem = new ToolStripButton(); + tsbDeleteItem = new ToolStripButton(); + lstWheels = new ListView(); + Index = new ColumnHeader(); + ID = new ColumnHeader(); + WheelName = new ColumnHeader(); + stsMain = new StatusStrip(); + stlStatusLabel = new ToolStripStatusLabel(); + menuStrip1.SuspendLayout(); + toolStrip1.SuspendLayout(); + stsMain.SuspendLayout(); + SuspendLayout(); + // + // menuStrip1 + // + menuStrip1.Items.AddRange(new ToolStripItem[] { itemsToolStripMenuItem }); + menuStrip1.Location = new Point(0, 0); + menuStrip1.Name = "menuStrip1"; + menuStrip1.Size = new Size(261, 24); + menuStrip1.TabIndex = 0; + menuStrip1.Text = "menuStrip1"; + // + // itemsToolStripMenuItem + // + itemsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { addItemToolStripMenuItem, copyItemToolStripMenuItem, deleteItemToolStripMenuItem }); + itemsToolStripMenuItem.Name = "itemsToolStripMenuItem"; + itemsToolStripMenuItem.Size = new Size(48, 20); + itemsToolStripMenuItem.Text = "Items"; + // + // addItemToolStripMenuItem + // + addItemToolStripMenuItem.Image = Properties.Resources.AddTableHS; + addItemToolStripMenuItem.Name = "addItemToolStripMenuItem"; + addItemToolStripMenuItem.Size = new Size(134, 22); + addItemToolStripMenuItem.Text = "Add Item"; + addItemToolStripMenuItem.Click += addItemToolStripMenuItem_Click; + // + // copyItemToolStripMenuItem + // + copyItemToolStripMenuItem.Enabled = false; + copyItemToolStripMenuItem.Image = Properties.Resources.CopyHS; + copyItemToolStripMenuItem.Name = "copyItemToolStripMenuItem"; + copyItemToolStripMenuItem.Size = new Size(134, 22); + copyItemToolStripMenuItem.Text = "Copy Item"; + copyItemToolStripMenuItem.Click += copyItemToolStripMenuItem_Click; + // + // deleteItemToolStripMenuItem + // + deleteItemToolStripMenuItem.Enabled = false; + deleteItemToolStripMenuItem.Image = Properties.Resources.remove_xform; + deleteItemToolStripMenuItem.Name = "deleteItemToolStripMenuItem"; + deleteItemToolStripMenuItem.Size = new Size(134, 22); + deleteItemToolStripMenuItem.Text = "Delete Item"; + deleteItemToolStripMenuItem.Click += deleteItemToolStripMenuItem_Click; + // + // toolStrip1 + // + toolStrip1.Items.AddRange(new ToolStripItem[] { tsbAddItem, tsbCopyItem, tsbDeleteItem }); + toolStrip1.Location = new Point(0, 24); + toolStrip1.Name = "toolStrip1"; + toolStrip1.Size = new Size(261, 25); + toolStrip1.TabIndex = 1; + toolStrip1.Text = "toolStrip1"; + // + // tsbAddItem + // + tsbAddItem.DisplayStyle = ToolStripItemDisplayStyle.Image; + tsbAddItem.Image = Properties.Resources.AddTableHS; + tsbAddItem.ImageTransparentColor = Color.Magenta; + tsbAddItem.Name = "tsbAddItem"; + tsbAddItem.Size = new Size(23, 22); + tsbAddItem.Text = "toolStripButton1"; + tsbAddItem.ToolTipText = "Add Item"; + tsbAddItem.Click += tsbAddItem_Click; + // + // tsbCopyItem + // + tsbCopyItem.DisplayStyle = ToolStripItemDisplayStyle.Image; + tsbCopyItem.Enabled = false; + tsbCopyItem.Image = Properties.Resources.CopyHS; + tsbCopyItem.ImageTransparentColor = Color.Magenta; + tsbCopyItem.Name = "tsbCopyItem"; + tsbCopyItem.Size = new Size(23, 22); + tsbCopyItem.Text = "toolStripButton2"; + tsbCopyItem.ToolTipText = "Copy Item"; + tsbCopyItem.Click += tsbCopyItem_Click; + // + // tsbDeleteItem + // + tsbDeleteItem.DisplayStyle = ToolStripItemDisplayStyle.Image; + tsbDeleteItem.Enabled = false; + tsbDeleteItem.Image = Properties.Resources.remove_xform; + tsbDeleteItem.ImageTransparentColor = Color.Magenta; + tsbDeleteItem.Name = "tsbDeleteItem"; + tsbDeleteItem.Size = new Size(23, 22); + tsbDeleteItem.Text = "toolStripButton3"; + tsbDeleteItem.ToolTipText = "Delete Item"; + tsbDeleteItem.Click += tsbDeleteItem_Click; + // + // lstWheels + // + lstWheels.Columns.AddRange(new ColumnHeader[] { Index, ID, WheelName }); + lstWheels.Dock = DockStyle.Fill; + lstWheels.FullRowSelect = true; + lstWheels.GridLines = true; + lstWheels.Location = new Point(0, 49); + lstWheels.Name = "lstWheels"; + lstWheels.Size = new Size(261, 370); + lstWheels.TabIndex = 2; + lstWheels.UseCompatibleStateImageBehavior = false; + lstWheels.View = View.Details; + lstWheels.ColumnClick += lstWheels_ColumnClick; + lstWheels.SelectedIndexChanged += lstWheels_SelectedIndexChanged; + lstWheels.MouseDoubleClick += lstWheels_MouseDoubleClick; + // + // Index + // + Index.Text = "Index"; + Index.Width = 48; + // + // ID + // + ID.Text = "ID"; + ID.Width = 64; + // + // WheelName + // + WheelName.Text = "Name"; + WheelName.Width = 128; + // + // stsMain + // + stsMain.Items.AddRange(new ToolStripItem[] { stlStatusLabel }); + stsMain.Location = new Point(0, 419); + stsMain.Name = "stsMain"; + stsMain.Size = new Size(261, 22); + stsMain.TabIndex = 3; + stsMain.Text = "statusStrip1"; + // + // stlStatusLabel + // + stlStatusLabel.Name = "stlStatusLabel"; + stlStatusLabel.Size = new Size(0, 17); + // + // WheelListForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(261, 441); + Controls.Add(lstWheels); + Controls.Add(stsMain); + Controls.Add(toolStrip1); + Controls.Add(menuStrip1); + MainMenuStrip = menuStrip1; + Name = "WheelListForm"; + Text = "Wheel List Viewer"; + menuStrip1.ResumeLayout(false); + menuStrip1.PerformLayout(); + toolStrip1.ResumeLayout(false); + toolStrip1.PerformLayout(); + stsMain.ResumeLayout(false); + stsMain.PerformLayout(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private MenuStrip menuStrip1; + private ToolStripMenuItem itemsToolStripMenuItem; + private ToolStripMenuItem addItemToolStripMenuItem; + private ToolStripMenuItem copyItemToolStripMenuItem; + private ToolStripMenuItem deleteItemToolStripMenuItem; + private ToolStrip toolStrip1; + private ToolStripButton tsbAddItem; + private ToolStripButton tsbCopyItem; + private ToolStripButton tsbDeleteItem; + private ListView lstWheels; + private StatusStrip stsMain; + private ColumnHeader Index; + private ColumnHeader ID; + private ColumnHeader WheelName; + private ToolStripStatusLabel stlStatusLabel; + } +} diff --git a/WheelList/WheelListForm.cs b/WheelList/WheelListForm.cs new file mode 100644 index 0000000..70b195e --- /dev/null +++ b/WheelList/WheelListForm.cs @@ -0,0 +1,290 @@ +using BundleUtilities; +using PluginAPI; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace WheelList +{ + public partial class WheelListForm : Form, IEntryEditor + { + public delegate void OnEdit(); + public event OnEdit Edit; + + private WheelListData _list; + public WheelListData List + { + get => _list; + set + { + _list = value; + UpdateDisplay(); + } + } + + public WheelListForm() + { + InitializeComponent(); + } + + private void UpdateDisplay() + { + lstWheels.Items.Clear(); + + if (List == null) + return; + + for (int i = 0; i < List.Entries.Count; i++) + { + Wheel wheel = List.Entries[i]; + + string[] value = { + wheel.Index.ToString(), + wheel.ID.Value, + wheel.Name + }; + lstWheels.Items.Add(new ListViewItem(value)); + } + + lstWheels.ListViewItemSorter = new WheelSorter(0); + lstWheels.Sort(); + + stlStatusLabel.Text = ""; + copyItemToolStripMenuItem.Enabled = false; + deleteItemToolStripMenuItem.Enabled = false; + tsbCopyItem.Enabled = false; + tsbDeleteItem.Enabled = false; + } + + private void EditSelectedEntry() + { + if (lstWheels.SelectedItems.Count > 1) + return; + if (List == null || lstWheels.SelectedIndices.Count <= 0) + return; + + if (!int.TryParse(lstWheels.SelectedItems[0].Text, out int index)) + return; + Wheel wheel = List.Entries[index]; + + WheelEditor editor = new WheelEditor(List.Entries.Count - 1); + editor.Wheel = wheel; + editor.OnDone += Editor_OnDone; + editor.ShowDialog(this); + } + + private void AddItem() + { + if (List == null) + return; + Wheel wheel = new(); + wheel.Index = List.Entries.Count; + wheel.ID = new EncryptedString(""); + wheel.Name = ""; + + WheelEditor editor = new WheelEditor(List.Entries.Count); + editor.Wheel = wheel; + editor.OnDone += Editor_OnDone1; ; + editor.ShowDialog(this); + } + + private void CopyItem() + { + if (List == null || lstWheels.SelectedItems.Count != 1 + || lstWheels.SelectedIndices.Count <= 0) + return; + + if (!int.TryParse(lstWheels.SelectedItems[0].Text, out int index)) + return; + Wheel wheel = new Wheel(List.Entries[index]); + wheel.Index = List.Entries.Count; + + WheelEditor editor = new WheelEditor(List.Entries.Count); + editor.Wheel = wheel; + editor.OnDone += Editor_OnDone1; + editor.ShowDialog(this); + } + + private void DeleteItem() + { + if (List == null || lstWheels.SelectedItems.Count != 1 + || lstWheels.SelectedIndices.Count <= 0) + return; + + if (!int.TryParse(lstWheels.SelectedItems[0].Text, out int index)) + return; + List.Entries.RemoveAt(index); + for (int i = index; i < List.Entries.Count; ++i) + List.Entries[i].Index--; + + Edit?.Invoke(); + UpdateDisplay(); + } + + private void Editor_OnDone1(Wheel wheel) + { + // Insert if not at end, else add + if (wheel.Index != List.Entries.Count) + { + List.Entries.Insert(wheel.Index, wheel); + + for (int i = 0; i < List.Entries.Count; ++i) + List.Entries[i].Index = i; + } + else + { + List.Entries.Add(wheel); + } + + Edit?.Invoke(); + UpdateDisplay(); + } + + private void Editor_OnDone(Wheel wheel) + { + // If the index has changed, edit the list + int oldIndex = int.Parse(lstWheels.SelectedItems[0].Text); // Tried in EditSelectedEntry() + if (oldIndex != wheel.Index) + { + Wheel old = List.Entries[oldIndex]; + List.Entries.RemoveAt(oldIndex); + List.Entries.Insert(wheel.Index, old); + + for (int i = 0; i < List.Entries.Count; ++i) + List.Entries[i].Index = i; + } + + // Edit the wheel + List.Entries[wheel.Index] = wheel; + Edit?.Invoke(); + UpdateDisplay(); + } + + private void lstWheels_MouseDoubleClick(object sender, MouseEventArgs e) + { + EditSelectedEntry(); + } + + private void lstWheels_SelectedIndexChanged(object sender, EventArgs e) + { + stlStatusLabel.Text = lstWheels.SelectedItems.Count + " Item(s) Selected"; + copyItemToolStripMenuItem.Enabled = true; + deleteItemToolStripMenuItem.Enabled = true; + tsbCopyItem.Enabled = true; + tsbDeleteItem.Enabled = true; + } + + private void lstWheels_ColumnClick(object sender, ColumnClickEventArgs e) + { + int column = e.Column; + + bool direction = false; + + if (lstWheels.ListViewItemSorter is WheelSorter sorter) + { + if (sorter.Column == column) + { + sorter.Swap(); + lstWheels.Sort(); + return; + } + direction = sorter.Direction; + } + + WheelSorter newSorter = new WheelSorter(column) + { + Direction = !direction + }; + lstWheels.ListViewItemSorter = newSorter; + lstWheels.Sort(); + } + + private class WheelSorter : IComparer + { + public readonly int Column; + public bool Direction; + + public WheelSorter(int column) + { + Column = column; + Direction = false; + } + + public int Compare(object x, object y) + { + ListViewItem itemX = (ListViewItem)x; + ListViewItem itemY = (ListViewItem)y; + + if (Column > itemX.SubItems.Count || Column > itemY.SubItems.Count) + { + if (Direction) + return -1; + return 1; + } + + string iX = itemX.SubItems[Column].Text; + string iY = itemY.SubItems[Column].Text; + + + if (int.TryParse(iX, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iXint)) + { + if (int.TryParse(iY, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out int iYint)) + { + int val2 = iXint.CompareTo(iYint); + if (this.Direction) + return val2 * -1; + return val2; + } + } + + int val = string.CompareOrdinal(iX, iY); + if (Direction) + return val * -1; + return val; + } + + public void Swap() + { + Direction = !Direction; + } + } + + private void addItemToolStripMenuItem_Click(object sender, EventArgs e) + { + AddItem(); + } + + private void tsbAddItem_Click(object sender, EventArgs e) + { + AddItem(); + } + + private void copyItemToolStripMenuItem_Click(object sender, EventArgs e) + { + CopyItem(); + } + + private void tsbCopyItem_Click(object sender, EventArgs e) + { + CopyItem(); + } + + private void deleteItemToolStripMenuItem_Click(object sender, EventArgs e) + { + DeleteItem(); + } + + private void tsbDeleteItem_Click(object sender, EventArgs e) + { + DeleteItem(); + } + } +} diff --git a/WheelList/WheelListForm.resx b/WheelList/WheelListForm.resx new file mode 100644 index 0000000..ca320dd --- /dev/null +++ b/WheelList/WheelListForm.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 132, 17 + + + 237, 17 + + \ No newline at end of file diff --git a/WheelList/WheelListPlugin.cs b/WheelList/WheelListPlugin.cs new file mode 100644 index 0000000..ddec0ea --- /dev/null +++ b/WheelList/WheelListPlugin.cs @@ -0,0 +1,23 @@ +using BundleFormat; +using PluginAPI; + +namespace WheelList +{ + public class WheelListPlugin : Plugin + { + public override void Init() + { + EntryTypeRegistry.Register(EntryType.WheelList, new WheelListData()); + } + + public override string GetID() + { + return "wheellistplugin"; + } + + public override string GetName() + { + return "WheelList Resource Handler"; + } + } +}