diff --git a/Ultima/Files.cs b/Ultima/Files.cs index 1144682c..d6d38fa5 100644 --- a/Ultima/Files.cs +++ b/Ultima/Files.cs @@ -97,6 +97,7 @@ public static void FireFileSaveEvent() "mobtypes.txt", "multi.idx", "multi.mul", + "multicollection.uop", "multimap.rle", "radarcol.mul", "skillgrp.mul", diff --git a/Ultima/Helpers/MythicDecompress.cs b/Ultima/Helpers/MythicDecompress.cs index ee3737f3..13418dbb 100644 --- a/Ultima/Helpers/MythicDecompress.cs +++ b/Ultima/Helpers/MythicDecompress.cs @@ -24,11 +24,16 @@ public static byte[] Decompress(byte[] buffer) using (var reader = new BinaryReader(new MemoryStream(buffer))) { var header = reader.ReadUInt32(); - uint dataLength = header ^ 0x8E2C9A3D; // Must be equal to output length, error otherwise + uint dataLength = header ^ 0x8E2C9A3D; - // MoveToFront decoding var list = reader.ReadBytes((int)(reader.BaseStream.Length - 4)); output = InternalDecompress(MoveToFrontCoding.Decode(list)); + + if (output.Length != dataLength) + { + throw new InvalidDataException( + $"Decompressed length {output.Length} does not match expected {dataLength}. File is not in compressed cliloc format."); + } } return output; diff --git a/Ultima/MultiComponentList.cs b/Ultima/MultiComponentList.cs index ae39b897..d183990d 100644 --- a/Ultima/MultiComponentList.cs +++ b/Ultima/MultiComponentList.cs @@ -39,6 +39,8 @@ public sealed class MultiComponentList public MultiTileEntry[] SortedTiles { get; } public int Surface { get; private set; } + public static HashSet DynamicItemIds { get; set; } + public struct MultiTileEntry { public ushort ItemId; @@ -433,7 +435,7 @@ public MultiComponentList(string fileName, Multis.ImportType type) var tempItem = new MultiTileEntry { ItemId = 0xFFFF, - Flags = 1, + Flags = 0, Unk1 = 0 }; @@ -444,10 +446,17 @@ public MultiComponentList(string fileName, Multis.ImportType type) { if (tempItem.ItemId != 0xFFFF) { + if (DynamicItemIds != null && DynamicItemIds.Contains(tempItem.ItemId)) + { + tempItem.Flags = 1; + } + SortedTiles[itemCount] = tempItem; ++itemCount; } + tempItem.ItemId = 0xFFFF; + tempItem.Flags = 0; } else if (line.StartsWith("ID")) { @@ -496,11 +505,37 @@ public MultiComponentList(string fileName, Multis.ImportType type) } } } + if (tempItem.ItemId != 0xFFFF) { + if (DynamicItemIds?.Contains(tempItem.ItemId) == true) + { + tempItem.Flags = 1; + } + SortedTiles[itemCount] = tempItem; } } + + // WSC files from a live UO world use absolute world coordinates. + // Tool-generated WSC files may already have relative offsets (possibly negative). + // Heuristic: if both min coords are positive AND each exceeds the multi's own + // extent, the file contains world coordinates and must be normalized. + int extentX = _max.X - _min.X; + int extentY = _max.Y - _min.Y; + if (_min.X > 0 && _min.Y > 0 && _min.X > extentX && _min.Y > extentY) + { + for (int i = 0; i < SortedTiles.Length; ++i) + { + SortedTiles[i].OffsetX = (short)(SortedTiles[i].OffsetX - _min.X); + SortedTiles[i].OffsetY = (short)(SortedTiles[i].OffsetY - _min.Y); + } + _max.X -= _min.X; + _max.Y -= _min.Y; + _min.X = 0; + _min.Y = 0; + } + break; } case Multis.ImportType.CSV: diff --git a/Ultima/Multis.cs b/Ultima/Multis.cs index c108f8df..dd0f1783 100644 --- a/Ultima/Multis.cs +++ b/Ultima/Multis.cs @@ -13,6 +13,9 @@ public sealed class Multis private static MultiComponentList[] _components = new MultiComponentList[MaximumMultiIndex]; private static FileIndex _fileIndex = new FileIndex("Multi.idx", "Multi.mul", MaximumMultiIndex, 14); + private static MultiComponentList[] _uopComponents = new MultiComponentList[MaximumMultiIndex]; + private static bool _uopLoaded; + public enum ImportType { TXT, @@ -33,6 +36,7 @@ public static void Reload() { _fileIndex = new FileIndex("Multi.idx", "Multi.mul", MaximumMultiIndex, 14); _components = new MultiComponentList[MaximumMultiIndex]; + ReloadUop(); } /// @@ -236,6 +240,167 @@ public static List LoadFromDesigner(string fileName) } } + public static bool HasUopFile => !string.IsNullOrEmpty(Files.GetFilePath("multicollection.uop")); + + public static void ReloadUop() + { + _uopComponents = new MultiComponentList[MaximumMultiIndex]; + _uopLoaded = false; + } + + public static MultiComponentList GetUopComponents(int index) + { + if (!_uopLoaded) + { + LoadUop(); + } + + if (index >= 0 && index < _uopComponents.Length) + { + return _uopComponents[index] ?? MultiComponentList.Empty; + } + + return MultiComponentList.Empty; + } + + private static void LoadUop() + { + _uopLoaded = true; + + string path = Files.GetFilePath("multicollection.uop"); + if (path == null) + { + return; + } + + try + { + using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + using var reader = new BinaryReader(fileStream); + + uint magic = reader.ReadUInt32(); + if (magic != 0x0050594D) + { + return; + } + + uint version = reader.ReadUInt32(); + if (version > 5) + { + return; + } + + reader.ReadUInt32(); // signature + ulong nextTableOffset = reader.ReadUInt64(); + reader.ReadUInt32(); // block capacity + reader.ReadUInt32(); // file count + reader.ReadUInt32(); // reserved + reader.ReadUInt32(); // reserved + reader.ReadUInt32(); // reserved + + var entries = new List<(long dataOffset, uint compressedSize, uint decompressedSize)>(); + + ulong next = nextTableOffset; + while (next != 0) + { + fileStream.Seek((long)next, SeekOrigin.Begin); + int count = reader.ReadInt32(); + next = reader.ReadUInt64(); + + for (int i = 0; i < count; i++) + { + ulong dataOffset = reader.ReadUInt64(); + uint headerSize = reader.ReadUInt32(); + uint compressedSize = reader.ReadUInt32(); + uint decompressedSize = reader.ReadUInt32(); + reader.ReadUInt64(); // hash + reader.ReadUInt32(); // unknown + ushort flag = reader.ReadUInt16(); + + if (dataOffset == 0 || decompressedSize == 0) + { + continue; + } + + if (flag == 0) + { + compressedSize = 0; + } + + entries.Add(((long)(dataOffset + headerSize), compressedSize, decompressedSize)); + } + } + + foreach (var (dataOffset, compressedSize, decompressedSize) in entries) + { + fileStream.Seek(dataOffset, SeekOrigin.Begin); + + byte[] raw; + if (compressedSize > 0) + { + byte[] compressed = reader.ReadBytes((int)compressedSize); + (bool ok, byte[] decompressed) = UopUtils.Decompress(compressed); + if (!ok) + { + continue; + } + + raw = decompressed; + } + else + { + raw = reader.ReadBytes((int)decompressedSize); + } + + using var memoryStream = new MemoryStream(raw); + using var binaryReader = new BinaryReader(memoryStream); + + uint multiId = binaryReader.ReadUInt32(); + int componentCount = binaryReader.ReadInt32(); + + if (multiId >= MaximumMultiIndex || componentCount <= 0) + { + continue; + } + + var tiles = new List(componentCount); + for (int j = 0; j < componentCount; j++) + { + ushort graphic = binaryReader.ReadUInt16(); + ushort ux = binaryReader.ReadUInt16(); + ushort uy = binaryReader.ReadUInt16(); + ushort uz = binaryReader.ReadUInt16(); + ushort uflags = binaryReader.ReadUInt16(); + int clilocsCount = binaryReader.ReadInt32(); + + if (clilocsCount > 0) + { + binaryReader.BaseStream.Seek(clilocsCount * 4L, SeekOrigin.Current); + } + + tiles.Add(new MultiComponentList.MultiTileEntry + { + ItemId = graphic, + OffsetX = (short)ux, + OffsetY = (short)uy, + OffsetZ = (short)uz, + Flags = uflags != 0 ? 0 : 1, + Unk1 = 0 + }); + } + + if (tiles.Count > 0) + { + _uopComponents[multiId] = new MultiComponentList(tiles); + } + } + } + catch + { + // leave array in its current partially-populated state + } + } + private static List RebuildTiles(MultiComponentList.MultiTileEntry[] tiles) { var newTiles = new List(); diff --git a/Ultima/StringList.cs b/Ultima/StringList.cs index 0f4f0704..f5c12b28 100644 --- a/Ultima/StringList.cs +++ b/Ultima/StringList.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Text; @@ -7,7 +8,7 @@ namespace Ultima { public sealed class StringList { - private readonly bool _decompress; + private bool _decompress; private int _header1; private short _header2; @@ -51,45 +52,63 @@ private void LoadEntry(string path) return; } - Entries = new List(); - _stringTable = new Dictionary(); - _entryTable = new Dictionary(); + using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + byte[] buffer = new byte[fileStream.Length]; + _ = fileStream.Read(buffer, 0, buffer.Length); - using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + if (!TryParse(buffer, _decompress)) { - byte[] buffer = new byte[fileStream.Length]; - _ = fileStream.Read(buffer, 0, buffer.Length); - - byte[] clilocData = _decompress - ? MythicDecompress.Decompress(buffer) - : buffer; - - using (var reader = new BinaryReader(new MemoryStream(clilocData))) + bool fallback = !_decompress; + if (!TryParse(buffer, fallback)) { - _header1 = reader.ReadInt32(); - _header2 = reader.ReadInt16(); + throw new InvalidDataException($"Failed to parse cliloc file '{path}' in either compressed or uncompressed format."); + } + _decompress = fallback; + } + } - while (reader.BaseStream.Length != reader.BaseStream.Position) - { - int number = reader.ReadInt32(); - byte flag = reader.ReadByte(); - int length = reader.ReadInt16(); + private bool TryParse(byte[] buffer, bool decompress) + { + try + { + byte[] clilocData = decompress ? MythicDecompress.Decompress(buffer) : buffer; - if (length > _buffer.Length) - { - _buffer = new byte[(length + 1023) & ~1023]; - } + var entries = new List(); + var stringTable = new Dictionary(); + var entryTable = new Dictionary(); - reader.Read(_buffer, 0, length); - string text = Encoding.UTF8.GetString(_buffer, 0, length); + using var reader = new BinaryReader(new MemoryStream(clilocData)); + _header1 = reader.ReadInt32(); + _header2 = reader.ReadInt16(); - var se = new StringEntry(number, text, flag); - Entries.Add(se); + while (reader.BaseStream.Length != reader.BaseStream.Position) + { + int number = reader.ReadInt32(); + byte flag = reader.ReadByte(); + int length = reader.ReadInt16(); - _stringTable[number] = text; - _entryTable[number] = se; + if (length > _buffer.Length) + { + _buffer = new byte[(length + 1023) & ~1023]; } + + reader.Read(_buffer, 0, length); + string text = Encoding.UTF8.GetString(_buffer, 0, length); + + var se = new StringEntry(number, text, flag); + entries.Add(se); + stringTable[number] = text; + entryTable[number] = se; } + + Entries = entries; + _stringTable = stringTable; + _entryTable = entryTable; + return true; + } + catch + { + return false; } } diff --git a/UoFiddler.Controls/Classes/DynamicItemsConfig.cs b/UoFiddler.Controls/Classes/DynamicItemsConfig.cs new file mode 100644 index 00000000..16c8c4f0 --- /dev/null +++ b/UoFiddler.Controls/Classes/DynamicItemsConfig.cs @@ -0,0 +1,89 @@ +/*************************************************************************** + * + * $Author: Turley + * + * "THE BEER-WARE LICENSE" + * As long as you retain this notice you can do whatever you want with + * this stuff. If we meet some day, and you think this stuff is worth it, + * you can buy me a beer in return. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Xml; +using Ultima; + +namespace UoFiddler.Controls.Classes +{ + public static class DynamicItemsConfig + { + private static bool _loaded; + + public static void EnsureLoaded() + { + if (_loaded) + { + return; + } + _loaded = true; + + string path = Path.Combine(Options.AppDataPath, "DynamicItems.xml"); + if (!File.Exists(path)) + { + Options.Logger?.Warning("DynamicItems.xml not found at {Path}", path); + return; + } + + var ids = new HashSet(); + var doc = new XmlDocument(); + doc.Load(path); + + foreach (XmlNode node in doc.DocumentElement!.ChildNodes) + { + if (node is not XmlElement elem) + { + continue; + } + + switch (elem.LocalName) + { + case "Item": + if (TryParseId(elem.GetAttribute("id"), out ushort id)) + { + ids.Add(id); + } + break; + case "Range": + if (TryParseId(elem.GetAttribute("from"), out ushort from) && + TryParseId(elem.GetAttribute("to"), out ushort to)) + { + for (ushort i = from; i <= to; i++) + { + ids.Add(i); + } + } + break; + } + } + + MultiComponentList.DynamicItemIds = ids; + } + + private static bool TryParseId(string value, out ushort result) + { + result = 0; + if (string.IsNullOrEmpty(value)) + { + return false; + } + if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + return ushort.TryParse(value[2..], NumberStyles.HexNumber, null, out result); + } + return ushort.TryParse(value, out result); + } + } +} diff --git a/UoFiddler.Controls/Classes/Options.cs b/UoFiddler.Controls/Classes/Options.cs index 057ae015..bcd74cf4 100644 --- a/UoFiddler.Controls/Classes/Options.cs +++ b/UoFiddler.Controls/Classes/Options.cs @@ -28,11 +28,6 @@ public static void SetLogger(ILogger logger) Logger = logger; } - /// - /// Should UOFiddler decompress cliloc files. For client version 7.104.0 or newer - /// - public static bool NewClilocFormat { get; set; } - /// /// Defines Element Width in ItemShow /// diff --git a/UoFiddler.Controls/Forms/MultisHelpForm.Designer.cs b/UoFiddler.Controls/Forms/MultisHelpForm.Designer.cs new file mode 100644 index 00000000..7401afd0 --- /dev/null +++ b/UoFiddler.Controls/Forms/MultisHelpForm.Designer.cs @@ -0,0 +1,99 @@ +namespace UoFiddler.Controls.Forms +{ + partial class MultisHelpForm + { + /// + /// 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() + { + _listView = new System.Windows.Forms.ListView(); + _columnKey = new System.Windows.Forms.ColumnHeader(); + _columnAction = new System.Windows.Forms.ColumnHeader(); + _btnClose = new System.Windows.Forms.Button(); + SuspendLayout(); + // + // _listView + // + _listView.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + _listView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { _columnKey, _columnAction }); + _listView.FullRowSelect = true; + _listView.GridLines = true; + _listView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + _listView.Location = new System.Drawing.Point(8, 8); + _listView.MultiSelect = false; + _listView.Name = "_listView"; + _listView.Size = new System.Drawing.Size(618, 289); + _listView.TabIndex = 0; + _listView.UseCompatibleStateImageBehavior = false; + _listView.View = System.Windows.Forms.View.Details; + // + // _columnKey + // + _columnKey.Text = "Shortcut / Control"; + _columnKey.Width = 180; + // + // _columnAction + // + _columnAction.Text = "Action"; + _columnAction.Width = 420; + // + // _btnClose + // + _btnClose.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right; + _btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; + _btnClose.Location = new System.Drawing.Point(551, 305); + _btnClose.Name = "_btnClose"; + _btnClose.Size = new System.Drawing.Size(75, 27); + _btnClose.TabIndex = 1; + _btnClose.Text = "Close"; + _btnClose.UseVisualStyleBackColor = true; + // + // MultisHelpForm + // + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + CancelButton = _btnClose; + ClientSize = new System.Drawing.Size(634, 341); + Controls.Add(_listView); + Controls.Add(_btnClose); + FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + Name = "MultisHelpForm"; + Padding = new System.Windows.Forms.Padding(8); + ShowInTaskbar = false; + StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + Text = "Multis — Keyboard Shortcuts & Controls"; + ResumeLayout(false); + } + + #endregion + + private System.Windows.Forms.ListView _listView; + private System.Windows.Forms.ColumnHeader _columnKey; + private System.Windows.Forms.ColumnHeader _columnAction; + private System.Windows.Forms.Button _btnClose; + } +} diff --git a/UoFiddler.Controls/Forms/MultisHelpForm.cs b/UoFiddler.Controls/Forms/MultisHelpForm.cs new file mode 100644 index 00000000..de0ae534 --- /dev/null +++ b/UoFiddler.Controls/Forms/MultisHelpForm.cs @@ -0,0 +1,50 @@ +/*************************************************************************** + * + * $Author: Turley + * + * "THE BEER-WARE LICENSE" + * As long as you retain this notice you can do whatever you want with + * this stuff. If we meet some day, and you think this stuff is worth it, + * you can buy me a beer in return. + * + ***************************************************************************/ + +using System.Windows.Forms; + +namespace UoFiddler.Controls.Forms +{ + public partial class MultisHelpForm : Form + { + public MultisHelpForm() + { + InitializeComponent(); + PopulateShortcuts(); + } + + private void PopulateShortcuts() + { + _listView.Groups.Add(new ListViewGroup("preview", "Preview")); + _listView.Groups.Add(new ListViewGroup("zoom", "Zoom (100% mode only)")); + _listView.Groups.Add(new ListViewGroup("pan", "Panning (100% mode only)")); + + Add("Fit preview to window", "Toggle button on toolbar — scales to fit or shows at 100% with scrollbars", "preview"); + + Add("Ctrl + Mouse Wheel", "Zoom In / Out", "zoom"); + Add("Shift + = (Plus key)", "Zoom In", "zoom"); + Add("- (Minus key)", "Zoom Out", "zoom"); + Add("Numpad +", "Zoom In", "zoom"); + Add("Numpad -", "Zoom Out", "zoom"); + Add("Ctrl + 0", "Reset zoom to 100%", "zoom"); + + Add("Left-click drag", "Pan the view", "pan"); + } + + private void Add(string key, string action, string groupKey) + { + var group = _listView.Groups[groupKey]; + var item = new ListViewItem(key, group); + item.SubItems.Add(action); + _listView.Items.Add(item); + } + } +} diff --git a/UoFiddler.Controls/Forms/MultisHelpForm.resx b/UoFiddler.Controls/Forms/MultisHelpForm.resx new file mode 100644 index 00000000..4edf53f8 --- /dev/null +++ b/UoFiddler.Controls/Forms/MultisHelpForm.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/UoFiddler.Controls/UserControls/ClilocControl.cs b/UoFiddler.Controls/UserControls/ClilocControl.cs index c248a972..7effd58b 100644 --- a/UoFiddler.Controls/UserControls/ClilocControl.cs +++ b/UoFiddler.Controls/UserControls/ClilocControl.cs @@ -54,18 +54,18 @@ private int Lang switch (value) { case 0: - _cliloc = new StringList("enu", Options.NewClilocFormat); + _cliloc = new StringList("enu", false); break; case 1: - _cliloc = new StringList("deu", Options.NewClilocFormat); + _cliloc = new StringList("deu", false); break; case 2: TestCustomLang("cliloc.custom1"); - _cliloc = new StringList("custom1", Options.NewClilocFormat); + _cliloc = new StringList("custom1", false); break; case 3: TestCustomLang("cliloc.custom2"); - _cliloc = new StringList("custom2", Options.NewClilocFormat); + _cliloc = new StringList("custom2", false); break; } } diff --git a/UoFiddler.Controls/UserControls/MultisControl.Designer.cs b/UoFiddler.Controls/UserControls/MultisControl.Designer.cs index a4dbd41d..76def1ec 100644 --- a/UoFiddler.Controls/UserControls/MultisControl.Designer.cs +++ b/UoFiddler.Controls/UserControls/MultisControl.Designer.cs @@ -1,9 +1,9 @@ /*************************************************************************** * * $Author: Turley - * + * * "THE BEER-WARE LICENSE" - * As long as you retain this notice you can do whatever you want with + * As long as you retain this notice you can do whatever you want with * this stuff. If we meet some day, and you think this stuff is worth it, * you can buy me a beer in return. * @@ -13,12 +13,12 @@ namespace UoFiddler.Controls.UserControls { partial class MultisControl { - /// + /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; - /// + /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. @@ -71,11 +71,14 @@ private void InitializeComponent() toXMLFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); saveToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + fitModeToolStripMenuItem = new System.Windows.Forms.ToolStripButton(); + helpToolStripButton = new System.Windows.Forms.ToolStripButton(); tabControl3 = new System.Windows.Forms.TabControl(); tabPage5 = new System.Windows.Forms.TabPage(); splitContainer3 = new System.Windows.Forms.SplitContainer(); HeightChangeMulti = new System.Windows.Forms.TrackBar(); splitContainer4 = new System.Windows.Forms.SplitContainer(); + panelMultiScroll = new System.Windows.Forms.Panel(); MultiPictureBox = new System.Windows.Forms.PictureBox(); contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(components); extractImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -89,6 +92,48 @@ private void InitializeComponent() MultiComponentBox = new System.Windows.Forms.RichTextBox(); toolTip = new System.Windows.Forms.ToolTip(components); colorDialog = new System.Windows.Forms.ColorDialog(); + panelUopScroll = new System.Windows.Forms.Panel(); + UopPictureBox = new System.Windows.Forms.PictureBox(); + contextMenuStripUopPic = new System.Windows.Forms.ContextMenuStrip(components); + uopExtractImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopAsBmpPicToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopAsTiffPicToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopAsJpgPicToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopAsPngPicToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopFitModeToolStripMenuItem = new System.Windows.Forms.ToolStripButton(); + uopHelpToolStripButton = new System.Windows.Forms.ToolStripButton(); + tabControlSource = new System.Windows.Forms.TabControl(); + tabPageMul = new System.Windows.Forms.TabPage(); + tabPageUop = new System.Windows.Forms.TabPage(); + splitContainerUop = new System.Windows.Forms.SplitContainer(); + treeViewUop = new System.Windows.Forms.TreeView(); + contextMenuStripUop = new System.Windows.Forms.ContextMenuStrip(components); + uopExportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopToUOAToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopToWscToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopToCsvToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + toolStripUop = new System.Windows.Forms.ToolStrip(); + toolStripDropDownUop = new System.Windows.Forms.ToolStripDropDownButton(); + uopExportAllImagesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopAsBmpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopAsTiffToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopAsJpgToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopAsPngToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopToolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + uopExportAllPartsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopToTextfileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopToUOAFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopToWSCFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + uopToCSVFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + tabControlUopDetail = new System.Windows.Forms.TabControl(); + tabPageUopPreview = new System.Windows.Forms.TabPage(); + splitContainerUop3 = new System.Windows.Forms.SplitContainer(); + HeightChangeUop = new System.Windows.Forms.TrackBar(); + splitContainerUop4 = new System.Windows.Forms.SplitContainer(); + statusStripUop = new System.Windows.Forms.StatusStrip(); + StatusUopText = new System.Windows.Forms.ToolStripStatusLabel(); + tabPageUopComponents = new System.Windows.Forms.TabPage(); + UopComponentBox = new System.Windows.Forms.RichTextBox(); ((System.ComponentModel.ISupportInitialize)splitContainer2).BeginInit(); splitContainer2.Panel1.SuspendLayout(); splitContainer2.Panel2.SuspendLayout(); @@ -106,10 +151,36 @@ private void InitializeComponent() splitContainer4.Panel1.SuspendLayout(); splitContainer4.Panel2.SuspendLayout(); splitContainer4.SuspendLayout(); + panelMultiScroll.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)MultiPictureBox).BeginInit(); contextMenuStrip1.SuspendLayout(); statusMulti.SuspendLayout(); tabPage6.SuspendLayout(); + panelUopScroll.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)UopPictureBox).BeginInit(); + contextMenuStripUopPic.SuspendLayout(); + tabControlSource.SuspendLayout(); + tabPageMul.SuspendLayout(); + tabPageUop.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitContainerUop).BeginInit(); + splitContainerUop.Panel1.SuspendLayout(); + splitContainerUop.Panel2.SuspendLayout(); + splitContainerUop.SuspendLayout(); + contextMenuStripUop.SuspendLayout(); + toolStripUop.SuspendLayout(); + tabControlUopDetail.SuspendLayout(); + tabPageUopPreview.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitContainerUop3).BeginInit(); + splitContainerUop3.Panel1.SuspendLayout(); + splitContainerUop3.Panel2.SuspendLayout(); + splitContainerUop3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)HeightChangeUop).BeginInit(); + ((System.ComponentModel.ISupportInitialize)splitContainerUop4).BeginInit(); + splitContainerUop4.Panel1.SuspendLayout(); + splitContainerUop4.Panel2.SuspendLayout(); + splitContainerUop4.SuspendLayout(); + statusStripUop.SuspendLayout(); + tabPageUopComponents.SuspendLayout(); SuspendLayout(); // // splitContainer2 @@ -127,7 +198,7 @@ private void InitializeComponent() // splitContainer2.Panel2 // splitContainer2.Panel2.Controls.Add(tabControl3); - splitContainer2.Size = new System.Drawing.Size(755, 442); + splitContainer2.Size = new System.Drawing.Size(747, 414); splitContainer2.SplitterDistance = 245; splitContainer2.SplitterWidth = 5; splitContainer2.TabIndex = 1; @@ -141,7 +212,7 @@ private void InitializeComponent() TreeViewMulti.Margin = new System.Windows.Forms.Padding(0); TreeViewMulti.Name = "TreeViewMulti"; TreeViewMulti.ShowNodeToolTips = true; - TreeViewMulti.Size = new System.Drawing.Size(245, 417); + TreeViewMulti.Size = new System.Drawing.Size(245, 389); TreeViewMulti.TabIndex = 0; TreeViewMulti.AfterSelect += AfterSelect_Multi; // @@ -218,7 +289,7 @@ private void InitializeComponent() // toolStrip1 // toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; - toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { toolStripDropDownButton1 }); + toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { toolStripDropDownButton1, fitModeToolStripMenuItem, helpToolStripButton }); toolStrip1.Location = new System.Drawing.Point(0, 0); toolStrip1.Name = "toolStrip1"; toolStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.System; @@ -355,6 +426,27 @@ private void InitializeComponent() saveToolStripMenuItem1.Text = "Save"; saveToolStripMenuItem1.Click += OnClickSave; // + // fitModeToolStripMenuItem + // + fitModeToolStripMenuItem.Checked = true; + fitModeToolStripMenuItem.CheckOnClick = true; + fitModeToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + fitModeToolStripMenuItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + fitModeToolStripMenuItem.Name = "fitModeToolStripMenuItem"; + fitModeToolStripMenuItem.Size = new System.Drawing.Size(127, 22); + fitModeToolStripMenuItem.Text = "Fit preview to window"; + fitModeToolStripMenuItem.ToolTipText = "When checked the preview scales to fit. When unchecked it shows 100% with scrollbars."; + fitModeToolStripMenuItem.CheckedChanged += OnToggleFitMode; + // + // helpToolStripButton + // + helpToolStripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + helpToolStripButton.Name = "helpToolStripButton"; + helpToolStripButton.Size = new System.Drawing.Size(36, 22); + helpToolStripButton.Text = "Help"; + helpToolStripButton.ToolTipText = "Show keyboard shortcuts and controls"; + helpToolStripButton.Click += OnClickHelp; + // // tabControl3 // tabControl3.Controls.Add(tabPage5); @@ -364,7 +456,7 @@ private void InitializeComponent() tabControl3.Margin = new System.Windows.Forms.Padding(0); tabControl3.Name = "tabControl3"; tabControl3.SelectedIndex = 0; - tabControl3.Size = new System.Drawing.Size(505, 442); + tabControl3.Size = new System.Drawing.Size(497, 414); tabControl3.TabIndex = 1; // // tabPage5 @@ -374,7 +466,7 @@ private void InitializeComponent() tabPage5.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); tabPage5.Name = "tabPage5"; tabPage5.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); - tabPage5.Size = new System.Drawing.Size(497, 414); + tabPage5.Size = new System.Drawing.Size(489, 386); tabPage5.TabIndex = 0; tabPage5.Text = "Graphic"; tabPage5.UseVisualStyleBackColor = true; @@ -394,7 +486,7 @@ private void InitializeComponent() // splitContainer3.Panel2 // splitContainer3.Panel2.Controls.Add(splitContainer4); - splitContainer3.Size = new System.Drawing.Size(489, 408); + splitContainer3.Size = new System.Drawing.Size(481, 380); splitContainer3.SplitterDistance = 41; splitContainer3.SplitterWidth = 1; splitContainer3.TabIndex = 0; @@ -407,7 +499,7 @@ private void InitializeComponent() HeightChangeMulti.MaximumSize = new System.Drawing.Size(0, 38); HeightChangeMulti.MinimumSize = new System.Drawing.Size(0, 38); HeightChangeMulti.Name = "HeightChangeMulti"; - HeightChangeMulti.Size = new System.Drawing.Size(489, 38); + HeightChangeMulti.Size = new System.Drawing.Size(481, 38); HeightChangeMulti.TabIndex = 0; HeightChangeMulti.ValueChanged += OnValue_HeightChangeMulti; // @@ -421,17 +513,29 @@ private void InitializeComponent() // // splitContainer4.Panel1 // - splitContainer4.Panel1.Controls.Add(MultiPictureBox); + splitContainer4.Panel1.Controls.Add(panelMultiScroll); // // splitContainer4.Panel2 // splitContainer4.Panel2.Controls.Add(statusMulti); splitContainer4.Panel2MinSize = 22; - splitContainer4.Size = new System.Drawing.Size(489, 366); - splitContainer4.SplitterDistance = 322; + splitContainer4.Size = new System.Drawing.Size(481, 338); + splitContainer4.SplitterDistance = 308; splitContainer4.SplitterWidth = 1; splitContainer4.TabIndex = 1; // + // panelMultiScroll + // + panelMultiScroll.AutoScroll = true; + panelMultiScroll.Controls.Add(MultiPictureBox); + panelMultiScroll.Dock = System.Windows.Forms.DockStyle.Fill; + panelMultiScroll.Location = new System.Drawing.Point(0, 0); + panelMultiScroll.Margin = new System.Windows.Forms.Padding(0); + panelMultiScroll.Name = "panelMultiScroll"; + panelMultiScroll.Size = new System.Drawing.Size(481, 308); + panelMultiScroll.TabIndex = 0; + panelMultiScroll.Resize += OnPanelMultiScroll_Resize; + // // MultiPictureBox // MultiPictureBox.BackColor = System.Drawing.Color.White; @@ -440,10 +544,13 @@ private void InitializeComponent() MultiPictureBox.Location = new System.Drawing.Point(0, 0); MultiPictureBox.Margin = new System.Windows.Forms.Padding(0); MultiPictureBox.Name = "MultiPictureBox"; - MultiPictureBox.Size = new System.Drawing.Size(489, 322); + MultiPictureBox.Size = new System.Drawing.Size(481, 308); MultiPictureBox.TabIndex = 0; MultiPictureBox.TabStop = false; MultiPictureBox.Paint += OnPaint_MultiPic; + MultiPictureBox.MouseDown += OnMulPan_MouseDown; + MultiPictureBox.MouseMove += OnMulPan_MouseMove; + MultiPictureBox.MouseUp += OnPan_MouseUp; // // contextMenuStrip1 // @@ -489,10 +596,10 @@ private void InitializeComponent() // statusMulti // statusMulti.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { StatusMultiText }); - statusMulti.Location = new System.Drawing.Point(0, 21); + statusMulti.Location = new System.Drawing.Point(0, 7); statusMulti.Name = "statusMulti"; statusMulti.Padding = new System.Windows.Forms.Padding(1, 0, 16, 0); - statusMulti.Size = new System.Drawing.Size(489, 22); + statusMulti.Size = new System.Drawing.Size(481, 22); statusMulti.TabIndex = 0; statusMulti.Text = "statusStrip2"; // @@ -509,7 +616,7 @@ private void InitializeComponent() tabPage6.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); tabPage6.Name = "tabPage6"; tabPage6.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); - tabPage6.Size = new System.Drawing.Size(497, 414); + tabPage6.Size = new System.Drawing.Size(489, 386); tabPage6.TabIndex = 1; tabPage6.Text = "Component List"; tabPage6.UseVisualStyleBackColor = true; @@ -521,7 +628,7 @@ private void InitializeComponent() MultiComponentBox.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); MultiComponentBox.Name = "MultiComponentBox"; MultiComponentBox.ReadOnly = true; - MultiComponentBox.Size = new System.Drawing.Size(489, 408); + MultiComponentBox.Size = new System.Drawing.Size(481, 380); MultiComponentBox.TabIndex = 0; MultiComponentBox.Text = ""; // @@ -529,11 +636,412 @@ private void InitializeComponent() // colorDialog.Color = System.Drawing.Color.White; // + // panelUopScroll + // + panelUopScroll.AutoScroll = true; + panelUopScroll.Controls.Add(UopPictureBox); + panelUopScroll.Dock = System.Windows.Forms.DockStyle.Fill; + panelUopScroll.Location = new System.Drawing.Point(0, 0); + panelUopScroll.Margin = new System.Windows.Forms.Padding(0); + panelUopScroll.Name = "panelUopScroll"; + panelUopScroll.Size = new System.Drawing.Size(481, 308); + panelUopScroll.TabIndex = 0; + panelUopScroll.Resize += OnPanelUopScroll_Resize; + // + // UopPictureBox + // + UopPictureBox.BackColor = System.Drawing.Color.White; + UopPictureBox.ContextMenuStrip = contextMenuStripUopPic; + UopPictureBox.Dock = System.Windows.Forms.DockStyle.Fill; + UopPictureBox.Location = new System.Drawing.Point(0, 0); + UopPictureBox.Margin = new System.Windows.Forms.Padding(0); + UopPictureBox.Name = "UopPictureBox"; + UopPictureBox.Size = new System.Drawing.Size(481, 308); + UopPictureBox.TabIndex = 0; + UopPictureBox.TabStop = false; + UopPictureBox.Paint += OnPaint_UopMultiPic; + UopPictureBox.MouseDown += OnUopPan_MouseDown; + UopPictureBox.MouseMove += OnUopPan_MouseMove; + UopPictureBox.MouseUp += OnPan_MouseUp; + // + // contextMenuStripUopPic + // + contextMenuStripUopPic.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { uopExtractImageToolStripMenuItem }); + contextMenuStripUopPic.Name = "contextMenuStripUopPic"; + contextMenuStripUopPic.Size = new System.Drawing.Size(153, 26); + // + // uopExtractImageToolStripMenuItem + // + uopExtractImageToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { uopAsBmpPicToolStripMenuItem, uopAsTiffPicToolStripMenuItem, uopAsJpgPicToolStripMenuItem, uopAsPngPicToolStripMenuItem }); + uopExtractImageToolStripMenuItem.Name = "uopExtractImageToolStripMenuItem"; + uopExtractImageToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + uopExtractImageToolStripMenuItem.Text = "extract Image.."; + // + // uopAsBmpPicToolStripMenuItem + // + uopAsBmpPicToolStripMenuItem.Name = "uopAsBmpPicToolStripMenuItem"; + uopAsBmpPicToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + uopAsBmpPicToolStripMenuItem.Text = "As Bmp"; + uopAsBmpPicToolStripMenuItem.Click += UopExtract_Image_ClickBmp; + // + // uopAsTiffPicToolStripMenuItem + // + uopAsTiffPicToolStripMenuItem.Name = "uopAsTiffPicToolStripMenuItem"; + uopAsTiffPicToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + uopAsTiffPicToolStripMenuItem.Text = "As Tiff"; + uopAsTiffPicToolStripMenuItem.Click += UopExtract_Image_ClickTiff; + // + // uopAsJpgPicToolStripMenuItem + // + uopAsJpgPicToolStripMenuItem.Name = "uopAsJpgPicToolStripMenuItem"; + uopAsJpgPicToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + uopAsJpgPicToolStripMenuItem.Text = "As Jpg"; + uopAsJpgPicToolStripMenuItem.Click += UopExtract_Image_ClickJpg; + // + // uopAsPngPicToolStripMenuItem + // + uopAsPngPicToolStripMenuItem.Name = "uopAsPngPicToolStripMenuItem"; + uopAsPngPicToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + uopAsPngPicToolStripMenuItem.Text = "As Png"; + uopAsPngPicToolStripMenuItem.Click += UopExtract_Image_ClickPng; + // + // uopFitModeToolStripMenuItem + // + uopFitModeToolStripMenuItem.Checked = true; + uopFitModeToolStripMenuItem.CheckOnClick = true; + uopFitModeToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; + uopFitModeToolStripMenuItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + uopFitModeToolStripMenuItem.Name = "uopFitModeToolStripMenuItem"; + uopFitModeToolStripMenuItem.Size = new System.Drawing.Size(127, 22); + uopFitModeToolStripMenuItem.Text = "Fit preview to window"; + uopFitModeToolStripMenuItem.ToolTipText = "When checked the preview scales to fit. When unchecked it shows 100% with scrollbars."; + uopFitModeToolStripMenuItem.CheckedChanged += OnToggleFitMode; + // + // uopHelpToolStripButton + // + uopHelpToolStripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + uopHelpToolStripButton.Name = "uopHelpToolStripButton"; + uopHelpToolStripButton.Size = new System.Drawing.Size(36, 22); + uopHelpToolStripButton.Text = "Help"; + uopHelpToolStripButton.ToolTipText = "Show keyboard shortcuts and controls"; + uopHelpToolStripButton.Click += OnClickHelp; + // + // tabControlSource + // + tabControlSource.Controls.Add(tabPageMul); + tabControlSource.Controls.Add(tabPageUop); + tabControlSource.Dock = System.Windows.Forms.DockStyle.Fill; + tabControlSource.Location = new System.Drawing.Point(0, 0); + tabControlSource.Margin = new System.Windows.Forms.Padding(0); + tabControlSource.Name = "tabControlSource"; + tabControlSource.SelectedIndex = 0; + tabControlSource.Size = new System.Drawing.Size(755, 442); + tabControlSource.TabIndex = 0; + // + // tabPageMul + // + tabPageMul.Controls.Add(splitContainer2); + tabPageMul.Location = new System.Drawing.Point(4, 24); + tabPageMul.Margin = new System.Windows.Forms.Padding(0); + tabPageMul.Name = "tabPageMul"; + tabPageMul.Size = new System.Drawing.Size(747, 414); + tabPageMul.TabIndex = 0; + tabPageMul.Text = "multi.mul"; + tabPageMul.UseVisualStyleBackColor = true; + // + // tabPageUop + // + tabPageUop.Controls.Add(splitContainerUop); + tabPageUop.Location = new System.Drawing.Point(4, 24); + tabPageUop.Margin = new System.Windows.Forms.Padding(0); + tabPageUop.Name = "tabPageUop"; + tabPageUop.Size = new System.Drawing.Size(747, 414); + tabPageUop.TabIndex = 1; + tabPageUop.Text = "MultiCollection.uop"; + tabPageUop.UseVisualStyleBackColor = true; + // + // splitContainerUop + // + splitContainerUop.Dock = System.Windows.Forms.DockStyle.Fill; + splitContainerUop.Location = new System.Drawing.Point(0, 0); + splitContainerUop.Margin = new System.Windows.Forms.Padding(0); + splitContainerUop.Name = "splitContainerUop"; + // + // splitContainerUop.Panel1 + // + splitContainerUop.Panel1.Controls.Add(treeViewUop); + splitContainerUop.Panel1.Controls.Add(toolStripUop); + // + // splitContainerUop.Panel2 + // + splitContainerUop.Panel2.Controls.Add(tabControlUopDetail); + splitContainerUop.Size = new System.Drawing.Size(747, 414); + splitContainerUop.SplitterDistance = 245; + splitContainerUop.SplitterWidth = 5; + splitContainerUop.TabIndex = 0; + // + // treeViewUop + // + treeViewUop.ContextMenuStrip = contextMenuStripUop; + treeViewUop.Dock = System.Windows.Forms.DockStyle.Fill; + treeViewUop.HideSelection = false; + treeViewUop.Location = new System.Drawing.Point(0, 25); + treeViewUop.Margin = new System.Windows.Forms.Padding(0); + treeViewUop.Name = "treeViewUop"; + treeViewUop.ShowNodeToolTips = true; + treeViewUop.Size = new System.Drawing.Size(245, 389); + treeViewUop.TabIndex = 0; + treeViewUop.AfterSelect += AfterSelect_UopMulti; + // + // contextMenuStripUop + // + contextMenuStripUop.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { uopExportToolStripMenuItem }); + contextMenuStripUop.Name = "contextMenuStripUop"; + contextMenuStripUop.Size = new System.Drawing.Size(115, 26); + // + // uopExportToolStripMenuItem + // + uopExportToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { uopToUOAToolStripMenuItem, uopToWscToolStripMenuItem, uopToCsvToolStripMenuItem }); + uopExportToolStripMenuItem.Name = "uopExportToolStripMenuItem"; + uopExportToolStripMenuItem.Size = new System.Drawing.Size(114, 22); + uopExportToolStripMenuItem.Text = "Export.."; + // + // uopToUOAToolStripMenuItem + // + uopToUOAToolStripMenuItem.Name = "uopToUOAToolStripMenuItem"; + uopToUOAToolStripMenuItem.Size = new System.Drawing.Size(114, 22); + uopToUOAToolStripMenuItem.Text = "To UOA"; + uopToUOAToolStripMenuItem.Click += OnUopExportUOAFile; + // + // uopToWscToolStripMenuItem + // + uopToWscToolStripMenuItem.Name = "uopToWscToolStripMenuItem"; + uopToWscToolStripMenuItem.Size = new System.Drawing.Size(114, 22); + uopToWscToolStripMenuItem.Text = "To WSC"; + uopToWscToolStripMenuItem.Click += OnUopExportWscFile; + // + // uopToCsvToolStripMenuItem + // + uopToCsvToolStripMenuItem.Name = "uopToCsvToolStripMenuItem"; + uopToCsvToolStripMenuItem.Size = new System.Drawing.Size(114, 22); + uopToCsvToolStripMenuItem.Text = "To CSV"; + uopToCsvToolStripMenuItem.Click += OnUopExportCsvFile; + // + // toolStripUop + // + toolStripUop.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + toolStripUop.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { toolStripDropDownUop, uopFitModeToolStripMenuItem, uopHelpToolStripButton }); + toolStripUop.Location = new System.Drawing.Point(0, 0); + toolStripUop.Name = "toolStripUop"; + toolStripUop.RenderMode = System.Windows.Forms.ToolStripRenderMode.System; + toolStripUop.Size = new System.Drawing.Size(245, 25); + toolStripUop.TabIndex = 1; + toolStripUop.Text = "toolStripUop"; + // + // toolStripDropDownUop + // + toolStripDropDownUop.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + toolStripDropDownUop.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { uopExportAllImagesToolStripMenuItem, uopToolStripSeparator1, uopExportAllPartsToolStripMenuItem }); + toolStripDropDownUop.ImageTransparentColor = System.Drawing.Color.Magenta; + toolStripDropDownUop.Name = "toolStripDropDownUop"; + toolStripDropDownUop.Size = new System.Drawing.Size(45, 22); + toolStripDropDownUop.Text = "Misc"; + // + // uopExportAllImagesToolStripMenuItem + // + uopExportAllImagesToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { uopAsBmpToolStripMenuItem, uopAsTiffToolStripMenuItem, uopAsJpgToolStripMenuItem, uopAsPngToolStripMenuItem }); + uopExportAllImagesToolStripMenuItem.Name = "uopExportAllImagesToolStripMenuItem"; + uopExportAllImagesToolStripMenuItem.Size = new System.Drawing.Size(161, 22); + uopExportAllImagesToolStripMenuItem.Text = "Export All Image"; + // + // uopAsBmpToolStripMenuItem + // + uopAsBmpToolStripMenuItem.Name = "uopAsBmpToolStripMenuItem"; + uopAsBmpToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + uopAsBmpToolStripMenuItem.Text = "As Bmp"; + uopAsBmpToolStripMenuItem.Click += OnUopClick_SaveAllBmp; + // + // uopAsTiffToolStripMenuItem + // + uopAsTiffToolStripMenuItem.Name = "uopAsTiffToolStripMenuItem"; + uopAsTiffToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + uopAsTiffToolStripMenuItem.Text = "As Tiff"; + uopAsTiffToolStripMenuItem.Click += OnUopClick_SaveAllTiff; + // + // uopAsJpgToolStripMenuItem + // + uopAsJpgToolStripMenuItem.Name = "uopAsJpgToolStripMenuItem"; + uopAsJpgToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + uopAsJpgToolStripMenuItem.Text = "As Jpg"; + uopAsJpgToolStripMenuItem.Click += OnUopClick_SaveAllJpg; + // + // uopAsPngToolStripMenuItem + // + uopAsPngToolStripMenuItem.Name = "uopAsPngToolStripMenuItem"; + uopAsPngToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + uopAsPngToolStripMenuItem.Text = "As Png"; + uopAsPngToolStripMenuItem.Click += OnUopClick_SaveAllPng; + // + // uopToolStripSeparator1 + // + uopToolStripSeparator1.Name = "uopToolStripSeparator1"; + uopToolStripSeparator1.Size = new System.Drawing.Size(158, 6); + // + // uopExportAllPartsToolStripMenuItem + // + uopExportAllPartsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { uopToTextfileToolStripMenuItem, uopToUOAFileToolStripMenuItem, uopToWSCFileToolStripMenuItem, uopToCSVFileToolStripMenuItem }); + uopExportAllPartsToolStripMenuItem.Name = "uopExportAllPartsToolStripMenuItem"; + uopExportAllPartsToolStripMenuItem.Size = new System.Drawing.Size(161, 22); + uopExportAllPartsToolStripMenuItem.Text = "Export All Parts"; + // + // uopToTextfileToolStripMenuItem + // + uopToTextfileToolStripMenuItem.Name = "uopToTextfileToolStripMenuItem"; + uopToTextfileToolStripMenuItem.Size = new System.Drawing.Size(135, 22); + uopToTextfileToolStripMenuItem.Text = "To Textfile"; + uopToTextfileToolStripMenuItem.Click += OnUopExportTextFile; + // + // uopToUOAFileToolStripMenuItem + // + uopToUOAFileToolStripMenuItem.Name = "uopToUOAFileToolStripMenuItem"; + uopToUOAFileToolStripMenuItem.Size = new System.Drawing.Size(135, 22); + uopToUOAFileToolStripMenuItem.Text = "To UOA File"; + uopToUOAFileToolStripMenuItem.Click += OnUopClick_SaveAllUOA; + // + // uopToWSCFileToolStripMenuItem + // + uopToWSCFileToolStripMenuItem.Name = "uopToWSCFileToolStripMenuItem"; + uopToWSCFileToolStripMenuItem.Size = new System.Drawing.Size(135, 22); + uopToWSCFileToolStripMenuItem.Text = "To WSC File"; + uopToWSCFileToolStripMenuItem.Click += OnUopClick_SaveAllWSC; + // + // uopToCSVFileToolStripMenuItem + // + uopToCSVFileToolStripMenuItem.Name = "uopToCSVFileToolStripMenuItem"; + uopToCSVFileToolStripMenuItem.Size = new System.Drawing.Size(135, 22); + uopToCSVFileToolStripMenuItem.Text = "To CSV File"; + uopToCSVFileToolStripMenuItem.Click += OnUopClick_SaveAllCSV; + // + // tabControlUopDetail + // + tabControlUopDetail.Controls.Add(tabPageUopPreview); + tabControlUopDetail.Controls.Add(tabPageUopComponents); + tabControlUopDetail.Dock = System.Windows.Forms.DockStyle.Fill; + tabControlUopDetail.Location = new System.Drawing.Point(0, 0); + tabControlUopDetail.Margin = new System.Windows.Forms.Padding(0); + tabControlUopDetail.Name = "tabControlUopDetail"; + tabControlUopDetail.SelectedIndex = 0; + tabControlUopDetail.Size = new System.Drawing.Size(497, 414); + tabControlUopDetail.TabIndex = 0; + // + // tabPageUopPreview + // + tabPageUopPreview.Controls.Add(splitContainerUop3); + tabPageUopPreview.Location = new System.Drawing.Point(4, 24); + tabPageUopPreview.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + tabPageUopPreview.Name = "tabPageUopPreview"; + tabPageUopPreview.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + tabPageUopPreview.Size = new System.Drawing.Size(489, 386); + tabPageUopPreview.TabIndex = 0; + tabPageUopPreview.Text = "Graphic"; + tabPageUopPreview.UseVisualStyleBackColor = true; + // + // splitContainerUop3 + // + splitContainerUop3.Dock = System.Windows.Forms.DockStyle.Fill; + splitContainerUop3.Location = new System.Drawing.Point(4, 3); + splitContainerUop3.Margin = new System.Windows.Forms.Padding(0); + splitContainerUop3.Name = "splitContainerUop3"; + splitContainerUop3.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainerUop3.Panel1 + // + splitContainerUop3.Panel1.Controls.Add(HeightChangeUop); + // + // splitContainerUop3.Panel2 + // + splitContainerUop3.Panel2.Controls.Add(splitContainerUop4); + splitContainerUop3.Size = new System.Drawing.Size(481, 380); + splitContainerUop3.SplitterDistance = 41; + splitContainerUop3.SplitterWidth = 1; + splitContainerUop3.TabIndex = 0; + // + // HeightChangeUop + // + HeightChangeUop.Dock = System.Windows.Forms.DockStyle.Fill; + HeightChangeUop.Location = new System.Drawing.Point(0, 0); + HeightChangeUop.Margin = new System.Windows.Forms.Padding(0); + HeightChangeUop.MaximumSize = new System.Drawing.Size(0, 38); + HeightChangeUop.MinimumSize = new System.Drawing.Size(0, 38); + HeightChangeUop.Name = "HeightChangeUop"; + HeightChangeUop.Size = new System.Drawing.Size(481, 38); + HeightChangeUop.TabIndex = 0; + HeightChangeUop.ValueChanged += OnValue_HeightChangeUop; + // + // splitContainerUop4 + // + splitContainerUop4.Dock = System.Windows.Forms.DockStyle.Fill; + splitContainerUop4.Location = new System.Drawing.Point(0, 0); + splitContainerUop4.Margin = new System.Windows.Forms.Padding(0); + splitContainerUop4.Name = "splitContainerUop4"; + splitContainerUop4.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainerUop4.Panel1 + // + splitContainerUop4.Panel1.Controls.Add(panelUopScroll); + // + // splitContainerUop4.Panel2 + // + splitContainerUop4.Panel2.Controls.Add(statusStripUop); + splitContainerUop4.Panel2MinSize = 22; + splitContainerUop4.Size = new System.Drawing.Size(481, 338); + splitContainerUop4.SplitterDistance = 308; + splitContainerUop4.SplitterWidth = 1; + splitContainerUop4.TabIndex = 1; + // + // statusStripUop + // + statusStripUop.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { StatusUopText }); + statusStripUop.Location = new System.Drawing.Point(0, 7); + statusStripUop.Name = "statusStripUop"; + statusStripUop.Padding = new System.Windows.Forms.Padding(1, 0, 16, 0); + statusStripUop.Size = new System.Drawing.Size(481, 22); + statusStripUop.TabIndex = 0; + statusStripUop.Text = "statusStripUop"; + // + // StatusUopText + // + StatusUopText.Name = "StatusUopText"; + StatusUopText.Size = new System.Drawing.Size(0, 17); + // + // tabPageUopComponents + // + tabPageUopComponents.Controls.Add(UopComponentBox); + tabPageUopComponents.Location = new System.Drawing.Point(4, 24); + tabPageUopComponents.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + tabPageUopComponents.Name = "tabPageUopComponents"; + tabPageUopComponents.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); + tabPageUopComponents.Size = new System.Drawing.Size(489, 386); + tabPageUopComponents.TabIndex = 1; + tabPageUopComponents.Text = "Component List"; + tabPageUopComponents.UseVisualStyleBackColor = true; + // + // UopComponentBox + // + UopComponentBox.Dock = System.Windows.Forms.DockStyle.Fill; + UopComponentBox.Location = new System.Drawing.Point(4, 3); + UopComponentBox.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + UopComponentBox.Name = "UopComponentBox"; + UopComponentBox.ReadOnly = true; + UopComponentBox.Size = new System.Drawing.Size(481, 380); + UopComponentBox.TabIndex = 0; + UopComponentBox.Text = ""; + // // MultisControl // AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - Controls.Add(splitContainer2); + Controls.Add(tabControlSource); DoubleBuffered = true; Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); Name = "MultisControl"; @@ -560,11 +1068,42 @@ private void InitializeComponent() splitContainer4.Panel2.PerformLayout(); ((System.ComponentModel.ISupportInitialize)splitContainer4).EndInit(); splitContainer4.ResumeLayout(false); + panelMultiScroll.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)MultiPictureBox).EndInit(); contextMenuStrip1.ResumeLayout(false); statusMulti.ResumeLayout(false); statusMulti.PerformLayout(); tabPage6.ResumeLayout(false); + panelUopScroll.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)UopPictureBox).EndInit(); + contextMenuStripUopPic.ResumeLayout(false); + tabControlSource.ResumeLayout(false); + tabPageMul.ResumeLayout(false); + tabPageUop.ResumeLayout(false); + splitContainerUop.Panel1.ResumeLayout(false); + splitContainerUop.Panel1.PerformLayout(); + splitContainerUop.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainerUop).EndInit(); + splitContainerUop.ResumeLayout(false); + contextMenuStripUop.ResumeLayout(false); + toolStripUop.ResumeLayout(false); + toolStripUop.PerformLayout(); + tabControlUopDetail.ResumeLayout(false); + tabPageUopPreview.ResumeLayout(false); + splitContainerUop3.Panel1.ResumeLayout(false); + splitContainerUop3.Panel1.PerformLayout(); + splitContainerUop3.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainerUop3).EndInit(); + splitContainerUop3.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)HeightChangeUop).EndInit(); + splitContainerUop4.Panel1.ResumeLayout(false); + splitContainerUop4.Panel2.ResumeLayout(false); + splitContainerUop4.Panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)splitContainerUop4).EndInit(); + splitContainerUop4.ResumeLayout(false); + statusStripUop.ResumeLayout(false); + statusStripUop.PerformLayout(); + tabPageUopComponents.ResumeLayout(false); ResumeLayout(false); } @@ -619,5 +1158,50 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem toUOX3FileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem toUOX3ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem toXMLFileToolStripMenuItem; + private System.Windows.Forms.ToolStripButton fitModeToolStripMenuItem; + private System.Windows.Forms.ToolStripButton uopFitModeToolStripMenuItem; + private System.Windows.Forms.ToolStripButton helpToolStripButton; + private System.Windows.Forms.ToolStripButton uopHelpToolStripButton; + private System.Windows.Forms.Panel panelMultiScroll; + private System.Windows.Forms.Panel panelUopScroll; + private System.Windows.Forms.TabControl tabControlSource; + private System.Windows.Forms.TabPage tabPageMul; + private System.Windows.Forms.TabPage tabPageUop; + private System.Windows.Forms.SplitContainer splitContainerUop; + private System.Windows.Forms.TreeView treeViewUop; + private System.Windows.Forms.ContextMenuStrip contextMenuStripUop; + private System.Windows.Forms.ToolStripMenuItem uopExportToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopToTextfileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopToUOAToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopToWscToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopToCsvToolStripMenuItem; + private System.Windows.Forms.ToolStrip toolStripUop; + private System.Windows.Forms.ToolStripDropDownButton toolStripDropDownUop; + private System.Windows.Forms.ToolStripMenuItem uopExportAllImagesToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopAsBmpToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopAsTiffToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopAsJpgToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopAsPngToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator uopToolStripSeparator1; + private System.Windows.Forms.ToolStripMenuItem uopExportAllPartsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopToUOAFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopToWSCFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopToCSVFileToolStripMenuItem; + private System.Windows.Forms.TabControl tabControlUopDetail; + private System.Windows.Forms.TabPage tabPageUopPreview; + private System.Windows.Forms.SplitContainer splitContainerUop3; + private System.Windows.Forms.TrackBar HeightChangeUop; + private System.Windows.Forms.SplitContainer splitContainerUop4; + private System.Windows.Forms.PictureBox UopPictureBox; + private System.Windows.Forms.ContextMenuStrip contextMenuStripUopPic; + private System.Windows.Forms.ToolStripMenuItem uopExtractImageToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopAsBmpPicToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopAsTiffPicToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopAsJpgPicToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uopAsPngPicToolStripMenuItem; + private System.Windows.Forms.StatusStrip statusStripUop; + private System.Windows.Forms.ToolStripStatusLabel StatusUopText; + private System.Windows.Forms.TabPage tabPageUopComponents; + private System.Windows.Forms.RichTextBox UopComponentBox; } } diff --git a/UoFiddler.Controls/UserControls/MultisControl.cs b/UoFiddler.Controls/UserControls/MultisControl.cs index fbe14c98..2d4f81fc 100644 --- a/UoFiddler.Controls/UserControls/MultisControl.cs +++ b/UoFiddler.Controls/UserControls/MultisControl.cs @@ -49,6 +49,18 @@ public MultisControl() private bool _showFreeSlots; private readonly MultisControl _refMarker; private bool _useTransparencyForPng = true; + private bool _previewFitMode = true; + private Bitmap _mulBitmap; + private Bitmap _uopBitmap; + private bool _isPanning; + private Point _panStartScreen; + private double _zoomLevel = 1.0; + private const double _zoomFactor = 1.25; + private const double _zoomMin = 0.25; + private const double _zoomMax = 2.0; + private string _mulStatusBase = string.Empty; + private string _uopStatusBase = string.Empty; + private MouseWheelFilter _mouseWheelFilter; /// /// ReLoads if loaded @@ -61,6 +73,57 @@ private void Reload() } } + private string BuildNodeLabel(int i) + { + if (_xmlDocument == null) + { + return string.Format("{0,5} (0x{0:X})", i); + } + + XmlNodeList xMultiNodeList = _xmlElementMultis.SelectNodes("/Multis/Multi[@id='" + i + "']"); + string name = ""; + foreach (XmlNode xMultiNode in xMultiNodeList) + { + name = xMultiNode.Attributes["name"].Value; + } + + return $"{i,5} (0x{i:X}) {name}"; + } + + private TreeNode BuildMulNode(int i, MultiComponentList multi) + { + TreeNode node; + if (_xmlDocument == null) + { + node = new TreeNode(BuildNodeLabel(i)); + } + else + { + node = new TreeNode(BuildNodeLabel(i)); + XmlNodeList xMultiNodeList = _xmlElementMultis.SelectNodes("/Multis/Multi[@id='" + i + "']"); + string name = ""; + foreach (XmlNode xMultiNode in xMultiNodeList) + { + name = xMultiNode.Attributes["name"].Value; + } + + XmlNodeList tooltipList = _xmlElementMultis.SelectNodes("/Multis/ToolTip[@id='" + i + "']"); + foreach (XmlNode xMultiNode in tooltipList) + { + node.ToolTipText = name + "\r\n" + xMultiNode.Attributes["text"].Value; + } + + if (tooltipList.Count == 0) + { + node.ToolTipText = name; + } + } + + node.Tag = multi; + node.Name = i.ToString(); + return node; + } + private void OnLoad(object sender, EventArgs e) { if (IsAncestorSiteInDesignMode || FormsDesignerHelper.IsInDesignMode()) @@ -88,37 +151,7 @@ private void OnLoad(object sender, EventArgs e) continue; } - TreeNode node; - if (_xmlDocument == null) - { - node = new TreeNode(string.Format("{0,5} (0x{0:X})", i)); - } - else - { - XmlNodeList xMultiNodeList = _xmlElementMultis.SelectNodes("/Multis/Multi[@id='" + i + "']"); - string j = ""; - - foreach (XmlNode xMultiNode in xMultiNodeList) - { - j = xMultiNode.Attributes["name"].Value; - } - - node = new TreeNode($"{i,5} (0x{i:X}) {j}"); - xMultiNodeList = _xmlElementMultis.SelectNodes("/Multis/ToolTip[@id='" + i + "']"); - foreach (XmlNode xMultiNode in xMultiNodeList) - { - node.ToolTipText = j + "\r\n" + xMultiNode.Attributes["text"].Value; - } - - if (xMultiNodeList.Count == 0) - { - node.ToolTipText = j; - } - } - - node.Tag = multi; - node.Name = i.ToString(); - cache.Add(node); + cache.Add(BuildMulNode(i, multi)); } TreeViewMulti.Nodes.AddRange(cache.ToArray()); @@ -141,17 +174,22 @@ private void OnLoad(object sender, EventArgs e) } _loaded = true; + + LoadUopTree(); + Cursor.Current = Cursors.Default; } private void OnFilePathChangeEvent() { + Multis.ReloadUop(); Reload(); } private void OnPreviewBackgroundColorChanged() { MultiPictureBox.BackColor = Options.PreviewBackgroundColor; + UopPictureBox.BackColor = Options.PreviewBackgroundColor; } private void OnMultiChangeEvent(object sender, int id) @@ -253,76 +291,104 @@ private void AfterSelect_Multi(object sender, TreeViewEventArgs e) { HeightChangeMulti.Maximum = 0; toolTip.SetToolTip(HeightChangeMulti, "MaxHeight: 0"); - StatusMultiText.Text = "Size: 0,0 MaxHeight: 0 MultiRegion: 0,0,0,0"; + SetMulStatus("Size: 0,0 MaxHeight: 0 MultiRegion: 0,0,0,0"); } else { HeightChangeMulti.Maximum = multi.MaxHeight; toolTip.SetToolTip(HeightChangeMulti, $"MaxHeight: {HeightChangeMulti.Maximum - HeightChangeMulti.Value}"); - StatusMultiText.Text = - $"Size: {multi.Width},{multi.Height} MaxHeight: {multi.MaxHeight} MultiRegion: {multi.Min.X},{multi.Min.Y},{multi.Max.X},{multi.Max.Y} Surface: {multi.Surface}"; + SetMulStatus($"Size: {multi.Width},{multi.Height} MaxHeight: {multi.MaxHeight} MultiRegion: {multi.Min.X},{multi.Min.Y},{multi.Max.X},{multi.Max.Y} Surface: {multi.Surface}"); } ChangeComponentList(multi); + RefreshMulBitmap(); + UpdateMulPictureBox(); + } + + private void RefreshMulBitmap() + { + _mulBitmap?.Dispose(); + _mulBitmap = null; + if (TreeViewMulti.SelectedNode?.Tag is MultiComponentList multi && multi != MultiComponentList.Empty) + { + int h = HeightChangeMulti.Maximum - HeightChangeMulti.Value; + _mulBitmap = multi.GetImage(h); + } + } + + private void UpdateMulPictureBox() + { + if (_previewFitMode || _mulBitmap == null) + { + MultiPictureBox.Dock = DockStyle.Fill; + MultiPictureBox.Cursor = Cursors.Default; + } + else + { + MultiPictureBox.Dock = DockStyle.None; + CenterPictureBox(MultiPictureBox, panelMultiScroll, GetZoomedSize(_mulBitmap.Size)); + MultiPictureBox.Cursor = Cursors.Hand; + } MultiPictureBox.Invalidate(); } private void OnPaint_MultiPic(object sender, PaintEventArgs e) { - if (TreeViewMulti.SelectedNode == null) + if (_mulBitmap == null) { + e.Graphics.Clear(MultiPictureBox.BackColor); return; } - if ((MultiComponentList)TreeViewMulti.SelectedNode.Tag == MultiComponentList.Empty) + if (_previewFitMode) { - e.Graphics.Clear(Color.White); - return; + DrawFit(e.Graphics, _mulBitmap, MultiPictureBox.Size); } - int h = HeightChangeMulti.Maximum - HeightChangeMulti.Value; - Bitmap mMainPictureMulti = ((MultiComponentList)TreeViewMulti.SelectedNode.Tag).GetImage(h); - if (mMainPictureMulti == null) + else { - e.Graphics.Clear(Color.White); - return; + e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; + e.Graphics.DrawImage(_mulBitmap, 0, 0, MultiPictureBox.Width, MultiPictureBox.Height); } + } + + private static void DrawFit(Graphics g, Bitmap bmp, Size box) + { Point location = Point.Empty; - Size size = MultiPictureBox.Size; Rectangle destRect; - if (mMainPictureMulti.Height < size.Height && mMainPictureMulti.Width < size.Width) + if (bmp.Height < box.Height && bmp.Width < box.Width) { - location.X = (MultiPictureBox.Width - mMainPictureMulti.Width) / 2; - location.Y = (MultiPictureBox.Height - mMainPictureMulti.Height) / 2; - destRect = new Rectangle(location, mMainPictureMulti.Size); + location.X = (box.Width - bmp.Width) / 2; + location.Y = (box.Height - bmp.Height) / 2; + destRect = new Rectangle(location, bmp.Size); } - else if (mMainPictureMulti.Height < size.Height) + else if (bmp.Height < box.Height) { - location.X = 0; - location.Y = (MultiPictureBox.Height - mMainPictureMulti.Height) / 2; - destRect = mMainPictureMulti.Width > size.Width - ? new Rectangle(location, new Size(size.Width, mMainPictureMulti.Height)) - : new Rectangle(location, mMainPictureMulti.Size); + location.Y = (box.Height - bmp.Height) / 2; + destRect = bmp.Width > box.Width + ? new Rectangle(location, new Size(box.Width, bmp.Height)) + : new Rectangle(location, bmp.Size); } - else if (mMainPictureMulti.Width < size.Width) + else if (bmp.Width < box.Width) { - location.X = (MultiPictureBox.Width - mMainPictureMulti.Width) / 2; - location.Y = 0; - destRect = mMainPictureMulti.Height > size.Height - ? new Rectangle(location, new Size(mMainPictureMulti.Width, size.Height)) - : new Rectangle(location, mMainPictureMulti.Size); + location.X = (box.Width - bmp.Width) / 2; + destRect = bmp.Height > box.Height + ? new Rectangle(location, new Size(bmp.Width, box.Height)) + : new Rectangle(location, bmp.Size); } else { - destRect = new Rectangle(new Point(0, 0), size); + destRect = new Rectangle(Point.Empty, box); } - e.Graphics.DrawImage(mMainPictureMulti, destRect, 0, 0, mMainPictureMulti.Width, mMainPictureMulti.Height, GraphicsUnit.Pixel); + g.DrawImage(bmp, destRect, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel); } private void OnValue_HeightChangeMulti(object sender, EventArgs e) { toolTip.SetToolTip(HeightChangeMulti, $"MaxHeight: {HeightChangeMulti.Maximum - HeightChangeMulti.Value}"); - MultiPictureBox.Invalidate(); + RefreshMulBitmap(); + UpdateMulPictureBox(); } private void ChangeComponentList(MultiComponentList multi) @@ -371,26 +437,16 @@ private void Extract_Image_ClickPng(object sender, EventArgs e) private void ExtractMultiImage(ImageFormat imageFormat, Color backgroundColor) { - string fileExtension = Utils.GetFileExtensionFor(imageFormat); - string floorSuffix = HeightChangeMulti.Value > 0 - ? $"_Z{HeightChangeMulti.Value:000}" - : string.Empty; - - string fileName = Path.Combine(Options.OutputPath, $"Multi 0x{int.Parse(TreeViewMulti.SelectedNode.Name):X4}{floorSuffix}.{fileExtension}"); - - int selectedMaxHeight = HeightChangeMulti.Maximum - HeightChangeMulti.Value; - - using (Bitmap multiBitmap = ((MultiComponentList)TreeViewMulti.SelectedNode.Tag)?.GetImage(selectedMaxHeight)) + if (_mulBitmap == null) { - if (multiBitmap == null) - { - return; - } - - SaveImage(multiBitmap, fileName, imageFormat, backgroundColor); - - FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + return; } + + string fileExtension = Utils.GetFileExtensionFor(imageFormat); + string floorSuffix = HeightChangeMulti.Value > 0 ? $"_Z{HeightChangeMulti.Value:000}" : string.Empty; + string fileName = Path.Combine(Options.OutputPath, $"Multi 0x{int.Parse(TreeViewMulti.SelectedNode.Name):X4}{floorSuffix}.{fileExtension}"); + SaveImage(_mulBitmap, fileName, imageFormat, backgroundColor); + FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); } private static void SaveImage(Image sourceImage, string fileName, ImageFormat imageFormat, Color backgroundColor) @@ -417,23 +473,7 @@ private void OnClickFreeSlots(object sender, EventArgs e) for (int i = 0; i < Multis.MaximumMultiIndex; ++i) { MultiComponentList multi = Multis.GetComponents(i); - TreeNode node; - if (_xmlDocument == null) - { - node = new TreeNode($"{i,5} (0x{i:X})"); - } - else - { - XmlNodeList xMultiNodeList = _xmlElementMultis.SelectNodes("/Multis/Multi[@id='" + i + "']"); - string j = ""; - foreach (XmlNode xMultiNode in xMultiNodeList) - { - j = xMultiNode.Attributes["name"].Value; - } - node = new TreeNode(string.Format("{0,5} (0x{0:X}) {1}", i, j)); - } - node.Name = i.ToString(); - node.Tag = multi; + TreeNode node = BuildMulNode(i, multi); if (multi == MultiComponentList.Empty) { node.ForeColor = Color.Red; @@ -452,24 +492,7 @@ private void OnClickFreeSlots(object sender, EventArgs e) continue; } - TreeNode node; - if (_xmlDocument == null) - { - node = new TreeNode($"{i,5} (0x{i:X})"); - } - else - { - XmlNodeList xMultiNodeList = _xmlElementMultis.SelectNodes("/Multis/Multi[@id='" + i + "']"); - string j = ""; - foreach (XmlNode xMultiNode in xMultiNodeList) - { - j = xMultiNode.Attributes["name"].Value; - } - node = new TreeNode(string.Format("{0,5} (0x{0:X}) {1}", i, j)); - } - node.Tag = multi; - node.Name = i.ToString(); - TreeViewMulti.Nodes.Add(node); + TreeViewMulti.Nodes.Add(BuildMulNode(i, multi)); } } TreeViewMulti.EndUpdate(); @@ -590,8 +613,9 @@ private void OnClickImport(object sender, EventArgs e) } } - using (var dialog = new MultiImportForm(id, ChangeMulti) { TopMost = true }) + using (var dialog = new MultiImportForm(id, ChangeMulti)) { + dialog.TopMost = true; dialog.ShowDialog(); } } @@ -879,6 +903,580 @@ private void UseTransparencyForPNGToolStripMenuItem_CheckedChanged(object sender _useTransparencyForPng = UseTransparencyForPNGToolStripMenuItem.Checked; } + private void LoadUopTree() + { + treeViewUop.BeginUpdate(); + treeViewUop.Nodes.Clear(); + + if (!Multis.HasUopFile) + { + treeViewUop.Nodes.Add(new TreeNode("multicollection.uop not found or path is not set.") { Name = "-1" }); + treeViewUop.EndUpdate(); + return; + } + + var cache = new List(); + for (int i = 0; i < Multis.MaximumMultiIndex; ++i) + { + MultiComponentList multi = Multis.GetUopComponents(i); + if (multi == MultiComponentList.Empty) + { + continue; + } + + cache.Add(new TreeNode(BuildNodeLabel(i)) { Tag = multi, Name = i.ToString() }); + } + + treeViewUop.Nodes.AddRange(cache.ToArray()); + treeViewUop.EndUpdate(); + + if (treeViewUop.Nodes.Count > 0) + { + treeViewUop.SelectedNode = treeViewUop.Nodes[0]; + } + } + + private void AfterSelect_UopMulti(object sender, TreeViewEventArgs e) + { + if (treeViewUop.SelectedNode?.Tag is not MultiComponentList multi) + { + return; + } + + if (multi == MultiComponentList.Empty) + { + HeightChangeUop.Maximum = 0; + toolTip.SetToolTip(HeightChangeUop, "MaxHeight: 0"); + SetUopStatus("Size: 0,0 MaxHeight: 0 MultiRegion: 0,0,0,0"); + } + else + { + HeightChangeUop.Maximum = multi.MaxHeight; + toolTip.SetToolTip(HeightChangeUop, $"MaxHeight: {HeightChangeUop.Maximum - HeightChangeUop.Value}"); + SetUopStatus($"Size: {multi.Width},{multi.Height} MaxHeight: {multi.MaxHeight} MultiRegion: {multi.Min.X},{multi.Min.Y},{multi.Max.X},{multi.Max.Y} Surface: {multi.Surface}"); + } + + ChangeUopComponentList(multi); + RefreshUopBitmap(); + UpdateUopPictureBox(); + } + + private void RefreshUopBitmap() + { + _uopBitmap?.Dispose(); + _uopBitmap = null; + if (treeViewUop.SelectedNode?.Tag is MultiComponentList multi && multi != MultiComponentList.Empty) + { + int h = HeightChangeUop.Maximum - HeightChangeUop.Value; + _uopBitmap = multi.GetImage(h); + } + } + + private void UpdateUopPictureBox() + { + if (_previewFitMode || _uopBitmap == null) + { + UopPictureBox.Dock = DockStyle.Fill; + UopPictureBox.Cursor = Cursors.Default; + } + else + { + UopPictureBox.Dock = DockStyle.None; + CenterPictureBox(UopPictureBox, panelUopScroll, GetZoomedSize(_uopBitmap.Size)); + UopPictureBox.Cursor = Cursors.Hand; + } + UopPictureBox.Invalidate(); + } + + private void ChangeUopComponentList(MultiComponentList multi) + { + UopComponentBox.Clear(); + if (multi == MultiComponentList.Empty) + { + return; + } + + bool isUohsa = Art.IsUOAHS(); + for (int x = 0; x < multi.Width; ++x) + { + for (int y = 0; y < multi.Height; ++y) + { + foreach (var mTile in multi.Tiles[x][y]) + { + UopComponentBox.AppendText( + isUohsa + ? $"0x{mTile.Id:X4} {x,3} {y,3} {mTile.Z,2} {mTile.Flag,2} {mTile.Unk1,2}\n" + : $"0x{mTile.Id:X4} {x,3} {y,3} {mTile.Z,2} {mTile.Flag,2}\n"); + } + } + } + } + + private void OnValue_HeightChangeUop(object sender, EventArgs e) + { + toolTip.SetToolTip(HeightChangeUop, $"MaxHeight: {HeightChangeUop.Maximum - HeightChangeUop.Value}"); + RefreshUopBitmap(); + UpdateUopPictureBox(); + } + + private void OnPaint_UopMultiPic(object sender, PaintEventArgs e) + { + if (_uopBitmap == null) + { + e.Graphics.Clear(UopPictureBox.BackColor); + return; + } + + if (_previewFitMode) + { + DrawFit(e.Graphics, _uopBitmap, UopPictureBox.Size); + } + else + { + e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; + e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; + e.Graphics.DrawImage(_uopBitmap, 0, 0, UopPictureBox.Width, UopPictureBox.Height); + } + } + + private void OnToggleFitMode(object sender, EventArgs e) + { + _previewFitMode = ((System.Windows.Forms.ToolStripButton)sender).Checked; + fitModeToolStripMenuItem.CheckedChanged -= OnToggleFitMode; + uopFitModeToolStripMenuItem.CheckedChanged -= OnToggleFitMode; + fitModeToolStripMenuItem.Checked = _previewFitMode; + uopFitModeToolStripMenuItem.Checked = _previewFitMode; + fitModeToolStripMenuItem.CheckedChanged += OnToggleFitMode; + uopFitModeToolStripMenuItem.CheckedChanged += OnToggleFitMode; + UpdateMulPictureBox(); + UpdateUopPictureBox(); + UpdateZoomStatus(); + } + + private static void CenterPictureBox(PictureBox pic, Panel panel, Size bitmapSize) + { + // Set size first so the panel can clamp AutoScrollPosition to the new valid range. + pic.Size = bitmapSize; + + int vx = Math.Max(0, (panel.ClientSize.Width - bitmapSize.Width) / 2); + int vy = Math.Max(0, (panel.ClientSize.Height - bitmapSize.Height) / 2); + + // AutoScrollPosition getter returns a negative offset (e.g. (0,-100) when scrolled 100 down). + // Control.Location in a scrolled Panel is relative to the current view, not the virtual origin, + // so we add the scroll offset to land at the correct virtual position. + Point scroll = panel.AutoScrollPosition; + pic.Location = new Point(vx + scroll.X, vy + scroll.Y); + } + + private void OnPanelMultiScroll_Resize(object sender, EventArgs e) + { + if (!_previewFitMode && _mulBitmap != null) + { + CenterPictureBox(MultiPictureBox, panelMultiScroll, GetZoomedSize(_mulBitmap.Size)); + } + } + + private void OnPanelUopScroll_Resize(object sender, EventArgs e) + { + if (!_previewFitMode && _uopBitmap != null) + { + CenterPictureBox(UopPictureBox, panelUopScroll, GetZoomedSize(_uopBitmap.Size)); + } + } + + private void OnMulPan_MouseDown(object sender, MouseEventArgs e) + { + if (_previewFitMode || e.Button != MouseButtons.Left) + { + return; + } + + _isPanning = true; + _panStartScreen = Cursor.Position; + MultiPictureBox.Cursor = Cursors.SizeAll; + } + + private void OnMulPan_MouseMove(object sender, MouseEventArgs e) + { + if (!_isPanning) + { + return; + } + + PanPanel(panelMultiScroll); + } + + private void OnUopPan_MouseDown(object sender, MouseEventArgs e) + { + if (_previewFitMode || e.Button != MouseButtons.Left) + { + return; + } + + _isPanning = true; + _panStartScreen = Cursor.Position; + UopPictureBox.Cursor = Cursors.SizeAll; + } + + private void OnUopPan_MouseMove(object sender, MouseEventArgs e) + { + if (!_isPanning) + { + return; + } + + PanPanel(panelUopScroll); + } + + private void OnPan_MouseUp(object sender, MouseEventArgs e) + { + if (!_isPanning) + { + return; + } + + _isPanning = false; + ((Control)sender).Cursor = _previewFitMode ? Cursors.Default : Cursors.Hand; + } + + private void PanPanel(Panel panel) + { + Point pos = Cursor.Position; + int dx = pos.X - _panStartScreen.X; + int dy = pos.Y - _panStartScreen.Y; + Point scroll = panel.AutoScrollPosition; + panel.AutoScrollPosition = new Point( + Math.Max(0, -scroll.X - dx), + Math.Max(0, -scroll.Y - dy) + ); + _panStartScreen = pos; + } + + private Size GetZoomedSize(Size bitmapSize) => + new Size(Math.Max(1, (int)(bitmapSize.Width * _zoomLevel)), + Math.Max(1, (int)(bitmapSize.Height * _zoomLevel))); + + private void ZoomIn() => SetZoom(_zoomLevel * _zoomFactor); + private void ZoomOut() => SetZoom(_zoomLevel / _zoomFactor); + private void ZoomReset() => SetZoom(1.0); + + private void SetZoom(double zoom) + { + _zoomLevel = Math.Clamp(zoom, _zoomMin, _zoomMax); + if (_previewFitMode) + { + return; + } + + UpdateMulPictureBox(); + UpdateUopPictureBox(); + UpdateZoomStatus(); + } + + private void UpdateZoomStatus() + { + SetMulStatus(_mulStatusBase); + SetUopStatus(_uopStatusBase); + } + + private void SetMulStatus(string baseText) + { + _mulStatusBase = baseText; + StatusMultiText.Text = _previewFitMode + ? baseText + : $"{baseText} Zoom: {_zoomLevel * 100:F0}%"; + } + + private void SetUopStatus(string baseText) + { + _uopStatusBase = baseText; + StatusUopText.Text = _previewFitMode + ? baseText + : $"{baseText} Zoom: {_zoomLevel * 100:F0}%"; + } + + protected override void OnHandleCreated(EventArgs e) + { + base.OnHandleCreated(e); + _mouseWheelFilter = new MouseWheelFilter(this); + Application.AddMessageFilter(_mouseWheelFilter); + } + + protected override void OnHandleDestroyed(EventArgs e) + { + if (_mouseWheelFilter != null) + { + Application.RemoveMessageFilter(_mouseWheelFilter); + } + + base.OnHandleDestroyed(e); + } + + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (_previewFitMode) + { + return base.ProcessCmdKey(ref msg, keyData); + } + + switch (keyData) + { + case Keys.Oemplus | Keys.Shift: + case Keys.Add: + ZoomIn(); + return true; + case Keys.OemMinus: + case Keys.Subtract: + ZoomOut(); + return true; + case Keys.D0 | Keys.Control: + case Keys.NumPad0 | Keys.Control: + ZoomReset(); + return true; + default: + return base.ProcessCmdKey(ref msg, keyData); + } + } + + private void OnClickHelp(object sender, EventArgs e) + { + using var form = new MultisHelpForm(); + form.ShowDialog(this); + } + + private void UopExtract_Image_ClickBmp(object sender, EventArgs e) => + ExtractUopMultiImage(ImageFormat.Bmp, Options.PreviewBackgroundColor); + + private void UopExtract_Image_ClickTiff(object sender, EventArgs e) => + ExtractUopMultiImage(ImageFormat.Tiff, Options.PreviewBackgroundColor); + + private void UopExtract_Image_ClickJpg(object sender, EventArgs e) => + ExtractUopMultiImage(ImageFormat.Jpeg, Options.PreviewBackgroundColor); + + private void UopExtract_Image_ClickPng(object sender, EventArgs e) => + ExtractUopMultiImage(ImageFormat.Png, _useTransparencyForPng ? Color.Transparent : Options.PreviewBackgroundColor); + + private void ExtractUopMultiImage(ImageFormat imageFormat, Color backgroundColor) + { + if (_uopBitmap == null) + { + return; + } + + string fileExtension = Utils.GetFileExtensionFor(imageFormat); + string floorSuffix = HeightChangeUop.Value > 0 ? $"_Z{HeightChangeUop.Value:000}" : string.Empty; + int id = int.Parse(treeViewUop.SelectedNode.Name); + string fileName = Path.Combine(Options.OutputPath, $"UopMulti 0x{id:X4}{floorSuffix}.{fileExtension}"); + SaveImage(_uopBitmap, fileName, imageFormat, backgroundColor); + FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + } + + private void OnUopExportTextFile(object sender, EventArgs e) + { + if (treeViewUop.SelectedNode?.Tag is not MultiComponentList multi || multi == MultiComponentList.Empty) + { + return; + } + + int id = int.Parse(treeViewUop.SelectedNode.Name); + string fileName = Path.Combine(Options.OutputPath, $"UopMulti 0x{id:X}.txt"); + multi.ExportToTextFile(fileName); + FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + } + + private void OnUopExportUOAFile(object sender, EventArgs e) + { + if (treeViewUop.SelectedNode?.Tag is not MultiComponentList multi || multi == MultiComponentList.Empty) + { + return; + } + + int id = int.Parse(treeViewUop.SelectedNode.Name); + string fileName = Path.Combine(Options.OutputPath, $"UopMulti 0x{id:X}.uoa"); + multi.ExportToUOAFile(fileName); + FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + } + + private void OnUopExportWscFile(object sender, EventArgs e) + { + if (treeViewUop.SelectedNode?.Tag is not MultiComponentList multi || multi == MultiComponentList.Empty) + { + return; + } + + int id = int.Parse(treeViewUop.SelectedNode.Name); + string fileName = Path.Combine(Options.OutputPath, $"UopMulti 0x{id:X}.wsc"); + multi.ExportToWscFile(fileName); + FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + } + + private void OnUopExportCsvFile(object sender, EventArgs e) + { + if (treeViewUop.SelectedNode?.Tag is not MultiComponentList multi || multi == MultiComponentList.Empty) + { + return; + } + + int id = int.Parse(treeViewUop.SelectedNode.Name); + string fileName = Path.Combine(Options.OutputPath, $"{id:D4}_uop.csv"); + multi.ExportToCsvFile(fileName); + FileSavedDialog.Show(FindForm(), fileName, "Multi saved successfully."); + } + + private void OnUopClick_SaveAllBmp(object sender, EventArgs e) => + ExportAllUopMultis(ImageFormat.Bmp, Options.PreviewBackgroundColor); + + private void OnUopClick_SaveAllTiff(object sender, EventArgs e) => + ExportAllUopMultis(ImageFormat.Tiff, Options.PreviewBackgroundColor); + + private void OnUopClick_SaveAllJpg(object sender, EventArgs e) => + ExportAllUopMultis(ImageFormat.Jpeg, Options.PreviewBackgroundColor); + + private void OnUopClick_SaveAllPng(object sender, EventArgs e) => + ExportAllUopMultis(ImageFormat.Png, _useTransparencyForPng ? Color.Transparent : Options.PreviewBackgroundColor); + + private void ExportAllUopMultis(ImageFormat imageFormat, Color backgroundColor) + { + string fileExtension = Utils.GetFileExtensionFor(imageFormat); + using var dialog = new FolderBrowserDialog { Description = "Select directory", ShowNewFolderButton = true }; + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + const int maxHeight = 127; + for (int i = 0; i < treeViewUop.Nodes.Count; i++) + { + if (!int.TryParse(treeViewUop.Nodes[i].Name, out int index) || index < 0) + { + continue; + } + + if (treeViewUop.Nodes[i].Tag is not MultiComponentList multi || multi == MultiComponentList.Empty) + { + continue; + } + + string fileName = Path.Combine(dialog.SelectedPath, $"UopMulti 0x{index:X4}.{fileExtension}"); + using Bitmap bitmap = multi.GetImage(maxHeight); + if (bitmap != null) + { + SaveImage(bitmap, fileName, imageFormat, backgroundColor); + } + } + + MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK, + MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + } + + private void OnUopClick_SaveAllText(object sender, EventArgs e) + { + using var dialog = new FolderBrowserDialog { Description = "Select directory", ShowNewFolderButton = true }; + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + for (int i = 0; i < treeViewUop.Nodes.Count; ++i) + { + if (!int.TryParse(treeViewUop.Nodes[i].Name, out int index) || index < 0) + { + continue; + } + + if (treeViewUop.Nodes[i].Tag is not MultiComponentList multi || multi == MultiComponentList.Empty) + { + continue; + } + + multi.ExportToTextFile(Path.Combine(dialog.SelectedPath, $"UopMulti 0x{index:X4}.txt")); + } + + MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK, + MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + } + + private void OnUopClick_SaveAllUOA(object sender, EventArgs e) + { + using var dialog = new FolderBrowserDialog { Description = "Select directory", ShowNewFolderButton = true }; + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + for (int i = 0; i < treeViewUop.Nodes.Count; ++i) + { + if (!int.TryParse(treeViewUop.Nodes[i].Name, out int index) || index < 0) + { + continue; + } + + if (treeViewUop.Nodes[i].Tag is not MultiComponentList multi || multi == MultiComponentList.Empty) + { + continue; + } + + multi.ExportToUOAFile(Path.Combine(dialog.SelectedPath, $"UopMulti 0x{index:X4}.uoa")); + } + + MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK, + MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + } + + private void OnUopClick_SaveAllWSC(object sender, EventArgs e) + { + using var dialog = new FolderBrowserDialog { Description = "Select directory", ShowNewFolderButton = true }; + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + for (int i = 0; i < treeViewUop.Nodes.Count; ++i) + { + if (!int.TryParse(treeViewUop.Nodes[i].Name, out int index) || index < 0) + { + continue; + } + + if (treeViewUop.Nodes[i].Tag is not MultiComponentList multi || multi == MultiComponentList.Empty) + { + continue; + } + + multi.ExportToWscFile(Path.Combine(dialog.SelectedPath, $"UopMulti 0x{index:X4}.wsc")); + } + + MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK, + MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + } + + private void OnUopClick_SaveAllCSV(object sender, EventArgs e) + { + using var dialog = new FolderBrowserDialog { Description = "Select directory", ShowNewFolderButton = true }; + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + for (int i = 0; i < treeViewUop.Nodes.Count; ++i) + { + if (!int.TryParse(treeViewUop.Nodes[i].Name, out int index) || index < 0) + { + continue; + } + + if (treeViewUop.Nodes[i].Tag is not MultiComponentList multi || multi == MultiComponentList.Empty) + { + continue; + } + + multi.ExportToCsvFile(Path.Combine(dialog.SelectedPath, $"{index:D4}_uop.csv")); + } + + MessageBox.Show($"All UOP Multis saved to {dialog.SelectedPath}", "Saved", MessageBoxButtons.OK, + MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + } + private void OnClick_SaveAllToXML(object sender, EventArgs e) { string path = Options.OutputPath; @@ -950,5 +1548,53 @@ private void OnClick_SaveAllToXML(object sender, EventArgs e) MessageBox.Show($"All Multis saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } + + private sealed class MouseWheelFilter : IMessageFilter + { + private const int WmMouseWheel = 0x020A; + private readonly MultisControl _owner; + + public MouseWheelFilter(MultisControl owner) => _owner = owner; + + public bool PreFilterMessage(ref Message m) + { + if (m.Msg != WmMouseWheel) + { + return false; + } + + if ((Control.ModifierKeys & Keys.Control) == 0) + { + return false; + } + + Point cursor = Cursor.Position; + if (IsOver(_owner.panelMultiScroll, cursor) || IsOver(_owner.panelUopScroll, cursor)) + { + int delta = (short)((int)m.WParam >> 16); + if (delta > 0) + { + _owner.ZoomIn(); + } + else + { + _owner.ZoomOut(); + } + + return true; + } + return false; + } + + private static bool IsOver(Control c, Point screenPt) + { + if (!c.IsHandleCreated) + { + return false; + } + + return new Rectangle(c.PointToScreen(Point.Empty), c.Size).Contains(screenPt); + } + } } } diff --git a/UoFiddler.Controls/UserControls/MultisControl.resx b/UoFiddler.Controls/UserControls/MultisControl.resx index 49fba347..11faaf95 100644 --- a/UoFiddler.Controls/UserControls/MultisControl.resx +++ b/UoFiddler.Controls/UserControls/MultisControl.resx @@ -118,21 +118,33 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - 453, 17 + 17, 54 - 598, 17 + 172, 54 - 308, 17 + 831, 17 - 17, 17 + 627, 17 - 223, 17 + 740, 17 - 703, 17 + 277, 54 + + + 309, 17 + + + 17, 17 + + + 188, 17 + + + 496, 17 \ No newline at end of file diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.Designer.cs b/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.Designer.cs index ecec82ed..bc598bca 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.Designer.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.Designer.cs @@ -1,9 +1,9 @@ -/*************************************************************************** +/*************************************************************************** * * $Author: Turley - * + * * "THE BEER-WARE LICENSE" - * As long as you retain this notice you can do whatever you want with + * As long as you retain this notice you can do whatever you want with * this stuff. If we meet some day, and you think this stuff is worth it, * you can buy me a beer in return. * @@ -13,12 +13,12 @@ namespace UoFiddler.Plugin.Compare.UserControls { partial class CompareCliLocControl { - /// + /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; - /// + /// /// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. @@ -39,10 +39,9 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - splitContainer1 = new System.Windows.Forms.SplitContainer(); + splitContainerMain = new System.Windows.Forms.SplitContainer(); dataGridView1 = new System.Windows.Forms.DataGridView(); - decompressFileTwoCheckBox = new System.Windows.Forms.CheckBox(); - decompressFileOneCheckBox = new System.Windows.Forms.CheckBox(); + toolbarPanel = new System.Windows.Forms.Panel(); button5 = new System.Windows.Forms.Button(); checkBox1 = new System.Windows.Forms.CheckBox(); button4 = new System.Windows.Forms.Button(); @@ -51,46 +50,47 @@ private void InitializeComponent() button1 = new System.Windows.Forms.Button(); textBox2 = new System.Windows.Forms.TextBox(); textBox1 = new System.Windows.Forms.TextBox(); - ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); - splitContainer1.Panel1.SuspendLayout(); - splitContainer1.Panel2.SuspendLayout(); - splitContainer1.SuspendLayout(); + splitContainerDiff = new System.Windows.Forms.SplitContainer(); + diffRichTextBox1 = new System.Windows.Forms.RichTextBox(); + labelDiff1 = new System.Windows.Forms.Label(); + diffRichTextBox2 = new System.Windows.Forms.RichTextBox(); + labelDiff2 = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)splitContainerMain).BeginInit(); + splitContainerMain.Panel1.SuspendLayout(); + splitContainerMain.Panel2.SuspendLayout(); + splitContainerMain.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)dataGridView1).BeginInit(); + toolbarPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitContainerDiff).BeginInit(); + splitContainerDiff.Panel1.SuspendLayout(); + splitContainerDiff.Panel2.SuspendLayout(); + splitContainerDiff.SuspendLayout(); SuspendLayout(); - // - // splitContainer1 - // - splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; - splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; - splitContainer1.IsSplitterFixed = true; - splitContainer1.Location = new System.Drawing.Point(0, 0); - splitContainer1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - splitContainer1.Name = "splitContainer1"; - splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; - // - // splitContainer1.Panel1 - // - splitContainer1.Panel1.Controls.Add(dataGridView1); - // - // splitContainer1.Panel2 - // - splitContainer1.Panel2.Controls.Add(decompressFileTwoCheckBox); - splitContainer1.Panel2.Controls.Add(decompressFileOneCheckBox); - splitContainer1.Panel2.Controls.Add(button5); - splitContainer1.Panel2.Controls.Add(checkBox1); - splitContainer1.Panel2.Controls.Add(button4); - splitContainer1.Panel2.Controls.Add(button3); - splitContainer1.Panel2.Controls.Add(button2); - splitContainer1.Panel2.Controls.Add(button1); - splitContainer1.Panel2.Controls.Add(textBox2); - splitContainer1.Panel2.Controls.Add(textBox1); - splitContainer1.Size = new System.Drawing.Size(729, 377); - splitContainer1.SplitterDistance = 278; - splitContainer1.SplitterWidth = 5; - splitContainer1.TabIndex = 0; - // + // + // splitContainerMain + // + splitContainerMain.Dock = System.Windows.Forms.DockStyle.Fill; + splitContainerMain.Location = new System.Drawing.Point(0, 0); + splitContainerMain.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + splitContainerMain.Name = "splitContainerMain"; + splitContainerMain.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainerMain.Panel1 — dataGrid fills top, toolbar docks to bottom + // + splitContainerMain.Panel1.Controls.Add(dataGridView1); + splitContainerMain.Panel1.Controls.Add(toolbarPanel); + // + // splitContainerMain.Panel2 — diff detail + // + splitContainerMain.Panel2.Controls.Add(splitContainerDiff); + splitContainerMain.Panel2MinSize = 80; + splitContainerMain.Size = new System.Drawing.Size(729, 500); + splitContainerMain.SplitterDistance = 377; + splitContainerMain.SplitterWidth = 5; + splitContainerMain.TabIndex = 0; + // // dataGridView1 - // + // dataGridView1.AllowUserToAddRows = false; dataGridView1.AllowUserToDeleteRows = false; dataGridView1.AllowUserToOrderColumns = true; @@ -104,38 +104,30 @@ private void InitializeComponent() dataGridView1.ReadOnly = true; dataGridView1.RowHeadersVisible = false; dataGridView1.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect; - dataGridView1.Size = new System.Drawing.Size(729, 278); + dataGridView1.Size = new System.Drawing.Size(729, 282); dataGridView1.TabIndex = 0; dataGridView1.CellFormatting += CellFormatting; dataGridView1.ColumnHeaderMouseClick += OnHeaderClicked; - // - // decompressFileTwoCheckBox - // - decompressFileTwoCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right; - decompressFileTwoCheckBox.AutoSize = true; - decompressFileTwoCheckBox.Location = new System.Drawing.Point(399, 39); - decompressFileTwoCheckBox.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - decompressFileTwoCheckBox.Name = "decompressFileTwoCheckBox"; - decompressFileTwoCheckBox.Size = new System.Drawing.Size(202, 19); - decompressFileTwoCheckBox.TabIndex = 9; - decompressFileTwoCheckBox.Text = "Decompress cliloc before reading"; - decompressFileTwoCheckBox.UseVisualStyleBackColor = true; - // - // decompressFileOneCheckBox - // - decompressFileOneCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left; - decompressFileOneCheckBox.AutoSize = true; - decompressFileOneCheckBox.Location = new System.Drawing.Point(5, 39); - decompressFileOneCheckBox.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - decompressFileOneCheckBox.Name = "decompressFileOneCheckBox"; - decompressFileOneCheckBox.Size = new System.Drawing.Size(202, 19); - decompressFileOneCheckBox.TabIndex = 8; - decompressFileOneCheckBox.Text = "Decompress cliloc before reading"; - decompressFileOneCheckBox.UseVisualStyleBackColor = true; - // + dataGridView1.SelectionChanged += OnSelectionChanged; + // + // toolbarPanel + // + toolbarPanel.Controls.Add(button5); + toolbarPanel.Controls.Add(checkBox1); + toolbarPanel.Controls.Add(button4); + toolbarPanel.Controls.Add(button3); + toolbarPanel.Controls.Add(button2); + toolbarPanel.Controls.Add(button1); + toolbarPanel.Controls.Add(textBox2); + toolbarPanel.Controls.Add(textBox1); + toolbarPanel.Dock = System.Windows.Forms.DockStyle.Bottom; + toolbarPanel.Height = 95; + toolbarPanel.Margin = new System.Windows.Forms.Padding(0); + toolbarPanel.Name = "toolbarPanel"; + toolbarPanel.TabIndex = 1; + // // button5 - // - button5.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + // button5.AutoSize = true; button5.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; button5.Location = new System.Drawing.Point(399, 7); @@ -146,10 +138,9 @@ private void InitializeComponent() button5.Text = "Find Next Diff"; button5.UseVisualStyleBackColor = true; button5.Click += OnClickFindNextDiff; - // + // // checkBox1 - // - checkBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + // checkBox1.AutoSize = true; checkBox1.Location = new System.Drawing.Point(236, 11); checkBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); @@ -159,10 +150,10 @@ private void InitializeComponent() checkBox1.Text = "Show Only Differences"; checkBox1.UseVisualStyleBackColor = true; checkBox1.Click += OnClickShowOnlyDiff; - // + // // button4 - // - button4.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right; + // + button4.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; button4.AutoSize = true; button4.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; button4.Location = new System.Drawing.Point(647, 63); @@ -173,10 +164,10 @@ private void InitializeComponent() button4.Text = ".."; button4.UseVisualStyleBackColor = true; button4.Click += OnClickDirFile2; - // + // // button3 - // - button3.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left; + // + button3.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left; button3.AutoSize = true; button3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; button3.Location = new System.Drawing.Point(236, 63); @@ -187,10 +178,10 @@ private void InitializeComponent() button3.Text = ".."; button3.UseVisualStyleBackColor = true; button3.Click += OnClickDirFile1; - // + // // button2 - // - button2.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right; + // + button2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; button2.AutoSize = true; button2.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; button2.Location = new System.Drawing.Point(681, 63); @@ -201,10 +192,10 @@ private void InitializeComponent() button2.Text = "Load"; button2.UseVisualStyleBackColor = true; button2.Click += OnLoad2; - // + // // button1 - // - button1.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left; + // + button1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left; button1.AutoSize = true; button1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; button1.Location = new System.Drawing.Point(270, 63); @@ -215,40 +206,112 @@ private void InitializeComponent() button1.Text = "Load"; button1.UseVisualStyleBackColor = true; button1.Click += OnLoad; - // + // // textBox2 - // - textBox2.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right; + // + textBox2.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; textBox2.Location = new System.Drawing.Point(399, 64); textBox2.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); textBox2.Name = "textBox2"; textBox2.Size = new System.Drawing.Size(236, 23); textBox2.TabIndex = 1; - // + // // textBox1 - // - textBox1.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left; + // + textBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left; textBox1.Location = new System.Drawing.Point(5, 64); textBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); textBox1.Name = "textBox1"; textBox1.Size = new System.Drawing.Size(223, 23); textBox1.TabIndex = 0; - // + // + // splitContainerDiff + // + splitContainerDiff.Dock = System.Windows.Forms.DockStyle.Fill; + splitContainerDiff.Location = new System.Drawing.Point(0, 0); + splitContainerDiff.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + splitContainerDiff.Name = "splitContainerDiff"; + // + // splitContainerDiff.Panel1 + // + splitContainerDiff.Panel1.Controls.Add(diffRichTextBox1); + splitContainerDiff.Panel1.Controls.Add(labelDiff1); + // + // splitContainerDiff.Panel2 + // + splitContainerDiff.Panel2.Controls.Add(diffRichTextBox2); + splitContainerDiff.Panel2.Controls.Add(labelDiff2); + splitContainerDiff.Size = new System.Drawing.Size(729, 118); + splitContainerDiff.SplitterDistance = 362; + splitContainerDiff.SplitterWidth = 5; + splitContainerDiff.TabIndex = 0; + // + // labelDiff1 + // + labelDiff1.Dock = System.Windows.Forms.DockStyle.Top; + labelDiff1.Location = new System.Drawing.Point(0, 0); + labelDiff1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelDiff1.Name = "labelDiff1"; + labelDiff1.Size = new System.Drawing.Size(362, 18); + labelDiff1.TabIndex = 0; + labelDiff1.Text = "File 1:"; + // + // diffRichTextBox1 + // + diffRichTextBox1.Dock = System.Windows.Forms.DockStyle.Fill; + diffRichTextBox1.Location = new System.Drawing.Point(0, 18); + diffRichTextBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + diffRichTextBox1.Name = "diffRichTextBox1"; + diffRichTextBox1.ReadOnly = true; + diffRichTextBox1.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; + diffRichTextBox1.Size = new System.Drawing.Size(362, 100); + diffRichTextBox1.TabIndex = 1; + diffRichTextBox1.Text = ""; + diffRichTextBox1.WordWrap = true; + // + // labelDiff2 + // + labelDiff2.Dock = System.Windows.Forms.DockStyle.Top; + labelDiff2.Location = new System.Drawing.Point(0, 0); + labelDiff2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + labelDiff2.Name = "labelDiff2"; + labelDiff2.Size = new System.Drawing.Size(362, 18); + labelDiff2.TabIndex = 0; + labelDiff2.Text = "File 2:"; + // + // diffRichTextBox2 + // + diffRichTextBox2.Dock = System.Windows.Forms.DockStyle.Fill; + diffRichTextBox2.Location = new System.Drawing.Point(0, 18); + diffRichTextBox2.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + diffRichTextBox2.Name = "diffRichTextBox2"; + diffRichTextBox2.ReadOnly = true; + diffRichTextBox2.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; + diffRichTextBox2.Size = new System.Drawing.Size(362, 100); + diffRichTextBox2.TabIndex = 1; + diffRichTextBox2.Text = ""; + diffRichTextBox2.WordWrap = true; + // // CompareCliLocControl - // + // AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - Controls.Add(splitContainer1); + Controls.Add(splitContainerMain); DoubleBuffered = true; Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); Name = "CompareCliLocControl"; - Size = new System.Drawing.Size(729, 377); - splitContainer1.Panel1.ResumeLayout(false); - splitContainer1.Panel2.ResumeLayout(false); - splitContainer1.Panel2.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); - splitContainer1.ResumeLayout(false); + Size = new System.Drawing.Size(729, 500); + splitContainerMain.Panel1.ResumeLayout(false); + splitContainerMain.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainerMain).EndInit(); + splitContainerMain.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)dataGridView1).EndInit(); + toolbarPanel.ResumeLayout(false); + toolbarPanel.PerformLayout(); + splitContainerDiff.Panel1.ResumeLayout(false); + splitContainerDiff.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainerDiff).EndInit(); + splitContainerDiff.ResumeLayout(false); ResumeLayout(false); } @@ -261,10 +324,14 @@ private void InitializeComponent() private System.Windows.Forms.Button button5; private System.Windows.Forms.CheckBox checkBox1; private System.Windows.Forms.DataGridView dataGridView1; - private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.SplitContainer splitContainerMain; + private System.Windows.Forms.Panel toolbarPanel; + private System.Windows.Forms.SplitContainer splitContainerDiff; private System.Windows.Forms.TextBox textBox1; private System.Windows.Forms.TextBox textBox2; - private System.Windows.Forms.CheckBox decompressFileTwoCheckBox; - private System.Windows.Forms.CheckBox decompressFileOneCheckBox; + private System.Windows.Forms.Label labelDiff1; + private System.Windows.Forms.Label labelDiff2; + private System.Windows.Forms.RichTextBox diffRichTextBox1; + private System.Windows.Forms.RichTextBox diffRichTextBox2; } } diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs index d8627af7..9a17e597 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareCliLocControl.cs @@ -51,7 +51,7 @@ private void OnLoad(object sender, EventArgs e) return; } - _cliloc1 = new StringList("1", path, decompressFileOneCheckBox.Checked); + _cliloc1 = new StringList("1", path, false); _cliloc1.Entries.Sort(new StringList.NumberComparer(false)); if (_cliloc2 != null) @@ -73,7 +73,7 @@ private void OnLoad2(object sender, EventArgs e) return; } - _cliloc2 = new StringList("2", path, decompressFileTwoCheckBox.Checked); + _cliloc2 = new StringList("2", path, false); _cliloc2.Entries.Sort(new StringList.NumberComparer(false)); if (_cliloc1 != null) @@ -268,6 +268,117 @@ private void OnClickFindNextDiff(object sender, EventArgs e) } } + private void OnSelectionChanged(object sender, EventArgs e) + { + if (dataGridView1.SelectedRows.Count == 0) + { + diffRichTextBox1.Clear(); + diffRichTextBox2.Clear(); + return; + } + + var entry = dataGridView1.SelectedRows[0].DataBoundItem as CompareEntry; + if (entry == null) + { + return; + } + + ShowWordDiff(entry.Text1 ?? string.Empty, entry.Text2 ?? string.Empty); + } + + private void ShowWordDiff(string text1, string text2) + { + diffRichTextBox1.Clear(); + diffRichTextBox2.Clear(); + + if (text1 == text2) + { + diffRichTextBox1.Text = text1; + diffRichTextBox2.Text = text2; + return; + } + + var diff = ComputeWordDiff(text1, text2); + bool first1 = true, first2 = true; + + foreach (var (op, word) in diff) + { + switch (op) + { + case WordDiffOp.Equal: + AppendWord(diffRichTextBox1, word, SystemColors.Window, ref first1); + AppendWord(diffRichTextBox2, word, SystemColors.Window, ref first2); + break; + case WordDiffOp.Delete: + AppendWord(diffRichTextBox1, word, Color.FromArgb(255, 200, 200), ref first1); + break; + case WordDiffOp.Insert: + AppendWord(diffRichTextBox2, word, Color.FromArgb(200, 255, 200), ref first2); + break; + } + } + + diffRichTextBox1.SelectionStart = 0; + diffRichTextBox1.SelectionLength = 0; + diffRichTextBox2.SelectionStart = 0; + diffRichTextBox2.SelectionLength = 0; + } + + private static void AppendWord(RichTextBox rtb, string word, Color backColor, ref bool isFirst) + { + rtb.SelectionStart = rtb.TextLength; + rtb.SelectionLength = 0; + rtb.SelectionBackColor = backColor; + rtb.SelectionColor = SystemColors.WindowText; + rtb.SelectedText = isFirst ? word : " " + word; + isFirst = false; + } + + private enum WordDiffOp { Equal, Delete, Insert } + + private static List<(WordDiffOp Op, string Word)> ComputeWordDiff(string text1, string text2) + { + string[] a = text1.Split(' '); + string[] b = text2.Split(' '); + int m = a.Length, n = b.Length; + + var dp = new int[m + 1, n + 1]; + for (int i = 1; i <= m; i++) + { + for (int j = 1; j <= n; j++) + { + dp[i, j] = a[i - 1] == b[j - 1] + ? dp[i - 1, j - 1] + 1 + : Math.Max(dp[i - 1, j], dp[i, j - 1]); + } + } + + var result = new List<(WordDiffOp, string)>(); + int ii = m, jj = n; + while (ii > 0 || jj > 0) + { + if (ii > 0 && jj > 0 && a[ii - 1] == b[jj - 1]) + { + result.Add((WordDiffOp.Equal, a[ii - 1])); + ii--; + jj--; + } + else if (jj > 0 && (ii == 0 || dp[ii, jj - 1] >= dp[ii - 1, jj])) + { + result.Add((WordDiffOp.Insert, b[jj - 1])); + jj--; + } + else + { + result.Add((WordDiffOp.Delete, a[ii - 1])); + ii--; + } + } + + result.Reverse(); + return result; + } + private void OnHeaderClicked(object sender, DataGridViewCellMouseEventArgs e) { if (_sortColumn == e.ColumnIndex) diff --git a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs index d41f44a5..d9b17111 100644 --- a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs +++ b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs @@ -104,7 +104,6 @@ public MultiEditorControl() pictureBoxDrawTiles.MouseWheel += PictureBoxDrawTiles_OnMouseWheel; pictureBoxMulti.MouseWheel += PictureBoxMulti_OnMouseWheel; - pictureBoxMulti.ContextMenuStrip = null; } @@ -758,6 +757,45 @@ private void OnLoad(object sender, EventArgs e) fileNode.Nodes.Add(csvNode); treeViewMultiList.Nodes.Add(fileNode); + + TreeNode uopNode = new TreeNode("multicollection.uop") { Name = "uop" }; + if (!Multis.HasUopFile) + { + uopNode.Nodes.Add(new TreeNode("File not found")); + } + else + { + for (int i = 0; i < Multis.MaximumMultiIndex; ++i) + { + if (Multis.GetUopComponents(i) == MultiComponentList.Empty) + { + continue; + } + + TreeNode node; + if (dom == null) + { + node = new TreeNode(string.Format("{0,5} (0x{0:X})", i)); + } + else + { + XmlNodeList xMultiNodeList = xMultis.SelectNodes("/Multis/Multi[@id='" + i + "']"); + string j = ""; + foreach (XmlNode xMultiNode in xMultiNodeList) + { + j = xMultiNode.Attributes["name"].Value; + } + + node = new TreeNode(string.Format("{0,5} (0x{0:X}) {1}", i, j)); + } + + node.Tag = i; + node.Name = i.ToString(); + uopNode.Nodes.Add(node); + } + } + + treeViewMultiList.Nodes.Add(uopNode); treeViewMultiList.EndUpdate(); if (!_loaded) @@ -1695,7 +1733,11 @@ private void TreeViewMultiList_NodeMouseDoubleClick(object sender, TreeNodeMouse } else { - _compList = new MultiEditorComponentList(Multis.GetComponents((int)e.Node.Tag), this); + MultiComponentList multi = e.Node.Parent?.Name == "uop" + ? Multis.GetUopComponents((int)e.Node.Tag) + : Multis.GetComponents((int)e.Node.Tag); + + _compList = new MultiEditorComponentList(multi, this); textBox_SaveToID.Text = e.Node.Tag.ToString(); } @@ -1726,7 +1768,9 @@ private void TreeViewMultiList_NodeMouseHover(object sender, TreeNodeMouseHoverE { case int nodeTag: { - MultiComponentList list = Multis.GetComponents(nodeTag); + MultiComponentList list = e.Node.Parent?.Name == "uop" + ? Multis.GetUopComponents(nodeTag) + : Multis.GetComponents(nodeTag); toolTip1.SetToolTip(treeViewMultiList, $"{list.Width}x{list.Height} {list.SortedTiles.Length}"); break; } diff --git a/UoFiddler/Classes/FiddlerOptions.cs b/UoFiddler/Classes/FiddlerOptions.cs index 0854e2e2..254d1722 100644 --- a/UoFiddler/Classes/FiddlerOptions.cs +++ b/UoFiddler/Classes/FiddlerOptions.cs @@ -85,6 +85,7 @@ public static void Startup() MoveFiles(di.GetFiles("Animationlist.xml", SearchOption.TopDirectoryOnly), Options.AppDataPath); MoveFiles(di.GetFiles("Multilist.xml", SearchOption.TopDirectoryOnly), Options.AppDataPath); MoveFiles(di.GetFiles("Gumplist.xml", SearchOption.TopDirectoryOnly), Options.AppDataPath); + MoveFiles(di.GetFiles("DynamicItems.xml", SearchOption.TopDirectoryOnly), Options.AppDataPath); di = new DirectoryInfo(Path.Combine(Application.StartupPath, "plugins")); MoveFiles(di.GetFiles("*.xml", SearchOption.TopDirectoryOnly), plugInPath); @@ -95,6 +96,8 @@ public static void Startup() Logger.Fatal("Can't find default profile file: {FileName}", fileName); throw new FileNotFoundException($"Can't load default profile file {fileName}", "Options_default.xml"); } + + DynamicItemsConfig.EnsureLoaded(); } public static void SaveProfile() @@ -129,11 +132,6 @@ public static void SaveProfile() elem = dom.CreateElement("ItemClip"); elem.SetAttribute("active", Options.ArtItemClip.ToString()); sr.AppendChild(elem); - comment = dom.CreateComment("NewClilocFormat should cliloc be decompressed before reading"); - sr.AppendChild(comment); - elem = dom.CreateElement("NewClilocFormat"); - elem.SetAttribute("active", Options.NewClilocFormat.ToString()); - sr.AppendChild(elem); comment = dom.CreateComment("CacheData should mul entries be cached for faster load"); sr.AppendChild(comment); elem = dom.CreateElement("CacheData"); @@ -326,12 +324,6 @@ public static void LoadProfile(string filename) Options.ArtItemSizeHeight = int.Parse(elem.GetAttribute("height")); } - elem = (XmlElement)xOptions.SelectSingleNode("NewClilocFormat"); - if (elem != null) - { - Options.NewClilocFormat = bool.Parse(elem.GetAttribute("active")); - } - elem = (XmlElement)xOptions.SelectSingleNode("ItemClip"); if (elem != null) { diff --git a/UoFiddler/DynamicItems.xml b/UoFiddler/DynamicItems.xml new file mode 100644 index 00000000..aee32ef8 --- /dev/null +++ b/UoFiddler/DynamicItems.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UoFiddler/Forms/AboutBoxForm.resx b/UoFiddler/Forms/AboutBoxForm.resx index 052eab94..fa2fb2a3 100644 --- a/UoFiddler/Forms/AboutBoxForm.resx +++ b/UoFiddler/Forms/AboutBoxForm.resx @@ -118,7 +118,14 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Version 4.18.1 + Version 4.18.2 +- Fixed WSC multi import where file has absolute coordinates. Now all coordinates are converted to relative ones. +- Added DynamicItems.xml with list of items that should be marked as dynamic when importing multis from WSC. +- Added support for viewing and importing Multicollection.uop multis (there is no save option for now). +- Improved CliLoc comparison. It shows word diff now with highlights. +- Removed `New cliloc format` option. Cliloc format is now autodetected. + +Version 4.18.1 - Mass import plugin now allows importing PNG and JPEG. - Invalid entries in Animationlist.xml will now be skipped nad will result in a message about the problem. - Multi editor now has additional form with shortcut list. diff --git a/UoFiddler/Forms/OptionsForm.Designer.cs b/UoFiddler/Forms/OptionsForm.Designer.cs index 9d36b035..f879c03b 100644 --- a/UoFiddler/Forms/OptionsForm.Designer.cs +++ b/UoFiddler/Forms/OptionsForm.Designer.cs @@ -47,7 +47,6 @@ private void InitializeComponent() numericUpDownItemSizeWidth = new System.Windows.Forms.NumericUpDown(); checkBoxCacheData = new System.Windows.Forms.CheckBox(); groupBox2 = new System.Windows.Forms.GroupBox(); - checkBoxNewClilocFormat = new System.Windows.Forms.CheckBox(); checkBoxPolSoundIdOffset = new System.Windows.Forms.CheckBox(); checkBoxuseDiff = new System.Windows.Forms.CheckBox(); checkBoxNewMapSize = new System.Windows.Forms.CheckBox(); @@ -169,7 +168,6 @@ private void InitializeComponent() // // groupBox2 // - groupBox2.Controls.Add(checkBoxNewClilocFormat); groupBox2.Controls.Add(checkBoxPolSoundIdOffset); groupBox2.Controls.Add(checkBoxuseDiff); groupBox2.Controls.Add(checkBoxNewMapSize); @@ -178,23 +176,11 @@ private void InitializeComponent() groupBox2.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); groupBox2.Name = "groupBox2"; groupBox2.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); - groupBox2.Size = new System.Drawing.Size(258, 157); + groupBox2.Size = new System.Drawing.Size(258, 132); groupBox2.TabIndex = 3; groupBox2.TabStop = false; groupBox2.Text = "Misc"; - // - // checkBoxNewClilocFormat - // - checkBoxNewClilocFormat.AutoSize = true; - checkBoxNewClilocFormat.Location = new System.Drawing.Point(7, 123); - checkBoxNewClilocFormat.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - checkBoxNewClilocFormat.Name = "checkBoxNewClilocFormat"; - checkBoxNewClilocFormat.Size = new System.Drawing.Size(120, 19); - checkBoxNewClilocFormat.TabIndex = 8; - checkBoxNewClilocFormat.Text = "New cliloc format"; - toolTip1.SetToolTip(checkBoxNewClilocFormat, "For client version 7.0.104 and newer this needs to be checked. It allows reading of new cliloc format. This option has only partial support so saving file will only produce old cliloc format."); - checkBoxNewClilocFormat.UseVisualStyleBackColor = true; - // + // // checkBoxPolSoundIdOffset // checkBoxPolSoundIdOffset.AutoSize = true; @@ -654,7 +640,6 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox checkBoxPolSoundIdOffset; private System.Windows.Forms.Button buttonClose; private System.Windows.Forms.CheckBox checkboxRemoveTileBorder; - private System.Windows.Forms.CheckBox checkBoxNewClilocFormat; private System.Windows.Forms.Label PreviewBackgroundColorLabel; private System.Windows.Forms.Button PreviewBackgroundColorButton; } diff --git a/UoFiddler/Forms/OptionsForm.cs b/UoFiddler/Forms/OptionsForm.cs index ad2ba77f..d9f441c4 100644 --- a/UoFiddler/Forms/OptionsForm.cs +++ b/UoFiddler/Forms/OptionsForm.cs @@ -84,7 +84,6 @@ public OptionsForm(Action updateAllTileViewsAction, cmdtext.Text = Options.MapCmd; argstext.Text = Options.MapArgs; textBoxOutputPath.Text = Options.OutputPath; - checkBoxNewClilocFormat.Checked = Options.NewClilocFormat; } private void OnClickApply(object sender, EventArgs e) @@ -129,11 +128,6 @@ private void OnClickApply(object sender, EventArgs e) _updateItemsTabAction(); } - if (checkBoxNewClilocFormat.Checked != Options.NewClilocFormat) - { - Options.NewClilocFormat = checkBoxNewClilocFormat.Checked; - } - if (checkBoxItemClip.Checked != Options.ArtItemClip) { Options.ArtItemClip = checkBoxItemClip.Checked; diff --git a/UoFiddler/Multilist.xml b/UoFiddler/Multilist.xml index 1e295cac..5d488f0d 100644 --- a/UoFiddler/Multilist.xml +++ b/UoFiddler/Multilist.xml @@ -251,6 +251,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/UoFiddler/Options_default.xml b/UoFiddler/Options_default.xml index 1af7ef98..571bfa4d 100644 --- a/UoFiddler/Options_default.xml +++ b/UoFiddler/Options_default.xml @@ -4,8 +4,6 @@ - - diff --git a/UoFiddler/UoFiddler.csproj b/UoFiddler/UoFiddler.csproj index a075b9b7..e2b637ac 100644 --- a/UoFiddler/UoFiddler.csproj +++ b/UoFiddler/UoFiddler.csproj @@ -9,9 +9,9 @@ UoFiddler UoFiddler Copyright © 2026 - 4.18.1 - 4.18.1 - 4.18.1 + 4.18.2 + 4.18.2 + 4.18.2 true @@ -140,6 +140,9 @@ PreserveNewest + + PreserveNewest +