diff --git a/Ultima/Art.cs b/Ultima/Art.cs index 4f3b87e4..4ab3b15c 100644 --- a/Ultima/Art.cs +++ b/Ultima/Art.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; @@ -34,6 +35,32 @@ static Art() _removed = new bool[0x14000]; } + /// + /// Validates if a static bitmap will fit within the MUL format limits. + /// The format uses 16-bit lookup table offsets, limiting total encoded data to ~65,535 ushorts. + /// + /// The bitmap to validate + /// Estimated size in ushorts (output) + /// True if the image should fit, false if it exceeds limits + public static unsafe bool ValidateStaticSize(Bitmap bmp, out int estimatedSize) + { + estimatedSize = 0; + if (bmp == null || bmp.Width <= 0 || bmp.Height <= 0) + { + return true; + } + + // Estimate worst case: each scanline has full width of visible pixels + // Format: 2 ushorts for offset/run + width ushorts for data + 2 ushorts for end markers per line + int maxUshortsPerLine = 4 + bmp.Width; + estimatedSize = bmp.Height * maxUshortsPerLine; + + // The lookup table uses 16-bit offsets, so we're limited to 65535 ushorts + const int maxUshorts = 65535; + + return estimatedSize <= maxUshorts; + } + public static int GetMaxItemId() { // High Seas @@ -101,11 +128,20 @@ public static void Reload() /// /// /// + /// Thrown when the bitmap is too large for the MUL format public static void ReplaceStatic(int index, Bitmap bmp) { index = GetLegalItemId(index); index += 0x4000; + if (bmp != null && !ValidateStaticSize(bmp, out int estimatedSize)) + { + throw new ArgumentException( + $"Image is too large for MUL format. Estimated size: {estimatedSize} ushorts (max: 65535). " + + $"Image dimensions: {bmp.Width}x{bmp.Height}. " + + "Consider using a smaller image or one with more transparent pixels."); + } + _cache[index] = bmp; _removed[index] = false; @@ -651,6 +687,19 @@ public static unsafe void Save(string path) } else { + // Validate static art size before encoding + if (!ValidateStaticSize(bmp, out int estimatedSize)) + { + // Skip this image and write empty entry + binidx.Write(-1); // lookup + binidx.Write(0); // Length + binidx.Write(-1); // extra + System.Diagnostics.Debug.WriteLine( + $"Warning: Skipping static art at index {index - 0x4000} - " + + $"image too large ({bmp.Width}x{bmp.Height}, estimated {estimatedSize} ushorts, max 65535)"); + continue; + } + byte[] imageData = bmp.ToArray(PixelFormat.Format16bppArgb1555).ToSha256(); if (CompareSaveImagesStatic(imageData, out ImageData resultImageData)) { @@ -697,7 +746,7 @@ public static unsafe void Save(string path) continue; } - if (cur[i] != 0) + if ((cur[i] & 0x8000) != 0) { break; } @@ -712,7 +761,7 @@ public static unsafe void Save(string path) for (j = i + 1; j < bmp.Width; ++j) { // next non set pixel - if (cur[j] == 0) + if ((cur[j] & 0x8000) == 0) { break; } diff --git a/Ultima/Map.cs b/Ultima/Map.cs index e06bd702..d170dbdb 100644 --- a/Ultima/Map.cs +++ b/Ultima/Map.cs @@ -1,3 +1,4 @@ +using System; using System.Drawing; using System.Drawing.Imaging; using System.IO; @@ -5,6 +6,101 @@ namespace Ultima { + /// + /// Altitude rendering mode for map preview generation + /// + public enum MapAltitudeMode + { + /// + /// Normal flat rendering without altitude effects + /// + Normal, + /// + /// Normal rendering with altitude-based shading + /// + NormalWithAltitude, + /// + /// Pure altitude map (grayscale based on height) + /// + Altitude + } + + /// + /// Altitude shading preset configuration + /// + public enum AltitudeShadingPreset + { + /// + /// Dramatic, high-contrast shading with sharp edges + /// + Sharp, + /// + /// More pronounced shading with higher contrast + /// + Normal, + /// + /// Very subtle, smooth shading (matches UO client closely) + /// + Soft, + /// + /// Custom settings (uses manual configuration) + /// + Custom + } + + /// + /// Configuration for altitude-based shading effects + /// + public class AltitudeShadingSettings + { + /// + /// Surface normal Z-component (higher = softer shading) + /// Sharp: 2.0, Normal: 4.0, Soft: 8.0+ + /// + public float NormalZ { get; set; } = 8.0f; + + /// + /// Brightness variation range (0.0 to 0.5) + /// Sharp: 0.40 (±40%), Normal: 0.30 (±30%), Soft: 0.15 (±15%) + /// + public float BrightnessRange { get; set; } = 0.15f; + + /// + /// Altitude gradient smoothing factor + /// Sharp: 0.75, Normal: 0.50, Soft: 0.25 + /// + public float GradientSmoothing { get; set; } = 0.25f; + + /// + /// Gets preset configuration + /// + public static AltitudeShadingSettings GetPreset(AltitudeShadingPreset preset) + { + return preset switch + { + AltitudeShadingPreset.Sharp => new AltitudeShadingSettings + { + NormalZ = 2.0f, + BrightnessRange = 0.40f, + GradientSmoothing = 0.75f + }, + AltitudeShadingPreset.Normal => new AltitudeShadingSettings + { + NormalZ = 4.0f, + BrightnessRange = 0.30f, + GradientSmoothing = 0.50f + }, + AltitudeShadingPreset.Soft => new AltitudeShadingSettings + { + NormalZ = 8.0f, + BrightnessRange = 0.15f, + GradientSmoothing = 0.25f + }, + _ => new AltitudeShadingSettings() // Default to Soft + }; + } + } + public sealed class Map { private TileMatrix _tiles; @@ -12,6 +108,22 @@ public sealed class Map private readonly string _path; private static bool _useDiff; + /// + /// Controls the intensity of altitude-based shading (1-20, lower = more contrast) + /// Default is 15 for subtle effect + /// + public static int AltitudeIntensity { get; set; } = 15; + + /// + /// Current altitude shading preset + /// + public static AltitudeShadingPreset ShadingPreset { get; set; } = AltitudeShadingPreset.Normal; + + /// + /// Custom altitude shading settings (used when ShadingPreset is Custom) + /// + public static AltitudeShadingSettings CustomShadingSettings { get; set; } = AltitudeShadingSettings.GetPreset(AltitudeShadingPreset.Soft); + public static bool UseDiff { get { return _useDiff; } @@ -947,5 +1059,363 @@ public void ReportInvalidMapIDs(string reportFile) } } } + + #region Altitude Map Rendering + + /// + /// Returns Bitmap with altitude rendering mode support + /// + /// 8x8 Block X + /// 8x8 Block Y + /// Width in 8x8 Blocks + /// Height in 8x8 Blocks + /// Include statics in rendering + /// Altitude rendering mode + /// Rendered bitmap + public Bitmap GetImageWithAltitude(int x, int y, int width, int height, bool statics, MapAltitudeMode altitudeMode) + { + PixelFormat format = altitudeMode == MapAltitudeMode.Altitude + ? PixelFormat.Format8bppIndexed + : PixelFormat.Format16bppRgb555; + + var bmp = new Bitmap(width << 3, height << 3, format); + + if (altitudeMode == MapAltitudeMode.Altitude) + { + // Create grayscale palette for altitude map + ColorPalette palette = bmp.Palette; + for (int i = 0; i < 256; i++) + { + palette.Entries[i] = Color.FromArgb(i, i, i); + } + bmp.Palette = palette; + } + + GetImageWithAltitude(x, y, width, height, bmp, statics, altitudeMode); + + return bmp; + } + + /// + /// Draws in given Bitmap with altitude rendering mode support + /// + /// 8x8 Block X + /// 8x8 Block Y + /// Width in 8x8 Blocks + /// Height in 8x8 Blocks + /// Target bitmap + /// Include statics in rendering + /// Altitude rendering mode + public unsafe void GetImageWithAltitude(int x, int y, int width, int height, Bitmap bmp, bool statics, MapAltitudeMode altitudeMode) + { + PixelFormat format = altitudeMode == MapAltitudeMode.Altitude + ? PixelFormat.Format8bppIndexed + : PixelFormat.Format16bppRgb555; + + BitmapData bd = bmp.LockBits( + new Rectangle(0, 0, width << 3, height << 3), ImageLockMode.WriteOnly, format); + int stride = bd.Stride; + int blockStride = stride << 3; + + var pStart = (byte*)bd.Scan0; + + if (altitudeMode == MapAltitudeMode.Altitude) + { + // 8-bit altitude mode + for (int oy = 0, by = y; oy < height; ++oy, ++by, pStart += blockStride) + { + var pRow0 = (byte*)(pStart + (0 * stride)); + var pRow1 = (byte*)(pStart + (1 * stride)); + var pRow2 = (byte*)(pStart + (2 * stride)); + var pRow3 = (byte*)(pStart + (3 * stride)); + var pRow4 = (byte*)(pStart + (4 * stride)); + var pRow5 = (byte*)(pStart + (5 * stride)); + var pRow6 = (byte*)(pStart + (6 * stride)); + var pRow7 = (byte*)(pStart + (7 * stride)); + + for (int ox = 0, bx = x; ox < width; ++ox, ++bx) + { + sbyte[] altitudeData = GetAltitudeBlock(bx, by, statics); + + for (int i = 0; i < 64; i++) + { + byte altValue = (byte)Math.Clamp(altitudeData[i] + 128, 0, 255); + int rowIndex = i / 8; + int colIndex = i % 8; + + switch (rowIndex) + { + case 0: pRow0[ox * 8 + colIndex] = altValue; break; + case 1: pRow1[ox * 8 + colIndex] = altValue; break; + case 2: pRow2[ox * 8 + colIndex] = altValue; break; + case 3: pRow3[ox * 8 + colIndex] = altValue; break; + case 4: pRow4[ox * 8 + colIndex] = altValue; break; + case 5: pRow5[ox * 8 + colIndex] = altValue; break; + case 6: pRow6[ox * 8 + colIndex] = altValue; break; + case 7: pRow7[ox * 8 + colIndex] = altValue; break; + } + } + } + } + } + else + { + // 16-bit color modes (Normal and NormalWithAltitude) + for (int oy = 0, by = y; oy < height; ++oy, ++by, pStart += blockStride) + { + var pRow0 = (ushort*)(pStart + (0 * stride)); + var pRow1 = (ushort*)(pStart + (1 * stride)); + var pRow2 = (ushort*)(pStart + (2 * stride)); + var pRow3 = (ushort*)(pStart + (3 * stride)); + var pRow4 = (ushort*)(pStart + (4 * stride)); + var pRow5 = (ushort*)(pStart + (5 * stride)); + var pRow6 = (ushort*)(pStart + (6 * stride)); + var pRow7 = (ushort*)(pStart + (7 * stride)); + + for (int ox = 0, bx = x; ox < width; ++ox, ++bx) + { + ushort[] colorData = GetRenderedBlock(bx, by, statics); + + if (altitudeMode == MapAltitudeMode.NormalWithAltitude) + { + sbyte[] altitudeData = GetAltitudeBlock(bx, by, statics); + colorData = ProcessBlockWithAltitude(colorData, altitudeData); + } + + for (int i = 0; i < 64; i++) + { + int rowIndex = i / 8; + int colIndex = i % 8; + + switch (rowIndex) + { + case 0: pRow0[ox * 8 + colIndex] = colorData[i]; break; + case 1: pRow1[ox * 8 + colIndex] = colorData[i]; break; + case 2: pRow2[ox * 8 + colIndex] = colorData[i]; break; + case 3: pRow3[ox * 8 + colIndex] = colorData[i]; break; + case 4: pRow4[ox * 8 + colIndex] = colorData[i]; break; + case 5: pRow5[ox * 8 + colIndex] = colorData[i]; break; + case 6: pRow6[ox * 8 + colIndex] = colorData[i]; break; + case 7: pRow7[ox * 8 + colIndex] = colorData[i]; break; + } + } + } + } + } + + bmp.UnlockBits(bd); + _tiles.CloseStreams(); + } + + /// + /// Gets altitude data for an 8x8 block + /// + private sbyte[] GetAltitudeBlock(int x, int y, bool drawStatics) + { + var altitudeData = new sbyte[64]; + TileMatrix matrix = Tiles; + + if (x < 0 || y < 0 || x >= matrix.BlockWidth || y >= matrix.BlockHeight) + { + return altitudeData; + } + + Tile[] tiles = _tiles.GetLandBlock(x, y, UseDiff); + + unsafe + { + fixed (int* pHeight = TileData.HeightTable) + { + fixed (Tile* ptTiles = tiles) + { + Tile* pTiles = ptTiles; + + for (int k = 0; k < 8; ++k) + { + for (int p = 0; p < 8; ++p) + { + int idx = k * 8 + p; + int highTop = -255; + int highZ = -255; + int highId = 0; + + if (drawStatics) + { + HuedTile[][][] statics = _tiles.GetStaticBlock(x, y, UseDiff); + HuedTile[] curStatics = statics[p][k]; + + if (curStatics.Length > 0) + { + fixed (HuedTile* phtStatics = curStatics) + { + HuedTile* pStatics = phtStatics; + HuedTile* pStaticsEnd = pStatics + curStatics.Length; + + while (pStatics < pStaticsEnd) + { + int z = pStatics->Z; + int top = z + pHeight[pStatics->Id]; + + if (top > highTop || (z > highZ && top >= highTop)) + { + highTop = top; + highZ = z; + highId = pStatics->Id; + } + + ++pStatics; + } + } + } + + StaticTile[] pending = _tiles.GetPendingStatics(x, y); + if (pending != null) + { + foreach (StaticTile penS in pending) + { + if (penS.X != p || penS.Y != k) + { + continue; + } + + int z = penS.Z; + int top = z + pHeight[penS.Id]; + + if (top > highTop || (z > highZ && top >= highTop)) + { + highTop = top; + highZ = z; + highId = penS.Id; + } + } + } + } + + int landTop = pTiles->Z; + if (landTop > highTop || !drawStatics) + { + highZ = landTop; + } + + altitudeData[idx] = (sbyte)Math.Clamp(highZ, -128, 127); + ++pTiles; + } + } + } + } + } + + return altitudeData; + } + + /// + /// Process colors with altitude-based shading (translates Pascal ProcessBlock/ProcessQuad/ProcessColor) + /// + private static ushort[] ProcessBlockWithAltitude(ushort[] colors, sbyte[] altitudes) + { + // Get current shading settings based on preset + AltitudeShadingSettings settings = ShadingPreset == AltitudeShadingPreset.Custom + ? CustomShadingSettings + : AltitudeShadingSettings.GetPreset(ShadingPreset); + + // Use configurable intensity (lower = more contrast, higher = softer) + int maxSlope = Math.Clamp(AltitudeIntensity, 1, 20); + + ushort[] processed = new ushort[64]; + Array.Copy(colors, processed, 64); + + // Light source comes from northwest (negative X, negative Y direction) + const float lightX = -0.577f; // Northwest direction (normalized) + const float lightY = -0.577f; + const float lightZ = 0.577f; // Equal components for 45-degree angle + + // Calculate lighting for each pixel using its surrounding pixels + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x++) + { + int idx = y * 8 + x; + + // Get altitude differences using configurable smoothing + float dx = GetAltitudeDifference(altitudes, x, y, 1, 0, settings.GradientSmoothing); + float dy = GetAltitudeDifference(altitudes, x, y, 0, 1, settings.GradientSmoothing); + + // Calculate surface normal with configurable nz + float nx = -dx; + float ny = -dy; + float nz = settings.NormalZ + (maxSlope - 10) * 0.5f; // Adjust based on intensity + + // Normalize the normal vector + float length = (float)Math.Sqrt(nx * nx + ny * ny + nz * nz); + if (length > 0) + { + nx /= length; + ny /= length; + nz /= length; + } + + // Calculate dot product with light direction (lambertian lighting) + float dotProduct = nx * lightX + ny * lightY + nz * lightZ; + dotProduct = Math.Clamp(dotProduct, 0.0f, 1.0f); + + // Apply configurable brightness range + float baseIntensity = 20.0f / maxSlope; // Higher maxSlope = less intense + float range = settings.BrightnessRange * baseIntensity; + float multiplier = 1.0f + (dotProduct - 0.5f) * 2.0f * range; + + // Clamp to safe range based on brightness range + float minMult = 1.0f - range; + float maxMult = 1.0f + range; + multiplier = Math.Clamp(multiplier, minMult, maxMult); + + // Apply lighting to the color + processed[idx] = ApplyLighting(processed[idx], multiplier); + } + } + + return processed; + } + + /// + /// Get altitude difference in a specific direction, with bounds checking and averaging + /// + private static float GetAltitudeDifference(sbyte[] altitudes, int x, int y, int dx, int dy, float smoothing) + { + int x1 = Math.Max(0, Math.Min(7, x - dx)); + int y1 = Math.Max(0, Math.Min(7, y - dy)); + int x2 = Math.Max(0, Math.Min(7, x + dx)); + int y2 = Math.Max(0, Math.Min(7, y + dy)); + + int idx1 = y1 * 8 + x1; + int idx2 = y2 * 8 + x2; + + return (altitudes[idx2] - altitudes[idx1]) * smoothing; + } + + /// + /// Apply lighting multiplier to a color + /// + private static ushort ApplyLighting(ushort color, float multiplier) + { + // Extract RGB components from 15-bit color (RGB555) + int red = (color >> 10) & 0x1F; + int green = (color >> 5) & 0x1F; + int blue = color & 0x1F; + + // Apply multiplier + red = (int)(red * multiplier); + green = (int)(green * multiplier); + blue = (int)(blue * multiplier); + + // Clamp to 5-bit range + red = Math.Clamp(red, 0, 31); + green = Math.Clamp(green, 0, 31); + blue = Math.Clamp(blue, 0, 31); + + // Recombine into RGB555 format + return (ushort)((red << 10) | (green << 5) | blue); + } + + #endregion } } \ No newline at end of file diff --git a/Ultima/TileData.cs b/Ultima/TileData.cs index 39c3c1f4..253df27e 100644 --- a/Ultima/TileData.cs +++ b/Ultima/TileData.cs @@ -249,6 +249,13 @@ public void ReadData(string[] split) return; } + // CSV may have been exported from an older client version that did not include extended HSA flags. + // Any missing flags default to 0, which is already set above. + if (i >= split.Length) + { + return; + } + temp = Convert.ToByte(split[i++]); if (temp != 0) { @@ -820,6 +827,13 @@ public void ReadData(string[] split) return; } + // CSV may have been exported from an older client version that did not include extended HSA flags. + // Any missing flags default to 0, which is already set above. + if (i >= split.Length) + { + return; + } + temp = Convert.ToByte(split[i++]); if (temp != 0) { diff --git a/UoFiddler.Controls/Classes/Options.cs b/UoFiddler.Controls/Classes/Options.cs index 7d489873..dab5525f 100644 --- a/UoFiddler.Controls/Classes/Options.cs +++ b/UoFiddler.Controls/Classes/Options.cs @@ -192,7 +192,8 @@ public static void SetLogger(ILogger logger) {17, true}, {18, true}, {19, true}, - {20, true} + {20, true}, + {21, true} }; public static Icon GetFiddlerIcon() diff --git a/UoFiddler.Controls/Forms/AnimationEditForm.Designer.cs b/UoFiddler.Controls/Forms/AnimationEditForm.Designer.cs index 6bc5074f..cfdb575c 100644 --- a/UoFiddler.Controls/Forms/AnimationEditForm.Designer.cs +++ b/UoFiddler.Controls/Forms/AnimationEditForm.Designer.cs @@ -250,7 +250,7 @@ private void InitializeComponent() // asBmpToolStripMenuItem // asBmpToolStripMenuItem.Name = "asBmpToolStripMenuItem"; - asBmpToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + asBmpToolStripMenuItem.Size = new System.Drawing.Size(180, 22); asBmpToolStripMenuItem.Tag = ".bmp"; asBmpToolStripMenuItem.Text = "As Bmp"; asBmpToolStripMenuItem.Click += OnClickExtractImages; @@ -258,7 +258,7 @@ private void InitializeComponent() // asTiffToolStripMenuItem // asTiffToolStripMenuItem.Name = "asTiffToolStripMenuItem"; - asTiffToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + asTiffToolStripMenuItem.Size = new System.Drawing.Size(180, 22); asTiffToolStripMenuItem.Tag = ".tiff"; asTiffToolStripMenuItem.Text = "As Tiff"; asTiffToolStripMenuItem.Click += OnClickExtractImages; @@ -266,7 +266,7 @@ private void InitializeComponent() // asJpgToolStripMenuItem // asJpgToolStripMenuItem.Name = "asJpgToolStripMenuItem"; - asJpgToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + asJpgToolStripMenuItem.Size = new System.Drawing.Size(180, 22); asJpgToolStripMenuItem.Tag = ".jpg"; asJpgToolStripMenuItem.Text = "As Jpg"; asJpgToolStripMenuItem.Click += OnClickExtractImages; @@ -274,7 +274,7 @@ private void InitializeComponent() // asPngToolStripMenuItem // asPngToolStripMenuItem.Name = "asPngToolStripMenuItem"; - asPngToolStripMenuItem.Size = new System.Drawing.Size(115, 22); + asPngToolStripMenuItem.Size = new System.Drawing.Size(180, 22); asPngToolStripMenuItem.Tag = ".png"; asPngToolStripMenuItem.Text = "As Png"; asPngToolStripMenuItem.Click += OnClickExtractImages; diff --git a/UoFiddler.Controls/Forms/AnimationEditForm.cs b/UoFiddler.Controls/Forms/AnimationEditForm.cs index 65e406d8..f2fc4994 100644 --- a/UoFiddler.Controls/Forms/AnimationEditForm.cs +++ b/UoFiddler.Controls/Forms/AnimationEditForm.cs @@ -661,8 +661,7 @@ private void OnClickExtractImages(object sender, EventArgs e) } } - MessageBox.Show($"Frames saved to {path}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + FileSavedDialog.Show(FindForm(), path, "Frames saved successfully."); } private void OnClickRemoveAction(object sender, EventArgs e) @@ -1192,8 +1191,7 @@ private void OnClickExportToVD(object sender, EventArgs e) string fileName = Path.Combine(path, $"anim{_fileType}_0x{_currentBody:X}.vd"); AnimationEdit.ExportToVD(_fileType, _currentBody, fileName); - MessageBox.Show($"Animation saved to {Options.OutputPath}", "Export", MessageBoxButtons.OK, - MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + FileSavedDialog.Show(FindForm(), Options.OutputPath, "Animation saved successfully."); } private void OnClickShowOnlyValid(object sender, EventArgs e) diff --git a/UoFiddler.Controls/Forms/AnimationEditForm.resx b/UoFiddler.Controls/Forms/AnimationEditForm.resx index e474dbfd..ef42f007 100644 --- a/UoFiddler.Controls/Forms/AnimationEditForm.resx +++ b/UoFiddler.Controls/Forms/AnimationEditForm.resx @@ -129,12 +129,6 @@ 343, 17 - - 196, 12 - - - 448, 47 - 448, 47 @@ -151,6 +145,9 @@ YII= + + 196, 12 + 309, 47 diff --git a/UoFiddler.Controls/Forms/FileSavedDialog.Designer.cs b/UoFiddler.Controls/Forms/FileSavedDialog.Designer.cs new file mode 100644 index 00000000..0532f9b1 --- /dev/null +++ b/UoFiddler.Controls/Forms/FileSavedDialog.Designer.cs @@ -0,0 +1,195 @@ +namespace UoFiddler.Controls.Forms +{ + partial class FileSavedDialog + { + /// + /// 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() + { + mainLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + iconPictureBox = new System.Windows.Forms.PictureBox(); + contentLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + statusLabel = new System.Windows.Forms.Label(); + pathLabel = new System.Windows.Forms.Label(); + buttonsPanel = new System.Windows.Forms.TableLayoutPanel(); + buttonOpenFolder = new System.Windows.Forms.Button(); + buttonOk = new System.Windows.Forms.Button(); + mainLayoutPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)iconPictureBox).BeginInit(); + contentLayoutPanel.SuspendLayout(); + buttonsPanel.SuspendLayout(); + SuspendLayout(); + // + // mainLayoutPanel + // + mainLayoutPanel.AutoSize = true; + mainLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + mainLayoutPanel.ColumnCount = 2; + mainLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + mainLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + mainLayoutPanel.Controls.Add(iconPictureBox, 0, 0); + mainLayoutPanel.Controls.Add(contentLayoutPanel, 1, 0); + mainLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + mainLayoutPanel.Location = new System.Drawing.Point(12, 12); + mainLayoutPanel.Margin = new System.Windows.Forms.Padding(0); + mainLayoutPanel.Name = "mainLayoutPanel"; + mainLayoutPanel.RowCount = 1; + mainLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + mainLayoutPanel.Size = new System.Drawing.Size(560, 86); + mainLayoutPanel.TabIndex = 0; + // + // iconPictureBox + // + iconPictureBox.Location = new System.Drawing.Point(0, 0); + iconPictureBox.Margin = new System.Windows.Forms.Padding(0, 0, 12, 0); + iconPictureBox.Name = "iconPictureBox"; + iconPictureBox.Size = new System.Drawing.Size(32, 32); + iconPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; + iconPictureBox.TabIndex = 0; + iconPictureBox.TabStop = false; + // + // contentLayoutPanel + // + contentLayoutPanel.AutoSize = true; + contentLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + contentLayoutPanel.ColumnCount = 1; + contentLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + contentLayoutPanel.Controls.Add(statusLabel, 0, 0); + contentLayoutPanel.Controls.Add(pathLabel, 0, 1); + contentLayoutPanel.Controls.Add(buttonsPanel, 0, 2); + contentLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + contentLayoutPanel.Location = new System.Drawing.Point(44, 0); + contentLayoutPanel.Margin = new System.Windows.Forms.Padding(0); + contentLayoutPanel.Name = "contentLayoutPanel"; + contentLayoutPanel.RowCount = 3; + contentLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + contentLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + contentLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + contentLayoutPanel.Size = new System.Drawing.Size(516, 86); + contentLayoutPanel.TabIndex = 1; + // + // statusLabel + // + statusLabel.AutoSize = true; + statusLabel.Location = new System.Drawing.Point(0, 0); + statusLabel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 8); + statusLabel.Name = "statusLabel"; + statusLabel.Size = new System.Drawing.Size(147, 15); + statusLabel.TabIndex = 0; + statusLabel.Text = "File saved successfully."; + // + // pathLabel + // + pathLabel.AutoSize = true; + pathLabel.Location = new System.Drawing.Point(0, 23); + pathLabel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 12); + pathLabel.MaximumSize = new System.Drawing.Size(516, 0); + pathLabel.Name = "pathLabel"; + pathLabel.Size = new System.Drawing.Size(0, 15); + pathLabel.TabIndex = 1; + pathLabel.UseMnemonic = false; + // + // buttonsPanel + // + buttonsPanel.Anchor = System.Windows.Forms.AnchorStyles.Right; + buttonsPanel.AutoSize = true; + buttonsPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + buttonsPanel.ColumnCount = 2; + buttonsPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + buttonsPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + buttonsPanel.Controls.Add(buttonOpenFolder, 0, 0); + buttonsPanel.Controls.Add(buttonOk, 1, 0); + buttonsPanel.Location = new System.Drawing.Point(260, 50); + buttonsPanel.Margin = new System.Windows.Forms.Padding(0); + buttonsPanel.Name = "buttonsPanel"; + buttonsPanel.RowCount = 1; + buttonsPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + buttonsPanel.Size = new System.Drawing.Size(256, 36); + buttonsPanel.TabIndex = 2; + // + // buttonOpenFolder + // + buttonOpenFolder.AutoSize = false; + buttonOpenFolder.Location = new System.Drawing.Point(0, 0); + buttonOpenFolder.Margin = new System.Windows.Forms.Padding(0, 0, 8, 0); + buttonOpenFolder.Name = "buttonOpenFolder"; + buttonOpenFolder.Size = new System.Drawing.Size(120, 32); + buttonOpenFolder.TabIndex = 0; + buttonOpenFolder.Text = "Open Folder"; + buttonOpenFolder.UseVisualStyleBackColor = true; + buttonOpenFolder.Click += OnOpenFolderClick; + // + // buttonOk + // + buttonOk.AutoSize = false; + buttonOk.DialogResult = System.Windows.Forms.DialogResult.OK; + buttonOk.Location = new System.Drawing.Point(128, 0); + buttonOk.Margin = new System.Windows.Forms.Padding(0); + buttonOk.Name = "buttonOk"; + buttonOk.Size = new System.Drawing.Size(120, 32); + buttonOk.TabIndex = 1; + buttonOk.Text = "OK"; + buttonOk.UseVisualStyleBackColor = true; + // + // FileSavedDialog + // + AcceptButton = buttonOk; + AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + AutoSize = true; + AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + CancelButton = buttonOk; + ClientSize = new System.Drawing.Size(584, 110); + Controls.Add(mainLayoutPanel); + FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + Name = "FileSavedDialog"; + Padding = new System.Windows.Forms.Padding(12); + ShowInTaskbar = false; + StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + Text = "Saved"; + mainLayoutPanel.ResumeLayout(false); + mainLayoutPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)iconPictureBox).EndInit(); + contentLayoutPanel.ResumeLayout(false); + contentLayoutPanel.PerformLayout(); + buttonsPanel.ResumeLayout(false); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel mainLayoutPanel; + private System.Windows.Forms.PictureBox iconPictureBox; + private System.Windows.Forms.TableLayoutPanel contentLayoutPanel; + private System.Windows.Forms.Label statusLabel; + private System.Windows.Forms.Label pathLabel; + private System.Windows.Forms.TableLayoutPanel buttonsPanel; + private System.Windows.Forms.Button buttonOpenFolder; + private System.Windows.Forms.Button buttonOk; + } +} diff --git a/UoFiddler.Controls/Forms/FileSavedDialog.cs b/UoFiddler.Controls/Forms/FileSavedDialog.cs new file mode 100644 index 00000000..aebcb92d --- /dev/null +++ b/UoFiddler.Controls/Forms/FileSavedDialog.cs @@ -0,0 +1,91 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Windows.Forms; + +namespace UoFiddler.Controls.Forms +{ + /// + /// A reusable dialog that displays a success message when a file is saved, + /// with options to close or open the containing folder. + /// + public sealed partial class FileSavedDialog : Form + { + private readonly string _filePath; + + public FileSavedDialog(string filePath, string message = null, string title = null) + { + _filePath = filePath ?? throw new ArgumentNullException(nameof(filePath)); + + InitializeComponent(); + + // Set the system information icon + iconPictureBox.Image = SystemIcons.Information.ToBitmap(); + + if (!string.IsNullOrWhiteSpace(title)) + { + Text = title; + } + + statusLabel.Text = message ?? "File saved successfully."; + pathLabel.Text = _filePath; + } + + private void OnOpenFolderClick(object sender, EventArgs e) + { + try + { + string folderPath = Directory.Exists(_filePath) ? _filePath : Path.GetDirectoryName(_filePath); + if (!string.IsNullOrEmpty(folderPath) && Directory.Exists(folderPath)) + { + Process.Start(new ProcessStartInfo + { + FileName = folderPath, + UseShellExecute = true + }); + + Close(); + } + } + catch (Exception ex) + { + MessageBox.Show( + this, + $"Unable to open folder: {ex.Message}", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + + /// + /// Shows the file saved dialog. + /// + /// The owner form. + /// The path to the saved file. + /// Optional custom success message. + /// Optional custom dialog title. + public static void Show(IWin32Window owner, string filePath, string message = null, string title = null) + { + using (var dialog = new FileSavedDialog(filePath, message, title)) + { + dialog.ShowDialog(owner); + } + } + + /// + /// Shows the file saved dialog without an owner. + /// + /// The path to the saved file. + /// Optional custom success message. + /// Optional custom dialog title. + public static void Show(string filePath, string message = null, string title = null) + { + using (var dialog = new FileSavedDialog(filePath, message, title)) + { + dialog.ShowDialog(); + } + } + } +} diff --git a/UoFiddler.Controls/Forms/FileSavedDialog.resx b/UoFiddler.Controls/Forms/FileSavedDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/UoFiddler.Controls/Forms/FileSavedDialog.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/Forms/ItemDetailForm.cs b/UoFiddler.Controls/Forms/ItemDetailForm.cs index 4c1276bb..4efed343 100644 --- a/UoFiddler.Controls/Forms/ItemDetailForm.cs +++ b/UoFiddler.Controls/Forms/ItemDetailForm.cs @@ -266,8 +266,7 @@ private void SaveImage(ImageFormat imageFormat) bit.Save(fileName, imageFormat); } - MessageBox.Show($"Item saved to {fileName}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + FileSavedDialog.Show(FindForm(), fileName, "Item image saved successfully."); } private void OnSizeChange(object sender, EventArgs e) diff --git a/UoFiddler.Controls/Forms/MapReplaceForm.cs b/UoFiddler.Controls/Forms/MapReplaceForm.cs index 7bf6d2e6..98b62b84 100644 --- a/UoFiddler.Controls/Forms/MapReplaceForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceForm.cs @@ -479,7 +479,7 @@ private void OnClickCopy(object sender, EventArgs e) mStaticsReaderCopy.Close(); } - MessageBox.Show($"Files saved to {Options.OutputPath}", "Saved", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + FileSavedDialog.Show(FindForm(), Options.OutputPath, "Files saved successfully."); } private class SupportedMaps diff --git a/UoFiddler.Controls/Forms/MapReplaceTilesForm.cs b/UoFiddler.Controls/Forms/MapReplaceTilesForm.cs index e997f838..64d4f58d 100644 --- a/UoFiddler.Controls/Forms/MapReplaceTilesForm.cs +++ b/UoFiddler.Controls/Forms/MapReplaceTilesForm.cs @@ -71,8 +71,7 @@ private void OnReplace(object sender, EventArgs e) richTextBox1.AppendText("Done."); - MessageBox.Show($"Files saved to {Options.OutputPath}", "Saved", MessageBoxButtons.OK, - MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); + FileSavedDialog.Show(FindForm(), Options.OutputPath, "Files saved successfully."); } finally { diff --git a/UoFiddler.Controls/UserControls/AnimDataControl.Designer.cs b/UoFiddler.Controls/UserControls/AnimDataControl.Designer.cs index dc362d2e..0efcd3ee 100644 --- a/UoFiddler.Controls/UserControls/AnimDataControl.Designer.cs +++ b/UoFiddler.Controls/UserControls/AnimDataControl.Designer.cs @@ -52,6 +52,7 @@ private void InitializeComponent() toolStripDropDownButton1 = new System.Windows.Forms.ToolStripDropDownButton(); hueToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); animateToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + showFrameBoundsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); toolStripStatusBaseGraphic = new System.Windows.Forms.ToolStripStatusLabel(); toolStripStatusGraphic = new System.Windows.Forms.ToolStripStatusLabel(); toolStripStatusHue = new System.Windows.Forms.ToolStripStatusLabel(); @@ -75,7 +76,6 @@ private void InitializeComponent() numericUpDownFrameDelay = new System.Windows.Forms.NumericUpDown(); label1 = new System.Windows.Forms.Label(); numericUpDownStartDelay = new System.Windows.Forms.NumericUpDown(); - showFrameBoundsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); splitContainer1.Panel1.SuspendLayout(); splitContainer1.Panel2.SuspendLayout(); @@ -111,7 +111,7 @@ private void InitializeComponent() // splitContainer1.Panel2.Controls.Add(splitContainer2); splitContainer1.Size = new System.Drawing.Size(857, 587); - splitContainer1.SplitterDistance = 246; + splitContainer1.SplitterDistance = 235; splitContainer1.SplitterWidth = 5; splitContainer1.TabIndex = 0; // @@ -123,7 +123,7 @@ private void InitializeComponent() treeView1.Location = new System.Drawing.Point(0, 0); treeView1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); treeView1.Name = "treeView1"; - treeView1.Size = new System.Drawing.Size(246, 587); + treeView1.Size = new System.Drawing.Size(235, 587); treeView1.TabIndex = 0; treeView1.AfterSelect += AfterNodeSelect; treeView1.NodeMouseClick += OnClickNode; @@ -174,8 +174,8 @@ private void InitializeComponent() splitContainer2.Panel2.Controls.Add(groupBox3); splitContainer2.Panel2.Controls.Add(groupBox4); splitContainer2.Panel2.Controls.Add(groupBox2); - splitContainer2.Size = new System.Drawing.Size(606, 587); - splitContainer2.SplitterDistance = 328; + splitContainer2.Size = new System.Drawing.Size(617, 587); + splitContainer2.SplitterDistance = 284; splitContainer2.SplitterWidth = 5; splitContainer2.TabIndex = 6; // @@ -188,7 +188,7 @@ private void InitializeComponent() groupBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); groupBox1.Name = "groupBox1"; groupBox1.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); - groupBox1.Size = new System.Drawing.Size(328, 587); + groupBox1.Size = new System.Drawing.Size(284, 587); groupBox1.TabIndex = 1; groupBox1.TabStop = false; groupBox1.Text = "Preview"; @@ -198,7 +198,7 @@ private void InitializeComponent() statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { toolStripDropDownButton1, toolStripStatusBaseGraphic, toolStripStatusGraphic, toolStripStatusHue }); statusStrip1.Location = new System.Drawing.Point(4, 562); statusStrip1.Name = "statusStrip1"; - statusStrip1.Size = new System.Drawing.Size(320, 22); + statusStrip1.Size = new System.Drawing.Size(276, 22); statusStrip1.TabIndex = 2; statusStrip1.Text = "statusStrip1"; // @@ -226,6 +226,13 @@ private void InitializeComponent() animateToolStripMenuItem.Text = "Animate"; animateToolStripMenuItem.Click += OnClickStartStop; // + // showFrameBoundsToolStripMenuItem + // + showFrameBoundsToolStripMenuItem.Name = "showFrameBoundsToolStripMenuItem"; + showFrameBoundsToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + showFrameBoundsToolStripMenuItem.Text = "Show frame bounds"; + showFrameBoundsToolStripMenuItem.Click += OnClickShowFrameBounds; + // // toolStripStatusBaseGraphic // toolStripStatusBaseGraphic.Name = "toolStripStatusBaseGraphic"; @@ -235,13 +242,13 @@ private void InitializeComponent() // toolStripStatusGraphic // toolStripStatusGraphic.Name = "toolStripStatusGraphic"; - toolStripStatusGraphic.Size = new System.Drawing.Size(89, 17); + toolStripStatusGraphic.Size = new System.Drawing.Size(89, 15); toolStripStatusGraphic.Text = "Graphic: 0 (0x0)"; // // toolStripStatusHue // toolStripStatusHue.Name = "toolStripStatusHue"; - toolStripStatusHue.Size = new System.Drawing.Size(41, 17); + toolStripStatusHue.Size = new System.Drawing.Size(41, 15); toolStripStatusHue.Text = "Hue: 0"; // // MainPictureBox @@ -255,7 +262,7 @@ private void InitializeComponent() MainPictureBox.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); MainPictureBox.Name = "MainPictureBox"; MainPictureBox.ShowFrameBounds = false; - MainPictureBox.Size = new System.Drawing.Size(320, 565); + MainPictureBox.Size = new System.Drawing.Size(276, 565); MainPictureBox.TabIndex = 0; MainPictureBox.TabStop = false; // @@ -282,14 +289,14 @@ private void InitializeComponent() groupBox3.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); groupBox3.Name = "groupBox3"; groupBox3.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); - groupBox3.Size = new System.Drawing.Size(273, 61); + groupBox3.Size = new System.Drawing.Size(328, 61); groupBox3.TabIndex = 6; groupBox3.TabStop = false; // // button8 // button8.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; - button8.Location = new System.Drawing.Point(28, 22); + button8.Location = new System.Drawing.Point(16, 22); button8.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); button8.Name = "button8"; button8.Size = new System.Drawing.Size(66, 27); @@ -301,7 +308,7 @@ private void InitializeComponent() // button7 // button7.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; - button7.Location = new System.Drawing.Point(104, 22); + button7.Location = new System.Drawing.Point(92, 22); button7.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); button7.Name = "button7"; button7.Size = new System.Drawing.Size(66, 27); @@ -313,7 +320,7 @@ private void InitializeComponent() // button6 // button6.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right; - button6.Location = new System.Drawing.Point(180, 22); + button6.Location = new System.Drawing.Point(168, 22); button6.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); button6.Name = "button6"; button6.Size = new System.Drawing.Size(66, 27); @@ -336,7 +343,7 @@ private void InitializeComponent() groupBox4.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); groupBox4.Name = "groupBox4"; groupBox4.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); - groupBox4.Size = new System.Drawing.Size(273, 423); + groupBox4.Size = new System.Drawing.Size(328, 423); groupBox4.TabIndex = 4; groupBox4.TabStop = false; groupBox4.Text = "Frames"; @@ -366,10 +373,10 @@ private void InitializeComponent() // button4 // button4.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F); - button4.Location = new System.Drawing.Point(227, 178); + button4.Location = new System.Drawing.Point(242, 165); button4.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); button4.Name = "button4"; - button4.Size = new System.Drawing.Size(26, 25); + button4.Size = new System.Drawing.Size(26, 36); button4.TabIndex = 3; button4.Text = "▼"; button4.UseVisualStyleBackColor = true; @@ -390,10 +397,10 @@ private void InitializeComponent() // button3 // button3.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F); - button3.Location = new System.Drawing.Point(227, 147); + button3.Location = new System.Drawing.Point(242, 123); button3.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); button3.Name = "button3"; - button3.Size = new System.Drawing.Size(26, 25); + button3.Size = new System.Drawing.Size(26, 36); button3.TabIndex = 2; button3.Text = "▲"; button3.UseVisualStyleBackColor = true; @@ -410,12 +417,11 @@ private void InitializeComponent() // // treeViewFrames // - treeViewFrames.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; treeViewFrames.HideSelection = false; treeViewFrames.Location = new System.Drawing.Point(14, 22); treeViewFrames.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); treeViewFrames.Name = "treeViewFrames"; - treeViewFrames.Size = new System.Drawing.Size(217, 326); + treeViewFrames.Size = new System.Drawing.Size(220, 326); treeViewFrames.TabIndex = 1; treeViewFrames.AfterSelect += AfterSelectTreeViewFrames; // @@ -430,7 +436,7 @@ 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(273, 95); + groupBox2.Size = new System.Drawing.Size(328, 95); groupBox2.TabIndex = 2; groupBox2.TabStop = false; groupBox2.Text = "Data"; @@ -475,13 +481,6 @@ private void InitializeComponent() numericUpDownStartDelay.TabIndex = 0; numericUpDownStartDelay.ValueChanged += OnValueChangedStartDelay; // - // showFrameBoundsToolStripMenuItem - // - showFrameBoundsToolStripMenuItem.Name = "showFrameBoundsToolStripMenuItem"; - showFrameBoundsToolStripMenuItem.Size = new System.Drawing.Size(180, 22); - showFrameBoundsToolStripMenuItem.Text = "Show frame bounds"; - showFrameBoundsToolStripMenuItem.Click += OnClickShowFrameBounds; - // // AnimDataControl // AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); @@ -531,7 +530,6 @@ private void InitializeComponent() private System.Windows.Forms.Label label2; private System.Windows.Forms.NumericUpDown numericUpDownFrameDelay; private System.Windows.Forms.NumericUpDown numericUpDownStartDelay; - private AnimatedPictureBox MainPictureBox; private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem; private System.Windows.Forms.SplitContainer splitContainer1; private System.Windows.Forms.SplitContainer splitContainer2; @@ -555,5 +553,6 @@ private void InitializeComponent() private System.Windows.Forms.ContextMenuStrip contextMenuStripMainPictureBox; private System.Windows.Forms.ToolStripMenuItem exportAsAnimatedGifToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem showFrameBoundsToolStripMenuItem; + private AnimatedPictureBox MainPictureBox; } } diff --git a/UoFiddler.Controls/UserControls/AnimDataControl.cs b/UoFiddler.Controls/UserControls/AnimDataControl.cs index 3fa2799d..3ab18b61 100644 --- a/UoFiddler.Controls/UserControls/AnimDataControl.cs +++ b/UoFiddler.Controls/UserControls/AnimDataControl.cs @@ -556,12 +556,9 @@ private void OnClickSave(object sender, EventArgs e) Cursor.Current = Cursors.WaitCursor; Animdata.Save(Options.OutputPath); Cursor.Current = Cursors.Default; - MessageBox.Show($"Saved to {Options.OutputPath}", - "Save", - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); Options.ChangedUltimaClass["Animdata"] = false; + + FileSavedDialog.Show(FindForm(), Options.OutputPath, "File saved successfully."); } private void OnClickRemoveAnim(object sender, EventArgs e) diff --git a/UoFiddler.Controls/UserControls/AnimDataControl.resx b/UoFiddler.Controls/UserControls/AnimDataControl.resx index 933c20a7..79f3e9e3 100644 --- a/UoFiddler.Controls/UserControls/AnimDataControl.resx +++ b/UoFiddler.Controls/UserControls/AnimDataControl.resx @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/UoFiddler.Plugin.Compare/Classes/SecondAnimdata.cs b/UoFiddler.Plugin.Compare/Classes/SecondAnimdata.cs new file mode 100644 index 00000000..2facbdc0 --- /dev/null +++ b/UoFiddler.Plugin.Compare/Classes/SecondAnimdata.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Ultima; + +namespace UoFiddler.Plugin.Compare.Classes +{ + internal static class SecondAnimdata + { + private static Dictionary _data; + + public static bool IsLoaded => _data != null; + + public static Animdata.AnimdataEntry GetAnimData(int id) => + _data != null && _data.TryGetValue(id, out Animdata.AnimdataEntry value) ? value : null; + + public static IEnumerable GetKeys() => + _data != null ? (IEnumerable)_data.Keys : Array.Empty(); + + /// + /// Reads an animdata.mul from the given file path. Returns false if the file + /// cannot be read. On success the internal dictionary is replaced. + /// + public static bool Initialize(string filePath) + { + if (!File.Exists(filePath)) + { + return false; + } + + var result = new Dictionary(); + + try + { + using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var bin = new BinaryReader(fs)) + { + unsafe + { + int id = 0; + long chunkCount = bin.BaseStream.Length / (4 + (8 * (64 + 4))); + + for (long h = 0; h < chunkCount; h++) + { + bin.ReadInt32(); // chunk header (discarded) + + byte[] buffer = bin.ReadBytes(544); + + fixed (byte* buf = buffer) + { + byte* data = buf; + + for (int i = 0; i < 8; ++i, ++id) + { + sbyte[] frame = new sbyte[64]; + for (int j = 0; j < 64; ++j) + { + frame[j] = (sbyte)*data++; + } + + byte unk = *data++; + byte frameCount = *data++; + byte frameInterval = *data++; + byte frameStart = *data++; + + if (frameCount > 0) + { + result[id] = new Animdata.AnimdataEntry(frame, unk, frameCount, frameInterval, frameStart); + } + } + } + } + } + } + } + catch (Exception) + { + return false; + } + + _data = result; + return true; + } + } +} diff --git a/UoFiddler.Plugin.Compare/Classes/SecondArt.cs b/UoFiddler.Plugin.Compare/Classes/SecondArt.cs index 05e09114..a3d95d27 100644 --- a/UoFiddler.Plugin.Compare/Classes/SecondArt.cs +++ b/UoFiddler.Plugin.Compare/Classes/SecondArt.cs @@ -1,4 +1,5 @@ -using System.Drawing; +using System; +using System.Drawing; using System.Drawing.Imaging; using System.IO; using Ultima; @@ -13,10 +14,13 @@ internal static class SecondArt private static byte[] _streamBuffer; private static byte[] _validBuffer; + internal static event Action FileIndexChanged; + public static void SetFileIndex(string idxPath, string mulPath) { _fileIndex = new SecondFileIndex(idxPath, mulPath, 0x14000); _cache = new Bitmap[0x14000]; + FileIndexChanged?.Invoke(); } public static int GetMaxItemId() @@ -58,6 +62,11 @@ private static int GetIdxLength() return (int)(_fileIndex.IdxLength / 12); } + public static bool IsUOAHS() + { + return GetIdxLength() >= 0x13FDC; + } + public static bool IsValidStatic(int index) { index = GetLegalItemId(index); diff --git a/UoFiddler.Plugin.Compare/Classes/SecondRadarCol.cs b/UoFiddler.Plugin.Compare/Classes/SecondRadarCol.cs new file mode 100644 index 00000000..bdc27a57 --- /dev/null +++ b/UoFiddler.Plugin.Compare/Classes/SecondRadarCol.cs @@ -0,0 +1,49 @@ +using System.IO; +using System.Runtime.InteropServices; + +namespace UoFiddler.Plugin.Compare.Classes +{ + internal static class SecondRadarCol + { + private static ushort[] _colors; + + public static bool IsLoaded => _colors != null; + + public static ushort GetColor(int index) => + _colors != null && index >= 0 && index < _colors.Length ? _colors[index] : (ushort)0; + + public static int Length => _colors?.Length ?? 0; + + /// + /// Reads a radarcol.mul from the given file path. Returns false if the file + /// cannot be read. + /// + public static bool Initialize(string filePath) + { + if (!File.Exists(filePath)) + { + return false; + } + + try + { + using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + var colors = new ushort[fs.Length / 2]; + var buffer = new byte[(int)fs.Length]; + fs.Read(buffer, 0, (int)fs.Length); + GCHandle gc = GCHandle.Alloc(colors, GCHandleType.Pinned); + Marshal.Copy(buffer, 0, gc.AddrOfPinnedObject(), (int)fs.Length); + gc.Free(); + _colors = colors; + } + } + catch + { + return false; + } + + return true; + } + } +} diff --git a/UoFiddler.Plugin.Compare/Classes/SecondTexture.cs b/UoFiddler.Plugin.Compare/Classes/SecondTexture.cs index 2e8eb6ad..87f002bf 100644 --- a/UoFiddler.Plugin.Compare/Classes/SecondTexture.cs +++ b/UoFiddler.Plugin.Compare/Classes/SecondTexture.cs @@ -24,7 +24,13 @@ public static void SetFileIndex(string idxPath, string mulPath) public static bool IsValidTexture(int index) { + if (_cache == null) + { + return false; + } + index &= 0x3FFF; + if (_cache[index] != null) { return true; @@ -37,6 +43,11 @@ public static bool IsValidTexture(int index) public static Bitmap GetTexture(int index) { + if (_cache == null) + { + return null; + } + index &= 0x3FFF; if (_cache[index] != null) diff --git a/UoFiddler.Plugin.Compare/Classes/SecondTileData.cs b/UoFiddler.Plugin.Compare/Classes/SecondTileData.cs new file mode 100644 index 00000000..802a1a1b --- /dev/null +++ b/UoFiddler.Plugin.Compare/Classes/SecondTileData.cs @@ -0,0 +1,114 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using Ultima; + +namespace UoFiddler.Plugin.Compare.Classes +{ + /// + /// Contains lists of land and item tile data. + /// + /// + /// + public class SecondTileData + { + /// + /// Gets the list of land tile data. + /// + public LandData[] LandTable { get; private set; } + + /// + /// Gets the list of item tile data. + /// + public ItemData[] ItemTable { get; private set; } + + public int[] HeightTable { get; private set; } + + public unsafe void Initialize(string path, bool useNeWTileDataFormat) + { + string filePath = path; + if (filePath == null) + { + return; + } + + using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + + var landHeader = new int[512]; + int j = 0; + LandTable = new LandData[0x4000]; + + var buffer = new byte[fs.Length]; + GCHandle gc = GCHandle.Alloc(buffer, GCHandleType.Pinned); + long currentPos = 0; + try + { + fs.Read(buffer, 0, buffer.Length); + for (int i = 0; i < 0x4000; i += 32) + { + var ptrHeader = new IntPtr((long)gc.AddrOfPinnedObject() + currentPos); + currentPos += 4; + landHeader[j++] = (int)Marshal.PtrToStructure(ptrHeader, typeof(int)); + for (int count = 0; count < 32; ++count) + { + var ptr = new IntPtr((long)gc.AddrOfPinnedObject() + currentPos); + if (useNeWTileDataFormat) + { + currentPos += sizeof(NewLandTileDataMul); + var cur = (NewLandTileDataMul)Marshal.PtrToStructure(ptr, typeof(NewLandTileDataMul)); + LandTable[i + count] = new LandData(cur); + } + else + { + currentPos += sizeof(OldLandTileDataMul); + var cur = (OldLandTileDataMul)Marshal.PtrToStructure(ptr, typeof(OldLandTileDataMul)); + LandTable[i + count] = new LandData(cur); + } + } + } + + long remaining = buffer.Length - currentPos; + + int structSize = useNeWTileDataFormat ? sizeof(NewItemTileDataMul) : sizeof(OldItemTileDataMul); + + var itemHeader = new int[remaining / ((structSize * 32) + 4)]; + int itemLength = itemHeader.Length * 32; + + ItemTable = new ItemData[itemLength]; + HeightTable = new int[itemLength]; + + j = 0; + for (int i = 0; i < itemLength; i += 32) + { + var ptrHeader = new IntPtr((long)gc.AddrOfPinnedObject() + currentPos); + currentPos += 4; + itemHeader[j++] = (int)Marshal.PtrToStructure(ptrHeader, typeof(int)); + for (int count = 0; count < 32; ++count) + { + var ptr = new IntPtr((long)gc.AddrOfPinnedObject() + currentPos); + if (useNeWTileDataFormat) + { + currentPos += sizeof(NewItemTileDataMul); + var cur = (NewItemTileDataMul)Marshal.PtrToStructure(ptr, typeof(NewItemTileDataMul)); + ItemTable[i + count] = new ItemData(cur); + HeightTable[i + count] = cur.height; + } + else + { + currentPos += sizeof(OldItemTileDataMul); + var cur = (OldItemTileDataMul)Marshal.PtrToStructure(ptr, typeof(OldItemTileDataMul)); + ItemTable[i + count] = new ItemData(cur); + HeightTable[i + count] = cur.height; + } + } + } + } + finally + { + gc.Free(); + } + } + } + } +} \ No newline at end of file diff --git a/UoFiddler.Plugin.Compare/Classes/TileDataCompareOptions.cs b/UoFiddler.Plugin.Compare/Classes/TileDataCompareOptions.cs new file mode 100644 index 00000000..cb59658a --- /dev/null +++ b/UoFiddler.Plugin.Compare/Classes/TileDataCompareOptions.cs @@ -0,0 +1,60 @@ +using Ultima; + +namespace UoFiddler.Plugin.Compare.Classes +{ + /// + /// Controls which fields and flags participate in TileData comparison. + /// All fields included and no flags ignored by default. + /// + public class TileDataCompareOptions + { + // ── Land tile fields ───────────────────────────────────────────────────── + public bool LandCompareName { get; set; } = true; + public bool LandCompareTextureId { get; set; } = true; + public bool LandCompareFlags { get; set; } = true; + + // ── Item tile fields ───────────────────────────────────────────────────── + public bool ItemCompareName { get; set; } = true; + public bool ItemCompareFlags { get; set; } = true; + public bool ItemCompareAnimation { get; set; } = true; + public bool ItemCompareWeight { get; set; } = true; + public bool ItemCompareQuality { get; set; } = true; + public bool ItemCompareQuantity { get; set; } = true; + public bool ItemCompareHue { get; set; } = true; + public bool ItemCompareStackingOffset { get; set; } = true; + public bool ItemCompareValue { get; set; } = true; + public bool ItemCompareHeight { get; set; } = true; + public bool ItemCompareMiscData { get; set; } = true; + public bool ItemCompareUnk2 { get; set; } = true; + public bool ItemCompareUnk3 { get; set; } = true; + + // ── Flag exclusions ────────────────────────────────────────────────────── + /// + /// Flags OR'd into this mask are excluded from comparison for both land and item tiles. + /// + public TileFlag IgnoredFlags { get; set; } = TileFlag.None; + + public void ResetToDefaults() + { + LandCompareName = true; + LandCompareTextureId = true; + LandCompareFlags = true; + + ItemCompareName = true; + ItemCompareFlags = true; + ItemCompareAnimation = true; + ItemCompareWeight = true; + ItemCompareQuality = true; + ItemCompareQuantity = true; + ItemCompareHue = true; + ItemCompareStackingOffset = true; + ItemCompareValue = true; + ItemCompareHeight = true; + ItemCompareMiscData = true; + ItemCompareUnk2 = true; + ItemCompareUnk3 = true; + + IgnoredFlags = TileFlag.None; + } + } +} diff --git a/UoFiddler.Plugin.Compare/Classes/Utils.cs b/UoFiddler.Plugin.Compare/Classes/Utils.cs new file mode 100644 index 00000000..bf5e14ad --- /dev/null +++ b/UoFiddler.Plugin.Compare/Classes/Utils.cs @@ -0,0 +1,920 @@ +/*************************************************************************** + * + * $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.Drawing; +using System.Drawing.Imaging; +using System.Globalization; +using System.IO; + +namespace UoFiddler.Plugin.Compare.Classes +{ + public static class Utils + { + /// + /// The color key auto-detection filter. + /// The color key is determined by the most common color of the 4x corner pixels. + /// + /// Image in 32-bit R8G8B8 format + /// Filtered image + public static unsafe Bitmap CKeyFilter(Bitmap bmp) + { + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); + uint* line = (uint*)bd.Scan0; + int delta = bd.Stride >> 2; + uint* line2 = line + delta * (bmp.Height - 1); + + Bitmap newBmp = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppRgb); + BitmapData newBitmapData = newBmp.LockBits(new Rectangle(0, 0, newBmp.Width, newBmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb); + + uint* newLine = (uint*)newBitmapData.Scan0; + int newDelta = newBitmapData.Stride >> 2; + + uint colorKey; + + uint colorKey1 = line[0]; + uint colorKey2 = line[bmp.Width - 1]; + uint colorKey3 = line2[0]; + uint colorKey4 = line2[bmp.Width - 1]; + + if (colorKey1 == colorKey2 || colorKey1 == colorKey3 || colorKey1 == colorKey4) + { + colorKey = colorKey1; + } + else if (colorKey2 == colorKey3 || colorKey2 == colorKey4) + { + colorKey = colorKey2; + } + else if (colorKey3 == colorKey4) + { + colorKey = colorKey3; + } + else + { + colorKey = colorKey4; + } + + for (int y = 0; y < bmp.Height; ++y, line += delta, newLine += newDelta) + { + uint* current = line; + uint* currentNew = newLine; + + for (int x = 0; x < bmp.Width; ++x) + { + if (current[x] == colorKey) + { + currentNew[x] = 0; + } + else + { + currentNew[x] = current[x]; + } + } + } + + bmp.UnlockBits(bd); + newBmp.UnlockBits(newBitmapData); + + return newBmp; + } + + /// + /// Black half-tone correction filter. + /// Brightens the black halftones to 8, 8, 8. To ensure that black halftones are not mistaken for a color key when converting to R5G5B5. + /// + /// Image in 32-bit R8G8B8 format + /// If true, it lightens the color key to 8, 8, 8. + /// Filtered image + public static unsafe Bitmap BColFilter(Bitmap bmp, bool forceCCol2BCol) + { + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); + uint* line = (uint*)bd.Scan0; + int delta = bd.Stride >> 2; + + Bitmap bmpnew = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppRgb); + BitmapData bdnew = bmpnew.LockBits(new Rectangle(0, 0, bmpnew.Width, bmpnew.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb); + + uint* linenew = (uint*)bdnew.Scan0; + int deltanew = bdnew.Stride >> 2; + + for (int Y = 0; Y < bmp.Height; ++Y, line += delta, linenew += deltanew) + { + uint* cur = line; + uint* curnew = linenew; + for (int X = 0; X < bmp.Width; ++X) + { + byte a = (byte)((cur[X] & 0xFF000000) >> 24); + byte r = (byte)((cur[X] & 0x00FF0000) >> 16); + byte g = (byte)((cur[X] & 0x0000FF00) >> 8); + byte b = (byte)((cur[X] & 0x000000FF) >> 0); + + if (r < 8 && g < 8 && b < 8) + { + byte max = Math.Max(r, Math.Max(g, b)); + if (!forceCCol2BCol) + { + if (r != 0 && r == max) + { + curnew[X] |= 0xFF080000; + } + + if (g != 0 && g == max) + { + curnew[X] |= 0xFF000800; + } + + if (b != 0 && b == max) + { + curnew[X] |= 0xFF000008; + } + } + else + { + if (r == max) + { + curnew[X] |= 0xFF080000; + } + + if (g == max) + { + curnew[X] |= 0xFF000800; + } + + if (b == max) + { + curnew[X] |= 0xFF000008; + } + } + } + else + { + curnew[X] = cur[X]; + } + } + } + bmp.UnlockBits(bd); + bmpnew.UnlockBits(bdnew); + return bmpnew; + } + + /// + /// Фильтр коррекции белых полутанов. + /// Затемняет белые полутона до 247, 247, 247. Для того чтобы при конвертировании в R5G5B5 белые полутона небыли ошибочно восприняты как цветовой ключ. + /// + /// Изображение в 32х битном формате R8G8B8 + /// Если true то осветляет цветовой ключ до 247, 247, 247. + /// Filtered image + public static unsafe Bitmap WColFilter(Bitmap bmp, bool forceCCol2WCol) + { + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); + uint* line = (uint*)bd.Scan0; + int delta = bd.Stride >> 2; + + Bitmap bmpnew = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppRgb); + BitmapData bdnew = bmpnew.LockBits(new Rectangle(0, 0, bmpnew.Width, bmpnew.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb); + + uint* linenew = (uint*)bdnew.Scan0; + int deltanew = bdnew.Stride >> 2; + + for (int Y = 0; Y < bmp.Height; ++Y, line += delta, linenew += deltanew) + { + uint* cur = line; + uint* curnew = linenew; + for (int X = 0; X < bmp.Width; ++X) + { + byte a = (byte)((cur[X] & 0xFF000000) >> 24); + byte r = (byte)((cur[X] & 0x00FF0000) >> 16); + byte g = (byte)((cur[X] & 0x0000FF00) >> 8); + byte b = (byte)((cur[X] & 0x000000FF) >> 0); + + if (r > 247 && g > 247 && b > 247) + { + byte min = Math.Min(r, Math.Max(g, b)); + if (!forceCCol2WCol) + { + if (r != 255 && r == min) + { + curnew[X] |= 0xFFF70000; + } + else + { + curnew[X] |= ((uint)r << 16); + } + + if (g != 255 && g == min) + { + curnew[X] |= 0xFF00F700; + } + else + { + curnew[X] |= ((uint)g << 8); + } + + if (b != 255 && b == min) + { + curnew[X] |= 0xFF0000F7; + } + else + { + curnew[X] |= ((uint)b << 0); + } + } + else + { + if (r == min) + { + curnew[X] |= 0xFFF70000; + } + else + { + curnew[X] |= ((uint)r << 16); + } + + if (g == min) + { + curnew[X] |= 0xFF00F700; + } + else + { + curnew[X] |= ((uint)g << 8); + } + + if (b == min) + { + curnew[X] |= 0xFF0000F7; + } + else + { + curnew[X] |= ((uint)b << 0); + } + } + } + else + { + curnew[X] = cur[X]; + } + } + } + bmp.UnlockBits(bd); + bmpnew.UnlockBits(bdnew); + return bmpnew; + } + + /// + /// Фильтр для стирания нижних границ тайла для убирания эфекта "сетки" при использовании тайла с флагом Translucent. + /// Входящее изображение должно иметь ширину 44, иначе фильтр возвратит передаенное ему изображение. + /// + /// Изображение в 32х битном формате R8G8B8 + /// Если true то тайлы с высотой отличной от 44 не преобразуются. + /// Filtered image + public static unsafe Bitmap CuttingRawBmpForTranslucent(Bitmap bmp, bool onlyraw = true) + { + if ((bmp.Height != 0 && bmp.Width != 44) || (onlyraw && bmp.Height != 44)) + { + return bmp; + } + + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); + uint* line = (uint*)bd.Scan0; + int delta = bd.Stride >> 2; + + Bitmap bmpnew = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format32bppRgb); + BitmapData bdnew = bmpnew.LockBits(new Rectangle(0, 0, bmpnew.Width, bmpnew.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb); + uint* linenew = (uint*)bdnew.Scan0; + int deltanew = bdnew.Stride >> 2; + + int y0 = Math.Max(0, bmp.Height - 22); + //line += y0 * delta; + //linenew += y0 * deltanew; + + int x1 = y0 > 0 ? 0 : 22 - bmp.Height; + int x2 = y0 > 0 ? 43 : 43 - x1; + + for (int Y = 0; Y < y0; ++Y, line += delta, linenew += deltanew) + { + uint* cur = line; + uint* curnew = linenew; + for (int X = 0; X < bmp.Width; ++X) + curnew[X] = cur[X]; + } + line = (uint*)bd.Scan0 + y0 * delta; + linenew = (uint*)bdnew.Scan0 + y0 * deltanew; + for (int Y = y0; Y < bmp.Height; ++Y, line += delta, linenew += deltanew) + { + uint* cur = line; + uint* curnew = linenew; + for (int X = 0; X < bmp.Width; ++X) + { + if (X != x1 && X != x2) + { + curnew[X] = cur[X]; + } + else + { + curnew[X] = unchecked((ushort)0xFF000000); + } + } + ++x1; + --x2; + } + bmp.UnlockBits(bd); + bmpnew.UnlockBits(bdnew); + return bmpnew; + } + + /// + /// Вычисляет средний цвет в изображении. + /// Подсчет введется как среднее арифмитическое составляющие всех цветов, кроме абсолютно черного (0,0,0). + /// + /// Изображение в 32х битном формате R8G8B8 или 16 битном A1R5G5B5. + /// Если true то осветляет возвращаемый результат до (8,8,8) если он равен (0,0,0). + /// Hue - цвет в 16 битном формате. + public static unsafe ushort AverageCol(Bitmap bmp, bool noneBlack = true) + { + ulong r = 0; + ulong g = 0; + ulong b = 0; + ulong count = 0; + + if (bmp.PixelFormat == PixelFormat.Format32bppRgb) + { + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb); + uint* line = (uint*)bd.Scan0; + int delta = bd.Stride >> 2; + for (int Y = 0; Y < bmp.Height; ++Y, line += delta) + { + uint* cur = line; + for (int X = 0; X < bmp.Width; ++X) + { + if ((uint)(cur[X] & 0x00FFFFFF) == 0) + { + continue; + } + + r += (ulong)((cur[X] & 0x00FF0000) >> 16); + g += (ulong)((cur[X] & 0x0000FF00) >> 8); + b += (ulong)((cur[X] & 0x000000FF) >> 0); + ++count; + } + } + bmp.UnlockBits(bd); + } + else if (bmp.PixelFormat == PixelFormat.Format16bppArgb1555) + { + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555); + ushort* line = (ushort*)bd.Scan0; + int delta = bd.Stride >> 1; + for (int Y = 0; Y < bmp.Height; ++Y, line += delta) + { + ushort* cur = line; + for (int X = 0; X < bmp.Width; ++X) + { + if ((ushort)(cur[X] & 0x7FFF) == 0) + { + continue; + } + + r += (ulong)((cur[X] & 0x7C00) >> 10); + g += (ulong)((cur[X] & 0x03E0) >> 5); + b += (ulong)((cur[X] & 0x001F) >> 0); + ++count; + } + } + bmp.UnlockBits(bd); + } + else + { + throw new ArgumentException("Неподдерживываемый формат пикселя"); + } + + r = (ulong)Math.Round(((double)r / (double)count)); + g = (ulong)Math.Round(((double)g / (double)count)); + b = (ulong)Math.Round(((double)b / (double)count)); + + ushort hue = 0x0421; + if (bmp.PixelFormat == PixelFormat.Format32bppRgb) + { + hue = Ultima.Hues.ColorToHue(Color.FromArgb((int)r, (int)g, (int)b)); + } + else if (bmp.PixelFormat == PixelFormat.Format16bppArgb1555) + { + hue = (ushort)((r << 10) | (g << 5) | (b)); + } + + if (noneBlack && (ushort)(hue & 0x7FFF) == 0) + { + hue = 0x0421; + } + + return hue; + } + + public static bool CompareBitmaps(Bitmap bmp10, Bitmap bmp20) + { + Bitmap bmp1 = new Bitmap(bmp10); + Bitmap bmp2 = new Bitmap(bmp20); + if (bmp1.Width != bmp2.Width || bmp1.Height != bmp2.Height) + { + return false; + } + + ImageLockMode Mode = ImageLockMode.ReadWrite; + Rectangle Range = new Rectangle(0, 0, bmp1.Width, bmp1.Height); + BitmapData BMPD1 = bmp1.LockBits(Range, Mode, bmp1.PixelFormat); + BitmapData BMPD2 = bmp2.LockBits(Range, Mode, bmp2.PixelFormat); + bool result = true; + try + { + unsafe + { + byte* p1 = (byte*)(void*)BMPD1.Scan0; + byte* p2 = (byte*)(void*)BMPD2.Scan0; + + int c = Range.Height * BMPD1.Stride; + for (int i = 0; i < c; i++) + { + if (*p1 != *p2) + { + result = false; + break; + } + p1++; + p2++; + } + } + } + finally + { + + } + + bmp1.UnlockBits(BMPD1); + bmp2.UnlockBits(BMPD2); + return result; + } + + public static unsafe Bitmap ConvertBmp(Bitmap bmp) + { + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555); + ushort* line = (ushort*)bd.Scan0; + int delta = bd.Stride >> 1; + + Bitmap bmpnew = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format16bppArgb1555); + BitmapData bdnew = bmpnew.LockBits(new Rectangle(0, 0, bmpnew.Width, bmpnew.Height), ImageLockMode.WriteOnly, PixelFormat.Format16bppArgb1555); + + ushort* linenew = (ushort*)bdnew.Scan0; + int deltanew = bdnew.Stride >> 1; + + for (int Y = 0; Y < bmp.Height; ++Y, line += delta, linenew += deltanew) + { + ushort* cur = line; + ushort* curnew = linenew; + for (int X = 0; X < bmp.Width; ++X) + { + if ((cur[X] != 32768) && (cur[X] != 65535)) //True Black/White + { + curnew[X] = cur[X]; + } + } + } + bmp.UnlockBits(bd); + bmpnew.UnlockBits(bdnew); + return bmpnew; + } + + public static unsafe Bitmap ConvertBmpAnim(Bitmap bmp, int Red, int Green, int Blue) + { + //Extra background + int ExtraBack; + ExtraBack = (Red / 8) * 1024 + (Green / 8) * 32 + (Blue / 8) + 32768; + // + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555); + ushort* line = (ushort*)bd.Scan0; + int delta = bd.Stride >> 1; + + Bitmap bmpnew = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format16bppArgb1555); + BitmapData bdnew = bmpnew.LockBits(new Rectangle(0, 0, bmpnew.Width, bmpnew.Height), ImageLockMode.WriteOnly, PixelFormat.Format16bppArgb1555); + + ushort* linenew = (ushort*)bdnew.Scan0; + int deltanew = bdnew.Stride >> 1; + + for (int Y = 0; Y < bmp.Height; ++Y, line += delta, linenew += deltanew) + { + ushort* cur = line; + ushort* curnew = linenew; + for (int X = 0; X < bmp.Width; ++X) + { + //My Soulblighter Modification + // Convert color 0,0,0 to 0,0,8 + //if ((cur[X] == 32768)) + // curnew[X] = 32769; + //if ((cur[X] != 65535 & cur[X] != ExtraBack & cur[X] > 32768)) //True White == BackGround + // curnew[X] = cur[X]; + //End of Soulblighter Modification + } + } + bmp.UnlockBits(bd); + bmpnew.UnlockBits(bdnew); + return bmpnew; + } + + public static unsafe Bitmap ConvertBmpAnimCV5(Bitmap bmp, int Red, int Green, int Blue) + { + //Extra background + int ExtraBack; + ExtraBack = (Red / 8) * 1024 + (Green / 8) * 32 + (Blue / 8) + 32768; + // + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555); + ushort* line = (ushort*)bd.Scan0; + int delta = bd.Stride >> 1; + + Bitmap bmpnew = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format16bppArgb1555); + BitmapData bdnew = bmpnew.LockBits(new Rectangle(0, 0, bmpnew.Width, bmpnew.Height), ImageLockMode.WriteOnly, PixelFormat.Format16bppArgb1555); + + ushort* linenew = (ushort*)bdnew.Scan0; + int deltanew = bdnew.Stride >> 1; + + for (int Y = 0; Y < bmp.Height; ++Y, line += delta, linenew += deltanew) + { + ushort* cur = line; + ushort* curnew = linenew; + for (int X = 0; X < bmp.Width; ++X) + { + //My Soulblighter Modification + // Convert color 0,0,0 to 0,0,8 + //if ((cur[X] == 32768)) + // curnew[X] = 32769; + //if ((cur[X] != 65535 & cur[X] != 54965 & cur[X] != ExtraBack & cur[X] > 32768)) //True White == BackGround + // curnew[X] = cur[X]; + //End of Soulblighter Modification + } + } + bmp.UnlockBits(bd); + bmpnew.UnlockBits(bdnew); + return bmpnew; + } + + public static unsafe Bitmap ConvertBmpAnimKR(Bitmap bmp, int Red, int Green, int Blue) + { + //Extra background + //int extraBack = (Red / 8) * 1024 + (Green / 8) * 32 + (Blue / 8) + 32768; + // + + BitmapData bd = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format16bppArgb1555); + ushort* line = (ushort*)bd.Scan0; + int delta = bd.Stride >> 1; + + Bitmap bmpnew = new Bitmap(bmp.Width, bmp.Height, PixelFormat.Format16bppArgb1555); + BitmapData bdnew = bmpnew.LockBits(new Rectangle(0, 0, bmpnew.Width, bmpnew.Height), ImageLockMode.WriteOnly, PixelFormat.Format16bppArgb1555); + + ushort* linenew = (ushort*)bdnew.Scan0; + int deltanew = bdnew.Stride >> 1; + + for (int Y = 0; Y < bmp.Height; ++Y, line += delta, linenew += deltanew) + { + ushort* cur = line; + ushort* curnew = linenew; + + for (int X = 0; X < bmp.Width; ++X) + { + //if (cur[X] != 53235) + //{ + // Convert back to RGB + int BlueTemp = ((cur[X] - 32768) / 32); + BlueTemp = BlueTemp * 32; + BlueTemp = (cur[X] - 32768) - BlueTemp; + + int GreenTemp = ((cur[X] - 32768) / 1024); + GreenTemp = GreenTemp * 1024; + GreenTemp = (cur[X] - 32768) - GreenTemp - BlueTemp; + GreenTemp = GreenTemp / 32; + + int RedTemp = ((cur[X] - 32768) / 1024); + + // remove green colors + if (GreenTemp > BlueTemp & GreenTemp > RedTemp & GreenTemp > 10) + { + cur[X] = 65535; + } + //} + + //My Soulblighter Modification + // Convert color 0,0,0 to 0,0,8 + //if ((cur[X] == 32768)) + // curnew[X] = 32769; + //if ((cur[X] != 65535 & cur[X] != 54965 & cur[X] != ExtraBack & cur[X] > 32768)) //True White == BackGround + // curnew[X] = cur[X]; + //End of Soulblighter Modification + } + } + + bmp.UnlockBits(bd); + bmpnew.UnlockBits(bdnew); + + return bmpnew; + } + + private static ColorPalette GetColorPalette(uint nColors) + { + // Assume monochrome image. + PixelFormat bitscolordepth = PixelFormat.Format1bppIndexed; + + // Determine number of colors. + if (nColors > 2) + { + bitscolordepth = PixelFormat.Format4bppIndexed; + } + + if (nColors > 16) + { + bitscolordepth = PixelFormat.Format8bppIndexed; + } + + // Make a new Bitmap object to get its Palette. + ColorPalette palette; + + using (Bitmap bitmap = new Bitmap(1, 1, bitscolordepth)) + { + palette = bitmap.Palette; + } + + return palette; + } + + private static ColorPalette GetColorPalette(uint nColors, Color[] usedColors) + { + PixelFormat bitscolordepth = nColors > 16 + ? PixelFormat.Format8bppIndexed + : nColors > 2 + ? PixelFormat.Format4bppIndexed + : PixelFormat.Format1bppIndexed; + + Bitmap bitmap = new Bitmap(1, 1, bitscolordepth); + ColorPalette palette = bitmap.Palette; + //palette.Flags = 0x00000001; // The color values in the array contain information about the alpha component. + bitmap.Dispose(); + + Array.Sort(usedColors); + + if (usedColors.Length > nColors) + { + + } + + palette.Entries[0] = Color.FromArgb(0, 0, 0, 0); + + for (uint i = 1; i < nColors; i++) + { + + uint intensity = i * 0xFF / (nColors - 1); // Even distribution. + + // The GIF encoder makes the first entry in the palette + // that has a ZERO alpha the transparent color in the GIF. + // Pick the first one arbitrarily, for demonstration purposes. + + //if (i == 0 && fTransparent) // Make this color index... + int alpha = 0; + + // Create a gray scale for demonstration purposes. + // Otherwise, use your favorite color reduction algorithm + // and an optimum palette for that algorithm generated here. + // For example, a color histogram, or a median cut palette. + palette.Entries[i] = Color.FromArgb((int)alpha, (int)intensity, (int)intensity, (int)intensity); + } + + return palette; + } + + public static void SaveGifWithNewColorTable(Image image, string filename, uint nColors, bool fTransparent) + { + // GIF codec supports 256 colors maximum, monochrome minimum. + if (nColors > 256) + { + nColors = 256; + } + + if (nColors < 2) + { + nColors = 2; + } + + // Make a new 8-BPP indexed bitmap that is the same size as the source image. + int width = image.Width; + int height = image.Height; + + // Always use PixelFormat8bppIndexed because that is the color + // table-based interface to the GIF codec. + Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed); + + // Create a color palette big enough to hold the colors you want. + ColorPalette pal = GetColorPalette(nColors); + + // Initialize a new color table with entries that are determined + // by some optimal palette-finding algorithm; for demonstration + // purposes, use a greyscale. + for (uint i = 0; i < nColors; i++) + { + uint alpha = 0xFF; // Colors are opaque. + uint intensity = i * 0xFF / (nColors - 1); // Even distribution. + + // The GIF encoder makes the first entry in the palette + // that has a ZERO alpha the transparent color in the GIF. + // Pick the first one arbitrarily, for demonstration purposes. + + if (i == 0 && fTransparent) // Make this color index... + { + alpha = 0; // Transparent + } + + // Create a gray scale for demonstration purposes. + // Otherwise, use your favorite color reduction algorithm + // and an optimum palette for that algorithm generated here. + // For example, a color histogram, or a median cut palette. + pal.Entries[i] = Color.FromArgb((int)alpha, + (int)intensity, + (int)intensity, + (int)intensity); + } + + // Set the palette into the new Bitmap object. + bitmap.Palette = pal; + + + // Use GetPixel below to pull out the color data of Image. + // Because GetPixel isn't defined on an Image, make a copy + // in a Bitmap instead. Make a new Bitmap that is the same size as the + // image that you want to export. Or, try to + // interpret the native pixel format of the image by using a LockBits + // call. Use PixelFormat32BppARGB so you can wrap a Graphics + // around it. + Bitmap bmpCopy = new Bitmap(width, height, PixelFormat.Format32bppArgb); + { + Graphics g = Graphics.FromImage(bmpCopy); + + g.PageUnit = GraphicsUnit.Pixel; + + // Transfer the Image to the Bitmap + g.DrawImage(image, 0, 0, width, height); + + // g goes out of scope and is marked for garbage collection. + // Force it, just to keep things clean. + g.Dispose(); + } + + // Lock a rectangular portion of the bitmap for writing. + Rectangle rect = new Rectangle(0, 0, width, height); + + BitmapData bitmapData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); + + // Write to the temporary buffer that is provided by LockBits. + // Copy the pixels from the source image in this loop. + // Because you want an index, convert RGB to the appropriate + // palette index here. + IntPtr pixels = bitmapData.Scan0; + + unsafe + { + // Get the pointer to the image bits. + // This is the unsafe operation. + byte* pBits; + if (bitmapData.Stride > 0) + { + pBits = (byte*)pixels.ToPointer(); + } + else + // If the Stide is negative, Scan0 points to the last + // scanline in the buffer. To normalize the loop, obtain + // a pointer to the front of the buffer that is located + // (Height-1) scanlines previous. + { + pBits = (byte*)pixels.ToPointer() + bitmapData.Stride * (height - 1); + } + + uint stride = (uint)Math.Abs(bitmapData.Stride); + + for (uint row = 0; row < height; ++row) + { + for (uint col = 0; col < width; ++col) + { + // Map palette indexes for a gray scale. + // If you use some other technique to color convert, + // put your favorite color reduction algorithm here. + Color pixel; // The source pixel. + + // The destination pixel. + // The pointer to the color index byte of the + // destination; this real pointer causes this + // code to be considered unsafe. + byte* p8bppPixel = pBits + row * stride + col; + + pixel = bmpCopy.GetPixel((int)col, (int)row); + + // Use luminance/chrominance conversion to get grayscale. + // Basically, turn the image into black and white TV. + // Do not calculate Cr or Cb because you + // discard the color anyway. + // Y = Red * 0.299 + Green * 0.587 + Blue * 0.114 + + // This expression is best as integer math for performance, + // however, because GetPixel listed earlier is the slowest + // part of this loop, the expression is left as + // floating point for clarity. + + double luminance = (pixel.R * 0.299) + + (pixel.G * 0.587) + + (pixel.B * 0.114); + + // Gray scale is an intensity map from black to white. + // Compute the index to the grayscale entry that + // approximates the luminance, and then round the index. + // Also, constrain the index choices by the number of + // colors to do, and then set that pixel's index to the + // byte value. + *p8bppPixel = (byte)(luminance * (nColors - 1) / 255 + 0.5); + + } /* end loop for col */ + } /* end loop for row */ + } /* end unsafe */ + + // To commit the changes, unlock the portion of the bitmap. + bitmap.UnlockBits(bitmapData); + + bitmap.Save(filename, ImageFormat.Gif); + + // Bitmap goes out of scope here and is also marked for + // garbage collection. + // Pal is referenced by bitmap and goes away. + // BmpCopy goes out of scope here and is marked for garbage + // collection. Force it, because it is probably quite large. + // The same applies to bitmap. + bmpCopy.Dispose(); + bitmap.Dispose(); + + } + + public static void FileRename(string folder, int startindex) + { + if (!Directory.Exists(folder)) + { + return; + } + + var files = Directory.GetFiles(folder, "*.bmp", SearchOption.AllDirectories); + var dicts = new Dictionary(files.Length); + foreach (var file in files) + { + string str_id; + int int_id; + + if (Path.GetFileNameWithoutExtension(file)[1] == '0' && Path.GetFileNameWithoutExtension(file)[2] == 'x') + { + str_id = Path.GetFileNameWithoutExtension(file).Substring(3); + if (int.TryParse(str_id, NumberStyles.HexNumber, null, out int_id)) + { + dicts.Add(int_id, file); + } + } + else + { + str_id = Path.GetFileNameWithoutExtension(file).Substring(1); + if (int.TryParse(str_id, NumberStyles.Integer, null, out int_id)) + { + dicts.Add(int_id, file); + } + } + } + + var keys = new List(dicts.Keys); + keys.Sort(); + + foreach (int key in keys) + { + var outf = Path.Combine(Path.Combine(folder, "__RENAMED__"), Path.GetDirectoryName(dicts[key]).Substring(folder.Length)); + var outn = $"{Path.GetFileName(dicts[key])[0]}0x{++startindex:X2}.{Path.GetExtension(dicts[key])}"; + Directory.CreateDirectory(outf); + File.Move(dicts[key], Path.Combine(outf, outn)); + } + } + } + + //public class MyEventArgs : EventArgs + //{ + // public enum TYPES + // { + // COMMON = 0, + // FORCERELOAD + // } + // public TYPES Type { get; private set; } + // public MyEventArgs() { Type = TYPES.COMMON; } + // public MyEventArgs(TYPES type) { Type = type; } + //} +} diff --git a/UoFiddler.Plugin.Compare/ComparePluginBase.cs b/UoFiddler.Plugin.Compare/ComparePluginBase.cs index 237bb11f..dbb4f494 100644 --- a/UoFiddler.Plugin.Compare/ComparePluginBase.cs +++ b/UoFiddler.Plugin.Compare/ComparePluginBase.cs @@ -34,7 +34,9 @@ public class ComparePluginBase : PluginBase + "Compares 2 Map files\r\n" + "Compares 2 Gump files\r\n" + "Compares 2 Texture files\r\n" - + "(Adds 7 new Tabs)"; + + "Compares 2 AnimData files\r\n" + + "Compares 2 RadarCol files\r\n" + + "(Adds 9 new Tabs)"; /// /// Author of the plugin @@ -133,6 +135,7 @@ public override void ModifyTabPages(TabControl tabControl) }; page6.Controls.Add(compM); tabControl.TabPages.Add(page6); + TabPage page7 = new TabPage { Tag = tabControl.TabCount + 1, @@ -144,6 +147,42 @@ public override void ModifyTabPages(TabControl tabControl) }; page7.Controls.Add(compTextureControl); tabControl.TabPages.Add(page7); + + TabPage page8 = new TabPage + { + Tag = tabControl.TabCount + 1, + Text = "Compare AnimData" + }; + CompareAnimDataControl compAnimData = new CompareAnimDataControl + { + Dock = DockStyle.Fill + }; + page8.Controls.Add(compAnimData); + tabControl.TabPages.Add(page8); + + TabPage page9 = new TabPage + { + Tag = tabControl.TabCount + 1, + Text = "Compare RadarCol" + }; + CompareRadarColControl compRadarCol = new CompareRadarColControl + { + Dock = DockStyle.Fill + }; + page9.Controls.Add(compRadarCol); + tabControl.TabPages.Add(page9); + + TabPage page10 = new TabPage + { + Tag = tabControl.TabCount + 1, + Text = "Compare TileData" + }; + CompareTileDataControl compTileDataControl = new CompareTileDataControl + { + Dock = DockStyle.Fill + }; + page10.Controls.Add(compTileDataControl); + tabControl.TabPages.Add(page10); } public override void ModifyPluginToolStrip(ToolStripDropDownButton toolStrip) diff --git a/UoFiddler.Plugin.Compare/UoFiddler.Plugin.Compare.csproj b/UoFiddler.Plugin.Compare/UoFiddler.Plugin.Compare.csproj index 58436a67..67a48ff1 100644 --- a/UoFiddler.Plugin.Compare/UoFiddler.Plugin.Compare.csproj +++ b/UoFiddler.Plugin.Compare/UoFiddler.Plugin.Compare.csproj @@ -69,6 +69,18 @@ CompareTextureControl.cs + + UserControl + + + CompareAnimDataControl.cs + + + UserControl + + + CompareRadarColControl.cs + True True @@ -107,6 +119,12 @@ CompareTextureControl.cs + + CompareAnimDataControl.cs + + + CompareRadarColControl.cs + ResXFileCodeGenerator Resources.Designer.cs diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.Designer.cs b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.Designer.cs new file mode 100644 index 00000000..72337c24 --- /dev/null +++ b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.Designer.cs @@ -0,0 +1,587 @@ +namespace UoFiddler.Plugin.Compare.UserControls +{ + partial class CompareAnimDataControl + { + private System.ComponentModel.IContainer components = null; + + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + splitContainer1 = new System.Windows.Forms.SplitContainer(); + tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + tileViewOrg = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + panelDetail = new System.Windows.Forms.Panel(); + groupBoxLegend = new System.Windows.Forms.GroupBox(); + legendSwatchOnlyInOrg = new System.Windows.Forms.Label(); + legendLabelOnlyInOrg = new System.Windows.Forms.Label(); + legendSwatchOnlyInSecond = new System.Windows.Forms.Label(); + legendLabelOnlyInSecond = new System.Windows.Forms.Label(); + legendSwatchDifferent = new System.Windows.Forms.Label(); + legendLabelDifferent = new System.Windows.Forms.Label(); + legendSwatchIdentical = new System.Windows.Forms.Label(); + legendLabelIdentical = new System.Windows.Forms.Label(); + groupBoxSec = new System.Windows.Forms.GroupBox(); + labelSecFrameCountCaption = new System.Windows.Forms.Label(); + labelSecFrameIntervalCaption = new System.Windows.Forms.Label(); + labelSecFrameStartCaption = new System.Windows.Forms.Label(); + labelSecFrameDataCaption = new System.Windows.Forms.Label(); + labelSecFrameCount = new System.Windows.Forms.Label(); + labelSecFrameInterval = new System.Windows.Forms.Label(); + labelSecFrameStart = new System.Windows.Forms.Label(); + labelSecFrameData = new System.Windows.Forms.Label(); + groupBoxOrg = new System.Windows.Forms.GroupBox(); + labelOrgFrameCountCaption = new System.Windows.Forms.Label(); + labelOrgFrameIntervalCaption = new System.Windows.Forms.Label(); + labelOrgFrameStartCaption = new System.Windows.Forms.Label(); + labelOrgFrameDataCaption = new System.Windows.Forms.Label(); + labelOrgFrameCount = new System.Windows.Forms.Label(); + labelOrgFrameInterval = new System.Windows.Forms.Label(); + labelOrgFrameStart = new System.Windows.Forms.Label(); + labelOrgFrameData = new System.Windows.Forms.Label(); + tileViewSec = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(components); + copyEntryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + buttonCopyAddedOnly = new System.Windows.Forms.Button(); + buttonCopyAllDiff = new System.Windows.Forms.Button(); + buttonCopySelected = new System.Windows.Forms.Button(); + checkBoxShowDiff = new System.Windows.Forms.CheckBox(); + buttonLoadSecond = new System.Windows.Forms.Button(); + buttonBrowse = new System.Windows.Forms.Button(); + textBoxSecondFile = new System.Windows.Forms.TextBox(); + ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); + splitContainer1.Panel1.SuspendLayout(); + splitContainer1.Panel2.SuspendLayout(); + splitContainer1.SuspendLayout(); + tableLayoutPanel1.SuspendLayout(); + panelDetail.SuspendLayout(); + groupBoxLegend.SuspendLayout(); + groupBoxSec.SuspendLayout(); + groupBoxOrg.SuspendLayout(); + contextMenuStrip1.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.Name = "splitContainer1"; + splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainer1.Panel1 + // + splitContainer1.Panel1.Controls.Add(tableLayoutPanel1); + // + // splitContainer1.Panel2 + // + splitContainer1.Panel2.Controls.Add(buttonCopyAddedOnly); + splitContainer1.Panel2.Controls.Add(buttonCopyAllDiff); + splitContainer1.Panel2.Controls.Add(buttonCopySelected); + splitContainer1.Panel2.Controls.Add(checkBoxShowDiff); + splitContainer1.Panel2.Controls.Add(buttonLoadSecond); + splitContainer1.Panel2.Controls.Add(buttonBrowse); + splitContainer1.Panel2.Controls.Add(textBoxSecondFile); + splitContainer1.Size = new System.Drawing.Size(900, 510); + splitContainer1.SplitterDistance = 454; + splitContainer1.SplitterWidth = 5; + splitContainer1.TabIndex = 0; + // + // tableLayoutPanel1 + // + tableLayoutPanel1.ColumnCount = 3; + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + tableLayoutPanel1.Controls.Add(tileViewOrg, 0, 0); + tableLayoutPanel1.Controls.Add(panelDetail, 1, 0); + tableLayoutPanel1.Controls.Add(tileViewSec, 2, 0); + tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 1; + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + tableLayoutPanel1.Size = new System.Drawing.Size(900, 454); + tableLayoutPanel1.TabIndex = 0; + // + // tileViewOrg + // + tileViewOrg.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewOrg.Location = new System.Drawing.Point(3, 3); + tileViewOrg.Name = "tileViewOrg"; + tileViewOrg.Size = new System.Drawing.Size(219, 448); + tileViewOrg.TabIndex = 0; + tileViewOrg.TileSize = new System.Drawing.Size(219, 15); + tileViewOrg.TileMargin = new System.Windows.Forms.Padding(0); + tileViewOrg.TilePadding = new System.Windows.Forms.Padding(0); + tileViewOrg.TileBorderWidth = 0f; + tileViewOrg.TileHighLightOpacity = 0.0; + tileViewOrg.DrawItem += new System.EventHandler(OnDrawItemOrg); + tileViewOrg.FocusSelectionChanged += new System.EventHandler(OnFocusChangedOrg); + tileViewOrg.SizeChanged += new System.EventHandler(OnTileViewSizeChanged); + // + // panelDetail + // + panelDetail.Controls.Add(groupBoxLegend); + panelDetail.Controls.Add(groupBoxSec); + panelDetail.Controls.Add(groupBoxOrg); + panelDetail.Dock = System.Windows.Forms.DockStyle.Fill; + panelDetail.Location = new System.Drawing.Point(228, 3); + panelDetail.Name = "panelDetail"; + panelDetail.Size = new System.Drawing.Size(444, 448); + panelDetail.TabIndex = 1; + // + // groupBoxLegend + // + groupBoxLegend.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + groupBoxLegend.Controls.Add(legendSwatchOnlyInOrg); + groupBoxLegend.Controls.Add(legendLabelOnlyInOrg); + groupBoxLegend.Controls.Add(legendSwatchOnlyInSecond); + groupBoxLegend.Controls.Add(legendLabelOnlyInSecond); + groupBoxLegend.Controls.Add(legendSwatchDifferent); + groupBoxLegend.Controls.Add(legendLabelDifferent); + groupBoxLegend.Controls.Add(legendSwatchIdentical); + groupBoxLegend.Controls.Add(legendLabelIdentical); + groupBoxLegend.Location = new System.Drawing.Point(6, 310); + groupBoxLegend.Name = "groupBoxLegend"; + groupBoxLegend.Size = new System.Drawing.Size(432, 125); + groupBoxLegend.TabIndex = 2; + groupBoxLegend.TabStop = false; + groupBoxLegend.Text = "Legend"; + // + // legendSwatchOnlyInOrg + // + legendSwatchOnlyInOrg.BackColor = System.Drawing.Color.Orange; + legendSwatchOnlyInOrg.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + legendSwatchOnlyInOrg.Location = new System.Drawing.Point(8, 22); + legendSwatchOnlyInOrg.Name = "legendSwatchOnlyInOrg"; + legendSwatchOnlyInOrg.Size = new System.Drawing.Size(16, 16); + legendSwatchOnlyInOrg.TabIndex = 0; + // + // legendLabelOnlyInOrg + // + legendLabelOnlyInOrg.AutoSize = true; + legendLabelOnlyInOrg.Location = new System.Drawing.Point(30, 23); + legendLabelOnlyInOrg.Name = "legendLabelOnlyInOrg"; + legendLabelOnlyInOrg.Size = new System.Drawing.Size(88, 15); + legendLabelOnlyInOrg.TabIndex = 1; + legendLabelOnlyInOrg.Text = "Only in original"; + // + // legendSwatchOnlyInSecond + // + legendSwatchOnlyInSecond.BackColor = System.Drawing.Color.Green; + legendSwatchOnlyInSecond.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + legendSwatchOnlyInSecond.Location = new System.Drawing.Point(8, 46); + legendSwatchOnlyInSecond.Name = "legendSwatchOnlyInSecond"; + legendSwatchOnlyInSecond.Size = new System.Drawing.Size(16, 16); + legendSwatchOnlyInSecond.TabIndex = 2; + // + // legendLabelOnlyInSecond + // + legendLabelOnlyInSecond.AutoSize = true; + legendLabelOnlyInSecond.Location = new System.Drawing.Point(30, 47); + legendLabelOnlyInSecond.Name = "legendLabelOnlyInSecond"; + legendLabelOnlyInSecond.Size = new System.Drawing.Size(86, 15); + legendLabelOnlyInSecond.TabIndex = 3; + legendLabelOnlyInSecond.Text = "Only in second"; + // + // legendSwatchDifferent + // + legendSwatchDifferent.BackColor = System.Drawing.Color.Blue; + legendSwatchDifferent.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + legendSwatchDifferent.Location = new System.Drawing.Point(8, 70); + legendSwatchDifferent.Name = "legendSwatchDifferent"; + legendSwatchDifferent.Size = new System.Drawing.Size(16, 16); + legendSwatchDifferent.TabIndex = 4; + // + // legendLabelDifferent + // + legendLabelDifferent.AutoSize = true; + legendLabelDifferent.Location = new System.Drawing.Point(30, 71); + legendLabelDifferent.Name = "legendLabelDifferent"; + legendLabelDifferent.Size = new System.Drawing.Size(89, 15); + legendLabelDifferent.TabIndex = 5; + legendLabelDifferent.Text = "Different values"; + // + // legendSwatchIdentical + // + legendSwatchIdentical.BackColor = System.Drawing.Color.Gray; + legendSwatchIdentical.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + legendSwatchIdentical.Location = new System.Drawing.Point(8, 96); + legendSwatchIdentical.Name = "legendSwatchIdentical"; + legendSwatchIdentical.Size = new System.Drawing.Size(16, 16); + legendSwatchIdentical.TabIndex = 6; + // + // legendLabelIdentical + // + legendLabelIdentical.AutoSize = true; + legendLabelIdentical.Location = new System.Drawing.Point(30, 97); + legendLabelIdentical.Name = "legendLabelIdentical"; + legendLabelIdentical.Size = new System.Drawing.Size(52, 15); + legendLabelIdentical.TabIndex = 7; + legendLabelIdentical.Text = "Identical"; + // + // groupBoxSec + // + groupBoxSec.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + groupBoxSec.Controls.Add(labelSecFrameCountCaption); + groupBoxSec.Controls.Add(labelSecFrameIntervalCaption); + groupBoxSec.Controls.Add(labelSecFrameStartCaption); + groupBoxSec.Controls.Add(labelSecFrameDataCaption); + groupBoxSec.Controls.Add(labelSecFrameCount); + groupBoxSec.Controls.Add(labelSecFrameInterval); + groupBoxSec.Controls.Add(labelSecFrameStart); + groupBoxSec.Controls.Add(labelSecFrameData); + groupBoxSec.Location = new System.Drawing.Point(6, 158); + groupBoxSec.Name = "groupBoxSec"; + groupBoxSec.Size = new System.Drawing.Size(432, 140); + groupBoxSec.TabIndex = 1; + groupBoxSec.TabStop = false; + groupBoxSec.Text = "Right (Second)"; + // + // labelSecFrameCountCaption + // + labelSecFrameCountCaption.AutoSize = true; + labelSecFrameCountCaption.Location = new System.Drawing.Point(6, 22); + labelSecFrameCountCaption.Name = "labelSecFrameCountCaption"; + labelSecFrameCountCaption.Size = new System.Drawing.Size(79, 15); + labelSecFrameCountCaption.TabIndex = 0; + labelSecFrameCountCaption.Text = "Frame Count:"; + // + // labelSecFrameIntervalCaption + // + labelSecFrameIntervalCaption.AutoSize = true; + labelSecFrameIntervalCaption.Location = new System.Drawing.Point(6, 44); + labelSecFrameIntervalCaption.Name = "labelSecFrameIntervalCaption"; + labelSecFrameIntervalCaption.Size = new System.Drawing.Size(85, 15); + labelSecFrameIntervalCaption.TabIndex = 2; + labelSecFrameIntervalCaption.Text = "Frame Interval:"; + // + // labelSecFrameStartCaption + // + labelSecFrameStartCaption.AutoSize = true; + labelSecFrameStartCaption.Location = new System.Drawing.Point(6, 66); + labelSecFrameStartCaption.Name = "labelSecFrameStartCaption"; + labelSecFrameStartCaption.Size = new System.Drawing.Size(70, 15); + labelSecFrameStartCaption.TabIndex = 4; + labelSecFrameStartCaption.Text = "Frame Start:"; + // + // labelSecFrameDataCaption + // + labelSecFrameDataCaption.AutoSize = true; + labelSecFrameDataCaption.Location = new System.Drawing.Point(6, 88); + labelSecFrameDataCaption.Name = "labelSecFrameDataCaption"; + labelSecFrameDataCaption.Size = new System.Drawing.Size(70, 15); + labelSecFrameDataCaption.TabIndex = 6; + labelSecFrameDataCaption.Text = "Frame Data:"; + // + // labelSecFrameCount + // + labelSecFrameCount.AutoSize = true; + labelSecFrameCount.Location = new System.Drawing.Point(120, 22); + labelSecFrameCount.Name = "labelSecFrameCount"; + labelSecFrameCount.Size = new System.Drawing.Size(12, 15); + labelSecFrameCount.TabIndex = 1; + labelSecFrameCount.Text = "-"; + // + // labelSecFrameInterval + // + labelSecFrameInterval.AutoSize = true; + labelSecFrameInterval.Location = new System.Drawing.Point(120, 44); + labelSecFrameInterval.Name = "labelSecFrameInterval"; + labelSecFrameInterval.Size = new System.Drawing.Size(12, 15); + labelSecFrameInterval.TabIndex = 3; + labelSecFrameInterval.Text = "-"; + // + // labelSecFrameStart + // + labelSecFrameStart.AutoSize = true; + labelSecFrameStart.Location = new System.Drawing.Point(120, 66); + labelSecFrameStart.Name = "labelSecFrameStart"; + labelSecFrameStart.Size = new System.Drawing.Size(12, 15); + labelSecFrameStart.TabIndex = 5; + labelSecFrameStart.Text = "-"; + // + // labelSecFrameData + // + labelSecFrameData.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + labelSecFrameData.Location = new System.Drawing.Point(120, 88); + labelSecFrameData.Name = "labelSecFrameData"; + labelSecFrameData.Size = new System.Drawing.Size(300, 44); + labelSecFrameData.TabIndex = 7; + labelSecFrameData.Text = "-"; + // + // groupBoxOrg + // + groupBoxOrg.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + groupBoxOrg.Controls.Add(labelOrgFrameCountCaption); + groupBoxOrg.Controls.Add(labelOrgFrameIntervalCaption); + groupBoxOrg.Controls.Add(labelOrgFrameStartCaption); + groupBoxOrg.Controls.Add(labelOrgFrameDataCaption); + groupBoxOrg.Controls.Add(labelOrgFrameCount); + groupBoxOrg.Controls.Add(labelOrgFrameInterval); + groupBoxOrg.Controls.Add(labelOrgFrameStart); + groupBoxOrg.Controls.Add(labelOrgFrameData); + groupBoxOrg.Location = new System.Drawing.Point(6, 6); + groupBoxOrg.Name = "groupBoxOrg"; + groupBoxOrg.Size = new System.Drawing.Size(432, 140); + groupBoxOrg.TabIndex = 0; + groupBoxOrg.TabStop = false; + groupBoxOrg.Text = "Left (Original)"; + // + // labelOrgFrameCountCaption + // + labelOrgFrameCountCaption.AutoSize = true; + labelOrgFrameCountCaption.Location = new System.Drawing.Point(6, 22); + labelOrgFrameCountCaption.Name = "labelOrgFrameCountCaption"; + labelOrgFrameCountCaption.Size = new System.Drawing.Size(79, 15); + labelOrgFrameCountCaption.TabIndex = 0; + labelOrgFrameCountCaption.Text = "Frame Count:"; + // + // labelOrgFrameIntervalCaption + // + labelOrgFrameIntervalCaption.AutoSize = true; + labelOrgFrameIntervalCaption.Location = new System.Drawing.Point(6, 44); + labelOrgFrameIntervalCaption.Name = "labelOrgFrameIntervalCaption"; + labelOrgFrameIntervalCaption.Size = new System.Drawing.Size(85, 15); + labelOrgFrameIntervalCaption.TabIndex = 2; + labelOrgFrameIntervalCaption.Text = "Frame Interval:"; + // + // labelOrgFrameStartCaption + // + labelOrgFrameStartCaption.AutoSize = true; + labelOrgFrameStartCaption.Location = new System.Drawing.Point(6, 66); + labelOrgFrameStartCaption.Name = "labelOrgFrameStartCaption"; + labelOrgFrameStartCaption.Size = new System.Drawing.Size(70, 15); + labelOrgFrameStartCaption.TabIndex = 4; + labelOrgFrameStartCaption.Text = "Frame Start:"; + // + // labelOrgFrameDataCaption + // + labelOrgFrameDataCaption.AutoSize = true; + labelOrgFrameDataCaption.Location = new System.Drawing.Point(6, 88); + labelOrgFrameDataCaption.Name = "labelOrgFrameDataCaption"; + labelOrgFrameDataCaption.Size = new System.Drawing.Size(70, 15); + labelOrgFrameDataCaption.TabIndex = 6; + labelOrgFrameDataCaption.Text = "Frame Data:"; + // + // labelOrgFrameCount + // + labelOrgFrameCount.AutoSize = true; + labelOrgFrameCount.Location = new System.Drawing.Point(120, 22); + labelOrgFrameCount.Name = "labelOrgFrameCount"; + labelOrgFrameCount.Size = new System.Drawing.Size(12, 15); + labelOrgFrameCount.TabIndex = 1; + labelOrgFrameCount.Text = "-"; + // + // labelOrgFrameInterval + // + labelOrgFrameInterval.AutoSize = true; + labelOrgFrameInterval.Location = new System.Drawing.Point(120, 44); + labelOrgFrameInterval.Name = "labelOrgFrameInterval"; + labelOrgFrameInterval.Size = new System.Drawing.Size(12, 15); + labelOrgFrameInterval.TabIndex = 3; + labelOrgFrameInterval.Text = "-"; + // + // labelOrgFrameStart + // + labelOrgFrameStart.AutoSize = true; + labelOrgFrameStart.Location = new System.Drawing.Point(120, 66); + labelOrgFrameStart.Name = "labelOrgFrameStart"; + labelOrgFrameStart.Size = new System.Drawing.Size(12, 15); + labelOrgFrameStart.TabIndex = 5; + labelOrgFrameStart.Text = "-"; + // + // labelOrgFrameData + // + labelOrgFrameData.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + labelOrgFrameData.Location = new System.Drawing.Point(120, 88); + labelOrgFrameData.Name = "labelOrgFrameData"; + labelOrgFrameData.Size = new System.Drawing.Size(300, 44); + labelOrgFrameData.TabIndex = 7; + labelOrgFrameData.Text = "-"; + // + // tileViewSec + // + tileViewSec.ContextMenuStrip = contextMenuStrip1; + tileViewSec.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewSec.Location = new System.Drawing.Point(678, 3); + tileViewSec.Name = "tileViewSec"; + tileViewSec.Size = new System.Drawing.Size(219, 448); + tileViewSec.TabIndex = 2; + tileViewSec.TileSize = new System.Drawing.Size(219, 15); + tileViewSec.TileMargin = new System.Windows.Forms.Padding(0); + tileViewSec.TilePadding = new System.Windows.Forms.Padding(0); + tileViewSec.TileBorderWidth = 0f; + tileViewSec.TileHighLightOpacity = 0.0; + tileViewSec.DrawItem += new System.EventHandler(OnDrawItemSec); + tileViewSec.FocusSelectionChanged += new System.EventHandler(OnFocusChangedSec); + tileViewSec.SizeChanged += new System.EventHandler(OnTileViewSizeChanged); + tileViewSec.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(OnDoubleClickSec); + // + // contextMenuStrip1 + // + contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { copyEntryToolStripMenuItem }); + contextMenuStrip1.Name = "contextMenuStrip1"; + contextMenuStrip1.Size = new System.Drawing.Size(165, 26); + // + // copyEntryToolStripMenuItem + // + copyEntryToolStripMenuItem.Name = "copyEntryToolStripMenuItem"; + copyEntryToolStripMenuItem.Size = new System.Drawing.Size(164, 22); + copyEntryToolStripMenuItem.Text = "Copy Entry 2 to 1"; + copyEntryToolStripMenuItem.Click += OnClickCopySelected; + // + // buttonCopyAddedOnly + // + buttonCopyAddedOnly.Location = new System.Drawing.Point(755, 11); + buttonCopyAddedOnly.Name = "buttonCopyAddedOnly"; + buttonCopyAddedOnly.Size = new System.Drawing.Size(100, 27); + buttonCopyAddedOnly.TabIndex = 6; + buttonCopyAddedOnly.Text = "Copy Added Only"; + buttonCopyAddedOnly.UseVisualStyleBackColor = true; + buttonCopyAddedOnly.Click += OnClickCopyAddedOnly; + // + // buttonCopyAllDiff + // + buttonCopyAllDiff.Location = new System.Drawing.Point(659, 11); + buttonCopyAllDiff.Name = "buttonCopyAllDiff"; + buttonCopyAllDiff.Size = new System.Drawing.Size(90, 27); + buttonCopyAllDiff.TabIndex = 5; + buttonCopyAllDiff.Text = "Copy All Diff"; + buttonCopyAllDiff.UseVisualStyleBackColor = true; + buttonCopyAllDiff.Click += OnClickCopyAllDiff; + // + // buttonCopySelected + // + buttonCopySelected.Location = new System.Drawing.Point(563, 11); + buttonCopySelected.Name = "buttonCopySelected"; + buttonCopySelected.Size = new System.Drawing.Size(90, 27); + buttonCopySelected.TabIndex = 4; + buttonCopySelected.Text = "Copy Selected"; + buttonCopySelected.UseVisualStyleBackColor = true; + buttonCopySelected.Click += OnClickCopySelected; + // + // checkBoxShowDiff + // + checkBoxShowDiff.AutoSize = true; + checkBoxShowDiff.Location = new System.Drawing.Point(408, 15); + checkBoxShowDiff.Name = "checkBoxShowDiff"; + checkBoxShowDiff.Size = new System.Drawing.Size(143, 19); + checkBoxShowDiff.TabIndex = 3; + checkBoxShowDiff.Text = "Show only Differences"; + checkBoxShowDiff.UseVisualStyleBackColor = true; + checkBoxShowDiff.Click += OnChangeShowDiff; + // + // buttonLoadSecond + // + buttonLoadSecond.AutoSize = true; + buttonLoadSecond.Location = new System.Drawing.Point(306, 11); + buttonLoadSecond.Name = "buttonLoadSecond"; + buttonLoadSecond.Size = new System.Drawing.Size(90, 27); + buttonLoadSecond.TabIndex = 2; + buttonLoadSecond.Text = "Load Second"; + buttonLoadSecond.UseVisualStyleBackColor = true; + buttonLoadSecond.Click += OnClickLoadSecond; + // + // buttonBrowse + // + buttonBrowse.AutoSize = true; + buttonBrowse.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + buttonBrowse.Location = new System.Drawing.Point(272, 13); + buttonBrowse.Name = "buttonBrowse"; + buttonBrowse.Size = new System.Drawing.Size(26, 25); + buttonBrowse.TabIndex = 1; + buttonBrowse.Text = "..."; + buttonBrowse.UseVisualStyleBackColor = true; + buttonBrowse.Click += OnClickBrowse; + // + // textBoxSecondFile + // + textBoxSecondFile.Location = new System.Drawing.Point(6, 15); + textBoxSecondFile.Name = "textBoxSecondFile"; + textBoxSecondFile.Size = new System.Drawing.Size(260, 23); + textBoxSecondFile.TabIndex = 0; + // + // CompareAnimDataControl + // + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + Controls.Add(splitContainer1); + DoubleBuffered = true; + Name = "CompareAnimDataControl"; + Size = new System.Drawing.Size(900, 510); + Load += OnLoad; + splitContainer1.Panel1.ResumeLayout(false); + splitContainer1.Panel2.ResumeLayout(false); + splitContainer1.Panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); + splitContainer1.ResumeLayout(false); + tableLayoutPanel1.ResumeLayout(false); + panelDetail.ResumeLayout(false); + groupBoxLegend.ResumeLayout(false); + groupBoxLegend.PerformLayout(); + groupBoxSec.ResumeLayout(false); + groupBoxSec.PerformLayout(); + groupBoxOrg.ResumeLayout(false); + groupBoxOrg.PerformLayout(); + contextMenuStrip1.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewOrg; + private System.Windows.Forms.Panel panelDetail; + private System.Windows.Forms.GroupBox groupBoxOrg; + private System.Windows.Forms.Label labelOrgFrameCountCaption; + private System.Windows.Forms.Label labelOrgFrameCount; + private System.Windows.Forms.Label labelOrgFrameIntervalCaption; + private System.Windows.Forms.Label labelOrgFrameInterval; + private System.Windows.Forms.Label labelOrgFrameStartCaption; + private System.Windows.Forms.Label labelOrgFrameStart; + private System.Windows.Forms.Label labelOrgFrameDataCaption; + private System.Windows.Forms.Label labelOrgFrameData; + private System.Windows.Forms.GroupBox groupBoxSec; + private System.Windows.Forms.Label labelSecFrameCountCaption; + private System.Windows.Forms.Label labelSecFrameCount; + private System.Windows.Forms.Label labelSecFrameIntervalCaption; + private System.Windows.Forms.Label labelSecFrameInterval; + private System.Windows.Forms.Label labelSecFrameStartCaption; + private System.Windows.Forms.Label labelSecFrameStart; + private System.Windows.Forms.Label labelSecFrameDataCaption; + private System.Windows.Forms.Label labelSecFrameData; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewSec; + private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; + private System.Windows.Forms.ToolStripMenuItem copyEntryToolStripMenuItem; + private System.Windows.Forms.TextBox textBoxSecondFile; + private System.Windows.Forms.Button buttonBrowse; + private System.Windows.Forms.Button buttonLoadSecond; + private System.Windows.Forms.CheckBox checkBoxShowDiff; + private System.Windows.Forms.Button buttonCopySelected; + private System.Windows.Forms.Button buttonCopyAllDiff; + private System.Windows.Forms.Button buttonCopyAddedOnly; + private System.Windows.Forms.GroupBox groupBoxLegend; + private System.Windows.Forms.Label legendSwatchOnlyInOrg; + private System.Windows.Forms.Label legendLabelOnlyInOrg; + private System.Windows.Forms.Label legendSwatchOnlyInSecond; + private System.Windows.Forms.Label legendLabelOnlyInSecond; + private System.Windows.Forms.Label legendSwatchDifferent; + private System.Windows.Forms.Label legendLabelDifferent; + private System.Windows.Forms.Label legendSwatchIdentical; + private System.Windows.Forms.Label legendLabelIdentical; + } +} diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs new file mode 100644 index 00000000..31aff792 --- /dev/null +++ b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.cs @@ -0,0 +1,432 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using Ultima; +using UoFiddler.Controls.Classes; +using UoFiddler.Controls.UserControls.TileView; +using UoFiddler.Plugin.Compare.Classes; + +namespace UoFiddler.Plugin.Compare.UserControls +{ + public partial class CompareAnimDataControl : UserControl + { + public CompareAnimDataControl() + { + InitializeComponent(); + } + + private readonly Dictionary _compare = new Dictionary(); + private readonly List _displayIndices = new List(); + private bool _syncingSelection; + + private void OnLoad(object sender, EventArgs e) + { + PopulateOrgList(); + ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; + } + + private void OnFilePathChangeEvent() + { + _compare.Clear(); + PopulateOrgList(); + } + + private void PopulateOrgList() + { + _displayIndices.Clear(); + foreach (int id in Animdata.AnimData.Keys.OrderBy(k => k)) + { + _displayIndices.Add(id); + } + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = 0; + } + + private void OnTileViewSizeChanged(object sender, EventArgs e) + { + var tv = (TileViewControl)sender; + int w = tv.DisplayRectangle.Width; + if (w > 0 && tv.TileSize.Width != w) + { + tv.TileSize = new Size(w, tv.TileSize.Height); + } + } + + private void OnDrawItemOrg(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawListItem(e, _displayIndices[e.Index]); + } + + private void OnDrawItemSec(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawListItem(e, _displayIndices[e.Index]); + } + + private void DrawListItem(DrawItemEventArgs e, int id) + { + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds); + } + else + { + e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds); + } + + Brush fontBrush = GetEntryBrush(id); + string text = $"0x{id:X4} ({id})"; + float y = e.Bounds.Y + (e.Bounds.Height - e.Graphics.MeasureString(text, e.Font).Height) / 2f; + e.Graphics.DrawString(text, e.Font, fontBrush, new PointF(4, y)); + } + + private Brush GetEntryBrush(int id) + { + bool inOrg = Animdata.AnimData.ContainsKey(id); + bool inSec = SecondAnimdata.IsLoaded && SecondAnimdata.GetAnimData(id) != null; + + if (SecondAnimdata.IsLoaded) + { + if (inOrg && !inSec) + { + return Brushes.Orange; + } + + if (!inOrg && inSec) + { + return Brushes.Green; + } + + if (inOrg && inSec && !Compare(id)) + { + return Brushes.Blue; + } + } + + return Brushes.Gray; + } + + private void OnFocusChangedOrg(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int id = _displayIndices[e.FocusedItemIndex]; + + if (SecondAnimdata.IsLoaded && tileViewSec.VirtualListSize > 0) + { + if (_syncingSelection) + { + return; + } + + _syncingSelection = true; + try + { + tileViewSec.FocusIndex = e.FocusedItemIndex; + } + finally + { + _syncingSelection = false; + } + } + + UpdateDetailPanel(id); + tileViewOrg.Invalidate(); + } + + private void OnFocusChangedSec(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int id = _displayIndices[e.FocusedItemIndex]; + + if (_syncingSelection) + { + return; + } + + _syncingSelection = true; + try + { + tileViewOrg.FocusIndex = e.FocusedItemIndex; + } + finally + { + _syncingSelection = false; + } + + UpdateDetailPanel(id); + tileViewSec.Invalidate(); + } + + private void UpdateDetailPanel(int id) + { + var orgEntry = Animdata.GetAnimData(id); + var secEntry = SecondAnimdata.GetAnimData(id); + + if (orgEntry != null) + { + labelOrgFrameCount.Text = orgEntry.FrameCount.ToString(); + labelOrgFrameInterval.Text = orgEntry.FrameInterval.ToString(); + labelOrgFrameStart.Text = orgEntry.FrameStart.ToString(); + labelOrgFrameData.Text = FormatFrameData(orgEntry.FrameData, orgEntry.FrameCount); + } + else + { + labelOrgFrameCount.Text = "-"; + labelOrgFrameInterval.Text = "-"; + labelOrgFrameStart.Text = "-"; + labelOrgFrameData.Text = "-"; + } + + if (secEntry != null) + { + labelSecFrameCount.Text = secEntry.FrameCount.ToString(); + labelSecFrameInterval.Text = secEntry.FrameInterval.ToString(); + labelSecFrameStart.Text = secEntry.FrameStart.ToString(); + labelSecFrameData.Text = FormatFrameData(secEntry.FrameData, secEntry.FrameCount); + } + else + { + labelSecFrameCount.Text = "-"; + labelSecFrameInterval.Text = "-"; + labelSecFrameStart.Text = "-"; + labelSecFrameData.Text = "-"; + } + } + + private static string FormatFrameData(sbyte[] data, byte count) + { + if (data == null || count == 0) + { + return "-"; + } + + int len = Math.Min(count, data.Length); + return string.Join(", ", data.Take(len)); + } + + private void OnClickBrowse(object sender, EventArgs e) + { + using (OpenFileDialog dialog = new OpenFileDialog()) + { + dialog.Title = "Select animdata.mul"; + dialog.Filter = "animdata.mul|animdata.mul|All files (*.*)|*.*"; + dialog.FileName = "animdata.mul"; + if (dialog.ShowDialog() == DialogResult.OK) + { + textBoxSecondFile.Text = dialog.FileName; + } + } + } + + private void OnClickLoadSecond(object sender, EventArgs e) + { + string path = textBoxSecondFile.Text?.Trim(); + if (string.IsNullOrEmpty(path)) + { + return; + } + + if (!SecondAnimdata.Initialize(path)) + { + MessageBox.Show("Failed to load the selected animdata.mul file.", "Error", + MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + _compare.Clear(); + RefreshLists(); + } + + private void RefreshLists() + { + var allIds = Animdata.AnimData.Keys + .Union(SecondAnimdata.GetKeys()) + .OrderBy(k => k) + .ToList(); + + _displayIndices.Clear(); + foreach (int id in allIds) + { + _displayIndices.Add(id); + } + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + } + + private void OnChangeShowDiff(object sender, EventArgs e) + { + if (!SecondAnimdata.IsLoaded) + { + if (checkBoxShowDiff.Checked) + { + MessageBox.Show("Second AnimData file is not loaded.", "Info", + MessageBoxButtons.OK, MessageBoxIcon.Information); + checkBoxShowDiff.Checked = false; + } + return; + } + + Cursor.Current = Cursors.WaitCursor; + var allIds = Animdata.AnimData.Keys + .Union(SecondAnimdata.GetKeys()) + .OrderBy(k => k); + + _displayIndices.Clear(); + foreach (int id in allIds) + { + if (!checkBoxShowDiff.Checked || !Compare(id)) + { + _displayIndices.Add(id); + } + } + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; + Cursor.Current = Cursors.Default; + } + + private bool Compare(int id) + { + if (_compare.TryGetValue(id, out bool cached)) + { + return cached; + } + + var e1 = Animdata.GetAnimData(id); + var e2 = SecondAnimdata.GetAnimData(id); + + if (e1 == null && e2 == null) + { + _compare[id] = true; + return true; + } + + if (e1 == null || e2 == null) + { + _compare[id] = false; + return false; + } + + bool same = e1.FrameCount == e2.FrameCount + && e1.FrameInterval == e2.FrameInterval + && e1.FrameStart == e2.FrameStart + && e1.FrameData.SequenceEqual(e2.FrameData); + + _compare[id] = same; + return same; + } + + private void OnDoubleClickSec(object sender, MouseEventArgs e) + { + OnClickCopySelected(sender, e); + } + + private void OnClickCopySelected(object sender, EventArgs e) + { + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) + { + return; + } + + int id = _displayIndices[focusIdx]; + CopyEntry(id); + + if (checkBoxShowDiff.Checked) + { + _displayIndices.RemoveAt(focusIdx); + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; + } + + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + UpdateDetailPanel(id); + } + + private void OnClickCopyAllDiff(object sender, EventArgs e) + { + if (!SecondAnimdata.IsLoaded) + { + return; + } + + bool changed = false; + var allIds = Animdata.AnimData.Keys.Union(SecondAnimdata.GetKeys()).ToList(); + foreach (int id in allIds) + { + if (!Compare(id) && SecondAnimdata.GetAnimData(id) != null) + { + CopyEntry(id); + changed = true; + } + } + + if (changed) + { + if (checkBoxShowDiff.Checked) + { + OnChangeShowDiff(sender, e); + } + + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + } + } + + private void OnClickCopyAddedOnly(object sender, EventArgs e) + { + if (!SecondAnimdata.IsLoaded) + { + return; + } + + bool changed = false; + foreach (int id in SecondAnimdata.GetKeys()) + { + if (!Animdata.AnimData.ContainsKey(id)) + { + CopyEntry(id); + changed = true; + } + } + + if (changed) + { + RefreshLists(); + } + } + + private void CopyEntry(int id) + { + var src = SecondAnimdata.GetAnimData(id); + if (src == null) + { + return; + } + + Animdata.AnimData[id] = new Animdata.AnimdataEntry( + (sbyte[])src.FrameData.Clone(), + src.Unknown, + src.FrameCount, + src.FrameInterval, + src.FrameStart); + + Options.ChangedUltimaClass["Animdata"] = true; + _compare[id] = true; + } + } +} diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.resx b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.resx new file mode 100644 index 00000000..68d1a995 --- /dev/null +++ b/UoFiddler.Plugin.Compare/UserControls/CompareAnimDataControl.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.Designer.cs b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.Designer.cs index 2e014f7b..e6c4671a 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.Designer.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.Designer.cs @@ -40,8 +40,8 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.listBox1 = new System.Windows.Forms.ListBox(); - this.listBox2 = new System.Windows.Forms.ListBox(); + this.tileView1 = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + this.tileView2 = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); this.extractAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.tiffToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -64,41 +64,41 @@ private void InitializeComponent() this.splitContainer1.Panel2.SuspendLayout(); this.splitContainer1.SuspendLayout(); this.SuspendLayout(); - // - // listBox1 - // - this.listBox1.Dock = System.Windows.Forms.DockStyle.Left; - this.listBox1.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.listBox1.FormattingEnabled = true; - this.listBox1.IntegralHeight = false; - this.listBox1.ItemHeight = 60; - this.listBox1.Location = new System.Drawing.Point(0, 0); - this.listBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.listBox1.Name = "listBox1"; - this.listBox1.Size = new System.Drawing.Size(174, 320); - this.listBox1.TabIndex = 0; - this.listBox1.Tag = 1; - this.listBox1.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.Listbox1_DrawItem); - this.listBox1.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.Listbox_measureItem); - this.listBox1.SelectedIndexChanged += new System.EventHandler(this.Listbox_SelectedChange); - // - // listBox2 - // - this.listBox2.ContextMenuStrip = this.contextMenuStrip1; - this.listBox2.Dock = System.Windows.Forms.DockStyle.Right; - this.listBox2.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.listBox2.FormattingEnabled = true; - this.listBox2.IntegralHeight = false; - this.listBox2.ItemHeight = 60; - this.listBox2.Location = new System.Drawing.Point(556, 0); - this.listBox2.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.listBox2.Name = "listBox2"; - this.listBox2.Size = new System.Drawing.Size(174, 320); - this.listBox2.TabIndex = 1; - this.listBox2.Tag = 2; - this.listBox2.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.Listbox1_DrawItem); - this.listBox2.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.Listbox_measureItem); - this.listBox2.SelectedIndexChanged += new System.EventHandler(this.Listbox_SelectedChange); + // + // tileView1 + // + this.tileView1.Dock = System.Windows.Forms.DockStyle.Left; + this.tileView1.Location = new System.Drawing.Point(0, 0); + this.tileView1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.tileView1.Name = "tileView1"; + this.tileView1.Size = new System.Drawing.Size(174, 320); + this.tileView1.TabIndex = 0; + this.tileView1.TileSize = new System.Drawing.Size(174, 60); + this.tileView1.TileMargin = new System.Windows.Forms.Padding(0); + this.tileView1.TilePadding = new System.Windows.Forms.Padding(0); + this.tileView1.TileBorderWidth = 0f; + this.tileView1.TileHighLightOpacity = 0.0; + this.tileView1.DrawItem += new System.EventHandler(this.OnDrawItem1); + this.tileView1.FocusSelectionChanged += new System.EventHandler(this.OnFocusChanged1); + this.tileView1.SizeChanged += new System.EventHandler(this.OnTileViewSizeChanged); + // + // tileView2 + // + this.tileView2.ContextMenuStrip = this.contextMenuStrip1; + this.tileView2.Dock = System.Windows.Forms.DockStyle.Right; + this.tileView2.Location = new System.Drawing.Point(556, 0); + this.tileView2.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.tileView2.Name = "tileView2"; + this.tileView2.Size = new System.Drawing.Size(174, 320); + this.tileView2.TabIndex = 1; + this.tileView2.TileSize = new System.Drawing.Size(174, 60); + this.tileView2.TileMargin = new System.Windows.Forms.Padding(0); + this.tileView2.TilePadding = new System.Windows.Forms.Padding(0); + this.tileView2.TileBorderWidth = 0f; + this.tileView2.TileHighLightOpacity = 0.0; + this.tileView2.DrawItem += new System.EventHandler(this.OnDrawItem2); + this.tileView2.FocusSelectionChanged += new System.EventHandler(this.OnFocusChanged2); + this.tileView2.SizeChanged += new System.EventHandler(this.OnTileViewSizeChanged); // // contextMenuStrip1 // @@ -188,8 +188,8 @@ private void InitializeComponent() // splitContainer1.Panel1 // this.splitContainer1.Panel1.Controls.Add(this.tableLayoutPanel1); - this.splitContainer1.Panel1.Controls.Add(this.listBox2); - this.splitContainer1.Panel1.Controls.Add(this.listBox1); + this.splitContainer1.Panel1.Controls.Add(this.tileView2); + this.splitContainer1.Panel1.Controls.Add(this.tileView1); // // splitContainer1.Panel2 // @@ -278,8 +278,8 @@ private void InitializeComponent() private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; private System.Windows.Forms.ToolStripMenuItem copyGump2To1ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem extractAsToolStripMenuItem; - private System.Windows.Forms.ListBox listBox1; - private System.Windows.Forms.ListBox listBox2; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileView1; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileView2; private System.Windows.Forms.PictureBox pictureBox1; private System.Windows.Forms.PictureBox pictureBox2; private System.Windows.Forms.SplitContainer splitContainer1; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs index a9a550bf..ec66eeac 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareGumpControl.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. * @@ -18,6 +18,7 @@ using System.Windows.Forms; using Ultima; using UoFiddler.Controls.Classes; +using UoFiddler.Controls.UserControls.TileView; using UoFiddler.Plugin.Compare.Classes; namespace UoFiddler.Plugin.Compare.UserControls @@ -27,12 +28,12 @@ public partial class CompareGumpControl : UserControl public CompareGumpControl() { InitializeComponent(); - SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true); } private readonly Dictionary _compare = new Dictionary(); private readonly SHA256 _sha256 = SHA256.Create(); - + private readonly List _displayIndices = new List(); + private bool _syncingSelection; private bool _loaded; private void OnLoad(object sender, EventArgs e) @@ -40,19 +41,18 @@ private void OnLoad(object sender, EventArgs e) Cursor.Current = Cursors.WaitCursor; Options.LoadedUltimaClass["Gumps"] = true; - listBox1.BeginUpdate(); - listBox1.Items.Clear(); - List cache = new List(); + _displayIndices.Clear(); for (int i = 0; i < 0x10000; i++) { - cache.Add(i); + _displayIndices.Add(i); } - listBox1.Items.AddRange(cache.ToArray()); - listBox1.EndUpdate(); - listBox2.Items.Clear(); - if (listBox1.Items.Count > 0) + + tileView1.VirtualListSize = _displayIndices.Count; + tileView2.VirtualListSize = 0; + + if (_displayIndices.Count > 0) { - listBox1.SelectedIndex = 0; + tileView1.FocusIndex = 0; } if (!_loaded) @@ -73,45 +73,56 @@ private void Reload() { if (_loaded) { - OnLoad(EventArgs.Empty); + OnLoad(this, EventArgs.Empty); } } - private void Listbox1_DrawItem(object sender, DrawItemEventArgs e) + private void OnTileViewSizeChanged(object sender, EventArgs e) { - ListBox listBox = (ListBox)sender; - if (e.Index < 0) + var tv = (TileViewControl)sender; + int w = tv.DisplayRectangle.Width; + if (w > 0 && tv.TileSize.Width != w) { - return; + tv.TileSize = new Size(w, tv.TileSize.Height); } + } - Brush fontBrush = Brushes.Gray; + private void OnDrawItem1(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawGumpItem(e, _displayIndices[e.Index], isSecondary: false); + } - int i = (int)listBox.Items[e.Index]; + private void OnDrawItem2(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawGumpItem(e, _displayIndices[e.Index], isSecondary: true); + } - if (listBox.SelectedIndex == e.Index) + private void DrawGumpItem(DrawItemEventArgs e, int i, bool isSecondary) + { + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds); + } + else { - e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); + e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds); } - bool valid = (int)listBox.Tag == 1 ? Gumps.IsValidIndex(i) : SecondGump.IsValidIndex(i); + bool valid = isSecondary ? SecondGump.IsValidIndex(i) : Gumps.IsValidIndex(i); + Brush fontBrush = Brushes.Gray; if (valid) { - Bitmap bmp = (int)listBox.Tag == 1 ? Gumps.GetGump(i) : SecondGump.GetGump(i); - + Bitmap bmp = isSecondary ? SecondGump.GetGump(i) : Gumps.GetGump(i); if (bmp != null) { - if (listBox2.Items.Count > 0) + if (tileView2.VirtualListSize > 0 && !Compare(i)) { - if (!Compare(i)) - { - fontBrush = Brushes.Blue; - } + fontBrush = Brushes.Blue; } - int width = bmp.Width > 80 ? 80 : bmp.Width; - int height = bmp.Height > 54 ? 54 : bmp.Height; + int width = bmp.Width > 80 ? 80 : bmp.Width; + int height = bmp.Height > 54 ? 54 : bmp.Height; e.Graphics.DrawImage(bmp, new Rectangle(e.Bounds.X + 3, e.Bounds.Y + 3, width, height)); } else @@ -124,79 +135,70 @@ private void Listbox1_DrawItem(object sender, DrawItemEventArgs e) fontBrush = Brushes.Red; } - e.Graphics.DrawString($"0x{i:X}", Font, fontBrush, - new PointF(85, - e.Bounds.Y + ((e.Bounds.Height / 2) - - (e.Graphics.MeasureString($"0x{i:X}", Font).Height / 2)))); + string label = $"0x{i:X}"; + float y = e.Bounds.Y + (e.Bounds.Height - e.Graphics.MeasureString(label, Font).Height) / 2f; + e.Graphics.DrawString(label, Font, fontBrush, new PointF(85, y)); } - private void Listbox_measureItem(object sender, MeasureItemEventArgs e) + private void OnFocusChanged1(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) { - e.ItemHeight = 60; - } - - private void Listbox_SelectedChange(object sender, EventArgs e) - { - ListBox listBox = (ListBox)sender; - if (listBox.SelectedIndex == -1) + if (e.FocusedItemIndex < 0) { return; } - int i = (int)listBox.Items[listBox.SelectedIndex]; - bool valid; - if ((int)listBox.Tag == 1) + int i = _displayIndices[e.FocusedItemIndex]; + + if (tileView2.VirtualListSize > 0) { - valid = Gumps.IsValidIndex(i); - if (listBox2.Items.Count > 0) + if (_syncingSelection) { - listBox2.SelectedIndex = listBox2.Items.IndexOf(i); + return; } + + _syncingSelection = true; + try { tileView2.FocusIndex = e.FocusedItemIndex; } + finally { _syncingSelection = false; } } - else + + UpdatePictureBox(pictureBox1, i, isSecondary: false); + UpdatePictureBox(pictureBox2, i, isSecondary: true); + } + + private void OnFocusChanged2(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) { - valid = SecondGump.IsValidIndex(i); - listBox1.SelectedIndex = listBox1.Items.IndexOf(i); + return; } - if (valid) + + int i = _displayIndices[e.FocusedItemIndex]; + + if (_syncingSelection) { - Bitmap bmp = (int)listBox.Tag == 1 ? Gumps.GetGump(i) : SecondGump.GetGump(i); + return; + } - if (bmp != null) - { - if ((int)listBox.Tag == 1) - { - pictureBox1.BackgroundImage = bmp; - } - else - { - pictureBox2.BackgroundImage = bmp; - } - } - else - { - if ((int)listBox.Tag == 1) - { - pictureBox1.BackgroundImage = null; - } - else - { - pictureBox2.BackgroundImage = null; - } - } + _syncingSelection = true; + try { tileView1.FocusIndex = e.FocusedItemIndex; } + finally { _syncingSelection = false; } + + UpdatePictureBox(pictureBox1, i, isSecondary: false); + UpdatePictureBox(pictureBox2, i, isSecondary: true); + } + + private void UpdatePictureBox(PictureBox box, int i, bool isSecondary) + { + bool valid = isSecondary ? SecondGump.IsValidIndex(i) : Gumps.IsValidIndex(i); + if (valid) + { + Bitmap bmp = isSecondary ? SecondGump.GetGump(i) : Gumps.GetGump(i); + box.BackgroundImage = bmp; } else { - if ((int)listBox.Tag == 1) - { - pictureBox1.BackgroundImage = null; - } - else - { - pictureBox2.BackgroundImage = null; - } + box.BackgroundImage = null; } - listBox.Invalidate(); } private void Browse_OnClick(object sender, EventArgs e) @@ -219,8 +221,8 @@ private void Load_Click(object sender, EventArgs e) return; } - string path = textBoxSecondDir.Text; - string file = Path.Combine(path, "gumpart.mul"); + string path = textBoxSecondDir.Text; + string file = Path.Combine(path, "gumpart.mul"); string file2 = Path.Combine(path, "gumpidx.mul"); if (File.Exists(file) && File.Exists(file2)) { @@ -232,16 +234,8 @@ private void Load_Click(object sender, EventArgs e) private void LoadSecond() { _compare.Clear(); - listBox2.BeginUpdate(); - listBox2.Items.Clear(); - List cache = new List(); - for (int i = 0; i < 0x10000; i++) - { - cache.Add(i); - } - listBox2.Items.AddRange(cache.ToArray()); - listBox2.EndUpdate(); - listBox1.Invalidate(); + tileView2.VirtualListSize = _displayIndices.Count; + tileView1.Invalidate(); } private bool Compare(int index) @@ -253,14 +247,13 @@ private bool Compare(int index) byte[] org = Gumps.GetRawGump(index, out int width1, out int height1); byte[] sec = SecondGump.GetRawGump(index, out int width2, out int height2); - bool res = false; + bool res; if (org == null && sec == null) { res = true; } - else if (org == null || sec == null - || org.Length != sec.Length) + else if (org == null || sec == null || org.Length != sec.Length) { res = false; } @@ -270,20 +263,18 @@ private bool Compare(int index) } else { - string hash1String = BitConverter.ToString(_sha256.ComputeHash(org)); - string hash2String = BitConverter.ToString(_sha256.ComputeHash(sec)); - if (hash1String == hash2String) - { - res = true; - } + string hash1 = BitConverter.ToString(_sha256.ComputeHash(org)); + string hash2 = BitConverter.ToString(_sha256.ComputeHash(sec)); + res = hash1 == hash2; } + _compare[index] = res; return res; } private void ShowDiff_OnClick(object sender, EventArgs e) { - if (_compare.Count < 1) + if (tileView2.VirtualListSize == 0) { if (checkBox1.Checked) { @@ -292,19 +283,16 @@ private void ShowDiff_OnClick(object sender, EventArgs e) } return; } + Cursor.Current = Cursors.WaitCursor; - listBox1.BeginUpdate(); - listBox2.BeginUpdate(); - listBox1.Items.Clear(); - listBox2.Items.Clear(); - List cache = new List(); + _displayIndices.Clear(); if (checkBox1.Checked) { for (int i = 0; i < 0x10000; i++) { if (!Compare(i)) { - cache.Add(i); + _displayIndices.Add(i); } } } @@ -312,72 +300,66 @@ private void ShowDiff_OnClick(object sender, EventArgs e) { for (int i = 0; i < 0x10000; i++) { - cache.Add(i); + _displayIndices.Add(i); } } - listBox1.Items.AddRange(cache.ToArray()); - listBox2.Items.AddRange(cache.ToArray()); - listBox1.EndUpdate(); - listBox2.EndUpdate(); + + tileView1.VirtualListSize = _displayIndices.Count; + tileView2.VirtualListSize = _displayIndices.Count; Cursor.Current = Cursors.Default; } private void Export_Bmp(object sender, EventArgs e) { - if (listBox2.SelectedIndex == -1) + int focusIdx = tileView2.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBox2.Items[listBox2.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondGump.IsValidIndex(i)) { return; } - string path = Options.OutputPath; + string path = Options.OutputPath; string fileName = Path.Combine(path, $"Gump(Sec) 0x{i:X}.bmp"); SecondGump.GetGump(i).Save(fileName, ImageFormat.Bmp); - MessageBox.Show( - $"Gump saved to {fileName}", - "Saved", - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + MessageBox.Show($"Gump saved to {fileName}", "Saved", + MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void Export_Tiff(object sender, EventArgs e) { - if (listBox2.SelectedIndex == -1) + int focusIdx = tileView2.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBox2.Items[listBox2.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondGump.IsValidIndex(i)) { return; } - string path = Options.OutputPath; + string path = Options.OutputPath; string fileName = Path.Combine(path, $"Gump(Sec) 0x{i:X}.tiff"); SecondGump.GetGump(i).Save(fileName, ImageFormat.Tiff); - MessageBox.Show( - $"Gump saved to {fileName}", - "Saved", - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + MessageBox.Show($"Gump saved to {fileName}", "Saved", + MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void OnClickCopy(object sender, EventArgs e) { - if (listBox2.SelectedIndex == -1) + int focusIdx = tileView2.FocusIndex; + if (focusIdx < 0) { return; } - int i = (int)listBox2.Items[listBox2.SelectedIndex]; + int i = _displayIndices[focusIdx]; if (!SecondGump.IsValidIndex(i)) { return; @@ -388,31 +370,11 @@ private void OnClickCopy(object sender, EventArgs e) Options.ChangedUltimaClass["Gumps"] = true; ControlEvents.FireGumpChangeEvent(this, i); _compare[i] = true; - listBox1.BeginUpdate(); - bool done = false; - for (int id = 0; id < 0x10000; id++) - { - if (id > i) - { - listBox1.Items.Insert(id, i); - done = true; - break; - } - if (id == i) - { - done = true; - break; - } - } - if (!done) - { - listBox1.Items.Add(i); - } - listBox1.EndUpdate(); - listBox1.Invalidate(); - listBox2.Invalidate(); - Listbox_SelectedChange(listBox1, null); + tileView1.Invalidate(); + tileView2.Invalidate(); + + UpdatePictureBox(pictureBox1, i, isSecondary: false); } } } diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.Designer.cs b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.Designer.cs index 69c94466..c4e813d5 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.Designer.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.Designer.cs @@ -40,8 +40,9 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.listBoxOrg = new System.Windows.Forms.ListBox(); - this.listBoxSec = new System.Windows.Forms.ListBox(); + this.tileViewOrg = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + this.tileViewSec = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + this.btnCopyAllDiff = new System.Windows.Forms.Button(); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); this.extractAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.tiffToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -66,37 +67,42 @@ private void InitializeComponent() this.splitContainer1.Panel2.SuspendLayout(); this.splitContainer1.SuspendLayout(); this.SuspendLayout(); - // - // listBoxOrg - // - this.listBoxOrg.Dock = System.Windows.Forms.DockStyle.Fill; - this.listBoxOrg.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.listBoxOrg.FormattingEnabled = true; - this.listBoxOrg.IntegralHeight = false; - this.listBoxOrg.Location = new System.Drawing.Point(4, 3); - this.listBoxOrg.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.listBoxOrg.Name = "listBoxOrg"; - this.listBoxOrg.Size = new System.Drawing.Size(188, 314); - this.listBoxOrg.TabIndex = 0; - this.listBoxOrg.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.DrawItemOrg); - this.listBoxOrg.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.MeasureOrg); - this.listBoxOrg.SelectedIndexChanged += new System.EventHandler(this.OnIndexChangedOrg); - // - // listBoxSec - // - this.listBoxSec.ContextMenuStrip = this.contextMenuStrip1; - this.listBoxSec.Dock = System.Windows.Forms.DockStyle.Fill; - this.listBoxSec.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.listBoxSec.FormattingEnabled = true; - this.listBoxSec.IntegralHeight = false; - this.listBoxSec.Location = new System.Drawing.Point(527, 3); - this.listBoxSec.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.listBoxSec.Name = "listBoxSec"; - this.listBoxSec.Size = new System.Drawing.Size(189, 314); - this.listBoxSec.TabIndex = 1; - this.listBoxSec.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.DrawItemSec); - this.listBoxSec.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.MeasureSec); - this.listBoxSec.SelectedIndexChanged += new System.EventHandler(this.OnIndexChangedSec); + // + // tileViewOrg + // + this.tileViewOrg.Dock = System.Windows.Forms.DockStyle.Fill; + this.tileViewOrg.Location = new System.Drawing.Point(4, 3); + this.tileViewOrg.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.tileViewOrg.Name = "tileViewOrg"; + this.tileViewOrg.Size = new System.Drawing.Size(188, 314); + this.tileViewOrg.TabIndex = 0; + this.tileViewOrg.TileSize = new System.Drawing.Size(188, 13); + this.tileViewOrg.TileMargin = new System.Windows.Forms.Padding(0); + this.tileViewOrg.TilePadding = new System.Windows.Forms.Padding(0); + this.tileViewOrg.TileBorderWidth = 0f; + this.tileViewOrg.TileHighLightOpacity = 0.0; + this.tileViewOrg.DrawItem += new System.EventHandler(this.OnDrawItemOrg); + this.tileViewOrg.FocusSelectionChanged += new System.EventHandler(this.OnFocusChangedOrg); + this.tileViewOrg.SizeChanged += new System.EventHandler(this.OnTileViewSizeChanged); + // + // tileViewSec + // + this.tileViewSec.ContextMenuStrip = this.contextMenuStrip1; + this.tileViewSec.Dock = System.Windows.Forms.DockStyle.Fill; + this.tileViewSec.Location = new System.Drawing.Point(527, 3); + this.tileViewSec.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.tileViewSec.Name = "tileViewSec"; + this.tileViewSec.Size = new System.Drawing.Size(189, 314); + this.tileViewSec.TabIndex = 1; + this.tileViewSec.TileSize = new System.Drawing.Size(189, 13); + this.tileViewSec.TileMargin = new System.Windows.Forms.Padding(0); + this.tileViewSec.TilePadding = new System.Windows.Forms.Padding(0); + this.tileViewSec.TileBorderWidth = 0f; + this.tileViewSec.TileHighLightOpacity = 0.0; + this.tileViewSec.DrawItem += new System.EventHandler(this.OnDrawItemSec); + this.tileViewSec.FocusSelectionChanged += new System.EventHandler(this.OnFocusChangedSec); + this.tileViewSec.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.OnDoubleClickSec); + this.tileViewSec.SizeChanged += new System.EventHandler(this.OnTileViewSizeChanged); // // contextMenuStrip1 // @@ -177,9 +183,21 @@ private void InitializeComponent() this.button1.Text = "Load Second"; this.button1.UseVisualStyleBackColor = true; this.button1.Click += new System.EventHandler(this.OnClickLoadSecond); - // + // + // btnCopyAllDiff + // + this.btnCopyAllDiff.AutoSize = true; + this.btnCopyAllDiff.Location = new System.Drawing.Point(598, 13); + this.btnCopyAllDiff.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.btnCopyAllDiff.Name = "btnCopyAllDiff"; + this.btnCopyAllDiff.Size = new System.Drawing.Size(99, 29); + this.btnCopyAllDiff.TabIndex = 9; + this.btnCopyAllDiff.Text = "Copy All Diff"; + this.btnCopyAllDiff.UseVisualStyleBackColor = true; + this.btnCopyAllDiff.Click += new System.EventHandler(this.OnClickCopyAllDiff); + // // checkBox1 - // + // this.checkBox1.AutoSize = true; this.checkBox1.Location = new System.Drawing.Point(443, 18); this.checkBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); @@ -213,8 +231,8 @@ private void InitializeComponent() this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27273F)); this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 45.45454F)); this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27273F)); - this.tableLayoutPanel2.Controls.Add(this.listBoxOrg, 0, 0); - this.tableLayoutPanel2.Controls.Add(this.listBoxSec, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.tileViewOrg, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.tileViewSec, 2, 0); this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel1, 1, 0); this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0); @@ -242,6 +260,7 @@ private void InitializeComponent() // // splitContainer1.Panel2 // + this.splitContainer1.Panel2.Controls.Add(this.btnCopyAllDiff); this.splitContainer1.Panel2.Controls.Add(this.button2); this.splitContainer1.Panel2.Controls.Add(this.textBoxSecondDir); this.splitContainer1.Panel2.Controls.Add(this.checkBox1); @@ -291,14 +310,15 @@ private void InitializeComponent() #endregion private System.Windows.Forms.ToolStripMenuItem bmpToolStripMenuItem; + private System.Windows.Forms.Button btnCopyAllDiff; private System.Windows.Forms.Button button1; private System.Windows.Forms.Button button2; private System.Windows.Forms.CheckBox checkBox1; private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; private System.Windows.Forms.ToolStripMenuItem copyItem2To1ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem extractAsToolStripMenuItem; - private System.Windows.Forms.ListBox listBoxOrg; - private System.Windows.Forms.ListBox listBoxSec; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewOrg; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewSec; private System.Windows.Forms.PictureBox pictureBoxOrg; private System.Windows.Forms.PictureBox pictureBoxSec; private System.Windows.Forms.SplitContainer splitContainer1; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs index dd64010c..2a002612 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareItemControl.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. * @@ -18,183 +18,204 @@ using System.Windows.Forms; using Ultima; using UoFiddler.Controls.Classes; +using UoFiddler.Controls.UserControls.TileView; using UoFiddler.Plugin.Compare.Classes; namespace UoFiddler.Plugin.Compare.UserControls { public partial class CompareItemControl : UserControl { - private readonly Dictionary _compare = new Dictionary(); - private readonly ImageConverter _ic = new ImageConverter(); - private readonly SHA256 _sha256 = SHA256.Create(); - public CompareItemControl() { InitializeComponent(); } + private readonly Dictionary _compare = new Dictionary(); + private readonly ImageConverter _ic = new ImageConverter(); + private readonly SHA256 _sha256 = SHA256.Create(); + private readonly List _displayIndices = new List(); + private bool _syncingSelection; + private bool _secondLoaded; + private void OnLoad(object sender, EventArgs e) { - listBoxOrg.Items.Clear(); - listBoxOrg.BeginUpdate(); - List cache = new List(); - int staticsLength = Art.GetMaxItemId() + 1; - for (int i = 0; i < staticsLength; i++) + _displayIndices.Clear(); + int count = Art.GetMaxItemId() + 1; + for (int i = 0; i < count; i++) { - cache.Add(i); + _displayIndices.Add(i); } - listBoxOrg.Items.AddRange(cache.ToArray()); - listBoxOrg.EndUpdate(); + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = 0; + + SecondArt.FileIndexChanged += OnSecondArtChanged; + ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; + } + + private void OnFilePathChangeEvent() + { + _compare.Clear(); + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); } - private void OnIndexChangedOrg(object sender, EventArgs e) + private void OnSecondArtChanged() { - if (listBoxOrg.SelectedIndex == -1 || listBoxOrg.Items.Count < 1) + if (!_secondLoaded) { return; } - int i = int.Parse(listBoxOrg.Items[listBoxOrg.SelectedIndex].ToString()); - if (listBoxSec.Items.Count > 0) + _compare.Clear(); + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + } + + private void OnTileViewSizeChanged(object sender, EventArgs e) + { + var tv = (TileViewControl)sender; + int w = tv.DisplayRectangle.Width; + if (w > 0 && tv.TileSize.Width != w) { - int pos = listBoxSec.Items.IndexOf(i); - if (pos >= 0) - { - listBoxSec.SelectedIndex = pos; - } + tv.TileSize = new Size(w, tv.TileSize.Height); } + } - pictureBoxOrg.BackgroundImage = Art.IsValidStatic(i) - ? Art.GetStatic(i) - : null; + private void OnDrawItemOrg(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawListItem(e, _displayIndices[e.Index], isSecondary: false); + } - listBoxOrg.Invalidate(); + private void OnDrawItemSec(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawListItem(e, _displayIndices[e.Index], isSecondary: true); } - private void DrawItemOrg(object sender, DrawItemEventArgs e) + private void DrawListItem(DrawItemEventArgs e, int i, bool isSecondary) { - if (e.Index == -1) + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { - return; + e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds); } - - Brush fontBrush = Brushes.Gray; - - int i = int.Parse(listBoxOrg.Items[e.Index].ToString()); - if (listBoxOrg.SelectedIndex == e.Index) + else { - e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); + e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds); } - if (!Art.IsValidStatic(i)) + Brush fontBrush = Brushes.Gray; + bool valid = isSecondary ? SecondArt.IsValidStatic(i) : Art.IsValidStatic(i); + + if (!valid) { fontBrush = Brushes.Red; } - else if (listBoxSec.Items.Count > 0) + else if (tileViewSec.VirtualListSize > 0 && !Compare(i)) { - if (!Compare(i)) - { - fontBrush = Brushes.Blue; - } + fontBrush = Brushes.Blue; } - e.Graphics.DrawString($"0x{i:X}", Font, fontBrush, - new PointF(5, - e.Bounds.Y + ((e.Bounds.Height / 2) - - (e.Graphics.MeasureString($"0x{i:X}", Font).Height / 2)))); + string label = $"0x{i:X}"; + float y = e.Bounds.Y + (e.Bounds.Height - e.Graphics.MeasureString(label, Font).Height) / 2f; + e.Graphics.DrawString(label, Font, fontBrush, new PointF(5, y)); } - private void MeasureOrg(object sender, MeasureItemEventArgs e) + private void OnFocusChangedOrg(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) { - e.ItemHeight = 13; - } - - private void OnClickLoadSecond(object sender, EventArgs e) - { - if (string.IsNullOrWhiteSpace(textBoxSecondDir.Text)) + if (e.FocusedItemIndex < 0) { return; } - string path = textBoxSecondDir.Text; - string file = Path.Combine(path, "art.mul"); - string file2 = Path.Combine(path, "artidx.mul"); - if (File.Exists(file) && File.Exists(file2)) - { - SecondArt.SetFileIndex(file2, file); - LoadSecond(); - } - } + int i = _displayIndices[e.FocusedItemIndex]; - private void LoadSecond() - { - _compare.Clear(); - listBoxSec.BeginUpdate(); - listBoxSec.Items.Clear(); - List cache = new List(); - int staticLength = SecondArt.GetMaxItemId() + 1; - for (int i = 0; i < staticLength; i++) + if (tileViewSec.VirtualListSize > 0) { - cache.Add(i); + if (_syncingSelection) + { + return; + } + + _syncingSelection = true; + try + { + int secIdx = _displayIndices.IndexOf(i); + if (secIdx >= 0 && secIdx < tileViewSec.VirtualListSize) + { + tileViewSec.FocusIndex = secIdx; + } + } + finally + { + _syncingSelection = false; + } } - listBoxSec.Items.AddRange(cache.ToArray()); - listBoxSec.EndUpdate(); + + pictureBoxOrg.BackgroundImage = Art.IsValidStatic(i) ? Art.GetStatic(i) : null; + tileViewOrg.Invalidate(); } - private void DrawItemSec(object sender, DrawItemEventArgs e) + private void OnFocusChangedSec(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) { - if (e.Index == -1) + if (e.FocusedItemIndex < 0) { return; } - Brush fontBrush = Brushes.Gray; + int i = _displayIndices[e.FocusedItemIndex]; - int i = int.Parse(listBoxSec.Items[e.Index].ToString()); - if (listBoxSec.SelectedIndex == e.Index) + if (_syncingSelection) { - e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); + return; } - if (!SecondArt.IsValidStatic(i)) + _syncingSelection = true; + try { - fontBrush = Brushes.Red; + tileViewOrg.FocusIndex = e.FocusedItemIndex; } - else if (!Compare(i)) + finally { - fontBrush = Brushes.Blue; + _syncingSelection = false; } - e.Graphics.DrawString($"0x{i:X}", Font, fontBrush, - new PointF(5, - e.Bounds.Y + ((e.Bounds.Height / 2) - - (e.Graphics.MeasureString($"0x{i:X}", Font).Height / 2)))); + pictureBoxSec.BackgroundImage = SecondArt.IsValidStatic(i) ? SecondArt.GetStatic(i) : null; + tileViewSec.Invalidate(); } - private void MeasureSec(object sender, MeasureItemEventArgs e) - { - e.ItemHeight = 13; - } - - private void OnIndexChangedSec(object sender, EventArgs e) + private void OnClickLoadSecond(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1 || listBoxSec.Items.Count < 1) + if (string.IsNullOrWhiteSpace(textBoxSecondDir.Text)) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); - int pos = listBoxOrg.Items.IndexOf(i); - if (pos >= 0) + string path = textBoxSecondDir.Text; + string file = Path.Combine(path, "art.mul"); + string file2 = Path.Combine(path, "artidx.mul"); + if (File.Exists(file) && File.Exists(file2)) { - listBoxOrg.SelectedIndex = pos; + SecondArt.SetFileIndex(file2, file); + LoadSecond(); } + } - pictureBoxSec.BackgroundImage = SecondArt.IsValidStatic(i) - ? SecondArt.GetStatic(i) - : null; + private void LoadSecond() + { + _secondLoaded = true; + _compare.Clear(); + int secMax = SecondArt.GetMaxItemId() + 1; + if (secMax > _displayIndices.Count) + { + for (int i = _displayIndices.Count; i < secMax; i++) + { + _displayIndices.Add(i); + } - listBoxSec.Invalidate(); + tileViewOrg.VirtualListSize = _displayIndices.Count; + } + tileViewSec.VirtualListSize = _displayIndices.Count; + tileViewOrg.Invalidate(); } private bool Compare(int index) @@ -211,36 +232,23 @@ private bool Compare(int index) _compare[index] = true; return true; } - if (bitorg == null || bitsec == null - || bitorg.Size != bitsec.Size) + + if (bitorg == null || bitsec == null || bitorg.Size != bitsec.Size) { _compare[index] = false; return false; } - byte[] btImage1 = new byte[1]; - btImage1 = (byte[])_ic.ConvertTo(bitorg, btImage1.GetType()); - byte[] btImage2 = new byte[1]; - btImage2 = (byte[])_ic.ConvertTo(bitsec, btImage2.GetType()); - - byte[] checksum1 = _sha256.ComputeHash(btImage1); - byte[] checksum2 = _sha256.ComputeHash(btImage2); - bool res = true; - for (int j = 0; j < checksum1.Length; ++j) - { - if (checksum1[j] != checksum2[j]) - { - res = false; - break; - } - } + byte[] b1 = (byte[])_ic.ConvertTo(bitorg, typeof(byte[])); + byte[] b2 = (byte[])_ic.ConvertTo(bitsec, typeof(byte[])); + bool res = BitConverter.ToString(_sha256.ComputeHash(b1)) == BitConverter.ToString(_sha256.ComputeHash(b2)); _compare[index] = res; return res; } private void OnChangeShowDiff(object sender, EventArgs e) { - if (_compare.Count < 1) + if (!_secondLoaded) { if (checkBox1.Checked) { @@ -250,98 +258,85 @@ private void OnChangeShowDiff(object sender, EventArgs e) return; } - listBoxOrg.BeginUpdate(); - listBoxSec.BeginUpdate(); - listBoxOrg.Items.Clear(); - listBoxSec.Items.Clear(); - List cache = new List(); - int staticLength = Math.Max(Art.GetMaxItemId(), SecondArt.GetMaxItemId()); + int maxId = Math.Max(Art.GetMaxItemId(), SecondArt.GetMaxItemId()); + _displayIndices.Clear(); if (checkBox1.Checked) { - for (int i = 0; i < staticLength; i++) + for (int i = 0; i < maxId; i++) { if (!Compare(i)) { - cache.Add(i); + _displayIndices.Add(i); } } } else { - for (int i = 0; i < staticLength; i++) + for (int i = 0; i < maxId; i++) { - cache.Add(i); + _displayIndices.Add(i); } } - listBoxOrg.Items.AddRange(cache.ToArray()); - listBoxSec.Items.AddRange(cache.ToArray()); - listBoxOrg.EndUpdate(); - listBoxSec.EndUpdate(); + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; } private void ExportAsBmp(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1) + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondArt.IsValidStatic(i)) { return; } - string path = Options.OutputPath; - string fileName = Path.Combine(path, $"Item(Sec) 0x{i:X}.bmp"); + string fileName = Path.Combine(Options.OutputPath, $"Item(Sec) 0x{i:X}.bmp"); SecondArt.GetStatic(i).Save(fileName, ImageFormat.Bmp); - MessageBox.Show( - $"Item saved to {fileName}", - "Saved", - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + MessageBox.Show($"Item saved to {fileName}", "Saved", + MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void ExportAsTiff(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1) + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondArt.IsValidStatic(i)) { return; } - string path = Options.OutputPath; - string fileName = Path.Combine(path, $"Item(Sec) 0x{i:X}.tiff"); + string fileName = Path.Combine(Options.OutputPath, $"Item(Sec) 0x{i:X}.tiff"); SecondArt.GetStatic(i).Save(fileName, ImageFormat.Tiff); - MessageBox.Show( - $"Item saved to {fileName}", - "Saved", - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + MessageBox.Show($"Item saved to {fileName}", "Saved", + MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void OnClickCopy(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1) + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondArt.IsValidStatic(i)) { return; } - int staticLength = Art.GetMaxItemId() + 1; - if (i >= staticLength) + if (i >= Art.GetMaxItemId() + 1) { return; } @@ -351,34 +346,65 @@ private void OnClickCopy(object sender, EventArgs e) Options.ChangedUltimaClass["Art"] = true; ControlEvents.FireItemChangeEvent(this, i); _compare[i] = true; - listBoxOrg.BeginUpdate(); - bool done = false; - for (int id = 0; id < staticLength; id++) + if (checkBox1.Checked) { - if (id > i) - { - listBoxOrg.Items.Insert(id, i); - done = true; - break; - } + _displayIndices.RemoveAt(focusIdx); + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; + } - if (id == i) + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + pictureBoxOrg.BackgroundImage = Art.IsValidStatic(i) ? Art.GetStatic(i) : null; + } + + private void OnDoubleClickSec(object sender, MouseEventArgs e) + { + OnClickCopy(sender, e); + } + + private void OnClickCopyAllDiff(object sender, EventArgs e) + { + if (!_secondLoaded) + { + return; + } + + Cursor.Current = Cursors.WaitCursor; + int maxId = Art.GetMaxItemId() + 1; + for (int i = 0; i < maxId; i++) + { + if (!SecondArt.IsValidStatic(i) || Compare(i)) { - done = true; - break; + continue; } + + Bitmap copy = new Bitmap(SecondArt.GetStatic(i)); + Art.ReplaceStatic(i, copy); + ControlEvents.FireItemChangeEvent(this, i); + _compare[i] = true; } - if (!done) + Options.ChangedUltimaClass["Art"] = true; + + if (checkBox1.Checked) { - listBoxOrg.Items.Add(i); + _displayIndices.Clear(); + for (int i = 0; i < maxId; i++) + { + if (!Compare(i)) + { + _displayIndices.Add(i); + } + } + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; } - listBoxOrg.EndUpdate(); - listBoxOrg.Invalidate(); - listBoxSec.Invalidate(); - OnIndexChangedOrg(this, null); + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + Cursor.Current = Cursors.Default; } private void OnClickBrowse(object sender, EventArgs e) @@ -387,7 +413,6 @@ private void OnClickBrowse(object sender, EventArgs e) { dialog.Description = "Select directory containing the art files"; dialog.ShowNewFolderButton = false; - if (dialog.ShowDialog() == DialogResult.OK) { textBoxSecondDir.Text = dialog.SelectedPath; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.Designer.cs b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.Designer.cs index 28d5594f..82fb85fb 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.Designer.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.Designer.cs @@ -40,13 +40,14 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.listBoxOrg = new System.Windows.Forms.ListBox(); + this.tileViewOrg = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + this.btnCopyAllDiff = new System.Windows.Forms.Button(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.pictureBoxSec = new System.Windows.Forms.PictureBox(); this.pictureBoxOrg = new System.Windows.Forms.PictureBox(); this.textBoxSecondDir = new System.Windows.Forms.TextBox(); this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); - this.listBoxSec = new System.Windows.Forms.ListBox(); + this.tileViewSec = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); this.exportImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.asBmpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -66,21 +67,23 @@ private void InitializeComponent() this.splitContainer1.Panel2.SuspendLayout(); this.splitContainer1.SuspendLayout(); this.SuspendLayout(); - // - // listBoxOrg - // - this.listBoxOrg.Dock = System.Windows.Forms.DockStyle.Fill; - this.listBoxOrg.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.listBoxOrg.FormattingEnabled = true; - this.listBoxOrg.IntegralHeight = false; - this.listBoxOrg.Location = new System.Drawing.Point(4, 3); - this.listBoxOrg.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.listBoxOrg.Name = "listBoxOrg"; - this.listBoxOrg.Size = new System.Drawing.Size(188, 364); - this.listBoxOrg.TabIndex = 0; - this.listBoxOrg.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.DrawitemOrg); - this.listBoxOrg.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.MeasureOrg); - this.listBoxOrg.SelectedIndexChanged += new System.EventHandler(this.OnIndexChangedOrg); + // + // tileViewOrg + // + this.tileViewOrg.Dock = System.Windows.Forms.DockStyle.Fill; + this.tileViewOrg.Location = new System.Drawing.Point(4, 3); + this.tileViewOrg.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.tileViewOrg.Name = "tileViewOrg"; + this.tileViewOrg.Size = new System.Drawing.Size(188, 364); + this.tileViewOrg.TabIndex = 0; + this.tileViewOrg.TileSize = new System.Drawing.Size(188, 13); + this.tileViewOrg.TileMargin = new System.Windows.Forms.Padding(0); + this.tileViewOrg.TilePadding = new System.Windows.Forms.Padding(0); + this.tileViewOrg.TileBorderWidth = 0f; + this.tileViewOrg.TileHighLightOpacity = 0.0; + this.tileViewOrg.DrawItem += new System.EventHandler(this.OnDrawItemOrg); + this.tileViewOrg.FocusSelectionChanged += new System.EventHandler(this.OnFocusChangedOrg); + this.tileViewOrg.SizeChanged += new System.EventHandler(this.OnTileViewSizeChanged); // // tableLayoutPanel1 // @@ -135,8 +138,8 @@ private void InitializeComponent() this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27273F)); this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 45.45454F)); this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27273F)); - this.tableLayoutPanel2.Controls.Add(this.listBoxOrg, 0, 0); - this.tableLayoutPanel2.Controls.Add(this.listBoxSec, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.tileViewOrg, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.tileViewSec, 2, 0); this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel1, 1, 0); this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0); @@ -146,22 +149,25 @@ private void InitializeComponent() this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel2.Size = new System.Drawing.Size(719, 370); this.tableLayoutPanel2.TabIndex = 8; - // - // listBoxSec - // - this.listBoxSec.ContextMenuStrip = this.contextMenuStrip1; - this.listBoxSec.Dock = System.Windows.Forms.DockStyle.Fill; - this.listBoxSec.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.listBoxSec.FormattingEnabled = true; - this.listBoxSec.IntegralHeight = false; - this.listBoxSec.Location = new System.Drawing.Point(526, 3); - this.listBoxSec.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.listBoxSec.Name = "listBoxSec"; - this.listBoxSec.Size = new System.Drawing.Size(189, 364); - this.listBoxSec.TabIndex = 1; - this.listBoxSec.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.DrawItemSec); - this.listBoxSec.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.MeasureSec); - this.listBoxSec.SelectedIndexChanged += new System.EventHandler(this.OnIndexChangedSec); + // + // tileViewSec + // + this.tileViewSec.ContextMenuStrip = this.contextMenuStrip1; + this.tileViewSec.Dock = System.Windows.Forms.DockStyle.Fill; + this.tileViewSec.Location = new System.Drawing.Point(526, 3); + this.tileViewSec.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.tileViewSec.Name = "tileViewSec"; + this.tileViewSec.Size = new System.Drawing.Size(189, 364); + this.tileViewSec.TabIndex = 1; + this.tileViewSec.TileSize = new System.Drawing.Size(189, 13); + this.tileViewSec.TileMargin = new System.Windows.Forms.Padding(0); + this.tileViewSec.TilePadding = new System.Windows.Forms.Padding(0); + this.tileViewSec.TileBorderWidth = 0f; + this.tileViewSec.TileHighLightOpacity = 0.0; + this.tileViewSec.DrawItem += new System.EventHandler(this.OnDrawItemSec); + this.tileViewSec.FocusSelectionChanged += new System.EventHandler(this.OnFocusChangedSec); + this.tileViewSec.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.OnDoubleClickSec); + this.tileViewSec.SizeChanged += new System.EventHandler(this.OnTileViewSizeChanged); // // contextMenuStrip1 // @@ -200,9 +206,21 @@ private void InitializeComponent() this.copyLandTile2To1ToolStripMenuItem.Size = new System.Drawing.Size(181, 22); this.copyLandTile2To1ToolStripMenuItem.Text = "Copy LandTile 2 to 1"; this.copyLandTile2To1ToolStripMenuItem.Click += new System.EventHandler(this.OnClickCopy); - // + // + // btnCopyAllDiff + // + this.btnCopyAllDiff.AutoSize = true; + this.btnCopyAllDiff.Location = new System.Drawing.Point(594, 11); + this.btnCopyAllDiff.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.btnCopyAllDiff.Name = "btnCopyAllDiff"; + this.btnCopyAllDiff.Size = new System.Drawing.Size(99, 29); + this.btnCopyAllDiff.TabIndex = 9; + this.btnCopyAllDiff.Text = "Copy All Diff"; + this.btnCopyAllDiff.UseVisualStyleBackColor = true; + this.btnCopyAllDiff.Click += new System.EventHandler(this.OnClickCopyAllDiff); + // // checkBox1 - // + // this.checkBox1.AutoSize = true; this.checkBox1.Location = new System.Drawing.Point(439, 15); this.checkBox1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); @@ -242,6 +260,7 @@ private void InitializeComponent() // // splitContainer1.Panel2 // + this.splitContainer1.Panel2.Controls.Add(this.btnCopyAllDiff); this.splitContainer1.Panel2.Controls.Add(this.button2); this.splitContainer1.Panel2.Controls.Add(this.textBoxSecondDir); this.splitContainer1.Panel2.Controls.Add(this.checkBox1); @@ -292,14 +311,15 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem asBmpToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem asTiffToolStripMenuItem; + private System.Windows.Forms.Button btnCopyAllDiff; private System.Windows.Forms.Button button1; private System.Windows.Forms.Button button2; private System.Windows.Forms.CheckBox checkBox1; private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; private System.Windows.Forms.ToolStripMenuItem copyLandTile2To1ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem exportImageToolStripMenuItem; - private System.Windows.Forms.ListBox listBoxOrg; - private System.Windows.Forms.ListBox listBoxSec; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewOrg; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewSec; private System.Windows.Forms.PictureBox pictureBoxOrg; private System.Windows.Forms.PictureBox pictureBoxSec; private System.Windows.Forms.SplitContainer splitContainer1; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs index 6ab70af0..961172d1 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareLandControl.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. * @@ -18,6 +18,7 @@ using System.Windows.Forms; using Ultima; using UoFiddler.Controls.Classes; +using UoFiddler.Controls.UserControls.TileView; using UoFiddler.Plugin.Compare.Classes; namespace UoFiddler.Plugin.Compare.UserControls @@ -32,156 +33,162 @@ public CompareLandControl() private readonly Dictionary _compare = new Dictionary(); private readonly SHA256 _sha256 = SHA256.Create(); private readonly ImageConverter _ic = new ImageConverter(); + private readonly List _displayIndices = new List(); + private bool _syncingSelection; + private bool _secondLoaded; private void OnLoad(object sender, EventArgs e) { - listBoxOrg.BeginUpdate(); - listBoxOrg.Items.Clear(); - List cache = new List(); + _displayIndices.Clear(); for (int i = 0; i < 0x4000; i++) { - cache.Add(i); + _displayIndices.Add(i); } - listBoxOrg.Items.AddRange(cache.ToArray()); - listBoxOrg.EndUpdate(); + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = 0; + + SecondArt.FileIndexChanged += OnSecondArtChanged; + ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; + } + + private void OnFilePathChangeEvent() + { + _compare.Clear(); + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); } - private void OnIndexChangedOrg(object sender, EventArgs e) + private void OnSecondArtChanged() { - if (listBoxOrg.SelectedIndex == -1 || listBoxOrg.Items.Count < 1) + if (!_secondLoaded) { return; } - int i = int.Parse(listBoxOrg.Items[listBoxOrg.SelectedIndex].ToString()); - if (listBoxSec.Items.Count > 0) + _compare.Clear(); + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + } + + private void OnTileViewSizeChanged(object sender, EventArgs e) + { + var tv = (TileViewControl)sender; + int w = tv.DisplayRectangle.Width; + if (w > 0 && tv.TileSize.Width != w) { - listBoxSec.SelectedIndex = listBoxSec.Items.IndexOf(i); + tv.TileSize = new Size(w, tv.TileSize.Height); } + } - pictureBoxOrg.BackgroundImage = Art.IsValidLand(i) - ? Art.GetLand(i) - : null; + private void OnDrawItemOrg(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawListItem(e, _displayIndices[e.Index], isSecondary: false); + } - listBoxOrg.Invalidate(); + private void OnDrawItemSec(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawListItem(e, _displayIndices[e.Index], isSecondary: true); } - private void DrawitemOrg(object sender, DrawItemEventArgs e) + private void DrawListItem(DrawItemEventArgs e, int i, bool isSecondary) { - if (e.Index == -1) + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { - return; + e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds); } - - Brush fontBrush = Brushes.Gray; - - int i = int.Parse(listBoxOrg.Items[e.Index].ToString()); - if (listBoxOrg.SelectedIndex == e.Index) + else { - e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); + e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds); } - if (!Art.IsValidLand(i)) + Brush fontBrush = Brushes.Gray; + bool valid = isSecondary ? SecondArt.IsValidLand(i) : Art.IsValidLand(i); + + if (!valid) { fontBrush = Brushes.Red; } - else if (listBoxSec.Items.Count > 0) + else if (tileViewSec.VirtualListSize > 0 && !Compare(i)) { - if (!Compare(i)) - { - fontBrush = Brushes.Blue; - } + fontBrush = Brushes.Blue; } - e.Graphics.DrawString($"0x{i:X}", Font, fontBrush, - new PointF(5, - e.Bounds.Y + ((e.Bounds.Height / 2) - - (e.Graphics.MeasureString($"0x{i:X}", Font).Height / 2)))); + string label = $"0x{i:X}"; + float y = e.Bounds.Y + (e.Bounds.Height - e.Graphics.MeasureString(label, Font).Height) / 2f; + e.Graphics.DrawString(label, Font, fontBrush, new PointF(5, y)); } - private void MeasureOrg(object sender, MeasureItemEventArgs e) + private void OnFocusChangedOrg(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) { - e.ItemHeight = 13; - } - - private void OnClickLoadSecond(object sender, EventArgs e) - { - if (textBoxSecondDir.Text == null) + if (e.FocusedItemIndex < 0) { return; } - string path = textBoxSecondDir.Text; - string file = Path.Combine(path, "art.mul"); - string file2 = Path.Combine(path, "artidx.mul"); - if (File.Exists(file) && File.Exists(file2)) - { - SecondArt.SetFileIndex(file2, file); - LoadSecond(); - } - } + int i = _displayIndices[e.FocusedItemIndex]; - private void LoadSecond() - { - _compare.Clear(); - listBoxSec.BeginUpdate(); - listBoxSec.Items.Clear(); - List cache = new List(); - for (int i = 0; i < 0x4000; i++) + if (tileViewSec.VirtualListSize > 0) { - cache.Add(i); + if (_syncingSelection) + { + return; + } + + _syncingSelection = true; + try { tileViewSec.FocusIndex = e.FocusedItemIndex; } + finally { _syncingSelection = false; } } - listBoxSec.Items.AddRange(cache.ToArray()); - listBoxSec.EndUpdate(); + + pictureBoxOrg.BackgroundImage = Art.IsValidLand(i) ? Art.GetLand(i) : null; + tileViewOrg.Invalidate(); } - private void DrawItemSec(object sender, DrawItemEventArgs e) + private void OnFocusChangedSec(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) { - if (e.Index == -1) + if (e.FocusedItemIndex < 0) { return; } - Brush fontBrush = Brushes.Gray; + int i = _displayIndices[e.FocusedItemIndex]; - int i = int.Parse(listBoxOrg.Items[e.Index].ToString()); - if (listBoxSec.SelectedIndex == e.Index) + if (_syncingSelection) { - e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); - } - - if (!SecondArt.IsValidLand(i)) - { - fontBrush = Brushes.Red; - } - else if (!Compare(i)) - { - fontBrush = Brushes.Blue; + return; } - e.Graphics.DrawString($"0x{i:X}", Font, fontBrush, - new PointF(5, - e.Bounds.Y + ((e.Bounds.Height / 2) - - (e.Graphics.MeasureString($"0x{i:X}", Font).Height / 2)))); - } + _syncingSelection = true; + try { tileViewOrg.FocusIndex = e.FocusedItemIndex; } + finally { _syncingSelection = false; } - private void MeasureSec(object sender, MeasureItemEventArgs e) - { - e.ItemHeight = 13; + pictureBoxSec.BackgroundImage = SecondArt.IsValidLand(i) ? SecondArt.GetLand(i) : null; + tileViewSec.Invalidate(); } - private void OnIndexChangedSec(object sender, EventArgs e) + private void OnClickLoadSecond(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1 || listBoxSec.Items.Count < 1) + if (textBoxSecondDir.Text == null) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); - listBoxOrg.SelectedIndex = listBoxOrg.Items.IndexOf(i); - pictureBoxSec.BackgroundImage = SecondArt.IsValidLand(i) ? SecondArt.GetLand(i) : null; + string path = textBoxSecondDir.Text; + string file = Path.Combine(path, "art.mul"); + string file2 = Path.Combine(path, "artidx.mul"); + if (File.Exists(file) && File.Exists(file2)) + { + SecondArt.SetFileIndex(file2, file); + LoadSecond(); + } + } - listBoxSec.Invalidate(); + private void LoadSecond() + { + _secondLoaded = true; + _compare.Clear(); + tileViewSec.VirtualListSize = _displayIndices.Count; + tileViewOrg.Invalidate(); } private bool Compare(int index) @@ -193,35 +200,19 @@ private bool Compare(int index) Bitmap bitorg = Art.GetLand(index); Bitmap bitsec = SecondArt.GetLand(index); - if (bitorg == null && bitsec == null) - { - _compare[index] = true; - return true; - } - if (bitorg == null || bitsec == null - || bitorg.Size != bitsec.Size) - { - _compare[index] = false; - return false; - } + if (bitorg == null && bitsec == null) { _compare[index] = true; return true; } + if (bitorg == null || bitsec == null || bitorg.Size != bitsec.Size) { _compare[index] = false; return false; } - byte[] btImage1 = new byte[1]; - btImage1 = (byte[])_ic.ConvertTo(bitorg, btImage1.GetType()); - byte[] btImage2 = new byte[1]; - btImage2 = (byte[])_ic.ConvertTo(bitsec, btImage2.GetType()); - - string hash1String = BitConverter.ToString(_sha256.ComputeHash(btImage1)); - string hash2String = BitConverter.ToString(_sha256.ComputeHash(btImage2)); - - bool res = hash1String == hash2String; + byte[] b1 = (byte[])_ic.ConvertTo(bitorg, typeof(byte[])); + byte[] b2 = (byte[])_ic.ConvertTo(bitsec, typeof(byte[])); + bool res = BitConverter.ToString(_sha256.ComputeHash(b1)) == BitConverter.ToString(_sha256.ComputeHash(b2)); _compare[index] = res; - return res; } private void OnChangeShowDiff(object sender, EventArgs e) { - if (_compare.Count < 1) + if (!_secondLoaded) { if (!checkBox1.Checked) { @@ -233,18 +224,14 @@ private void OnChangeShowDiff(object sender, EventArgs e) return; } - listBoxOrg.BeginUpdate(); - listBoxSec.BeginUpdate(); - listBoxOrg.Items.Clear(); - listBoxSec.Items.Clear(); - List cache = new List(); + _displayIndices.Clear(); if (checkBox1.Checked) { for (int i = 0; i < 0x4000; i++) { if (!Compare(i)) { - cache.Add(i); + _displayIndices.Add(i); } } } @@ -252,61 +239,52 @@ private void OnChangeShowDiff(object sender, EventArgs e) { for (int i = 0; i < 0x4000; i++) { - cache.Add(i); + _displayIndices.Add(i); } } - listBoxOrg.Items.AddRange(cache.ToArray()); - listBoxSec.Items.AddRange(cache.ToArray()); - listBoxOrg.EndUpdate(); - listBoxSec.EndUpdate(); + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; } private void ExportAsBmp(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1) + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondArt.IsValidLand(i)) { return; } - string path = Options.OutputPath; - string fileName = Path.Combine(path, $"Landtile(Sec) 0x{i:X}.bmp"); + string fileName = Path.Combine(Options.OutputPath, $"Landtile(Sec) 0x{i:X}.bmp"); SecondArt.GetLand(i).Save(fileName, ImageFormat.Bmp); - MessageBox.Show( - $"Landtile saved to {fileName}", - "Saved", - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + MessageBox.Show($"Landtile saved to {fileName}", "Saved", + MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void ExportAsTiff(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1) + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondArt.IsValidLand(i)) { return; } - string path = Options.OutputPath; - string fileName = Path.Combine(path, $"Landtile(Sec) 0x{i:X}.tiff"); + string fileName = Path.Combine(Options.OutputPath, $"Landtile(Sec) 0x{i:X}.tiff"); SecondArt.GetLand(i).Save(fileName, ImageFormat.Tiff); - MessageBox.Show( - $"Landtile saved to {fileName}", - "Saved", - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + MessageBox.Show($"Landtile saved to {fileName}", "Saved", + MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void BrowseOnClick(object sender, EventArgs e) @@ -324,12 +302,13 @@ private void BrowseOnClick(object sender, EventArgs e) private void OnClickCopy(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1) + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondArt.IsValidLand(i)) { return; @@ -340,31 +319,64 @@ private void OnClickCopy(object sender, EventArgs e) Options.ChangedUltimaClass["Art"] = true; ControlEvents.FireLandTileChangeEvent(this, i); _compare[i] = true; - listBoxOrg.BeginUpdate(); - bool done = false; - for (int id = 0; id < 0x4000; id++) + + if (checkBox1.Checked) { - if (id > i) - { - listBoxOrg.Items.Insert(id, i); - done = true; - break; - } - if (id == i) + _displayIndices.RemoveAt(focusIdx); + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; + } + + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + pictureBoxOrg.BackgroundImage = Art.IsValidLand(i) ? Art.GetLand(i) : null; + } + + private void OnDoubleClickSec(object sender, MouseEventArgs e) + { + OnClickCopy(sender, e); + } + + private void OnClickCopyAllDiff(object sender, EventArgs e) + { + if (!_secondLoaded) + { + return; + } + + Cursor.Current = Cursors.WaitCursor; + for (int i = 0; i < 0x4000; i++) + { + if (!SecondArt.IsValidLand(i) || Compare(i)) { - done = true; - break; + continue; } + + Bitmap copy = new Bitmap(SecondArt.GetLand(i)); + Art.ReplaceLand(i, copy); + ControlEvents.FireLandTileChangeEvent(this, i); + _compare[i] = true; } - if (!done) + + Options.ChangedUltimaClass["Art"] = true; + + if (checkBox1.Checked) { - listBoxOrg.Items.Add(i); + _displayIndices.Clear(); + for (int i = 0; i < 0x4000; i++) + { + if (!Compare(i)) + { + _displayIndices.Add(i); + } + } + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; } - listBoxOrg.EndUpdate(); - listBoxOrg.Invalidate(); - listBoxSec.Invalidate(); - OnIndexChangedOrg(this, null); + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + Cursor.Current = Cursors.Default; } } } diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.Designer.cs b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.Designer.cs new file mode 100644 index 00000000..bed5c208 --- /dev/null +++ b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.Designer.cs @@ -0,0 +1,563 @@ +namespace UoFiddler.Plugin.Compare.UserControls +{ + partial class CompareRadarColControl + { + private System.ComponentModel.IContainer components = null; + + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + splitContainer1 = new System.Windows.Forms.SplitContainer(); + tabControl = new System.Windows.Forms.TabControl(); + tabPageLand = new System.Windows.Forms.TabPage(); + tableLayoutLand = new System.Windows.Forms.TableLayoutPanel(); + tileViewOrg = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + contextMenuStripOrg = new System.Windows.Forms.ContextMenuStrip(components); + copyEntry1To2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + panelDetail = new System.Windows.Forms.Panel(); + groupBoxLegend = new System.Windows.Forms.GroupBox(); + legendSwatchDifferent = new System.Windows.Forms.Label(); + legendLabelDifferent = new System.Windows.Forms.Label(); + legendSwatchIdentical = new System.Windows.Forms.Label(); + legendLabelIdentical = new System.Windows.Forms.Label(); + groupBoxSec = new System.Windows.Forms.GroupBox(); + labelSecColorCaption = new System.Windows.Forms.Label(); + labelSecColorValue = new System.Windows.Forms.Label(); + pictureBoxSecColor = new System.Windows.Forms.PictureBox(); + groupBoxOrg = new System.Windows.Forms.GroupBox(); + labelOrgColorCaption = new System.Windows.Forms.Label(); + labelOrgColorValue = new System.Windows.Forms.Label(); + pictureBoxOrgColor = new System.Windows.Forms.PictureBox(); + tileViewSec = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + contextMenuStripSec = new System.Windows.Forms.ContextMenuStrip(components); + copyEntry2To1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + tabPageItem = new System.Windows.Forms.TabPage(); + tableLayoutItem = new System.Windows.Forms.TableLayoutPanel(); + tileViewItemOrg = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + tileViewItemSec = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + buttonCopyAllDiff = new System.Windows.Forms.Button(); + buttonCopySelected = new System.Windows.Forms.Button(); + checkBoxShowDiff = new System.Windows.Forms.CheckBox(); + buttonLoadSecond = new System.Windows.Forms.Button(); + buttonBrowse = new System.Windows.Forms.Button(); + textBoxSecondFile = new System.Windows.Forms.TextBox(); + ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); + splitContainer1.Panel1.SuspendLayout(); + splitContainer1.Panel2.SuspendLayout(); + splitContainer1.SuspendLayout(); + tabControl.SuspendLayout(); + tabPageLand.SuspendLayout(); + tableLayoutLand.SuspendLayout(); + contextMenuStripOrg.SuspendLayout(); + panelDetail.SuspendLayout(); + groupBoxLegend.SuspendLayout(); + groupBoxSec.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)pictureBoxSecColor).BeginInit(); + groupBoxOrg.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)pictureBoxOrgColor).BeginInit(); + contextMenuStripSec.SuspendLayout(); + tabPageItem.SuspendLayout(); + tableLayoutItem.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.Name = "splitContainer1"; + splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; + // + // splitContainer1.Panel1 + // + splitContainer1.Panel1.Controls.Add(tabControl); + // + // splitContainer1.Panel2 + // + splitContainer1.Panel2.Controls.Add(buttonCopyAllDiff); + splitContainer1.Panel2.Controls.Add(buttonCopySelected); + splitContainer1.Panel2.Controls.Add(checkBoxShowDiff); + splitContainer1.Panel2.Controls.Add(buttonLoadSecond); + splitContainer1.Panel2.Controls.Add(buttonBrowse); + splitContainer1.Panel2.Controls.Add(textBoxSecondFile); + splitContainer1.Size = new System.Drawing.Size(940, 510); + splitContainer1.SplitterDistance = 451; + splitContainer1.SplitterWidth = 5; + splitContainer1.TabIndex = 0; + // + // tabControl + // + tabControl.Controls.Add(tabPageLand); + tabControl.Controls.Add(tabPageItem); + tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + tabControl.Location = new System.Drawing.Point(0, 0); + tabControl.Name = "tabControl"; + tabControl.SelectedIndex = 0; + tabControl.Size = new System.Drawing.Size(940, 451); + tabControl.TabIndex = 0; + tabControl.SelectedIndexChanged += OnTabChanged; + // + // tabPageLand + // + tabPageLand.Controls.Add(tableLayoutLand); + tabPageLand.Location = new System.Drawing.Point(4, 24); + tabPageLand.Name = "tabPageLand"; + tabPageLand.Size = new System.Drawing.Size(932, 423); + tabPageLand.TabIndex = 0; + tabPageLand.Text = "Land Tiles"; + tabPageLand.UseVisualStyleBackColor = true; + // + // tableLayoutLand + // + tableLayoutLand.ColumnCount = 3; + tableLayoutLand.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27F)); + tableLayoutLand.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 45.46F)); + tableLayoutLand.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27F)); + tableLayoutLand.Controls.Add(tileViewOrg, 0, 0); + tableLayoutLand.Controls.Add(panelDetail, 1, 0); + tableLayoutLand.Controls.Add(tileViewSec, 2, 0); + tableLayoutLand.Dock = System.Windows.Forms.DockStyle.Fill; + tableLayoutLand.Location = new System.Drawing.Point(0, 0); + tableLayoutLand.Name = "tableLayoutLand"; + tableLayoutLand.RowCount = 1; + tableLayoutLand.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + tableLayoutLand.Size = new System.Drawing.Size(932, 423); + tableLayoutLand.TabIndex = 0; + // + // tileViewOrg + // + tileViewOrg.ContextMenuStrip = contextMenuStripOrg; + tileViewOrg.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewOrg.FocusIndex = -1; + tileViewOrg.Location = new System.Drawing.Point(3, 3); + tileViewOrg.MultiSelect = false; + tileViewOrg.Name = "tileViewOrg"; + tileViewOrg.Size = new System.Drawing.Size(248, 417); + tileViewOrg.TabIndex = 0; + tileViewOrg.TileBackgroundColor = System.Drawing.SystemColors.Window; + tileViewOrg.TileBorderColor = System.Drawing.Color.FromArgb(0, 0, 0); + tileViewOrg.TileBorderWidth = 0F; + tileViewOrg.TileFocusColor = System.Drawing.Color.DarkRed; + tileViewOrg.TileHighlightColor = System.Drawing.SystemColors.Highlight; + tileViewOrg.TileHighLightOpacity = 0D; + tileViewOrg.TileMargin = new System.Windows.Forms.Padding(0); + tileViewOrg.TilePadding = new System.Windows.Forms.Padding(0); + tileViewOrg.TileSize = new System.Drawing.Size(248, 15); + tileViewOrg.VirtualListSize = 0; + tileViewOrg.FocusSelectionChanged += OnFocusChangedLandOrg; + tileViewOrg.DrawItem += OnDrawItemLandOrg; + tileViewOrg.SizeChanged += OnTileViewSizeChanged; + tileViewOrg.MouseDoubleClick += OnDoubleClickOrg; + // + // contextMenuStripOrg + // + contextMenuStripOrg.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { copyEntry1To2ToolStripMenuItem }); + contextMenuStripOrg.Name = "contextMenuStripOrg"; + contextMenuStripOrg.Size = new System.Drawing.Size(165, 26); + // + // copyEntry1To2ToolStripMenuItem + // + copyEntry1To2ToolStripMenuItem.Name = "copyEntry1To2ToolStripMenuItem"; + copyEntry1To2ToolStripMenuItem.Size = new System.Drawing.Size(164, 22); + copyEntry1To2ToolStripMenuItem.Text = "Copy Entry 1 to 2"; + copyEntry1To2ToolStripMenuItem.Click += OnClickCopy1To2; + // + // panelDetail + // + panelDetail.Controls.Add(groupBoxOrg); + panelDetail.Controls.Add(groupBoxSec); + panelDetail.Controls.Add(groupBoxLegend); + panelDetail.Dock = System.Windows.Forms.DockStyle.Fill; + panelDetail.Location = new System.Drawing.Point(257, 3); + panelDetail.Name = "panelDetail"; + panelDetail.Size = new System.Drawing.Size(417, 417); + panelDetail.TabIndex = 1; + // + // groupBoxLegend + // + groupBoxLegend.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + groupBoxLegend.Controls.Add(legendSwatchDifferent); + groupBoxLegend.Controls.Add(legendLabelDifferent); + groupBoxLegend.Controls.Add(legendSwatchIdentical); + groupBoxLegend.Controls.Add(legendLabelIdentical); + groupBoxLegend.Location = new System.Drawing.Point(6, 325); + groupBoxLegend.Name = "groupBoxLegend"; + groupBoxLegend.Size = new System.Drawing.Size(405, 70); + groupBoxLegend.TabIndex = 2; + groupBoxLegend.TabStop = false; + groupBoxLegend.Text = "Legend"; + // + // legendSwatchDifferent + // + legendSwatchDifferent.BackColor = System.Drawing.Color.Blue; + legendSwatchDifferent.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + legendSwatchDifferent.Location = new System.Drawing.Point(8, 22); + legendSwatchDifferent.Name = "legendSwatchDifferent"; + legendSwatchDifferent.Size = new System.Drawing.Size(16, 16); + legendSwatchDifferent.TabIndex = 0; + // + // legendLabelDifferent + // + legendLabelDifferent.AutoSize = true; + legendLabelDifferent.Location = new System.Drawing.Point(30, 22); + legendLabelDifferent.Name = "legendLabelDifferent"; + legendLabelDifferent.Size = new System.Drawing.Size(89, 15); + legendLabelDifferent.TabIndex = 1; + legendLabelDifferent.Text = "Different values"; + // + // legendSwatchIdentical + // + legendSwatchIdentical.BackColor = System.Drawing.Color.Gray; + legendSwatchIdentical.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + legendSwatchIdentical.Location = new System.Drawing.Point(8, 46); + legendSwatchIdentical.Name = "legendSwatchIdentical"; + legendSwatchIdentical.Size = new System.Drawing.Size(16, 16); + legendSwatchIdentical.TabIndex = 2; + // + // legendLabelIdentical + // + legendLabelIdentical.AutoSize = true; + legendLabelIdentical.Location = new System.Drawing.Point(30, 46); + legendLabelIdentical.Name = "legendLabelIdentical"; + legendLabelIdentical.Size = new System.Drawing.Size(52, 15); + legendLabelIdentical.TabIndex = 3; + legendLabelIdentical.Text = "Identical"; + // + // groupBoxSec + // + groupBoxSec.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + groupBoxSec.Controls.Add(labelSecColorCaption); + groupBoxSec.Controls.Add(labelSecColorValue); + groupBoxSec.Controls.Add(pictureBoxSecColor); + groupBoxSec.Location = new System.Drawing.Point(6, 164); + groupBoxSec.Name = "groupBoxSec"; + groupBoxSec.Size = new System.Drawing.Size(405, 155); + groupBoxSec.TabIndex = 1; + groupBoxSec.TabStop = false; + groupBoxSec.Text = "Right (Second)"; + // + // labelSecColorCaption + // + labelSecColorCaption.AutoSize = true; + labelSecColorCaption.Location = new System.Drawing.Point(8, 115); + labelSecColorCaption.Name = "labelSecColorCaption"; + labelSecColorCaption.Size = new System.Drawing.Size(39, 15); + labelSecColorCaption.TabIndex = 0; + labelSecColorCaption.Text = "Color:"; + // + // labelSecColorValue + // + labelSecColorValue.AutoSize = true; + labelSecColorValue.Location = new System.Drawing.Point(55, 115); + labelSecColorValue.Name = "labelSecColorValue"; + labelSecColorValue.Size = new System.Drawing.Size(12, 15); + labelSecColorValue.TabIndex = 1; + labelSecColorValue.Text = "-"; + // + // pictureBoxSecColor + // + pictureBoxSecColor.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + pictureBoxSecColor.Location = new System.Drawing.Point(60, 22); + pictureBoxSecColor.Name = "pictureBoxSecColor"; + pictureBoxSecColor.Size = new System.Drawing.Size(80, 80); + pictureBoxSecColor.TabIndex = 2; + pictureBoxSecColor.TabStop = false; + // + // groupBoxOrg + // + groupBoxOrg.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + groupBoxOrg.Controls.Add(labelOrgColorCaption); + groupBoxOrg.Controls.Add(labelOrgColorValue); + groupBoxOrg.Controls.Add(pictureBoxOrgColor); + groupBoxOrg.Location = new System.Drawing.Point(6, 3); + groupBoxOrg.Name = "groupBoxOrg"; + groupBoxOrg.Size = new System.Drawing.Size(405, 155); + groupBoxOrg.TabIndex = 0; + groupBoxOrg.TabStop = false; + groupBoxOrg.Text = "Left (Original)"; + // + // labelOrgColorCaption + // + labelOrgColorCaption.AutoSize = true; + labelOrgColorCaption.Location = new System.Drawing.Point(8, 115); + labelOrgColorCaption.Name = "labelOrgColorCaption"; + labelOrgColorCaption.Size = new System.Drawing.Size(39, 15); + labelOrgColorCaption.TabIndex = 0; + labelOrgColorCaption.Text = "Color:"; + // + // labelOrgColorValue + // + labelOrgColorValue.AutoSize = true; + labelOrgColorValue.Location = new System.Drawing.Point(55, 115); + labelOrgColorValue.Name = "labelOrgColorValue"; + labelOrgColorValue.Size = new System.Drawing.Size(12, 15); + labelOrgColorValue.TabIndex = 1; + labelOrgColorValue.Text = "-"; + // + // pictureBoxOrgColor + // + pictureBoxOrgColor.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + pictureBoxOrgColor.Location = new System.Drawing.Point(60, 22); + pictureBoxOrgColor.Name = "pictureBoxOrgColor"; + pictureBoxOrgColor.Size = new System.Drawing.Size(80, 80); + pictureBoxOrgColor.TabIndex = 2; + pictureBoxOrgColor.TabStop = false; + // + // tileViewSec + // + tileViewSec.ContextMenuStrip = contextMenuStripSec; + tileViewSec.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewSec.FocusIndex = -1; + tileViewSec.Location = new System.Drawing.Point(680, 3); + tileViewSec.MultiSelect = false; + tileViewSec.Name = "tileViewSec"; + tileViewSec.Size = new System.Drawing.Size(249, 417); + tileViewSec.TabIndex = 2; + tileViewSec.TileBackgroundColor = System.Drawing.SystemColors.Window; + tileViewSec.TileBorderColor = System.Drawing.Color.FromArgb(0, 0, 0); + tileViewSec.TileBorderWidth = 0F; + tileViewSec.TileFocusColor = System.Drawing.Color.DarkRed; + tileViewSec.TileHighlightColor = System.Drawing.SystemColors.Highlight; + tileViewSec.TileHighLightOpacity = 0D; + tileViewSec.TileMargin = new System.Windows.Forms.Padding(0); + tileViewSec.TilePadding = new System.Windows.Forms.Padding(0); + tileViewSec.TileSize = new System.Drawing.Size(248, 15); + tileViewSec.VirtualListSize = 0; + tileViewSec.FocusSelectionChanged += OnFocusChangedLandSec; + tileViewSec.DrawItem += OnDrawItemLandSec; + tileViewSec.SizeChanged += OnTileViewSizeChanged; + tileViewSec.MouseDoubleClick += OnDoubleClickSec; + // + // contextMenuStripSec + // + contextMenuStripSec.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { copyEntry2To1ToolStripMenuItem }); + contextMenuStripSec.Name = "contextMenuStripSec"; + contextMenuStripSec.Size = new System.Drawing.Size(165, 26); + // + // copyEntry2To1ToolStripMenuItem + // + copyEntry2To1ToolStripMenuItem.Name = "copyEntry2To1ToolStripMenuItem"; + copyEntry2To1ToolStripMenuItem.Size = new System.Drawing.Size(164, 22); + copyEntry2To1ToolStripMenuItem.Text = "Copy Entry 2 to 1"; + copyEntry2To1ToolStripMenuItem.Click += OnClickCopySelected; + // + // tabPageItem + // + tabPageItem.Controls.Add(tableLayoutItem); + tabPageItem.Location = new System.Drawing.Point(4, 24); + tabPageItem.Name = "tabPageItem"; + tabPageItem.Size = new System.Drawing.Size(932, 424); + tabPageItem.TabIndex = 1; + tabPageItem.Text = "Static Tiles"; + tabPageItem.UseVisualStyleBackColor = true; + // + // tableLayoutItem + // + tableLayoutItem.ColumnCount = 3; + tableLayoutItem.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27F)); + tableLayoutItem.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 45.46F)); + tableLayoutItem.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27F)); + tableLayoutItem.Controls.Add(tileViewItemOrg, 0, 0); + tableLayoutItem.Controls.Add(tileViewItemSec, 2, 0); + tableLayoutItem.Dock = System.Windows.Forms.DockStyle.Fill; + tableLayoutItem.Location = new System.Drawing.Point(0, 0); + tableLayoutItem.Name = "tableLayoutItem"; + tableLayoutItem.RowCount = 1; + tableLayoutItem.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + tableLayoutItem.Size = new System.Drawing.Size(932, 424); + tableLayoutItem.TabIndex = 0; + // + // tileViewItemOrg + // + tileViewItemOrg.ContextMenuStrip = contextMenuStripOrg; + tileViewItemOrg.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewItemOrg.FocusIndex = -1; + tileViewItemOrg.Location = new System.Drawing.Point(3, 3); + tileViewItemOrg.MultiSelect = false; + tileViewItemOrg.Name = "tileViewItemOrg"; + tileViewItemOrg.Size = new System.Drawing.Size(248, 418); + tileViewItemOrg.TabIndex = 0; + tileViewItemOrg.TileBackgroundColor = System.Drawing.SystemColors.Window; + tileViewItemOrg.TileBorderColor = System.Drawing.Color.FromArgb(0, 0, 0); + tileViewItemOrg.TileBorderWidth = 0F; + tileViewItemOrg.TileFocusColor = System.Drawing.Color.DarkRed; + tileViewItemOrg.TileHighlightColor = System.Drawing.SystemColors.Highlight; + tileViewItemOrg.TileHighLightOpacity = 0D; + tileViewItemOrg.TileMargin = new System.Windows.Forms.Padding(0); + tileViewItemOrg.TilePadding = new System.Windows.Forms.Padding(0); + tileViewItemOrg.TileSize = new System.Drawing.Size(248, 15); + tileViewItemOrg.VirtualListSize = 0; + tileViewItemOrg.FocusSelectionChanged += OnFocusChangedItemOrg; + tileViewItemOrg.DrawItem += OnDrawItemItemOrg; + tileViewItemOrg.SizeChanged += OnTileViewSizeChanged; + tileViewItemOrg.MouseDoubleClick += OnDoubleClickOrg; + // + // tileViewItemSec + // + tileViewItemSec.ContextMenuStrip = contextMenuStripSec; + tileViewItemSec.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewItemSec.FocusIndex = -1; + tileViewItemSec.Location = new System.Drawing.Point(680, 3); + tileViewItemSec.MultiSelect = false; + tileViewItemSec.Name = "tileViewItemSec"; + tileViewItemSec.Size = new System.Drawing.Size(249, 418); + tileViewItemSec.TabIndex = 2; + tileViewItemSec.TileBackgroundColor = System.Drawing.SystemColors.Window; + tileViewItemSec.TileBorderColor = System.Drawing.Color.FromArgb(0, 0, 0); + tileViewItemSec.TileBorderWidth = 0F; + tileViewItemSec.TileFocusColor = System.Drawing.Color.DarkRed; + tileViewItemSec.TileHighlightColor = System.Drawing.SystemColors.Highlight; + tileViewItemSec.TileHighLightOpacity = 0D; + tileViewItemSec.TileMargin = new System.Windows.Forms.Padding(0); + tileViewItemSec.TilePadding = new System.Windows.Forms.Padding(0); + tileViewItemSec.TileSize = new System.Drawing.Size(248, 15); + tileViewItemSec.VirtualListSize = 0; + tileViewItemSec.FocusSelectionChanged += OnFocusChangedItemSec; + tileViewItemSec.DrawItem += OnDrawItemItemSec; + tileViewItemSec.SizeChanged += OnTileViewSizeChanged; + tileViewItemSec.MouseDoubleClick += OnDoubleClickSec; + // + // buttonCopyAllDiff + // + buttonCopyAllDiff.Location = new System.Drawing.Point(659, 11); + buttonCopyAllDiff.Name = "buttonCopyAllDiff"; + buttonCopyAllDiff.Size = new System.Drawing.Size(90, 27); + buttonCopyAllDiff.TabIndex = 5; + buttonCopyAllDiff.Text = "Copy All Diff"; + buttonCopyAllDiff.UseVisualStyleBackColor = true; + buttonCopyAllDiff.Click += OnClickCopyAllDiff; + // + // buttonCopySelected + // + buttonCopySelected.Location = new System.Drawing.Point(563, 11); + buttonCopySelected.Name = "buttonCopySelected"; + buttonCopySelected.Size = new System.Drawing.Size(90, 27); + buttonCopySelected.TabIndex = 4; + buttonCopySelected.Text = "Copy Selected"; + buttonCopySelected.UseVisualStyleBackColor = true; + buttonCopySelected.Click += OnClickCopySelected; + // + // checkBoxShowDiff + // + checkBoxShowDiff.AutoSize = true; + checkBoxShowDiff.Location = new System.Drawing.Point(408, 15); + checkBoxShowDiff.Name = "checkBoxShowDiff"; + checkBoxShowDiff.Size = new System.Drawing.Size(143, 19); + checkBoxShowDiff.TabIndex = 3; + checkBoxShowDiff.Text = "Show only Differences"; + checkBoxShowDiff.UseVisualStyleBackColor = true; + checkBoxShowDiff.Click += OnChangeShowDiff; + // + // buttonLoadSecond + // + buttonLoadSecond.AutoSize = true; + buttonLoadSecond.Location = new System.Drawing.Point(306, 11); + buttonLoadSecond.Name = "buttonLoadSecond"; + buttonLoadSecond.Size = new System.Drawing.Size(90, 27); + buttonLoadSecond.TabIndex = 2; + buttonLoadSecond.Text = "Load Second"; + buttonLoadSecond.UseVisualStyleBackColor = true; + buttonLoadSecond.Click += OnClickLoadSecond; + // + // buttonBrowse + // + buttonBrowse.AutoSize = true; + buttonBrowse.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + buttonBrowse.Location = new System.Drawing.Point(272, 13); + buttonBrowse.Name = "buttonBrowse"; + buttonBrowse.Size = new System.Drawing.Size(26, 25); + buttonBrowse.TabIndex = 1; + buttonBrowse.Text = "..."; + buttonBrowse.UseVisualStyleBackColor = true; + buttonBrowse.Click += OnClickBrowse; + // + // textBoxSecondFile + // + textBoxSecondFile.Location = new System.Drawing.Point(6, 15); + textBoxSecondFile.Name = "textBoxSecondFile"; + textBoxSecondFile.Size = new System.Drawing.Size(260, 23); + textBoxSecondFile.TabIndex = 0; + // + // CompareRadarColControl + // + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + Controls.Add(splitContainer1); + DoubleBuffered = true; + Name = "CompareRadarColControl"; + Size = new System.Drawing.Size(940, 510); + Load += OnLoad; + splitContainer1.Panel1.ResumeLayout(false); + splitContainer1.Panel2.ResumeLayout(false); + splitContainer1.Panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); + splitContainer1.ResumeLayout(false); + tabControl.ResumeLayout(false); + tabPageLand.ResumeLayout(false); + tableLayoutLand.ResumeLayout(false); + contextMenuStripOrg.ResumeLayout(false); + panelDetail.ResumeLayout(false); + groupBoxLegend.ResumeLayout(false); + groupBoxLegend.PerformLayout(); + groupBoxSec.ResumeLayout(false); + groupBoxSec.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)pictureBoxSecColor).EndInit(); + groupBoxOrg.ResumeLayout(false); + groupBoxOrg.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)pictureBoxOrgColor).EndInit(); + contextMenuStripSec.ResumeLayout(false); + tabPageItem.ResumeLayout(false); + tableLayoutItem.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabPageLand; + private System.Windows.Forms.TableLayoutPanel tableLayoutLand; + private System.Windows.Forms.TabPage tabPageItem; + private System.Windows.Forms.TableLayoutPanel tableLayoutItem; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewOrg; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewSec; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewItemOrg; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewItemSec; + private System.Windows.Forms.Panel panelDetail; + private System.Windows.Forms.GroupBox groupBoxOrg; + private System.Windows.Forms.Label labelOrgColorCaption; + private System.Windows.Forms.Label labelOrgColorValue; + private System.Windows.Forms.PictureBox pictureBoxOrgColor; + private System.Windows.Forms.GroupBox groupBoxSec; + private System.Windows.Forms.Label labelSecColorCaption; + private System.Windows.Forms.Label labelSecColorValue; + private System.Windows.Forms.PictureBox pictureBoxSecColor; + private System.Windows.Forms.GroupBox groupBoxLegend; + private System.Windows.Forms.Label legendSwatchDifferent; + private System.Windows.Forms.Label legendLabelDifferent; + private System.Windows.Forms.Label legendSwatchIdentical; + private System.Windows.Forms.Label legendLabelIdentical; + private System.Windows.Forms.ContextMenuStrip contextMenuStripOrg; + private System.Windows.Forms.ToolStripMenuItem copyEntry1To2ToolStripMenuItem; + private System.Windows.Forms.ContextMenuStrip contextMenuStripSec; + private System.Windows.Forms.ToolStripMenuItem copyEntry2To1ToolStripMenuItem; + private System.Windows.Forms.TextBox textBoxSecondFile; + private System.Windows.Forms.Button buttonBrowse; + private System.Windows.Forms.Button buttonLoadSecond; + private System.Windows.Forms.CheckBox checkBoxShowDiff; + private System.Windows.Forms.Button buttonCopySelected; + private System.Windows.Forms.Button buttonCopyAllDiff; + } +} diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs new file mode 100644 index 00000000..dbaaf87e --- /dev/null +++ b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.cs @@ -0,0 +1,476 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using Ultima; +using UoFiddler.Controls.Classes; +using UoFiddler.Controls.UserControls.TileView; +using UoFiddler.Plugin.Compare.Classes; + +namespace UoFiddler.Plugin.Compare.UserControls +{ + public partial class CompareRadarColControl : UserControl + { + public CompareRadarColControl() + { + InitializeComponent(); + } + + private readonly Dictionary _compare = new Dictionary(); + private readonly List _landDisplayIndices = new List(); + private readonly List _itemDisplayIndices = new List(); + private bool _syncingSelection; + + private bool IsLandSection => tabControl.SelectedIndex == 0; + + private TileViewControl ActiveOrgView => IsLandSection ? tileViewOrg : tileViewItemOrg; + private TileViewControl ActiveSecView => IsLandSection ? tileViewSec : tileViewItemSec; + private List ActiveIndices => IsLandSection ? _landDisplayIndices : _itemDisplayIndices; + + private void OnLoad(object sender, EventArgs e) + { + PopulateOrgOnly(isLand: true); + ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; + } + + private void OnFilePathChangeEvent() + { + _compare.Clear(); + PopulateOrgOnly(IsLandSection); + ActiveOrgView.Invalidate(); + } + + private void OnTabChanged(object sender, EventArgs e) + { + bool isLand = IsLandSection; + var targetLayout = isLand ? tableLayoutLand : tableLayoutItem; + if (panelDetail.Parent != targetLayout) + { + var prevLayout = isLand ? tableLayoutItem : tableLayoutLand; + prevLayout.SuspendLayout(); + targetLayout.SuspendLayout(); + prevLayout.Controls.Remove(panelDetail); + targetLayout.Controls.Add(panelDetail); + targetLayout.SetCellPosition(panelDetail, new System.Windows.Forms.TableLayoutPanelCellPosition(1, 0)); + targetLayout.ResumeLayout(false); + prevLayout.ResumeLayout(false); + } + + if (SecondRadarCol.IsLoaded) + { + PopulateSection(isLand, checkBoxShowDiff.Checked); + } + else + { + PopulateOrgOnly(isLand); + } + } + + private void PopulateOrgOnly(bool isLand) + { + int start = isLand ? 0x0000 : 0x4000; + int end = isLand ? 0x4000 : 0x8000; + int limit = RadarCol.Colors?.Length ?? end; + end = Math.Min(end, limit); + + var indices = isLand ? _landDisplayIndices : _itemDisplayIndices; + indices.Clear(); + for (int i = start; i < end; i++) + { + indices.Add(i); + } + + var orgView = isLand ? tileViewOrg : tileViewItemOrg; + var secView = isLand ? tileViewSec : tileViewItemSec; + orgView.VirtualListSize = indices.Count; + secView.VirtualListSize = 0; + } + + private void PopulateSection(bool isLand, bool showDiffOnly) + { + Cursor.Current = Cursors.WaitCursor; + try + { + int totalCount = Math.Max(RadarCol.Colors?.Length ?? 0, + SecondRadarCol.IsLoaded ? SecondRadarCol.Length : 0); + if (totalCount == 0) + { + totalCount = 0x8000; + } + + int start = isLand ? 0x0000 : 0x4000; + int end = Math.Min(isLand ? 0x4000 : 0x8000, totalCount); + + var indices = isLand ? _landDisplayIndices : _itemDisplayIndices; + indices.Clear(); + for (int i = start; i < end; i++) + { + if (!showDiffOnly || IsDifferent(i)) + { + indices.Add(i); + } + } + + var orgView = isLand ? tileViewOrg : tileViewItemOrg; + var secView = isLand ? tileViewSec : tileViewItemSec; + orgView.VirtualListSize = indices.Count; + secView.VirtualListSize = SecondRadarCol.IsLoaded ? indices.Count : 0; + } + finally + { + Cursor.Current = Cursors.Default; + } + } + + private void OnTileViewSizeChanged(object sender, EventArgs e) + { + var tv = (TileViewControl)sender; + int w = tv.DisplayRectangle.Width; + if (w > 0 && tv.TileSize.Width != w) + { + tv.TileSize = new Size(w, tv.TileSize.Height); + } + } + + private void OnDrawItemLandOrg(object sender, TileViewControl.DrawTileListItemEventArgs e) + => DrawListItem(e, _landDisplayIndices[e.Index]); + + private void OnDrawItemLandSec(object sender, TileViewControl.DrawTileListItemEventArgs e) + => DrawListItem(e, _landDisplayIndices[e.Index]); + + private void OnDrawItemItemOrg(object sender, TileViewControl.DrawTileListItemEventArgs e) + => DrawListItem(e, _itemDisplayIndices[e.Index]); + + private void OnDrawItemItemSec(object sender, TileViewControl.DrawTileListItemEventArgs e) + => DrawListItem(e, _itemDisplayIndices[e.Index]); + + private void DrawListItem(DrawItemEventArgs e, int idx) + { + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds); + } + else + { + e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds); + } + + Brush fontBrush = SecondRadarCol.IsLoaded && IsDifferent(idx) + ? Brushes.Blue + : Brushes.Gray; + + string section = idx < 0x4000 ? "Land" : "Item"; + string text = $"0x{idx:X4} [{section}]"; + float y = e.Bounds.Y + (e.Bounds.Height - e.Graphics.MeasureString(text, e.Font).Height) / 2f; + e.Graphics.DrawString(text, e.Font, fontBrush, new PointF(4, y)); + } + + private void OnFocusChangedLandOrg(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int idx = _landDisplayIndices[e.FocusedItemIndex]; + if (SecondRadarCol.IsLoaded && tileViewSec.VirtualListSize > 0) + { + if (_syncingSelection) + { + return; + } + + _syncingSelection = true; + try { tileViewSec.FocusIndex = e.FocusedItemIndex; } + finally { _syncingSelection = false; } + } + + UpdateDetailPanel(idx); + } + + private void OnFocusChangedLandSec(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int idx = _landDisplayIndices[e.FocusedItemIndex]; + if (_syncingSelection) + { + return; + } + + _syncingSelection = true; + try + { + tileViewOrg.FocusIndex = e.FocusedItemIndex; + } + finally + { + _syncingSelection = false; + } + + UpdateDetailPanel(idx); + } + + private void OnFocusChangedItemOrg(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int idx = _itemDisplayIndices[e.FocusedItemIndex]; + if (SecondRadarCol.IsLoaded && tileViewItemSec.VirtualListSize > 0) + { + if (_syncingSelection) + { + return; + } + + _syncingSelection = true; + try + { + tileViewItemSec.FocusIndex = e.FocusedItemIndex; + } + finally + { + _syncingSelection = false; + } + } + + UpdateDetailPanel(idx); + } + + private void OnFocusChangedItemSec(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int idx = _itemDisplayIndices[e.FocusedItemIndex]; + if (_syncingSelection) + { + return; + } + + _syncingSelection = true; + try + { + tileViewItemOrg.FocusIndex = e.FocusedItemIndex; + } + finally + { + _syncingSelection = false; + } + + UpdateDetailPanel(idx); + } + + private void UpdateDetailPanel(int idx) + { + ushort orgColor = RadarCol.Colors != null && idx < RadarCol.Colors.Length + ? RadarCol.Colors[idx] + : (ushort)0; + + ushort secColor = SecondRadarCol.IsLoaded ? SecondRadarCol.GetColor(idx) : (ushort)0; + + labelOrgColorValue.Text = $"0x{orgColor:X4} ({orgColor})"; + pictureBoxOrgColor.BackColor = UshortToColor(orgColor); + + if (SecondRadarCol.IsLoaded) + { + labelSecColorValue.Text = $"0x{secColor:X4} ({secColor})"; + pictureBoxSecColor.BackColor = UshortToColor(secColor); + } + else + { + labelSecColorValue.Text = "-"; + pictureBoxSecColor.BackColor = SystemColors.Control; + } + } + + private static Color UshortToColor(ushort value) + { + if (value == 0) + { + return Color.Black; + } + + int b = (value & 0x7C00) >> 10; + int g = (value & 0x03E0) >> 5; + int r = value & 0x001F; + return Color.FromArgb((r << 3) | (r >> 2), (g << 3) | (g >> 2), (b << 3) | (b >> 2)); + } + + private void OnClickBrowse(object sender, EventArgs e) + { + using (OpenFileDialog dialog = new OpenFileDialog()) + { + dialog.Title = "Select radarcol.mul"; + dialog.Filter = "radarcol.mul|radarcol.mul|All files (*.*)|*.*"; + dialog.FileName = "radarcol.mul"; + if (dialog.ShowDialog() == DialogResult.OK) + { + textBoxSecondFile.Text = dialog.FileName; + } + } + } + + private void OnClickLoadSecond(object sender, EventArgs e) + { + string path = textBoxSecondFile.Text?.Trim(); + if (string.IsNullOrEmpty(path)) + { + return; + } + + Cursor.Current = Cursors.WaitCursor; + bool ok = SecondRadarCol.Initialize(path); + Cursor.Current = Cursors.Default; + + if (!ok) + { + MessageBox.Show("Failed to load the selected radarcol.mul file.", "Error", + MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + _compare.Clear(); + PopulateSection(IsLandSection, checkBoxShowDiff.Checked); + } + + private void OnChangeShowDiff(object sender, EventArgs e) + { + if (!SecondRadarCol.IsLoaded) + { + if (checkBoxShowDiff.Checked) + { + MessageBox.Show("Second RadarCol file is not loaded.", "Info", + MessageBoxButtons.OK, MessageBoxIcon.Information); + checkBoxShowDiff.Checked = false; + } + return; + } + + PopulateSection(IsLandSection, checkBoxShowDiff.Checked); + } + + private bool IsDifferent(int idx) + { + if (_compare.TryGetValue(idx, out bool cached)) + { + return !cached; + } + + bool same = RadarCol.Colors != null + && idx < RadarCol.Colors.Length + && RadarCol.Colors[idx] == SecondRadarCol.GetColor(idx); + + _compare[idx] = same; + return !same; + } + + private void OnDoubleClickSec(object sender, MouseEventArgs e) => OnClickCopySelected(sender, e); + private void OnDoubleClickOrg(object sender, MouseEventArgs e) => OnClickCopy1To2(sender, e); + + private void OnClickCopySelected(object sender, EventArgs e) + { + var secView = ActiveSecView; + if (secView.FocusIndex < 0) + { + return; + } + + int idx = ActiveIndices[secView.FocusIndex]; + CopySecToOrg(idx); + + if (checkBoxShowDiff.Checked) + { + int displayIdx = ActiveIndices.IndexOf(idx); + if (displayIdx >= 0) + { + ActiveIndices.RemoveAt(displayIdx); + ActiveOrgView.VirtualListSize = ActiveIndices.Count; + secView.VirtualListSize = ActiveIndices.Count; + } + } + + ActiveOrgView.Invalidate(); + secView.Invalidate(); + UpdateDetailPanel(idx); + } + + private void OnClickCopy1To2(object sender, EventArgs e) + { + var orgView = ActiveOrgView; + if (orgView.FocusIndex < 0) + { + return; + } + + CopyOrgToSec(ActiveIndices[orgView.FocusIndex]); + } + + private void OnClickCopyAllDiff(object sender, EventArgs e) + { + if (!SecondRadarCol.IsLoaded) + { + return; + } + + bool isLand = IsLandSection; + int start = isLand ? 0x0000 : 0x4000; + int end = Math.Min(isLand ? 0x4000 : 0x8000, + Math.Max(RadarCol.Colors?.Length ?? 0, SecondRadarCol.Length)); + bool changed = false; + + for (int i = start; i < end; i++) + { + if (IsDifferent(i)) + { + CopySecToOrg(i); changed = true; + } + } + + if (changed) + { + if (checkBoxShowDiff.Checked) + { + PopulateSection(isLand, showDiffOnly: true); + } + + ActiveOrgView.Invalidate(); + ActiveSecView.Invalidate(); + } + } + + private void CopySecToOrg(int idx) + { + ushort value = SecondRadarCol.GetColor(idx); + if (idx < 0x4000) + { + RadarCol.SetLandColor(idx, value); + } + else + { + RadarCol.SetItemColor(idx - 0x4000, value); + } + + Options.ChangedUltimaClass["RadarCol"] = true; + _compare[idx] = true; + } + + private void CopyOrgToSec(int idx) + { + MessageBox.Show( + "The second file is a read-only reference source.\n" + + "Use 'Copy Entry 2 to 1' to transfer from second to original.", + "Read-only", + MessageBoxButtons.OK, + MessageBoxIcon.Information); + } + } +} diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.resx b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.resx new file mode 100644 index 00000000..e506a25e --- /dev/null +++ b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 186, 17 + + \ No newline at end of file diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.Designer.cs b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.Designer.cs index b88caa26..53d28579 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.Designer.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.Designer.cs @@ -40,13 +40,13 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.listBoxOrg = new System.Windows.Forms.ListBox(); + this.tileViewOrg = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.pictureBoxSec = new System.Windows.Forms.PictureBox(); this.pictureBoxOrg = new System.Windows.Forms.PictureBox(); this.textBoxSecondDir = new System.Windows.Forms.TextBox(); this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); - this.listBoxSec = new System.Windows.Forms.ListBox(); + this.tileViewSec = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); this.exportImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.asBmpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -68,21 +68,23 @@ private void InitializeComponent() this.splitContainer1.Panel2.SuspendLayout(); this.splitContainer1.SuspendLayout(); this.SuspendLayout(); - // - // listBoxOrg - // - this.listBoxOrg.Dock = System.Windows.Forms.DockStyle.Fill; - this.listBoxOrg.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.listBoxOrg.FormattingEnabled = true; - this.listBoxOrg.IntegralHeight = false; - this.listBoxOrg.Location = new System.Drawing.Point(4, 3); - this.listBoxOrg.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.listBoxOrg.Name = "listBoxOrg"; - this.listBoxOrg.Size = new System.Drawing.Size(189, 364); - this.listBoxOrg.TabIndex = 0; - this.listBoxOrg.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.DrawitemOrg); - this.listBoxOrg.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.MeasureOrg); - this.listBoxOrg.SelectedIndexChanged += new System.EventHandler(this.OnIndexChangedOrg); + // + // tileViewOrg + // + this.tileViewOrg.Dock = System.Windows.Forms.DockStyle.Fill; + this.tileViewOrg.Location = new System.Drawing.Point(4, 3); + this.tileViewOrg.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.tileViewOrg.Name = "tileViewOrg"; + this.tileViewOrg.Size = new System.Drawing.Size(189, 364); + this.tileViewOrg.TabIndex = 0; + this.tileViewOrg.TileSize = new System.Drawing.Size(189, 13); + this.tileViewOrg.TileMargin = new System.Windows.Forms.Padding(0); + this.tileViewOrg.TilePadding = new System.Windows.Forms.Padding(0); + this.tileViewOrg.TileBorderWidth = 0f; + this.tileViewOrg.TileHighLightOpacity = 0.0; + this.tileViewOrg.DrawItem += new System.EventHandler(this.OnDrawItemOrg); + this.tileViewOrg.FocusSelectionChanged += new System.EventHandler(this.OnFocusChangedOrg); + this.tileViewOrg.SizeChanged += new System.EventHandler(this.OnTileViewSizeChanged); // // tableLayoutPanel1 // @@ -137,8 +139,8 @@ private void InitializeComponent() this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27273F)); this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 45.45454F)); this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 27.27273F)); - this.tableLayoutPanel2.Controls.Add(this.listBoxOrg, 0, 0); - this.tableLayoutPanel2.Controls.Add(this.listBoxSec, 2, 0); + this.tableLayoutPanel2.Controls.Add(this.tileViewOrg, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.tileViewSec, 2, 0); this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel1, 1, 0); this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0); @@ -148,23 +150,25 @@ private void InitializeComponent() this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); this.tableLayoutPanel2.Size = new System.Drawing.Size(724, 370); this.tableLayoutPanel2.TabIndex = 8; - // - // listBoxSec - // - this.listBoxSec.ContextMenuStrip = this.contextMenuStrip1; - this.listBoxSec.Dock = System.Windows.Forms.DockStyle.Fill; - this.listBoxSec.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; - this.listBoxSec.FormattingEnabled = true; - this.listBoxSec.IntegralHeight = false; - this.listBoxSec.Location = new System.Drawing.Point(530, 3); - this.listBoxSec.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - this.listBoxSec.Name = "listBoxSec"; - this.listBoxSec.Size = new System.Drawing.Size(190, 364); - this.listBoxSec.TabIndex = 1; - this.listBoxSec.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.DrawItemSec); - this.listBoxSec.MeasureItem += new System.Windows.Forms.MeasureItemEventHandler(this.MeasureSec); - this.listBoxSec.SelectedIndexChanged += new System.EventHandler(this.OnIndexChangedSec); - this.listBoxSec.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.CopyToLeft_Click); + // + // tileViewSec + // + this.tileViewSec.ContextMenuStrip = this.contextMenuStrip1; + this.tileViewSec.Dock = System.Windows.Forms.DockStyle.Fill; + this.tileViewSec.Location = new System.Drawing.Point(530, 3); + this.tileViewSec.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + this.tileViewSec.Name = "tileViewSec"; + this.tileViewSec.Size = new System.Drawing.Size(190, 364); + this.tileViewSec.TabIndex = 1; + this.tileViewSec.TileSize = new System.Drawing.Size(190, 13); + this.tileViewSec.TileMargin = new System.Windows.Forms.Padding(0); + this.tileViewSec.TilePadding = new System.Windows.Forms.Padding(0); + this.tileViewSec.TileBorderWidth = 0f; + this.tileViewSec.TileHighLightOpacity = 0.0; + this.tileViewSec.DrawItem += new System.EventHandler(this.OnDrawItemSec); + this.tileViewSec.FocusSelectionChanged += new System.EventHandler(this.OnFocusChangedSec); + this.tileViewSec.SizeChanged += new System.EventHandler(this.OnTileViewSizeChanged); + this.tileViewSec.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.CopyToLeft_Click); // // contextMenuStrip1 // @@ -317,13 +321,13 @@ private void InitializeComponent() #endregion - private System.Windows.Forms.ListBox listBoxOrg; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewOrg; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private System.Windows.Forms.PictureBox pictureBoxSec; private System.Windows.Forms.PictureBox pictureBoxOrg; private System.Windows.Forms.TextBox textBoxSecondDir; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; - private System.Windows.Forms.ListBox listBoxSec; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewSec; private System.Windows.Forms.CheckBox checkBox1; private System.Windows.Forms.Button button1; private System.Windows.Forms.SplitContainer splitContainer1; diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs index 5e87dc78..fcf70b5b 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareTextureControl.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. * @@ -18,6 +18,7 @@ using System.Windows.Forms; using Ultima; using UoFiddler.Controls.Classes; +using UoFiddler.Controls.UserControls.TileView; using UoFiddler.Plugin.Compare.Classes; namespace UoFiddler.Plugin.Compare.UserControls @@ -32,156 +33,151 @@ public CompareTextureControl() private readonly Dictionary _compare = new Dictionary(); private readonly SHA256 _sha256 = SHA256.Create(); private readonly ImageConverter _ic = new ImageConverter(); + private readonly List _displayIndices = new List(); + private bool _syncingSelection; + private bool _secondLoaded; private void OnLoad(object sender, EventArgs e) { - listBoxOrg.BeginUpdate(); - listBoxOrg.Items.Clear(); - List cache = new List(); + _displayIndices.Clear(); for (int i = 0; i < 0x4000; i++) { - cache.Add(i); + _displayIndices.Add(i); } - listBoxOrg.Items.AddRange(cache.ToArray()); - listBoxOrg.EndUpdate(); + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = 0; + + ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; } - private void OnIndexChangedOrg(object sender, EventArgs e) + private void OnFilePathChangeEvent() { - if (listBoxOrg.SelectedIndex == -1 || listBoxOrg.Items.Count < 1) - { - return; - } + _compare.Clear(); + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + } - int i = int.Parse(listBoxOrg.Items[listBoxOrg.SelectedIndex].ToString()); - if (listBoxSec.Items.Count > 0) + private void OnTileViewSizeChanged(object sender, EventArgs e) + { + var tv = (TileViewControl)sender; + int w = tv.DisplayRectangle.Width; + if (w > 0 && tv.TileSize.Width != w) { - listBoxSec.SelectedIndex = listBoxSec.Items.IndexOf(i); + tv.TileSize = new Size(w, tv.TileSize.Height); } + } - pictureBoxOrg.BackgroundImage = Textures.TestTexture(i) - ? Textures.GetTexture(i) - : null; + private void OnDrawItemOrg(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawListItem(e, _displayIndices[e.Index], isSecondary: false); + } - listBoxOrg.Invalidate(); + private void OnDrawItemSec(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawListItem(e, _displayIndices[e.Index], isSecondary: true); } - private void DrawitemOrg(object sender, DrawItemEventArgs e) + private void DrawListItem(DrawItemEventArgs e, int i, bool isSecondary) { - if (e.Index == -1) + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { - return; + e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds); } - - Brush fontBrush = Brushes.Gray; - - int i = int.Parse(listBoxOrg.Items[e.Index].ToString()); - if (listBoxOrg.SelectedIndex == e.Index) + else { - e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); + e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds); } - if (!Textures.TestTexture(i)) + Brush fontBrush = Brushes.Gray; + bool valid = isSecondary ? SecondTexture.IsValidTexture(i) : Textures.TestTexture(i); + + if (!valid) { fontBrush = Brushes.Red; } - else if (listBoxSec.Items.Count > 0) + else if (tileViewSec.VirtualListSize > 0 && !Compare(i)) { - if (!Compare(i)) - { - fontBrush = Brushes.Blue; - } + fontBrush = Brushes.Blue; } - e.Graphics.DrawString($"0x{i:X}", Font, fontBrush, - new PointF(5, - e.Bounds.Y + ((e.Bounds.Height / 2) - - (e.Graphics.MeasureString($"0x{i:X}", Font).Height / 2)))); + string label = $"0x{i:X}"; + float y = e.Bounds.Y + (e.Bounds.Height - e.Graphics.MeasureString(label, Font).Height) / 2f; + e.Graphics.DrawString(label, Font, fontBrush, new PointF(5, y)); } - private void MeasureOrg(object sender, MeasureItemEventArgs e) + private void OnFocusChangedOrg(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) { - e.ItemHeight = 13; - } - - private void OnClickLoadSecond(object sender, EventArgs e) - { - if (textBoxSecondDir.Text == null) + if (e.FocusedItemIndex < 0) { return; } - string path = textBoxSecondDir.Text; - string file = Path.Combine(path, "texmaps.mul"); - string file2 = Path.Combine(path, "texidx.mul"); - if (File.Exists(file) && File.Exists(file2)) - { - SecondTexture.SetFileIndex(file2, file); - LoadSecond(); - } - } + int i = _displayIndices[e.FocusedItemIndex]; - private void LoadSecond() - { - _compare.Clear(); - listBoxSec.BeginUpdate(); - listBoxSec.Items.Clear(); - List cache = new List(); - for (int i = 0; i < 0x4000; i++) + if (tileViewSec.VirtualListSize > 0) { - cache.Add(i); + if (_syncingSelection) + { + return; + } + + _syncingSelection = true; + try { tileViewSec.FocusIndex = e.FocusedItemIndex; } + finally { _syncingSelection = false; } } - listBoxSec.Items.AddRange(cache.ToArray()); - listBoxSec.EndUpdate(); + + pictureBoxOrg.BackgroundImage = Textures.TestTexture(i) ? Textures.GetTexture(i) : null; + pictureBoxSec.BackgroundImage = SecondTexture.IsValidTexture(i) ? SecondTexture.GetTexture(i) : null; + tileViewOrg.Invalidate(); } - private void DrawItemSec(object sender, DrawItemEventArgs e) + private void OnFocusChangedSec(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) { - if (e.Index == -1) + if (e.FocusedItemIndex < 0) { return; } - Brush fontBrush = Brushes.Gray; - - int i = int.Parse(listBoxOrg.Items[e.Index].ToString()); - if (listBoxSec.SelectedIndex == e.Index) - { - e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); - } + int i = _displayIndices[e.FocusedItemIndex]; - if (!SecondTexture.IsValidTexture(i)) - { - fontBrush = Brushes.Red; - } - else if (!Compare(i)) + if (_syncingSelection) { - fontBrush = Brushes.Blue; + return; } - e.Graphics.DrawString($"0x{i:X}", Font, fontBrush, - new PointF(5, - e.Bounds.Y + ((e.Bounds.Height / 2) - - (e.Graphics.MeasureString($"0x{i:X}", Font).Height / 2)))); - } + _syncingSelection = true; + try { tileViewOrg.FocusIndex = e.FocusedItemIndex; } + finally { _syncingSelection = false; } - private void MeasureSec(object sender, MeasureItemEventArgs e) - { - e.ItemHeight = 13; + pictureBoxOrg.BackgroundImage = Textures.TestTexture(i) ? Textures.GetTexture(i) : null; + pictureBoxSec.BackgroundImage = SecondTexture.IsValidTexture(i) ? SecondTexture.GetTexture(i) : null; + tileViewSec.Invalidate(); } - private void OnIndexChangedSec(object sender, EventArgs e) + private void OnClickLoadSecond(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1 || listBoxSec.Items.Count < 1) + if (textBoxSecondDir.Text == null) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); - listBoxOrg.SelectedIndex = listBoxOrg.Items.IndexOf(i); - pictureBoxSec.BackgroundImage = SecondTexture.IsValidTexture(i) ? SecondTexture.GetTexture(i) : null; + string path = textBoxSecondDir.Text; + string file = Path.Combine(path, "texmaps.mul"); + string file2 = Path.Combine(path, "texidx.mul"); + if (File.Exists(file) && File.Exists(file2)) + { + SecondTexture.SetFileIndex(file2, file); + LoadSecond(); + } + } - listBoxSec.Invalidate(); + private void LoadSecond() + { + _secondLoaded = true; + _compare.Clear(); + tileViewSec.VirtualListSize = _displayIndices.Count; + tileViewOrg.Invalidate(); } private bool Compare(int index) @@ -193,34 +189,19 @@ private bool Compare(int index) Bitmap bitorg = Textures.GetTexture(index); Bitmap bitsec = SecondTexture.GetTexture(index); - if (bitorg == null && bitsec == null) - { - _compare[index] = true; - return true; - } - if (bitorg == null || bitsec == null - || bitorg.Size != bitsec.Size) - { - _compare[index] = false; - return false; - } - - byte[] btImage1 = new byte[1]; - btImage1 = (byte[])_ic.ConvertTo(bitorg, btImage1.GetType()); - byte[] btImage2 = new byte[1]; - btImage2 = (byte[])_ic.ConvertTo(bitsec, btImage2.GetType()); + if (bitorg == null && bitsec == null) { _compare[index] = true; return true; } + if (bitorg == null || bitsec == null || bitorg.Size != bitsec.Size) { _compare[index] = false; return false; } - string hash1String = BitConverter.ToString(_sha256.ComputeHash(btImage1)); - string hash2String = BitConverter.ToString(_sha256.ComputeHash(btImage2)); - - bool res = hash1String == hash2String; + byte[] b1 = (byte[])_ic.ConvertTo(bitorg, typeof(byte[])); + byte[] b2 = (byte[])_ic.ConvertTo(bitsec, typeof(byte[])); + bool res = BitConverter.ToString(_sha256.ComputeHash(b1)) == BitConverter.ToString(_sha256.ComputeHash(b2)); _compare[index] = res; return res; } private void OnChangeShowDiff(object sender, EventArgs e) { - if (_compare.Count < 1) + if (!_secondLoaded) { if (checkBox1.Checked) { @@ -231,18 +212,14 @@ private void OnChangeShowDiff(object sender, EventArgs e) } Cursor.Current = Cursors.WaitCursor; - listBoxOrg.BeginUpdate(); - listBoxSec.BeginUpdate(); - listBoxOrg.Items.Clear(); - listBoxSec.Items.Clear(); - List cache = new List(); + _displayIndices.Clear(); if (checkBox1.Checked) { for (int i = 0; i < 0x4000; i++) { if (!Compare(i)) { - cache.Add(i); + _displayIndices.Add(i); } } } @@ -250,62 +227,53 @@ private void OnChangeShowDiff(object sender, EventArgs e) { for (int i = 0; i < 0x4000; i++) { - cache.Add(i); + _displayIndices.Add(i); } } - listBoxOrg.Items.AddRange(cache.ToArray()); - listBoxSec.Items.AddRange(cache.ToArray()); - listBoxOrg.EndUpdate(); - listBoxSec.EndUpdate(); + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; Cursor.Current = Cursors.Default; } private void ExportAsBmp(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1) + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondTexture.IsValidTexture(i)) { return; } - string path = Options.OutputPath; - string fileName = Path.Combine(path, $"Texture(Sec) 0x{i:X}.bmp"); + string fileName = Path.Combine(Options.OutputPath, $"Texture(Sec) 0x{i:X}.bmp"); SecondTexture.GetTexture(i).Save(fileName, ImageFormat.Bmp); - MessageBox.Show( - $"Texture saved to {fileName}", - "Saved", - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + MessageBox.Show($"Texture saved to {fileName}", "Saved", + MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void ExportAsTiff(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1) + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondTexture.IsValidTexture(i)) { return; } - string path = Options.OutputPath; - string fileName = Path.Combine(path, $"Texture(Sec) 0x{i:X}.tiff"); + string fileName = Path.Combine(Options.OutputPath, $"Texture(Sec) 0x{i:X}.tiff"); SecondTexture.GetTexture(i).Save(fileName, ImageFormat.Tiff); - MessageBox.Show( - $"Texture saved to {fileName}", - "Saved", - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1); + MessageBox.Show($"Texture saved to {fileName}", "Saved", + MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1); } private void BrowseOnClick(object sender, EventArgs e) @@ -323,12 +291,13 @@ private void BrowseOnClick(object sender, EventArgs e) private void OnClickCopy(object sender, EventArgs e) { - if (listBoxSec.SelectedIndex == -1) + int focusIdx = tileViewSec.FocusIndex; + if (focusIdx < 0) { return; } - int i = int.Parse(listBoxSec.Items[listBoxSec.SelectedIndex].ToString()); + int i = _displayIndices[focusIdx]; if (!SecondTexture.IsValidTexture(i)) { return; @@ -339,45 +308,29 @@ private void OnClickCopy(object sender, EventArgs e) Options.ChangedUltimaClass["Texture"] = true; ControlEvents.FireTextureChangeEvent(this, i); _compare[i] = true; - listBoxOrg.BeginUpdate(); - bool done = false; - for (int id = 0; id < 0x4000; id++) - { - if (id > i) - { - listBoxOrg.Items.Insert(id, i); - done = true; - break; - } - - if (id == i) - { - done = true; - break; - } - } - if (!done) + if (checkBox1.Checked) { - listBoxOrg.Items.Add(i); + _displayIndices.RemoveAt(focusIdx); + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; } - listBoxOrg.EndUpdate(); - listBoxOrg.Invalidate(); - listBoxSec.Invalidate(); - OnIndexChangedOrg(this, null); + tileViewOrg.Invalidate(); + tileViewSec.Invalidate(); + pictureBoxOrg.BackgroundImage = Textures.TestTexture(i) ? Textures.GetTexture(i) : null; + } + + private void CopyToLeft_Click(object sender, MouseEventArgs e) + { + OnClickCopy(sender, e); } private void CopyAll_Click(object sender, EventArgs e) { for (int i = 0; i < 0x4000; i++) { - if (!SecondTexture.IsValidTexture(i)) - { - continue; - } - - if (Compare(i)) + if (!SecondTexture.IsValidTexture(i) || Compare(i)) { continue; } @@ -387,33 +340,38 @@ private void CopyAll_Click(object sender, EventArgs e) ControlEvents.FireTextureChangeEvent(this, i); } + Options.ChangedUltimaClass["Texture"] = true; _compare.Clear(); - listBoxOrg.BeginUpdate(); - listBoxOrg.Items.Clear(); - List cache = new List(); - for (int i = 0; i < 0x4000; i++) + + if (checkBox1.Checked) + { + _displayIndices.Clear(); + for (int i = 0; i < 0x4000; i++) + { + if (!Compare(i)) + { + _displayIndices.Add(i); + } + } + } + else { - cache.Add(i); + _displayIndices.Clear(); + for (int i = 0; i < 0x4000; i++) + { + _displayIndices.Add(i); + } } - listBoxOrg.Items.AddRange(cache.ToArray()); - listBoxOrg.EndUpdate(); - } - private void CopyToLeft_Click(object sender, MouseEventArgs e) - { - OnClickCopy(sender, e); + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; } private void CopyAddOnly_Click(object sender, EventArgs e) { for (int i = 0; i < 0x4000; i++) { - if (!SecondTexture.IsValidTexture(i)) - { - continue; - } - - if (Textures.TestTexture(i)) + if (!SecondTexture.IsValidTexture(i) || Textures.TestTexture(i)) { continue; } @@ -423,17 +381,31 @@ private void CopyAddOnly_Click(object sender, EventArgs e) ControlEvents.FireTextureChangeEvent(this, i); } + Options.ChangedUltimaClass["Texture"] = true; _compare.Clear(); - listBoxOrg.BeginUpdate(); - listBoxOrg.Items.Clear(); - List cache = new List(); - for (int i = 0; i < 0x4000; i++) + + if (checkBox1.Checked) { - cache.Add(i); + _displayIndices.Clear(); + for (int i = 0; i < 0x4000; i++) + { + if (!Compare(i)) + { + _displayIndices.Add(i); + } + } } - listBoxOrg.Items.AddRange(cache.ToArray()); - listBoxOrg.EndUpdate(); + else + { + _displayIndices.Clear(); + for (int i = 0; i < 0x4000; i++) + { + _displayIndices.Add(i); + } + } + + tileViewOrg.VirtualListSize = _displayIndices.Count; + tileViewSec.VirtualListSize = _displayIndices.Count; } } } - diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.Designer.cs b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.Designer.cs new file mode 100644 index 00000000..737fd38c --- /dev/null +++ b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.Designer.cs @@ -0,0 +1,1275 @@ +namespace UoFiddler.Plugin.Compare.UserControls +{ + partial class CompareTileDataControl + { + private System.ComponentModel.IContainer components = null; + + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + private void InitializeComponent() + { + panelTop = new System.Windows.Forms.Panel(); + labelDir = new System.Windows.Forms.Label(); + textBoxSecondDir = new System.Windows.Forms.TextBox(); + btnBrowse = new System.Windows.Forms.Button(); + btnLoad = new System.Windows.Forms.Button(); + chkShowDiff = new System.Windows.Forms.CheckBox(); + btnToggleRules = new System.Windows.Forms.Button(); + panelRules = new System.Windows.Forms.Panel(); + gbLandFields = new System.Windows.Forms.GroupBox(); + chkLandName = new System.Windows.Forms.CheckBox(); + chkLandTexId = new System.Windows.Forms.CheckBox(); + chkLandFlags = new System.Windows.Forms.CheckBox(); + gbItemFields = new System.Windows.Forms.GroupBox(); + chkItemName = new System.Windows.Forms.CheckBox(); + chkItemFlags = new System.Windows.Forms.CheckBox(); + chkItemAnim = new System.Windows.Forms.CheckBox(); + chkItemWeight = new System.Windows.Forms.CheckBox(); + chkItemQuality = new System.Windows.Forms.CheckBox(); + chkItemQty = new System.Windows.Forms.CheckBox(); + chkItemHue = new System.Windows.Forms.CheckBox(); + chkItemStack = new System.Windows.Forms.CheckBox(); + chkItemValue = new System.Windows.Forms.CheckBox(); + chkItemHeight = new System.Windows.Forms.CheckBox(); + chkItemMisc = new System.Windows.Forms.CheckBox(); + chkItemUnk2 = new System.Windows.Forms.CheckBox(); + chkItemUnk3 = new System.Windows.Forms.CheckBox(); + gbIgnoreFlags = new System.Windows.Forms.GroupBox(); + clbFlags = new System.Windows.Forms.CheckedListBox(); + btnResetRules = new System.Windows.Forms.Button(); + btnApplyRules = new System.Windows.Forms.Button(); + tabControl = new System.Windows.Forms.TabControl(); + tabLand = new System.Windows.Forms.TabPage(); + splitLand = new System.Windows.Forms.SplitContainer(); + tileViewLandOrg = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + splitLandInner = new System.Windows.Forms.SplitContainer(); + panelLandDetail = new System.Windows.Forms.Panel(); + tlpLandDetail = new System.Windows.Forms.TableLayoutPanel(); + panelLandButtons = new System.Windows.Forms.Panel(); + btnCopyLandSelected = new System.Windows.Forms.Button(); + btnCopyLandAllDiff = new System.Windows.Forms.Button(); + tileViewLandSec = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + tabItem = new System.Windows.Forms.TabPage(); + splitItem = new System.Windows.Forms.SplitContainer(); + tileViewItemOrg = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + splitItemInner = new System.Windows.Forms.SplitContainer(); + panelItemDetail = new System.Windows.Forms.Panel(); + tlpItemDetail = new System.Windows.Forms.TableLayoutPanel(); + panelItemButtons = new System.Windows.Forms.Panel(); + btnCopyItemSelected = new System.Windows.Forms.Button(); + btnCopyItemAllDiff = new System.Windows.Forms.Button(); + tileViewItemSec = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); + lblLandName = new System.Windows.Forms.Label(); + txtLandOrgName = new System.Windows.Forms.TextBox(); + txtLandSecName = new System.Windows.Forms.TextBox(); + lblLandTexId = new System.Windows.Forms.Label(); + txtLandOrgTexId = new System.Windows.Forms.TextBox(); + txtLandSecTexId = new System.Windows.Forms.TextBox(); + lblLandFlags = new System.Windows.Forms.Label(); + lblItemName = new System.Windows.Forms.Label(); + txtItemOrgName = new System.Windows.Forms.TextBox(); + txtItemSecName = new System.Windows.Forms.TextBox(); + lblItemFlags = new System.Windows.Forms.Label(); + lblItemAnim = new System.Windows.Forms.Label(); + txtItemOrgAnim = new System.Windows.Forms.TextBox(); + txtItemSecAnim = new System.Windows.Forms.TextBox(); + lblItemWeight = new System.Windows.Forms.Label(); + txtItemOrgWeight = new System.Windows.Forms.TextBox(); + txtItemSecWeight = new System.Windows.Forms.TextBox(); + lblItemQuality = new System.Windows.Forms.Label(); + txtItemOrgQuality = new System.Windows.Forms.TextBox(); + txtItemSecQuality = new System.Windows.Forms.TextBox(); + lblItemQty = new System.Windows.Forms.Label(); + txtItemOrgQty = new System.Windows.Forms.TextBox(); + txtItemSecQty = new System.Windows.Forms.TextBox(); + lblItemHue = new System.Windows.Forms.Label(); + txtItemOrgHue = new System.Windows.Forms.TextBox(); + txtItemSecHue = new System.Windows.Forms.TextBox(); + lblItemStack = new System.Windows.Forms.Label(); + txtItemOrgStack = new System.Windows.Forms.TextBox(); + txtItemSecStack = new System.Windows.Forms.TextBox(); + lblItemValue = new System.Windows.Forms.Label(); + txtItemOrgValue = new System.Windows.Forms.TextBox(); + txtItemSecValue = new System.Windows.Forms.TextBox(); + lblItemHeight = new System.Windows.Forms.Label(); + txtItemOrgHeight = new System.Windows.Forms.TextBox(); + txtItemSecHeight = new System.Windows.Forms.TextBox(); + lblItemMisc = new System.Windows.Forms.Label(); + txtItemOrgMisc = new System.Windows.Forms.TextBox(); + txtItemSecMisc = new System.Windows.Forms.TextBox(); + lblItemUnk2 = new System.Windows.Forms.Label(); + txtItemOrgUnk2 = new System.Windows.Forms.TextBox(); + txtItemSecUnk2 = new System.Windows.Forms.TextBox(); + lblItemUnk3 = new System.Windows.Forms.Label(); + txtItemOrgUnk3 = new System.Windows.Forms.TextBox(); + txtItemSecUnk3 = new System.Windows.Forms.TextBox(); + panelTop.SuspendLayout(); + panelRules.SuspendLayout(); + gbLandFields.SuspendLayout(); + gbItemFields.SuspendLayout(); + gbIgnoreFlags.SuspendLayout(); + tabControl.SuspendLayout(); + tabLand.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitLand).BeginInit(); + splitLand.Panel1.SuspendLayout(); + splitLand.Panel2.SuspendLayout(); + splitLand.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitLandInner).BeginInit(); + splitLandInner.Panel1.SuspendLayout(); + splitLandInner.Panel2.SuspendLayout(); + splitLandInner.SuspendLayout(); + panelLandDetail.SuspendLayout(); + panelLandButtons.SuspendLayout(); + tabItem.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitItem).BeginInit(); + splitItem.Panel1.SuspendLayout(); + splitItem.Panel2.SuspendLayout(); + splitItem.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitItemInner).BeginInit(); + splitItemInner.Panel1.SuspendLayout(); + splitItemInner.Panel2.SuspendLayout(); + splitItemInner.SuspendLayout(); + panelItemDetail.SuspendLayout(); + panelItemButtons.SuspendLayout(); + SuspendLayout(); + // + // panelTop + // + panelTop.Controls.Add(labelDir); + panelTop.Controls.Add(textBoxSecondDir); + panelTop.Controls.Add(btnBrowse); + panelTop.Controls.Add(btnLoad); + panelTop.Controls.Add(chkShowDiff); + panelTop.Controls.Add(btnToggleRules); + panelTop.Dock = System.Windows.Forms.DockStyle.Bottom; + panelTop.Location = new System.Drawing.Point(0, 591); + panelTop.Name = "panelTop"; + panelTop.Padding = new System.Windows.Forms.Padding(4, 4, 4, 0); + panelTop.Size = new System.Drawing.Size(941, 32); + panelTop.TabIndex = 2; + // + // labelDir + // + labelDir.AutoSize = true; + labelDir.Location = new System.Drawing.Point(4, 8); + labelDir.Name = "labelDir"; + labelDir.Size = new System.Drawing.Size(58, 15); + labelDir.TabIndex = 0; + labelDir.Text = "Directory:"; + // + // textBoxSecondDir + // + textBoxSecondDir.Location = new System.Drawing.Point(68, 5); + textBoxSecondDir.Name = "textBoxSecondDir"; + textBoxSecondDir.Size = new System.Drawing.Size(260, 23); + textBoxSecondDir.TabIndex = 1; + // + // btnBrowse + // + btnBrowse.Location = new System.Drawing.Point(333, 3); + btnBrowse.Name = "btnBrowse"; + btnBrowse.Size = new System.Drawing.Size(70, 23); + btnBrowse.TabIndex = 2; + btnBrowse.Text = "Browse..."; + btnBrowse.Click += OnClickBrowse; + // + // btnLoad + // + btnLoad.Location = new System.Drawing.Point(408, 3); + btnLoad.Name = "btnLoad"; + btnLoad.Size = new System.Drawing.Size(55, 23); + btnLoad.TabIndex = 3; + btnLoad.Text = "Load"; + btnLoad.Click += OnClickLoad; + // + // chkShowDiff + // + chkShowDiff.AutoSize = true; + chkShowDiff.Location = new System.Drawing.Point(470, 6); + chkShowDiff.Name = "chkShowDiff"; + chkShowDiff.Size = new System.Drawing.Size(145, 19); + chkShowDiff.TabIndex = 4; + chkShowDiff.Text = "Show Differences Only"; + chkShowDiff.CheckedChanged += OnChangeShowDiff; + // + // btnToggleRules + // + btnToggleRules.AutoSize = true; + btnToggleRules.Location = new System.Drawing.Point(650, 3); + btnToggleRules.Name = "btnToggleRules"; + btnToggleRules.Size = new System.Drawing.Size(75, 25); + btnToggleRules.TabIndex = 5; + btnToggleRules.Text = "Rules ▲"; + btnToggleRules.Click += OnClickToggleRules; + // + // panelRules + // + panelRules.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + panelRules.Controls.Add(gbLandFields); + panelRules.Controls.Add(gbItemFields); + panelRules.Controls.Add(gbIgnoreFlags); + panelRules.Dock = System.Windows.Forms.DockStyle.Bottom; + panelRules.Location = new System.Drawing.Point(0, 441); + panelRules.Name = "panelRules"; + panelRules.Size = new System.Drawing.Size(941, 150); + panelRules.TabIndex = 1; + panelRules.Visible = false; + // + // gbLandFields + // + gbLandFields.Controls.Add(chkLandName); + gbLandFields.Controls.Add(chkLandTexId); + gbLandFields.Controls.Add(chkLandFlags); + gbLandFields.Location = new System.Drawing.Point(4, 4); + gbLandFields.Name = "gbLandFields"; + gbLandFields.Size = new System.Drawing.Size(160, 90); + gbLandFields.TabIndex = 0; + gbLandFields.TabStop = false; + gbLandFields.Text = "Land Fields"; + // + // chkLandName + // + chkLandName.AutoSize = true; + chkLandName.Checked = true; + chkLandName.CheckState = System.Windows.Forms.CheckState.Checked; + chkLandName.Location = new System.Drawing.Point(8, 20); + chkLandName.Name = "chkLandName"; + chkLandName.Size = new System.Drawing.Size(58, 19); + chkLandName.TabIndex = 0; + chkLandName.Text = "Name"; + // + // chkLandTexId + // + chkLandTexId.AutoSize = true; + chkLandTexId.Checked = true; + chkLandTexId.CheckState = System.Windows.Forms.CheckState.Checked; + chkLandTexId.Location = new System.Drawing.Point(8, 42); + chkLandTexId.Name = "chkLandTexId"; + chkLandTexId.Size = new System.Drawing.Size(74, 19); + chkLandTexId.TabIndex = 1; + chkLandTexId.Text = "TextureId"; + // + // chkLandFlags + // + chkLandFlags.AutoSize = true; + chkLandFlags.Checked = true; + chkLandFlags.CheckState = System.Windows.Forms.CheckState.Checked; + chkLandFlags.Location = new System.Drawing.Point(8, 64); + chkLandFlags.Name = "chkLandFlags"; + chkLandFlags.Size = new System.Drawing.Size(53, 19); + chkLandFlags.TabIndex = 2; + chkLandFlags.Text = "Flags"; + // + // gbItemFields + // + gbItemFields.Controls.Add(chkItemName); + gbItemFields.Controls.Add(chkItemFlags); + gbItemFields.Controls.Add(chkItemAnim); + gbItemFields.Controls.Add(chkItemWeight); + gbItemFields.Controls.Add(chkItemQuality); + gbItemFields.Controls.Add(chkItemQty); + gbItemFields.Controls.Add(chkItemHue); + gbItemFields.Controls.Add(chkItemStack); + gbItemFields.Controls.Add(chkItemValue); + gbItemFields.Controls.Add(chkItemHeight); + gbItemFields.Controls.Add(chkItemMisc); + gbItemFields.Controls.Add(chkItemUnk2); + gbItemFields.Controls.Add(chkItemUnk3); + gbItemFields.Location = new System.Drawing.Point(170, 4); + gbItemFields.Name = "gbItemFields"; + gbItemFields.Size = new System.Drawing.Size(310, 136); + gbItemFields.TabIndex = 1; + gbItemFields.TabStop = false; + gbItemFields.Text = "Item Fields"; + // + // chkItemName + // + chkItemName.AutoSize = true; + chkItemName.Checked = true; + chkItemName.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemName.Location = new System.Drawing.Point(8, 20); + chkItemName.Name = "chkItemName"; + chkItemName.Size = new System.Drawing.Size(58, 19); + chkItemName.TabIndex = 0; + chkItemName.Text = "Name"; + // + // chkItemFlags + // + chkItemFlags.AutoSize = true; + chkItemFlags.Checked = true; + chkItemFlags.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemFlags.Location = new System.Drawing.Point(8, 42); + chkItemFlags.Name = "chkItemFlags"; + chkItemFlags.Size = new System.Drawing.Size(53, 19); + chkItemFlags.TabIndex = 1; + chkItemFlags.Text = "Flags"; + // + // chkItemAnim + // + chkItemAnim.AutoSize = true; + chkItemAnim.Checked = true; + chkItemAnim.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemAnim.Location = new System.Drawing.Point(8, 64); + chkItemAnim.Name = "chkItemAnim"; + chkItemAnim.Size = new System.Drawing.Size(55, 19); + chkItemAnim.TabIndex = 2; + chkItemAnim.Text = "Anim"; + // + // chkItemWeight + // + chkItemWeight.AutoSize = true; + chkItemWeight.Checked = true; + chkItemWeight.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemWeight.Location = new System.Drawing.Point(8, 86); + chkItemWeight.Name = "chkItemWeight"; + chkItemWeight.Size = new System.Drawing.Size(64, 19); + chkItemWeight.TabIndex = 3; + chkItemWeight.Text = "Weight"; + // + // chkItemQuality + // + chkItemQuality.AutoSize = true; + chkItemQuality.Checked = true; + chkItemQuality.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemQuality.Location = new System.Drawing.Point(8, 108); + chkItemQuality.Name = "chkItemQuality"; + chkItemQuality.Size = new System.Drawing.Size(64, 19); + chkItemQuality.TabIndex = 4; + chkItemQuality.Text = "Quality"; + // + // chkItemQty + // + chkItemQty.AutoSize = true; + chkItemQty.Checked = true; + chkItemQty.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemQty.Location = new System.Drawing.Point(110, 20); + chkItemQty.Name = "chkItemQty"; + chkItemQty.Size = new System.Drawing.Size(72, 19); + chkItemQty.TabIndex = 5; + chkItemQty.Text = "Quantity"; + // + // chkItemHue + // + chkItemHue.AutoSize = true; + chkItemHue.Checked = true; + chkItemHue.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemHue.Location = new System.Drawing.Point(110, 42); + chkItemHue.Name = "chkItemHue"; + chkItemHue.Size = new System.Drawing.Size(48, 19); + chkItemHue.TabIndex = 6; + chkItemHue.Text = "Hue"; + // + // chkItemStack + // + chkItemStack.AutoSize = true; + chkItemStack.Checked = true; + chkItemStack.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemStack.Location = new System.Drawing.Point(110, 64); + chkItemStack.Name = "chkItemStack"; + chkItemStack.Size = new System.Drawing.Size(86, 19); + chkItemStack.TabIndex = 7; + chkItemStack.Text = "StackOffset"; + // + // chkItemValue + // + chkItemValue.AutoSize = true; + chkItemValue.Checked = true; + chkItemValue.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemValue.Location = new System.Drawing.Point(110, 86); + chkItemValue.Name = "chkItemValue"; + chkItemValue.Size = new System.Drawing.Size(54, 19); + chkItemValue.TabIndex = 8; + chkItemValue.Text = "Value"; + // + // chkItemHeight + // + chkItemHeight.AutoSize = true; + chkItemHeight.Checked = true; + chkItemHeight.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemHeight.Location = new System.Drawing.Point(110, 108); + chkItemHeight.Name = "chkItemHeight"; + chkItemHeight.Size = new System.Drawing.Size(62, 19); + chkItemHeight.TabIndex = 9; + chkItemHeight.Text = "Height"; + // + // chkItemMisc + // + chkItemMisc.AutoSize = true; + chkItemMisc.Checked = true; + chkItemMisc.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemMisc.Location = new System.Drawing.Point(210, 20); + chkItemMisc.Name = "chkItemMisc"; + chkItemMisc.Size = new System.Drawing.Size(75, 19); + chkItemMisc.TabIndex = 10; + chkItemMisc.Text = "MiscData"; + // + // chkItemUnk2 + // + chkItemUnk2.AutoSize = true; + chkItemUnk2.Checked = true; + chkItemUnk2.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemUnk2.Location = new System.Drawing.Point(210, 42); + chkItemUnk2.Name = "chkItemUnk2"; + chkItemUnk2.Size = new System.Drawing.Size(53, 19); + chkItemUnk2.TabIndex = 11; + chkItemUnk2.Text = "Unk2"; + // + // chkItemUnk3 + // + chkItemUnk3.AutoSize = true; + chkItemUnk3.Checked = true; + chkItemUnk3.CheckState = System.Windows.Forms.CheckState.Checked; + chkItemUnk3.Location = new System.Drawing.Point(210, 64); + chkItemUnk3.Name = "chkItemUnk3"; + chkItemUnk3.Size = new System.Drawing.Size(53, 19); + chkItemUnk3.TabIndex = 12; + chkItemUnk3.Text = "Unk3"; + // + // gbIgnoreFlags + // + gbIgnoreFlags.Controls.Add(clbFlags); + gbIgnoreFlags.Controls.Add(btnResetRules); + gbIgnoreFlags.Controls.Add(btnApplyRules); + gbIgnoreFlags.Location = new System.Drawing.Point(486, 4); + gbIgnoreFlags.Name = "gbIgnoreFlags"; + gbIgnoreFlags.Size = new System.Drawing.Size(428, 136); + gbIgnoreFlags.TabIndex = 2; + gbIgnoreFlags.TabStop = false; + gbIgnoreFlags.Text = "Ignore Flags (checked = excluded from compare)"; + // + // clbFlags + // + clbFlags.CheckOnClick = true; + clbFlags.ColumnWidth = 100; + clbFlags.Location = new System.Drawing.Point(6, 18); + clbFlags.MultiColumn = true; + clbFlags.Name = "clbFlags"; + clbFlags.Size = new System.Drawing.Size(300, 112); + clbFlags.TabIndex = 0; + // + // btnResetRules + // + btnResetRules.AutoSize = true; + btnResetRules.Location = new System.Drawing.Point(312, 16); + btnResetRules.Name = "btnResetRules"; + btnResetRules.Size = new System.Drawing.Size(105, 25); + btnResetRules.TabIndex = 1; + btnResetRules.Text = "Reset to Defaults"; + btnResetRules.Click += OnClickResetRules; + // + // btnApplyRules + // + btnApplyRules.AutoSize = true; + btnApplyRules.Font = new System.Drawing.Font(btnApplyRules.Font, System.Drawing.FontStyle.Bold); + btnApplyRules.Location = new System.Drawing.Point(312, 50); + btnApplyRules.Name = "btnApplyRules"; + btnApplyRules.Size = new System.Drawing.Size(105, 25); + btnApplyRules.TabIndex = 2; + btnApplyRules.Text = "Apply"; + btnApplyRules.Click += OnClickApplyRules; + // + // tabControl + // + tabControl.Controls.Add(tabLand); + tabControl.Controls.Add(tabItem); + tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + tabControl.Location = new System.Drawing.Point(0, 0); + tabControl.Name = "tabControl"; + tabControl.SelectedIndex = 0; + tabControl.Size = new System.Drawing.Size(941, 441); + tabControl.TabIndex = 0; + tabControl.SelectedIndexChanged += OnTabChanged; + // + // tabLand + // + tabLand.Controls.Add(splitLand); + tabLand.Location = new System.Drawing.Point(4, 24); + tabLand.Name = "tabLand"; + tabLand.Size = new System.Drawing.Size(933, 413); + tabLand.TabIndex = 0; + tabLand.Text = "Land Tiles"; + // + // splitLand + // + splitLand.Dock = System.Windows.Forms.DockStyle.Fill; + splitLand.FixedPanel = System.Windows.Forms.FixedPanel.Panel1; + splitLand.Location = new System.Drawing.Point(0, 0); + splitLand.Name = "splitLand"; + // + // splitLand.Panel1 + // + splitLand.Panel1.Controls.Add(tileViewLandOrg); + splitLand.Panel1MinSize = 120; + // + // splitLand.Panel2 + // + splitLand.Panel2.Controls.Add(splitLandInner); + splitLand.Panel2MinSize = 150; + splitLand.Size = new System.Drawing.Size(933, 413); + splitLand.SplitterDistance = 280; + splitLand.TabIndex = 0; + // + // tileViewLandOrg + // + tileViewLandOrg.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewLandOrg.Location = new System.Drawing.Point(0, 0); + tileViewLandOrg.Name = "tileViewLandOrg"; + tileViewLandOrg.Size = new System.Drawing.Size(280, 413); + tileViewLandOrg.TabIndex = 0; + tileViewLandOrg.TileSize = new System.Drawing.Size(280, 15); + tileViewLandOrg.TileMargin = new System.Windows.Forms.Padding(0); + tileViewLandOrg.TilePadding = new System.Windows.Forms.Padding(0); + tileViewLandOrg.TileBorderWidth = 0f; + tileViewLandOrg.TileHighLightOpacity = 0.0; + tileViewLandOrg.DrawItem += OnDrawItemLandOrg; + tileViewLandOrg.FocusSelectionChanged += OnFocusChangedLandOrg; + tileViewLandOrg.SizeChanged += OnTileViewSizeChanged; + // + // splitLandInner + // + splitLandInner.Dock = System.Windows.Forms.DockStyle.Fill; + splitLandInner.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; + splitLandInner.Location = new System.Drawing.Point(0, 0); + splitLandInner.Name = "splitLandInner"; + // + // splitLandInner.Panel1 + // + splitLandInner.Panel1.Controls.Add(panelLandDetail); + splitLandInner.Panel1MinSize = 100; + // + // splitLandInner.Panel2 + // + splitLandInner.Panel2.Controls.Add(tileViewLandSec); + splitLandInner.Size = new System.Drawing.Size(649, 413); + splitLandInner.SplitterDistance = 588; + splitLandInner.TabIndex = 0; + // + // panelLandDetail + // + panelLandDetail.Controls.Add(tlpLandDetail); + panelLandDetail.Controls.Add(panelLandButtons); + panelLandDetail.Dock = System.Windows.Forms.DockStyle.Fill; + panelLandDetail.Location = new System.Drawing.Point(0, 0); + panelLandDetail.Name = "panelLandDetail"; + panelLandDetail.Size = new System.Drawing.Size(588, 413); + panelLandDetail.TabIndex = 0; + // + // tlpLandDetail + // + tlpLandDetail.AutoSize = true; + tlpLandDetail.ColumnCount = 3; + tlpLandDetail.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 70F)); + tlpLandDetail.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + tlpLandDetail.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + tlpLandDetail.Dock = System.Windows.Forms.DockStyle.Top; + tlpLandDetail.Location = new System.Drawing.Point(0, 0); + tlpLandDetail.Name = "tlpLandDetail"; + tlpLandDetail.Padding = new System.Windows.Forms.Padding(4); + tlpLandDetail.RowCount = 2; + tlpLandDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpLandDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpLandDetail.Size = new System.Drawing.Size(588, 80); + tlpLandDetail.TabIndex = 0; + // + // panelLandButtons + // + panelLandButtons.Controls.Add(btnCopyLandSelected); + panelLandButtons.Controls.Add(btnCopyLandAllDiff); + panelLandButtons.Dock = System.Windows.Forms.DockStyle.Bottom; + panelLandButtons.Location = new System.Drawing.Point(0, 383); + panelLandButtons.Name = "panelLandButtons"; + panelLandButtons.Size = new System.Drawing.Size(588, 30); + panelLandButtons.TabIndex = 1; + // + // btnCopyLandSelected + // + btnCopyLandSelected.AutoSize = true; + btnCopyLandSelected.Location = new System.Drawing.Point(4, 4); + btnCopyLandSelected.Name = "btnCopyLandSelected"; + btnCopyLandSelected.Size = new System.Drawing.Size(92, 25); + btnCopyLandSelected.TabIndex = 0; + btnCopyLandSelected.Text = "Copy Selected"; + btnCopyLandSelected.Click += OnClickCopyLandSelected; + // + // btnCopyLandAllDiff + // + btnCopyLandAllDiff.AutoSize = true; + btnCopyLandAllDiff.Location = new System.Drawing.Point(110, 4); + btnCopyLandAllDiff.Name = "btnCopyLandAllDiff"; + btnCopyLandAllDiff.Size = new System.Drawing.Size(111, 25); + btnCopyLandAllDiff.TabIndex = 1; + btnCopyLandAllDiff.Text = "Copy All Different"; + btnCopyLandAllDiff.Click += OnClickCopyLandAllDiff; + // + // tileViewLandSec + // + tileViewLandSec.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewLandSec.Location = new System.Drawing.Point(0, 0); + tileViewLandSec.Name = "tileViewLandSec"; + tileViewLandSec.Size = new System.Drawing.Size(57, 413); + tileViewLandSec.TabIndex = 0; + tileViewLandSec.TileSize = new System.Drawing.Size(57, 15); + tileViewLandSec.TileMargin = new System.Windows.Forms.Padding(0); + tileViewLandSec.TilePadding = new System.Windows.Forms.Padding(0); + tileViewLandSec.TileBorderWidth = 0f; + tileViewLandSec.TileHighLightOpacity = 0.0; + tileViewLandSec.DrawItem += OnDrawItemLandSec; + tileViewLandSec.FocusSelectionChanged += OnFocusChangedLandSec; + tileViewLandSec.SizeChanged += OnTileViewSizeChanged; + tileViewLandSec.MouseDoubleClick += OnDoubleClickLandSec; + // + // tabItem + // + tabItem.Controls.Add(splitItem); + tabItem.Location = new System.Drawing.Point(4, 24); + tabItem.Name = "tabItem"; + tabItem.Size = new System.Drawing.Size(850, 413); + tabItem.TabIndex = 1; + tabItem.Text = "Static Tiles"; + // + // splitItem + // + splitItem.Dock = System.Windows.Forms.DockStyle.Fill; + splitItem.FixedPanel = System.Windows.Forms.FixedPanel.Panel1; + splitItem.Location = new System.Drawing.Point(0, 0); + splitItem.Name = "splitItem"; + // + // splitItem.Panel1 + // + splitItem.Panel1.Controls.Add(tileViewItemOrg); + splitItem.Panel1MinSize = 120; + // + // splitItem.Panel2 + // + splitItem.Panel2.Controls.Add(splitItemInner); + splitItem.Panel2MinSize = 150; + splitItem.Size = new System.Drawing.Size(850, 413); + splitItem.SplitterDistance = 280; + splitItem.TabIndex = 0; + // + // tileViewItemOrg + // + tileViewItemOrg.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewItemOrg.Location = new System.Drawing.Point(0, 0); + tileViewItemOrg.Name = "tileViewItemOrg"; + tileViewItemOrg.Size = new System.Drawing.Size(280, 413); + tileViewItemOrg.TabIndex = 0; + tileViewItemOrg.TileSize = new System.Drawing.Size(280, 15); + tileViewItemOrg.TileMargin = new System.Windows.Forms.Padding(0); + tileViewItemOrg.TilePadding = new System.Windows.Forms.Padding(0); + tileViewItemOrg.TileBorderWidth = 0f; + tileViewItemOrg.TileHighLightOpacity = 0.0; + tileViewItemOrg.DrawItem += OnDrawItemItemOrg; + tileViewItemOrg.FocusSelectionChanged += OnFocusChangedItemOrg; + tileViewItemOrg.SizeChanged += OnTileViewSizeChanged; + // + // splitItemInner + // + splitItemInner.Dock = System.Windows.Forms.DockStyle.Fill; + splitItemInner.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; + splitItemInner.Location = new System.Drawing.Point(0, 0); + splitItemInner.Name = "splitItemInner"; + // + // splitItemInner.Panel1 + // + splitItemInner.Panel1.Controls.Add(panelItemDetail); + splitItemInner.Panel1MinSize = 100; + // + // splitItemInner.Panel2 + // + splitItemInner.Panel2.Controls.Add(tileViewItemSec); + splitItemInner.Panel2MinSize = 120; + splitItemInner.Size = new System.Drawing.Size(566, 413); + splitItemInner.SplitterDistance = 441; + splitItemInner.TabIndex = 0; + // + // panelItemDetail + // + panelItemDetail.Controls.Add(tlpItemDetail); + panelItemDetail.Controls.Add(panelItemButtons); + panelItemDetail.Dock = System.Windows.Forms.DockStyle.Fill; + panelItemDetail.Location = new System.Drawing.Point(0, 0); + panelItemDetail.Name = "panelItemDetail"; + panelItemDetail.Size = new System.Drawing.Size(441, 413); + panelItemDetail.TabIndex = 0; + // + // tlpItemDetail + // + tlpItemDetail.AutoSize = true; + tlpItemDetail.ColumnCount = 3; + tlpItemDetail.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 70F)); + tlpItemDetail.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + tlpItemDetail.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + tlpItemDetail.Dock = System.Windows.Forms.DockStyle.Top; + tlpItemDetail.Location = new System.Drawing.Point(0, 0); + tlpItemDetail.Name = "tlpItemDetail"; + tlpItemDetail.Padding = new System.Windows.Forms.Padding(4); + tlpItemDetail.RowCount = 12; + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 24F)); + tlpItemDetail.Size = new System.Drawing.Size(441, 320); + tlpItemDetail.TabIndex = 0; + // + // panelItemButtons + // + panelItemButtons.Controls.Add(btnCopyItemSelected); + panelItemButtons.Controls.Add(btnCopyItemAllDiff); + panelItemButtons.Dock = System.Windows.Forms.DockStyle.Bottom; + panelItemButtons.Location = new System.Drawing.Point(0, 383); + panelItemButtons.Name = "panelItemButtons"; + panelItemButtons.Size = new System.Drawing.Size(441, 30); + panelItemButtons.TabIndex = 1; + // + // btnCopyItemSelected + // + btnCopyItemSelected.AutoSize = true; + btnCopyItemSelected.Location = new System.Drawing.Point(4, 4); + btnCopyItemSelected.Name = "btnCopyItemSelected"; + btnCopyItemSelected.Size = new System.Drawing.Size(92, 25); + btnCopyItemSelected.TabIndex = 0; + btnCopyItemSelected.Text = "Copy Selected"; + btnCopyItemSelected.Click += OnClickCopyItemSelected; + // + // btnCopyItemAllDiff + // + btnCopyItemAllDiff.AutoSize = true; + btnCopyItemAllDiff.Location = new System.Drawing.Point(110, 4); + btnCopyItemAllDiff.Name = "btnCopyItemAllDiff"; + btnCopyItemAllDiff.Size = new System.Drawing.Size(111, 25); + btnCopyItemAllDiff.TabIndex = 1; + btnCopyItemAllDiff.Text = "Copy All Different"; + btnCopyItemAllDiff.Click += OnClickCopyItemAllDiff; + // + // tileViewItemSec + // + tileViewItemSec.Dock = System.Windows.Forms.DockStyle.Fill; + tileViewItemSec.Location = new System.Drawing.Point(0, 0); + tileViewItemSec.Name = "tileViewItemSec"; + tileViewItemSec.Size = new System.Drawing.Size(121, 413); + tileViewItemSec.TabIndex = 0; + tileViewItemSec.TileSize = new System.Drawing.Size(121, 15); + tileViewItemSec.TileMargin = new System.Windows.Forms.Padding(0); + tileViewItemSec.TilePadding = new System.Windows.Forms.Padding(0); + tileViewItemSec.TileBorderWidth = 0f; + tileViewItemSec.TileHighLightOpacity = 0.0; + tileViewItemSec.DrawItem += OnDrawItemItemSec; + tileViewItemSec.FocusSelectionChanged += OnFocusChangedItemSec; + tileViewItemSec.SizeChanged += OnTileViewSizeChanged; + tileViewItemSec.MouseDoubleClick += OnDoubleClickItemSec; + // + // lblLandName + // + lblLandName.Location = new System.Drawing.Point(0, 0); + lblLandName.Name = "lblLandName"; + lblLandName.Size = new System.Drawing.Size(100, 23); + lblLandName.TabIndex = 0; + // + // txtLandOrgName + // + txtLandOrgName.Location = new System.Drawing.Point(0, 0); + txtLandOrgName.Name = "txtLandOrgName"; + txtLandOrgName.Size = new System.Drawing.Size(100, 23); + txtLandOrgName.TabIndex = 0; + // + // txtLandSecName + // + txtLandSecName.Location = new System.Drawing.Point(0, 0); + txtLandSecName.Name = "txtLandSecName"; + txtLandSecName.Size = new System.Drawing.Size(100, 23); + txtLandSecName.TabIndex = 0; + // + // lblLandTexId + // + lblLandTexId.Location = new System.Drawing.Point(0, 0); + lblLandTexId.Name = "lblLandTexId"; + lblLandTexId.Size = new System.Drawing.Size(100, 23); + lblLandTexId.TabIndex = 0; + // + // txtLandOrgTexId + // + txtLandOrgTexId.Location = new System.Drawing.Point(0, 0); + txtLandOrgTexId.Name = "txtLandOrgTexId"; + txtLandOrgTexId.Size = new System.Drawing.Size(100, 23); + txtLandOrgTexId.TabIndex = 0; + // + // txtLandSecTexId + // + txtLandSecTexId.Location = new System.Drawing.Point(0, 0); + txtLandSecTexId.Name = "txtLandSecTexId"; + txtLandSecTexId.Size = new System.Drawing.Size(100, 23); + txtLandSecTexId.TabIndex = 0; + // + // lblLandFlags + // + lblLandFlags.Location = new System.Drawing.Point(0, 0); + lblLandFlags.Name = "lblLandFlags"; + lblLandFlags.Size = new System.Drawing.Size(100, 23); + lblLandFlags.TabIndex = 0; + // + // lblItemName + // + lblItemName.Location = new System.Drawing.Point(0, 0); + lblItemName.Name = "lblItemName"; + lblItemName.Size = new System.Drawing.Size(100, 23); + lblItemName.TabIndex = 0; + // + // txtItemOrgName + // + txtItemOrgName.Location = new System.Drawing.Point(0, 0); + txtItemOrgName.Name = "txtItemOrgName"; + txtItemOrgName.Size = new System.Drawing.Size(100, 23); + txtItemOrgName.TabIndex = 0; + // + // txtItemSecName + // + txtItemSecName.Location = new System.Drawing.Point(0, 0); + txtItemSecName.Name = "txtItemSecName"; + txtItemSecName.Size = new System.Drawing.Size(100, 23); + txtItemSecName.TabIndex = 0; + // + // lblItemFlags + // + lblItemFlags.Location = new System.Drawing.Point(0, 0); + lblItemFlags.Name = "lblItemFlags"; + lblItemFlags.Size = new System.Drawing.Size(100, 23); + lblItemFlags.TabIndex = 0; + // + // lblItemAnim + // + lblItemAnim.Location = new System.Drawing.Point(0, 0); + lblItemAnim.Name = "lblItemAnim"; + lblItemAnim.Size = new System.Drawing.Size(100, 23); + lblItemAnim.TabIndex = 0; + // + // txtItemOrgAnim + // + txtItemOrgAnim.Location = new System.Drawing.Point(0, 0); + txtItemOrgAnim.Name = "txtItemOrgAnim"; + txtItemOrgAnim.Size = new System.Drawing.Size(100, 23); + txtItemOrgAnim.TabIndex = 0; + // + // txtItemSecAnim + // + txtItemSecAnim.Location = new System.Drawing.Point(0, 0); + txtItemSecAnim.Name = "txtItemSecAnim"; + txtItemSecAnim.Size = new System.Drawing.Size(100, 23); + txtItemSecAnim.TabIndex = 0; + // + // lblItemWeight + // + lblItemWeight.Location = new System.Drawing.Point(0, 0); + lblItemWeight.Name = "lblItemWeight"; + lblItemWeight.Size = new System.Drawing.Size(100, 23); + lblItemWeight.TabIndex = 0; + // + // txtItemOrgWeight + // + txtItemOrgWeight.Location = new System.Drawing.Point(0, 0); + txtItemOrgWeight.Name = "txtItemOrgWeight"; + txtItemOrgWeight.Size = new System.Drawing.Size(100, 23); + txtItemOrgWeight.TabIndex = 0; + // + // txtItemSecWeight + // + txtItemSecWeight.Location = new System.Drawing.Point(0, 0); + txtItemSecWeight.Name = "txtItemSecWeight"; + txtItemSecWeight.Size = new System.Drawing.Size(100, 23); + txtItemSecWeight.TabIndex = 0; + // + // lblItemQuality + // + lblItemQuality.Location = new System.Drawing.Point(0, 0); + lblItemQuality.Name = "lblItemQuality"; + lblItemQuality.Size = new System.Drawing.Size(100, 23); + lblItemQuality.TabIndex = 0; + // + // txtItemOrgQuality + // + txtItemOrgQuality.Location = new System.Drawing.Point(0, 0); + txtItemOrgQuality.Name = "txtItemOrgQuality"; + txtItemOrgQuality.Size = new System.Drawing.Size(100, 23); + txtItemOrgQuality.TabIndex = 0; + // + // txtItemSecQuality + // + txtItemSecQuality.Location = new System.Drawing.Point(0, 0); + txtItemSecQuality.Name = "txtItemSecQuality"; + txtItemSecQuality.Size = new System.Drawing.Size(100, 23); + txtItemSecQuality.TabIndex = 0; + // + // lblItemQty + // + lblItemQty.Location = new System.Drawing.Point(0, 0); + lblItemQty.Name = "lblItemQty"; + lblItemQty.Size = new System.Drawing.Size(100, 23); + lblItemQty.TabIndex = 0; + // + // txtItemOrgQty + // + txtItemOrgQty.Location = new System.Drawing.Point(0, 0); + txtItemOrgQty.Name = "txtItemOrgQty"; + txtItemOrgQty.Size = new System.Drawing.Size(100, 23); + txtItemOrgQty.TabIndex = 0; + // + // txtItemSecQty + // + txtItemSecQty.Location = new System.Drawing.Point(0, 0); + txtItemSecQty.Name = "txtItemSecQty"; + txtItemSecQty.Size = new System.Drawing.Size(100, 23); + txtItemSecQty.TabIndex = 0; + // + // lblItemHue + // + lblItemHue.Location = new System.Drawing.Point(0, 0); + lblItemHue.Name = "lblItemHue"; + lblItemHue.Size = new System.Drawing.Size(100, 23); + lblItemHue.TabIndex = 0; + // + // txtItemOrgHue + // + txtItemOrgHue.Location = new System.Drawing.Point(0, 0); + txtItemOrgHue.Name = "txtItemOrgHue"; + txtItemOrgHue.Size = new System.Drawing.Size(100, 23); + txtItemOrgHue.TabIndex = 0; + // + // txtItemSecHue + // + txtItemSecHue.Location = new System.Drawing.Point(0, 0); + txtItemSecHue.Name = "txtItemSecHue"; + txtItemSecHue.Size = new System.Drawing.Size(100, 23); + txtItemSecHue.TabIndex = 0; + // + // lblItemStack + // + lblItemStack.Location = new System.Drawing.Point(0, 0); + lblItemStack.Name = "lblItemStack"; + lblItemStack.Size = new System.Drawing.Size(100, 23); + lblItemStack.TabIndex = 0; + // + // txtItemOrgStack + // + txtItemOrgStack.Location = new System.Drawing.Point(0, 0); + txtItemOrgStack.Name = "txtItemOrgStack"; + txtItemOrgStack.Size = new System.Drawing.Size(100, 23); + txtItemOrgStack.TabIndex = 0; + // + // txtItemSecStack + // + txtItemSecStack.Location = new System.Drawing.Point(0, 0); + txtItemSecStack.Name = "txtItemSecStack"; + txtItemSecStack.Size = new System.Drawing.Size(100, 23); + txtItemSecStack.TabIndex = 0; + // + // lblItemValue + // + lblItemValue.Location = new System.Drawing.Point(0, 0); + lblItemValue.Name = "lblItemValue"; + lblItemValue.Size = new System.Drawing.Size(100, 23); + lblItemValue.TabIndex = 0; + // + // txtItemOrgValue + // + txtItemOrgValue.Location = new System.Drawing.Point(0, 0); + txtItemOrgValue.Name = "txtItemOrgValue"; + txtItemOrgValue.Size = new System.Drawing.Size(100, 23); + txtItemOrgValue.TabIndex = 0; + // + // txtItemSecValue + // + txtItemSecValue.Location = new System.Drawing.Point(0, 0); + txtItemSecValue.Name = "txtItemSecValue"; + txtItemSecValue.Size = new System.Drawing.Size(100, 23); + txtItemSecValue.TabIndex = 0; + // + // lblItemHeight + // + lblItemHeight.Location = new System.Drawing.Point(0, 0); + lblItemHeight.Name = "lblItemHeight"; + lblItemHeight.Size = new System.Drawing.Size(100, 23); + lblItemHeight.TabIndex = 0; + // + // txtItemOrgHeight + // + txtItemOrgHeight.Location = new System.Drawing.Point(0, 0); + txtItemOrgHeight.Name = "txtItemOrgHeight"; + txtItemOrgHeight.Size = new System.Drawing.Size(100, 23); + txtItemOrgHeight.TabIndex = 0; + // + // txtItemSecHeight + // + txtItemSecHeight.Location = new System.Drawing.Point(0, 0); + txtItemSecHeight.Name = "txtItemSecHeight"; + txtItemSecHeight.Size = new System.Drawing.Size(100, 23); + txtItemSecHeight.TabIndex = 0; + // + // lblItemMisc + // + lblItemMisc.Location = new System.Drawing.Point(0, 0); + lblItemMisc.Name = "lblItemMisc"; + lblItemMisc.Size = new System.Drawing.Size(100, 23); + lblItemMisc.TabIndex = 0; + // + // txtItemOrgMisc + // + txtItemOrgMisc.Location = new System.Drawing.Point(0, 0); + txtItemOrgMisc.Name = "txtItemOrgMisc"; + txtItemOrgMisc.Size = new System.Drawing.Size(100, 23); + txtItemOrgMisc.TabIndex = 0; + // + // txtItemSecMisc + // + txtItemSecMisc.Location = new System.Drawing.Point(0, 0); + txtItemSecMisc.Name = "txtItemSecMisc"; + txtItemSecMisc.Size = new System.Drawing.Size(100, 23); + txtItemSecMisc.TabIndex = 0; + // + // lblItemUnk2 + // + lblItemUnk2.Location = new System.Drawing.Point(0, 0); + lblItemUnk2.Name = "lblItemUnk2"; + lblItemUnk2.Size = new System.Drawing.Size(100, 23); + lblItemUnk2.TabIndex = 0; + // + // txtItemOrgUnk2 + // + txtItemOrgUnk2.Location = new System.Drawing.Point(0, 0); + txtItemOrgUnk2.Name = "txtItemOrgUnk2"; + txtItemOrgUnk2.Size = new System.Drawing.Size(100, 23); + txtItemOrgUnk2.TabIndex = 0; + // + // txtItemSecUnk2 + // + txtItemSecUnk2.Location = new System.Drawing.Point(0, 0); + txtItemSecUnk2.Name = "txtItemSecUnk2"; + txtItemSecUnk2.Size = new System.Drawing.Size(100, 23); + txtItemSecUnk2.TabIndex = 0; + // + // lblItemUnk3 + // + lblItemUnk3.Location = new System.Drawing.Point(0, 0); + lblItemUnk3.Name = "lblItemUnk3"; + lblItemUnk3.Size = new System.Drawing.Size(100, 23); + lblItemUnk3.TabIndex = 0; + // + // txtItemOrgUnk3 + // + txtItemOrgUnk3.Location = new System.Drawing.Point(0, 0); + txtItemOrgUnk3.Name = "txtItemOrgUnk3"; + txtItemOrgUnk3.Size = new System.Drawing.Size(100, 23); + txtItemOrgUnk3.TabIndex = 0; + // + // txtItemSecUnk3 + // + txtItemSecUnk3.Location = new System.Drawing.Point(0, 0); + txtItemSecUnk3.Name = "txtItemSecUnk3"; + txtItemSecUnk3.Size = new System.Drawing.Size(100, 23); + txtItemSecUnk3.TabIndex = 0; + // + // CompareTileDataControl + // + Controls.Add(tabControl); + Controls.Add(panelRules); + Controls.Add(panelTop); + Name = "CompareTileDataControl"; + Size = new System.Drawing.Size(941, 623); + Load += OnLoad; + panelTop.ResumeLayout(false); + panelTop.PerformLayout(); + panelRules.ResumeLayout(false); + gbLandFields.ResumeLayout(false); + gbLandFields.PerformLayout(); + gbItemFields.ResumeLayout(false); + gbItemFields.PerformLayout(); + gbIgnoreFlags.ResumeLayout(false); + gbIgnoreFlags.PerformLayout(); + tabControl.ResumeLayout(false); + tabLand.ResumeLayout(false); + splitLand.Panel1.ResumeLayout(false); + splitLand.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitLand).EndInit(); + splitLand.ResumeLayout(false); + splitLandInner.Panel1.ResumeLayout(false); + splitLandInner.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitLandInner).EndInit(); + splitLandInner.ResumeLayout(false); + panelLandDetail.ResumeLayout(false); + panelLandDetail.PerformLayout(); + panelLandButtons.ResumeLayout(false); + panelLandButtons.PerformLayout(); + tabItem.ResumeLayout(false); + splitItem.Panel1.ResumeLayout(false); + splitItem.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitItem).EndInit(); + splitItem.ResumeLayout(false); + splitItemInner.Panel1.ResumeLayout(false); + splitItemInner.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitItemInner).EndInit(); + splitItemInner.ResumeLayout(false); + panelItemDetail.ResumeLayout(false); + panelItemDetail.PerformLayout(); + panelItemButtons.ResumeLayout(false); + panelItemButtons.PerformLayout(); + ResumeLayout(false); + } + + // Helper: add a label + two read-only textboxes as a TLP row + private static void AddDetailRow( + System.Windows.Forms.TableLayoutPanel tlp, + int row, + System.Windows.Forms.Label lbl, + string labelText, + System.Windows.Forms.TextBox txtOrg, + System.Windows.Forms.TextBox txtSec, + bool wideRow) + { + lbl.Text = labelText; + lbl.Dock = System.Windows.Forms.DockStyle.Fill; + lbl.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + + txtOrg.ReadOnly = true; + txtOrg.Dock = System.Windows.Forms.DockStyle.Fill; + + txtSec.ReadOnly = true; + txtSec.Dock = System.Windows.Forms.DockStyle.Fill; + + tlp.Controls.Add(lbl, 0, row); + tlp.Controls.Add(txtOrg, 1, row); + tlp.Controls.Add(txtSec, 2, row); + + if (wideRow) + { + tlp.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 22)); + } + else + { + tlp.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 22)); + } + } + + #endregion + + // ── Field declarations ──────────────────────────────────────────────────── + private System.Windows.Forms.Panel panelTop; + private System.Windows.Forms.Label labelDir; + private System.Windows.Forms.TextBox textBoxSecondDir; + private System.Windows.Forms.Button btnBrowse; + private System.Windows.Forms.Button btnLoad; + private System.Windows.Forms.CheckBox chkShowDiff; + private System.Windows.Forms.Button btnToggleRules; + + private System.Windows.Forms.Panel panelRules; + private System.Windows.Forms.GroupBox gbLandFields; + private System.Windows.Forms.CheckBox chkLandName; + private System.Windows.Forms.CheckBox chkLandTexId; + private System.Windows.Forms.CheckBox chkLandFlags; + + private System.Windows.Forms.GroupBox gbItemFields; + private System.Windows.Forms.CheckBox chkItemName; + private System.Windows.Forms.CheckBox chkItemFlags; + private System.Windows.Forms.CheckBox chkItemAnim; + private System.Windows.Forms.CheckBox chkItemWeight; + private System.Windows.Forms.CheckBox chkItemQuality; + private System.Windows.Forms.CheckBox chkItemQty; + private System.Windows.Forms.CheckBox chkItemHue; + private System.Windows.Forms.CheckBox chkItemStack; + private System.Windows.Forms.CheckBox chkItemValue; + private System.Windows.Forms.CheckBox chkItemHeight; + private System.Windows.Forms.CheckBox chkItemMisc; + private System.Windows.Forms.CheckBox chkItemUnk2; + private System.Windows.Forms.CheckBox chkItemUnk3; + + private System.Windows.Forms.GroupBox gbIgnoreFlags; + private System.Windows.Forms.CheckedListBox clbFlags; + private System.Windows.Forms.Button btnResetRules; + private System.Windows.Forms.Button btnApplyRules; + + private System.Windows.Forms.TabControl tabControl; + + // Land tab + private System.Windows.Forms.TabPage tabLand; + private System.Windows.Forms.SplitContainer splitLand; + private System.Windows.Forms.SplitContainer splitLandInner; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewLandOrg; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewLandSec; + private System.Windows.Forms.Panel panelLandDetail; + private System.Windows.Forms.TableLayoutPanel tlpLandDetail; + private System.Windows.Forms.Label lblLandName; + private System.Windows.Forms.TextBox txtLandOrgName; + private System.Windows.Forms.TextBox txtLandSecName; + private System.Windows.Forms.Label lblLandTexId; + private System.Windows.Forms.TextBox txtLandOrgTexId; + private System.Windows.Forms.TextBox txtLandSecTexId; + private System.Windows.Forms.Label lblLandFlags; + private System.Windows.Forms.Panel panelLandButtons; + private System.Windows.Forms.Button btnCopyLandSelected; + private System.Windows.Forms.Button btnCopyLandAllDiff; + + // Item tab + private System.Windows.Forms.TabPage tabItem; + private System.Windows.Forms.SplitContainer splitItem; + private System.Windows.Forms.SplitContainer splitItemInner; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewItemOrg; + private UoFiddler.Controls.UserControls.TileView.TileViewControl tileViewItemSec; + private System.Windows.Forms.Panel panelItemDetail; + private System.Windows.Forms.TableLayoutPanel tlpItemDetail; + private System.Windows.Forms.Label lblItemName; + private System.Windows.Forms.TextBox txtItemOrgName; + private System.Windows.Forms.TextBox txtItemSecName; + private System.Windows.Forms.Label lblItemFlags; + private System.Windows.Forms.Label lblItemAnim; + private System.Windows.Forms.TextBox txtItemOrgAnim; + private System.Windows.Forms.TextBox txtItemSecAnim; + private System.Windows.Forms.Label lblItemWeight; + private System.Windows.Forms.TextBox txtItemOrgWeight; + private System.Windows.Forms.TextBox txtItemSecWeight; + private System.Windows.Forms.Label lblItemQuality; + private System.Windows.Forms.TextBox txtItemOrgQuality; + private System.Windows.Forms.TextBox txtItemSecQuality; + private System.Windows.Forms.Label lblItemQty; + private System.Windows.Forms.TextBox txtItemOrgQty; + private System.Windows.Forms.TextBox txtItemSecQty; + private System.Windows.Forms.Label lblItemHue; + private System.Windows.Forms.TextBox txtItemOrgHue; + private System.Windows.Forms.TextBox txtItemSecHue; + private System.Windows.Forms.Label lblItemStack; + private System.Windows.Forms.TextBox txtItemOrgStack; + private System.Windows.Forms.TextBox txtItemSecStack; + private System.Windows.Forms.Label lblItemValue; + private System.Windows.Forms.TextBox txtItemOrgValue; + private System.Windows.Forms.TextBox txtItemSecValue; + private System.Windows.Forms.Label lblItemHeight; + private System.Windows.Forms.TextBox txtItemOrgHeight; + private System.Windows.Forms.TextBox txtItemSecHeight; + private System.Windows.Forms.Label lblItemMisc; + private System.Windows.Forms.TextBox txtItemOrgMisc; + private System.Windows.Forms.TextBox txtItemSecMisc; + private System.Windows.Forms.Label lblItemUnk2; + private System.Windows.Forms.TextBox txtItemOrgUnk2; + private System.Windows.Forms.TextBox txtItemSecUnk2; + private System.Windows.Forms.Label lblItemUnk3; + private System.Windows.Forms.TextBox txtItemOrgUnk3; + private System.Windows.Forms.TextBox txtItemSecUnk3; + private System.Windows.Forms.Panel panelItemButtons; + private System.Windows.Forms.Button btnCopyItemSelected; + private System.Windows.Forms.Button btnCopyItemAllDiff; + } +} diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs new file mode 100644 index 00000000..29dce967 --- /dev/null +++ b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.cs @@ -0,0 +1,1324 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using Ultima; +using UoFiddler.Controls.Classes; +using UoFiddler.Controls.UserControls.TileView; +using UoFiddler.Plugin.Compare.Classes; + +namespace UoFiddler.Plugin.Compare.UserControls +{ + public partial class CompareTileDataControl : UserControl + { + public CompareTileDataControl() + { + InitializeComponent(); + } + + // ── State ──────────────────────────────────────────────────────────────── + + private SecondTileData _secondTileData; + private readonly Dictionary _compareLand = new Dictionary(); + private readonly Dictionary _compareItem = new Dictionary(); + private readonly TileDataCompareOptions _options = new TileDataCompareOptions(); + private readonly List _landDisplayIndices = new List(); + private readonly List _itemDisplayIndices = new List(); + + private bool IsLandTab => tabControl.SelectedIndex == 0; + + // ── Flag rows ───────────────────────────────────────────────────────────── + + private static readonly (string Name, TileFlag Flag)[] MeaningfulFlags = + { + ("Background", TileFlag.Background), + ("Weapon", TileFlag.Weapon), + ("Transparent", TileFlag.Transparent), + ("Translucent", TileFlag.Translucent), + ("Wall", TileFlag.Wall), + ("Damaging", TileFlag.Damaging), + ("Impassable", TileFlag.Impassable), + ("Wet", TileFlag.Wet), + ("Unknown1", TileFlag.Unknown1), + ("Surface", TileFlag.Surface), + ("Bridge", TileFlag.Bridge), + ("Generic", TileFlag.Generic), + ("Window", TileFlag.Window), + ("NoShoot", TileFlag.NoShoot), + ("ArticleA", TileFlag.ArticleA), + ("ArticleAn", TileFlag.ArticleAn), + ("ArticleThe", TileFlag.ArticleThe), + ("Foliage", TileFlag.Foliage), + ("PartialHue", TileFlag.PartialHue), + ("NoHouse", TileFlag.NoHouse), + ("Map", TileFlag.Map), + ("Container", TileFlag.Container), + ("Wearable", TileFlag.Wearable), + ("LightSource", TileFlag.LightSource), + ("Animation", TileFlag.Animation), + ("HoverOver", TileFlag.HoverOver), + ("NoDiagonal", TileFlag.NoDiagonal), + ("Armor", TileFlag.Armor), + ("Roof", TileFlag.Roof), + ("Door", TileFlag.Door), + ("StairBack", TileFlag.StairBack), + ("StairRight", TileFlag.StairRight), + ("AlphaBlend", TileFlag.AlphaBlend), + ("UseNewArt", TileFlag.UseNewArt), + ("ArtUsed", TileFlag.ArtUsed), + ("NoShadow", TileFlag.NoShadow), + ("PixelBleed", TileFlag.PixelBleed), + ("PlayAnimOnce", TileFlag.PlayAnimOnce), + ("MultiMovable", TileFlag.MultiMovable), + }; + + private CheckBox[] _landFlagOrgChecks; + private CheckBox[] _landFlagSecChecks; + private Label[] _landFlagLabels; + private TableLayoutPanel _landFlagTlp; + + private CheckBox[] _itemFlagOrgChecks; + private CheckBox[] _itemFlagSecChecks; + private Label[] _itemFlagLabels; + private TableLayoutPanel _itemFlagTlp; + + // ── Load ───────────────────────────────────────────────────────────────── + + private const int ListBoxWidth = 280; + + private void OnLoad(object sender, EventArgs e) + { + SetupDetailPanels(); + PopulateItemOrg(); + PopulateLandOrg(); + BuildRulesPanel(); + SetInnerSplitterPositions(); + } + + private void SetupDetailPanels() + { + // Land detail — 2 rows (Name, TextureId); Flags shown per-flag below + SetupDetailRow(tlpLandDetail, 0, lblLandName, "Name", txtLandOrgName, txtLandSecName); + SetupDetailRow(tlpLandDetail, 1, lblLandTexId, "Texture ID", txtLandOrgTexId, txtLandSecTexId); + SetupFlagsPanel(panelLandDetail, + out _landFlagOrgChecks, out _landFlagSecChecks, out _landFlagLabels, out _landFlagTlp); + // Push tlpLandDetail to the back so it gets the highest z-order and docks topmost + panelLandDetail.Controls.SetChildIndex(tlpLandDetail, panelLandDetail.Controls.Count - 1); + + // Item detail — 12 rows (no Flags row); Flags shown per-flag below + SetupDetailRow(tlpItemDetail, 0, lblItemName, "Name", txtItemOrgName, txtItemSecName); + SetupDetailRow(tlpItemDetail, 1, lblItemAnim, "Animation", txtItemOrgAnim, txtItemSecAnim); + SetupDetailRow(tlpItemDetail, 2, lblItemWeight, "Weight", txtItemOrgWeight, txtItemSecWeight); + SetupDetailRow(tlpItemDetail, 3, lblItemQuality, "Quality", txtItemOrgQuality, txtItemSecQuality); + SetupDetailRow(tlpItemDetail, 4, lblItemQty, "Quantity", txtItemOrgQty, txtItemSecQty); + SetupDetailRow(tlpItemDetail, 5, lblItemHue, "Hue", txtItemOrgHue, txtItemSecHue); + SetupDetailRow(tlpItemDetail, 6, lblItemStack, "StackOffset", txtItemOrgStack, txtItemSecStack); + SetupDetailRow(tlpItemDetail, 7, lblItemValue, "Value", txtItemOrgValue, txtItemSecValue); + SetupDetailRow(tlpItemDetail, 8, lblItemHeight, "Height", txtItemOrgHeight, txtItemSecHeight); + SetupDetailRow(tlpItemDetail, 9, lblItemMisc, "MiscData", txtItemOrgMisc, txtItemSecMisc); + SetupDetailRow(tlpItemDetail, 10, lblItemUnk2, "Unk2", txtItemOrgUnk2, txtItemSecUnk2); + SetupDetailRow(tlpItemDetail, 11, lblItemUnk3, "Unk3", txtItemOrgUnk3, txtItemSecUnk3); + SetupFlagsPanel(panelItemDetail, + out _itemFlagOrgChecks, out _itemFlagSecChecks, out _itemFlagLabels, out _itemFlagTlp); + // Push tlpItemDetail to the back so it gets the highest z-order and docks topmost + panelItemDetail.Controls.SetChildIndex(tlpItemDetail, panelItemDetail.Controls.Count - 1); + } + + private void SetupFlagsPanel( + Panel detailPanel, + out CheckBox[] orgChecks, + out CheckBox[] secChecks, + out Label[] labels, + out TableLayoutPanel flagTlp) + { + int count = MeaningfulFlags.Length; + orgChecks = new CheckBox[count]; + secChecks = new CheckBox[count]; + labels = new Label[count]; + + // Header row + var header = new Panel { Dock = DockStyle.Top, Height = 22, BackColor = SystemColors.ControlLight }; + var hLbl = new Label { Text = "Flag", Dock = DockStyle.Fill, TextAlign = ContentAlignment.MiddleLeft, Padding = new Padding(4, 0, 0, 0) }; + var hSec = new Label { Text = "Sec", Width = 44, Dock = DockStyle.Right, TextAlign = ContentAlignment.MiddleCenter }; + var hOrg = new Label { Text = "Org", Width = 44, Dock = DockStyle.Right, TextAlign = ContentAlignment.MiddleCenter }; + header.Controls.Add(hLbl); + header.Controls.Add(hSec); + header.Controls.Add(hOrg); + + // Scrollable area + var scroll = new Panel { Dock = DockStyle.Fill, AutoScroll = true }; + + // Flag rows TLP + var tlp = new TableLayoutPanel + { + ColumnCount = 3, + RowCount = count, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowAndShrink, + Dock = DockStyle.Top, + }; + tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); + tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 44)); + tlp.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 44)); + + tlp.SuspendLayout(); + for (int i = 0; i < count; i++) + { + tlp.RowStyles.Add(new RowStyle(SizeType.Absolute, 0)); + + var lbl = new Label + { + Text = MeaningfulFlags[i].Name, + Dock = DockStyle.Fill, + TextAlign = ContentAlignment.MiddleLeft, + Padding = new Padding(4, 0, 0, 0), + Visible = false, + }; + var orgChk = new CheckBox + { + AutoCheck = false, + Dock = DockStyle.Fill, + CheckAlign = ContentAlignment.MiddleCenter, + Text = string.Empty, + Visible = false, + }; + var secChk = new CheckBox + { + AutoCheck = false, + Dock = DockStyle.Fill, + CheckAlign = ContentAlignment.MiddleCenter, + Text = string.Empty, + Visible = false, + }; + + tlp.Controls.Add(lbl, 0, i); + tlp.Controls.Add(orgChk, 1, i); + tlp.Controls.Add(secChk, 2, i); + + labels[i] = lbl; + orgChecks[i] = orgChk; + secChecks[i] = secChk; + } + tlp.ResumeLayout(false); + + flagTlp = tlp; + scroll.Controls.Add(tlp); + // Add Fill first, then Top — highest index docks first, so header ends up at top + detailPanel.Controls.Add(scroll); + detailPanel.Controls.Add(header); + } + + private void UpdateFlagRows( + CheckBox[] orgChecks, CheckBox[] secChecks, Label[] labels, TableLayoutPanel flagTlp, + TileFlag orgFlags, TileFlag secFlags, + bool hasOrg, bool hasSec, + bool compareFlags) + { + Color def = SystemColors.Window; + + var scrollPanel = flagTlp.Parent; + scrollPanel?.SuspendLayout(); + flagTlp.SuspendLayout(); + try + { + for (int i = 0; i < MeaningfulFlags.Length; i++) + { + TileFlag f = MeaningfulFlags[i].Flag; + + bool orgHas = hasOrg && (orgFlags & f) != 0; + bool secHas = hasSec && (secFlags & f) != 0; + + // Hide rows where neither side has the flag set + bool visible = orgHas || secHas; + labels[i].Visible = visible; + orgChecks[i].Visible = visible; + secChecks[i].Visible = visible; + flagTlp.RowStyles[i].Height = visible ? 22F : 0F; + + if (!visible) + { + continue; + } + + orgChecks[i].Checked = orgHas; + secChecks[i].Checked = secHas; + + bool ignored = (_options.IgnoredFlags & f) != 0; + bool differs = hasOrg && hasSec && compareFlags && !ignored && orgHas != secHas; + + Color bg = differs ? DiffColor : def; + labels[i].BackColor = bg; + orgChecks[i].BackColor = bg; + secChecks[i].BackColor = bg; + } + } + finally + { + flagTlp.ResumeLayout(true); + scrollPanel?.ResumeLayout(false); + } + } + + private static void SetupDetailRow( + System.Windows.Forms.TableLayoutPanel tlp, int row, + System.Windows.Forms.Label lbl, string labelText, + System.Windows.Forms.TextBox orgBox, System.Windows.Forms.TextBox secBox) + { + lbl.Text = labelText; + lbl.Dock = System.Windows.Forms.DockStyle.Fill; + lbl.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + + orgBox.ReadOnly = true; + orgBox.Dock = System.Windows.Forms.DockStyle.Fill; + + secBox.ReadOnly = true; + secBox.Dock = System.Windows.Forms.DockStyle.Fill; + + tlp.Controls.Add(lbl, 0, row); + tlp.Controls.Add(orgBox, 1, row); + tlp.Controls.Add(secBox, 2, row); + } + + private void SetInnerSplitterPositions() + { + SetInnerSplitter(splitLandInner); + SetInnerSplitter(splitItemInner); + } + + private static void SetInnerSplitter(System.Windows.Forms.SplitContainer sc) + { + int dist = sc.Width - ListBoxWidth - sc.SplitterWidth; + if (dist > sc.Panel1MinSize) + { + sc.SplitterDistance = dist; + } + } + + private void PopulateLandOrg() + { + _landDisplayIndices.Clear(); + for (int i = 0; i < TileData.LandTable.Length; i++) + { + _landDisplayIndices.Add(i); + } + + tileViewLandOrg.VirtualListSize = _landDisplayIndices.Count; + tileViewLandSec.VirtualListSize = 0; + } + + private void PopulateItemOrg() + { + _itemDisplayIndices.Clear(); + for (int i = 0; i < TileData.ItemTable.Length; i++) + { + _itemDisplayIndices.Add(i); + } + + tileViewItemOrg.VirtualListSize = _itemDisplayIndices.Count; + tileViewItemSec.VirtualListSize = 0; + } + + // ── Browse / Load second file ───────────────────────────────────────────── + + private void OnClickBrowse(object sender, EventArgs e) + { + using (var dialog = new FolderBrowserDialog()) + { + dialog.Description = "Select directory containing the UO files"; + dialog.ShowNewFolderButton = false; + if (dialog.ShowDialog() == DialogResult.OK) + { + textBoxSecondDir.Text = dialog.SelectedPath; + } + } + } + + private void OnClickLoad(object sender, EventArgs e) + { + string path = textBoxSecondDir.Text?.Trim(); + if (string.IsNullOrEmpty(path)) + { + return; + } + + string tileFile = Path.Combine(path, "tiledata.mul"); + string artFile = Path.Combine(path, "art.mul"); + string artIdx = Path.Combine(path, "artidx.mul"); + + if (!File.Exists(tileFile) || !File.Exists(artFile) || !File.Exists(artIdx)) + { + MessageBox.Show("Could not find tiledata.mul, art.mul and artidx.mul in the selected directory.", + "Missing Files", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + SecondArt.SetFileIndex(artIdx, artFile); + + _secondTileData = new SecondTileData(); + _secondTileData.Initialize(tileFile, SecondArt.IsUOAHS()); + + InvalidateCompareCache(); + RefreshBothLists(); + } + + // ── Compare cache ──────────────────────────────────────────────────────── + + private void InvalidateCompareCache() + { + _compareLand.Clear(); + _compareItem.Clear(); + tileViewLandOrg.Invalidate(); + tileViewLandSec.Invalidate(); + tileViewItemOrg.Invalidate(); + tileViewItemSec.Invalidate(); + } + + private bool CompareLand(int index) + { + if (_secondTileData == null) + { + return true; + } + + if (_compareLand.TryGetValue(index, out bool cached)) + { + return cached; + } + + if (index >= TileData.LandTable.Length || index >= _secondTileData.LandTable.Length) + { + _compareLand[index] = false; + return false; + } + + var left = TileData.LandTable[index]; + var right = _secondTileData.LandTable[index]; + + bool same = true; + + if (_options.LandCompareName && same) + { + same = left.Name == right.Name; + } + + if (_options.LandCompareTextureId && same) + { + same = left.TextureId == right.TextureId; + } + + if (_options.LandCompareFlags && same) + { + TileFlag lf = left.Flags & ~_options.IgnoredFlags; + TileFlag rf = right.Flags & ~_options.IgnoredFlags; + same = lf == rf; + } + + _compareLand[index] = same; + return same; + } + + private bool CompareItem(int index) + { + if (_secondTileData == null) + { + return true; + } + + if (_compareItem.TryGetValue(index, out bool cached)) + { + return cached; + } + + if (index >= TileData.ItemTable.Length || index >= _secondTileData.ItemTable.Length) + { + _compareItem[index] = false; + return false; + } + + var left = TileData.ItemTable[index]; + var right = _secondTileData.ItemTable[index]; + + bool same = true; + + if (_options.ItemCompareName && same) + { + same = left.Name == right.Name; + } + + if (_options.ItemCompareFlags && same) + { + TileFlag lf = left.Flags & ~_options.IgnoredFlags; + TileFlag rf = right.Flags & ~_options.IgnoredFlags; + same = lf == rf; + } + + if (_options.ItemCompareAnimation && same) + { + same = left.Animation == right.Animation; + } + + if (_options.ItemCompareWeight && same) + { + same = left.Weight == right.Weight; + } + + if (_options.ItemCompareQuality && same) + { + same = left.Quality == right.Quality; + } + + if (_options.ItemCompareQuantity && same) + { + same = left.Quantity == right.Quantity; + } + + if (_options.ItemCompareHue && same) + { + same = left.Hue == right.Hue; + } + + if (_options.ItemCompareStackingOffset && same) + { + same = left.StackingOffset == right.StackingOffset; + } + + if (_options.ItemCompareValue && same) + { + same = left.Value == right.Value; + } + + if (_options.ItemCompareHeight && same) + { + same = left.Height == right.Height; + } + + if (_options.ItemCompareMiscData && same) + { + same = left.MiscData == right.MiscData; + } + + if (_options.ItemCompareUnk2 && same) + { + same = left.Unk2 == right.Unk2; + } + + if (_options.ItemCompareUnk3 && same) + { + same = left.Unk3 == right.Unk3; + } + + _compareItem[index] = same; + return same; + } + + // ── List population / refresh ───────────────────────────────────────────── + + private void RefreshBothLists() + { + RefreshLandLists(); + RefreshItemLists(); + } + + private void RefreshLandLists() + { + bool diffOnly = chkShowDiff.Checked && _secondTileData != null; + int orgLen = TileData.LandTable.Length; + int secLen = _secondTileData?.LandTable.Length ?? 0; + int total = Math.Max(orgLen, secLen); + + _landDisplayIndices.Clear(); + for (int i = 0; i < total; i++) + { + if (!diffOnly || !CompareLand(i)) + { + _landDisplayIndices.Add(i); + } + } + + tileViewLandOrg.VirtualListSize = _landDisplayIndices.Count; + tileViewLandSec.VirtualListSize = _landDisplayIndices.Count; + } + + private void RefreshItemLists() + { + bool diffOnly = chkShowDiff.Checked && _secondTileData != null; + int orgLen = TileData.ItemTable.Length; + int secLen = _secondTileData?.ItemTable.Length ?? 0; + int total = Math.Max(orgLen, secLen); + + _itemDisplayIndices.Clear(); + for (int i = 0; i < total; i++) + { + if (!diffOnly || !CompareItem(i)) + { + _itemDisplayIndices.Add(i); + } + } + + tileViewItemOrg.VirtualListSize = _itemDisplayIndices.Count; + tileViewItemSec.VirtualListSize = _itemDisplayIndices.Count; + } + + // ── Show Differences Only ───────────────────────────────────────────────── + + private void OnChangeShowDiff(object sender, EventArgs e) + { + if (chkShowDiff.Checked && _secondTileData == null) + { + MessageBox.Show("Second tiledata file is not loaded.", "Info", + MessageBoxButtons.OK, MessageBoxIcon.Information); + chkShowDiff.Checked = false; + return; + } + + Cursor.Current = Cursors.WaitCursor; + if (IsLandTab) + { + RefreshLandLists(); + } + else + { + RefreshItemLists(); + } + Cursor.Current = Cursors.Default; + } + + private void OnTabChanged(object sender, EventArgs e) + { + Cursor.Current = Cursors.WaitCursor; + try + { + if (chkShowDiff.Checked && _secondTileData != null) + { + if (IsLandTab) + { + RefreshLandLists(); + } + else + { + RefreshItemLists(); + } + } + } + finally + { + Cursor.Current = Cursors.Default; + } + } + + // ── Owner-draw helpers ──────────────────────────────────────────────────── + + private void OnTileViewSizeChanged(object sender, EventArgs e) + { + var tv = (TileViewControl)sender; + int w = tv.DisplayRectangle.Width; + if (w > 0 && tv.TileSize.Width != w) + { + tv.TileSize = new Size(w, tv.TileSize.Height); + } + } + + // Land org + private void OnDrawItemLandOrg(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawLandItem(e, _landDisplayIndices[e.Index], isSecondary: false); + } + + // Land sec + private void OnDrawItemLandSec(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawLandItem(e, _landDisplayIndices[e.Index], isSecondary: true); + } + + private void DrawLandItem(DrawItemEventArgs e, int i, bool isSecondary) + { + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds); + } + else + { + e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds); + } + + Brush brush = GetLandBrush(i, isSecondary); + string label = GetLandLabel(i, isSecondary); + + float y = e.Bounds.Y + (e.Bounds.Height - e.Graphics.MeasureString(label, e.Font).Height) / 2f; + e.Graphics.DrawString(label, e.Font, brush, new PointF(4, y)); + } + + private Brush GetLandBrush(int i, bool isSecondary) + { + bool inOrg = i < TileData.LandTable.Length; + bool inSec = _secondTileData != null && i < _secondTileData.LandTable.Length; + + if (_secondTileData != null) + { + if (inOrg && !inSec) + { + return Brushes.Orange; + } + + if (!inOrg && inSec) + { + return Brushes.Green; + } + + if (!CompareLand(i)) + { + return Brushes.Blue; + } + } + + return Brushes.Gray; + } + + private string GetLandLabel(int i, bool isSecondary) + { + bool inOrg = i < TileData.LandTable.Length; + bool inSec = _secondTileData != null && i < _secondTileData.LandTable.Length; + + if (isSecondary) + { + if (!inSec) + { + return $"0x{i:X4} ({i}) "; + } + + return $"0x{i:X4} ({i}) {_secondTileData.LandTable[i].Name}"; + } + else + { + if (!inOrg) + { + return $"0x{i:X4} ({i}) "; + } + + return $"0x{i:X4} ({i}) {TileData.LandTable[i].Name}"; + } + } + + // Item org + private void OnDrawItemItemOrg(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawItemEntry(e, _itemDisplayIndices[e.Index], isSecondary: false); + } + + // Item sec + private void OnDrawItemItemSec(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + DrawItemEntry(e, _itemDisplayIndices[e.Index], isSecondary: true); + } + + private void DrawItemEntry(DrawItemEventArgs e, int i, bool isSecondary) + { + if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) + { + e.Graphics.FillRectangle(Brushes.LightSteelBlue, e.Bounds); + } + else + { + e.Graphics.FillRectangle(new SolidBrush(e.BackColor), e.Bounds); + } + + Brush brush = GetItemBrush(i); + string label = GetItemLabel(i, isSecondary); + + float y = e.Bounds.Y + (e.Bounds.Height - e.Graphics.MeasureString(label, e.Font).Height) / 2f; + e.Graphics.DrawString(label, e.Font, brush, new PointF(4, y)); + } + + private Brush GetItemBrush(int i) + { + bool inOrg = i < TileData.ItemTable.Length; + bool inSec = _secondTileData != null && i < _secondTileData.ItemTable.Length; + + if (_secondTileData != null) + { + if (inOrg && !inSec) + { + return Brushes.Orange; + } + + if (!inOrg && inSec) + { + return Brushes.Green; + } + + if (!CompareItem(i)) + { + return Brushes.Blue; + } + } + else if (!inOrg) + { + return Brushes.Red; + } + + return Brushes.Gray; + } + + private string GetItemLabel(int i, bool isSecondary) + { + bool inOrg = i < TileData.ItemTable.Length; + bool inSec = _secondTileData != null && i < _secondTileData.ItemTable.Length; + + if (isSecondary) + { + if (!inSec) + { + return $"0x{i:X4} ({i}) "; + } + + return $"0x{i:X4} ({i}) {_secondTileData.ItemTable[i].Name}"; + } + else + { + if (!inOrg) + { + return $"0x{i:X4} ({i}) "; + } + + return $"0x{i:X4} ({i}) {TileData.ItemTable[i].Name}"; + } + } + + // ── Selection sync + detail panels ─────────────────────────────────────── + + private bool _syncingSelection; + + private void SyncTileView(TileViewControl target, List displayIndices, int tileId) + { + if (_syncingSelection || target.VirtualListSize == 0) + { + return; + } + + _syncingSelection = true; + try + { + int displayIdx = displayIndices.IndexOf(tileId); + if (displayIdx >= 0 && displayIdx < target.VirtualListSize) + { + target.FocusIndex = displayIdx; + } + } + finally + { + _syncingSelection = false; + } + } + + private void OnFocusChangedLandOrg(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int tileId = _landDisplayIndices[e.FocusedItemIndex]; + SyncTileView(tileViewLandSec, _landDisplayIndices, tileId); + UpdateLandDetail(tileId); + } + + private void OnFocusChangedLandSec(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int tileId = _landDisplayIndices[e.FocusedItemIndex]; + SyncTileView(tileViewLandOrg, _landDisplayIndices, tileId); + UpdateLandDetail(tileId); + } + + private void OnFocusChangedItemOrg(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int tileId = _itemDisplayIndices[e.FocusedItemIndex]; + SyncTileView(tileViewItemSec, _itemDisplayIndices, tileId); + UpdateItemDetail(tileId); + } + + private void OnFocusChangedItemSec(object sender, TileViewControl.ListViewFocusedItemSelectionChangedEventArgs e) + { + if (e.FocusedItemIndex < 0) + { + return; + } + + int tileId = _itemDisplayIndices[e.FocusedItemIndex]; + SyncTileView(tileViewItemOrg, _itemDisplayIndices, tileId); + UpdateItemDetail(tileId); + } + + // ── Detail panel population ─────────────────────────────────────────────── + + private static readonly Color DiffColor = Color.LightYellow; + + private void ResetLandDetailHighlights() + { + Color def = SystemColors.Window; + txtLandOrgName.BackColor = def; + txtLandOrgTexId.BackColor = def; + txtLandSecName.BackColor = def; + txtLandSecTexId.BackColor = def; + } + + private void UpdateLandDetail(int id) + { + ResetLandDetailHighlights(); + + bool inOrg = id < TileData.LandTable.Length; + bool inSec = _secondTileData != null && id < _secondTileData.LandTable.Length; + + TileFlag orgLandFlags = default; + TileFlag secLandFlags = default; + + if (inOrg) + { + var d = TileData.LandTable[id]; + txtLandOrgName.Text = d.Name; + txtLandOrgTexId.Text = d.TextureId.ToString(); + orgLandFlags = d.Flags; + } + else + { + txtLandOrgName.Text = string.Empty; + txtLandOrgTexId.Text = string.Empty; + } + + if (inSec) + { + var d = _secondTileData.LandTable[id]; + txtLandSecName.Text = d.Name; + txtLandSecTexId.Text = d.TextureId.ToString(); + secLandFlags = d.Flags; + } + else + { + txtLandSecName.Text = string.Empty; + txtLandSecTexId.Text = string.Empty; + } + + if (inOrg && inSec) + { + var org = TileData.LandTable[id]; + var sec = _secondTileData.LandTable[id]; + + if (_options.LandCompareName && org.Name != sec.Name) + { + txtLandOrgName.BackColor = DiffColor; + txtLandSecName.BackColor = DiffColor; + } + + if (_options.LandCompareTextureId && org.TextureId != sec.TextureId) + { + txtLandOrgTexId.BackColor = DiffColor; + txtLandSecTexId.BackColor = DiffColor; + } + } + + UpdateFlagRows(_landFlagOrgChecks, _landFlagSecChecks, _landFlagLabels, _landFlagTlp, + orgLandFlags, secLandFlags, inOrg, inSec, _options.LandCompareFlags); + } + + private void ResetItemDetailHighlights() + { + Color def = SystemColors.Window; + txtItemOrgName.BackColor = def; + txtItemOrgAnim.BackColor = def; + txtItemOrgWeight.BackColor = def; + txtItemOrgQuality.BackColor = def; + txtItemOrgQty.BackColor = def; + txtItemOrgHue.BackColor = def; + txtItemOrgStack.BackColor = def; + txtItemOrgValue.BackColor = def; + txtItemOrgHeight.BackColor = def; + txtItemOrgMisc.BackColor = def; + txtItemOrgUnk2.BackColor = def; + txtItemOrgUnk3.BackColor = def; + + txtItemSecName.BackColor = def; + txtItemSecAnim.BackColor = def; + txtItemSecWeight.BackColor = def; + txtItemSecQuality.BackColor = def; + txtItemSecQty.BackColor = def; + txtItemSecHue.BackColor = def; + txtItemSecStack.BackColor = def; + txtItemSecValue.BackColor = def; + txtItemSecHeight.BackColor = def; + txtItemSecMisc.BackColor = def; + txtItemSecUnk2.BackColor = def; + txtItemSecUnk3.BackColor = def; + } + + private void UpdateItemDetail(int id) + { + ResetItemDetailHighlights(); + + bool inOrg = id < TileData.ItemTable.Length; + bool inSec = _secondTileData != null && id < _secondTileData.ItemTable.Length; + + TileFlag orgFlags = TileFlag.None; + TileFlag secFlags = TileFlag.None; + + if (inOrg) + { + var d = TileData.ItemTable[id]; + orgFlags = d.Flags; + txtItemOrgName.Text = d.Name; + txtItemOrgAnim.Text = d.Animation.ToString(); + txtItemOrgWeight.Text = d.Weight.ToString(); + txtItemOrgQuality.Text = d.Quality.ToString(); + txtItemOrgQty.Text = d.Quantity.ToString(); + txtItemOrgHue.Text = d.Hue.ToString(); + txtItemOrgStack.Text = d.StackingOffset.ToString(); + txtItemOrgValue.Text = d.Value.ToString(); + txtItemOrgHeight.Text = d.Height.ToString(); + txtItemOrgMisc.Text = d.MiscData.ToString(); + txtItemOrgUnk2.Text = d.Unk2.ToString(); + txtItemOrgUnk3.Text = d.Unk3.ToString(); + } + else + { + ClearItemOrgFields(); + } + + if (inSec) + { + var d = _secondTileData.ItemTable[id]; + secFlags = d.Flags; + txtItemSecName.Text = d.Name; + txtItemSecAnim.Text = d.Animation.ToString(); + txtItemSecWeight.Text = d.Weight.ToString(); + txtItemSecQuality.Text = d.Quality.ToString(); + txtItemSecQty.Text = d.Quantity.ToString(); + txtItemSecHue.Text = d.Hue.ToString(); + txtItemSecStack.Text = d.StackingOffset.ToString(); + txtItemSecValue.Text = d.Value.ToString(); + txtItemSecHeight.Text = d.Height.ToString(); + txtItemSecMisc.Text = d.MiscData.ToString(); + txtItemSecUnk2.Text = d.Unk2.ToString(); + txtItemSecUnk3.Text = d.Unk3.ToString(); + } + else + { + ClearItemSecFields(); + } + + UpdateFlagRows(_itemFlagOrgChecks, _itemFlagSecChecks, _itemFlagLabels, _itemFlagTlp, + orgFlags, secFlags, inOrg, inSec, _options.ItemCompareFlags); + + if (inOrg && inSec) + { + HighlightItemDiffs(id); + } + } + + private void ClearItemOrgFields() + { + txtItemOrgName.Text = txtItemOrgAnim.Text = + txtItemOrgWeight.Text = txtItemOrgQuality.Text = txtItemOrgQty.Text = + txtItemOrgHue.Text = txtItemOrgStack.Text = txtItemOrgValue.Text = + txtItemOrgHeight.Text = txtItemOrgMisc.Text = txtItemOrgUnk2.Text = + txtItemOrgUnk3.Text = string.Empty; + } + + private void ClearItemSecFields() + { + txtItemSecName.Text = txtItemSecAnim.Text = + txtItemSecWeight.Text = txtItemSecQuality.Text = txtItemSecQty.Text = + txtItemSecHue.Text = txtItemSecStack.Text = txtItemSecValue.Text = + txtItemSecHeight.Text = txtItemSecMisc.Text = txtItemSecUnk2.Text = + txtItemSecUnk3.Text = string.Empty; + } + + private void HighlightItemDiffs(int id) + { + var org = TileData.ItemTable[id]; + var sec = _secondTileData.ItemTable[id]; + + Highlight(_options.ItemCompareName && org.Name != sec.Name, txtItemOrgName, txtItemSecName); + Highlight(_options.ItemCompareAnimation && org.Animation != sec.Animation, txtItemOrgAnim, txtItemSecAnim); + Highlight(_options.ItemCompareWeight && org.Weight != sec.Weight, txtItemOrgWeight, txtItemSecWeight); + Highlight(_options.ItemCompareQuality && org.Quality != sec.Quality, txtItemOrgQuality, txtItemSecQuality); + Highlight(_options.ItemCompareQuantity && org.Quantity != sec.Quantity, txtItemOrgQty, txtItemSecQty); + Highlight(_options.ItemCompareHue && org.Hue != sec.Hue, txtItemOrgHue, txtItemSecHue); + Highlight(_options.ItemCompareStackingOffset && org.StackingOffset != sec.StackingOffset, txtItemOrgStack, txtItemSecStack); + Highlight(_options.ItemCompareValue && org.Value != sec.Value, txtItemOrgValue, txtItemSecValue); + Highlight(_options.ItemCompareHeight && org.Height != sec.Height, txtItemOrgHeight, txtItemSecHeight); + Highlight(_options.ItemCompareMiscData && org.MiscData != sec.MiscData, txtItemOrgMisc, txtItemSecMisc); + Highlight(_options.ItemCompareUnk2 && org.Unk2 != sec.Unk2, txtItemOrgUnk2, txtItemSecUnk2); + Highlight(_options.ItemCompareUnk3 && org.Unk3 != sec.Unk3, txtItemOrgUnk3, txtItemSecUnk3); + } + + private static void Highlight(bool differs, TextBox orgBox, TextBox secBox) + { + if (differs) + { + orgBox.BackColor = DiffColor; + secBox.BackColor = DiffColor; + } + } + + // ── Transfer ───────────────────────────────────────────────────────────── + + private void OnClickCopyLandSelected(object sender, EventArgs e) + { + if (_secondTileData == null || tileViewLandSec.FocusIndex < 0) + { + return; + } + + int id = _landDisplayIndices[tileViewLandSec.FocusIndex]; + CopyLandEntry(id); + + if (chkShowDiff.Checked) + { + int displayIdx = _landDisplayIndices.IndexOf(id); + if (displayIdx >= 0) + { + _landDisplayIndices.RemoveAt(displayIdx); + tileViewLandOrg.VirtualListSize = _landDisplayIndices.Count; + tileViewLandSec.VirtualListSize = _landDisplayIndices.Count; + } + } + + tileViewLandOrg.Invalidate(); + tileViewLandSec.Invalidate(); + UpdateLandDetail(id); + } + + private void OnClickCopyLandAllDiff(object sender, EventArgs e) + { + if (_secondTileData == null) + { + return; + } + + Cursor.Current = Cursors.WaitCursor; + int total = Math.Max(TileData.LandTable.Length, _secondTileData.LandTable.Length); + for (int i = 0; i < total; i++) + { + if (!CompareLand(i) && i < _secondTileData.LandTable.Length) + { + CopyLandEntry(i); + } + } + + if (chkShowDiff.Checked) + { + RefreshLandLists(); + } + + Cursor.Current = Cursors.Default; + tileViewLandOrg.Invalidate(); + tileViewLandSec.Invalidate(); + } + + private void CopyLandEntry(int id) + { + if (id >= _secondTileData.LandTable.Length) + { + return; + } + + TileData.LandTable[id] = _secondTileData.LandTable[id]; + Options.ChangedUltimaClass["TileData"] = true; + ControlEvents.FireTileDataChangeEvent(this, id); + _compareLand[id] = true; + } + + private void OnClickCopyItemSelected(object sender, EventArgs e) + { + if (_secondTileData == null || tileViewItemSec.FocusIndex < 0) + { + return; + } + + int id = _itemDisplayIndices[tileViewItemSec.FocusIndex]; + CopyItemEntry(id); + + if (chkShowDiff.Checked) + { + int displayIdx = _itemDisplayIndices.IndexOf(id); + if (displayIdx >= 0) + { + _itemDisplayIndices.RemoveAt(displayIdx); + tileViewItemOrg.VirtualListSize = _itemDisplayIndices.Count; + tileViewItemSec.VirtualListSize = _itemDisplayIndices.Count; + } + } + + tileViewItemOrg.Invalidate(); + tileViewItemSec.Invalidate(); + UpdateItemDetail(id); + } + + private void OnClickCopyItemAllDiff(object sender, EventArgs e) + { + if (_secondTileData == null) + { + return; + } + + Cursor.Current = Cursors.WaitCursor; + int total = Math.Max(TileData.ItemTable.Length, _secondTileData.ItemTable.Length); + for (int i = 0; i < total; i++) + { + if (!CompareItem(i) && i < _secondTileData.ItemTable.Length) + { + CopyItemEntry(i); + } + } + + if (chkShowDiff.Checked) + { + RefreshItemLists(); + } + + Cursor.Current = Cursors.Default; + tileViewItemOrg.Invalidate(); + tileViewItemSec.Invalidate(); + } + + private void OnDoubleClickItemSec(object sender, MouseEventArgs e) + { + OnClickCopyItemSelected(sender, e); + } + + private void OnDoubleClickLandSec(object sender, MouseEventArgs e) + { + OnClickCopyLandSelected(sender, e); + } + + private void CopyItemEntry(int id) + { + if (id >= _secondTileData.ItemTable.Length) + { + return; + } + + TileData.ItemTable[id] = _secondTileData.ItemTable[id]; + Options.ChangedUltimaClass["TileData"] = true; + ControlEvents.FireTileDataChangeEvent(this, id); + _compareItem[id] = true; + } + + // ── Compare Rules panel ─────────────────────────────────────────────────── + + private void BuildRulesPanel() + { + // Land field checkboxes + WireFieldCheckbox(chkLandName, () => _options.LandCompareName, v => _options.LandCompareName = v); + WireFieldCheckbox(chkLandTexId, () => _options.LandCompareTextureId, v => _options.LandCompareTextureId = v); + WireFieldCheckbox(chkLandFlags, () => _options.LandCompareFlags, v => _options.LandCompareFlags = v); + + // Item field checkboxes + WireFieldCheckbox(chkItemName, () => _options.ItemCompareName, v => _options.ItemCompareName = v); + WireFieldCheckbox(chkItemFlags, () => _options.ItemCompareFlags, v => _options.ItemCompareFlags = v); + WireFieldCheckbox(chkItemAnim, () => _options.ItemCompareAnimation, v => _options.ItemCompareAnimation = v); + WireFieldCheckbox(chkItemWeight, () => _options.ItemCompareWeight, v => _options.ItemCompareWeight = v); + WireFieldCheckbox(chkItemQuality, () => _options.ItemCompareQuality, v => _options.ItemCompareQuality = v); + WireFieldCheckbox(chkItemQty, () => _options.ItemCompareQuantity, v => _options.ItemCompareQuantity = v); + WireFieldCheckbox(chkItemHue, () => _options.ItemCompareHue, v => _options.ItemCompareHue = v); + WireFieldCheckbox(chkItemStack, () => _options.ItemCompareStackingOffset, v => _options.ItemCompareStackingOffset = v); + WireFieldCheckbox(chkItemValue, () => _options.ItemCompareValue, v => _options.ItemCompareValue = v); + WireFieldCheckbox(chkItemHeight, () => _options.ItemCompareHeight, v => _options.ItemCompareHeight = v); + WireFieldCheckbox(chkItemMisc, () => _options.ItemCompareMiscData, v => _options.ItemCompareMiscData = v); + WireFieldCheckbox(chkItemUnk2, () => _options.ItemCompareUnk2, v => _options.ItemCompareUnk2 = v); + WireFieldCheckbox(chkItemUnk3, () => _options.ItemCompareUnk3, v => _options.ItemCompareUnk3 = v); + + // Build flag checkboxes dynamically into clbFlags (CheckedListBox) + clbFlags.Items.Clear(); + foreach (var (name, _) in MeaningfulFlags) + { + clbFlags.Items.Add(name, isChecked: false); // unchecked = not ignored + } + + } + + private void WireFieldCheckbox(CheckBox chk, Func getter, Action setter) + { + chk.Checked = getter(); + chk.CheckedChanged += (s, e) => setter(chk.Checked); + } + + private void OnClickApplyRules(object sender, EventArgs e) + { + // Rebuild ignored flags mask from the CheckedListBox state + TileFlag mask = TileFlag.None; + for (int i = 0; i < clbFlags.Items.Count && i < MeaningfulFlags.Length; i++) + { + if (clbFlags.GetItemChecked(i)) + { + mask |= MeaningfulFlags[i].Flag; + } + } + + _options.IgnoredFlags = mask; + + Cursor.Current = Cursors.WaitCursor; + try + { + InvalidateCompareCache(); + if (IsLandTab) + { + RefreshLandLists(); + } + else + { + RefreshItemLists(); + } + } + finally + { + Cursor.Current = Cursors.Default; + } + } + + private void OnClickResetRules(object sender, EventArgs e) + { + _options.ResetToDefaults(); + + chkLandName.Checked = true; + chkLandTexId.Checked = true; + chkLandFlags.Checked = true; + chkItemName.Checked = true; + chkItemFlags.Checked = true; + chkItemAnim.Checked = true; + chkItemWeight.Checked = true; + chkItemQuality.Checked = true; + chkItemQty.Checked = true; + chkItemHue.Checked = true; + chkItemStack.Checked = true; + chkItemValue.Checked = true; + chkItemHeight.Checked = true; + chkItemMisc.Checked = true; + chkItemUnk2.Checked = true; + chkItemUnk3.Checked = true; + + for (int i = 0; i < clbFlags.Items.Count; i++) + { + clbFlags.SetItemChecked(i, false); + } + + // Apply immediately after reset + OnClickApplyRules(sender, e); + } + + private void OnClickToggleRules(object sender, EventArgs e) + { + panelRules.Visible = !panelRules.Visible; + btnToggleRules.Text = panelRules.Visible ? "Rules ▼" : "Rules ▲"; + } + } +} diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.resx b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.resx new file mode 100644 index 00000000..8b2ff64a --- /dev/null +++ b/UoFiddler.Plugin.Compare/UserControls/CompareTileDataControl.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.Plugin.MassImport/Forms/MassImportForm.cs b/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs index ec95c16b..1e573761 100644 --- a/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs +++ b/UoFiddler.Plugin.MassImport/Forms/MassImportForm.cs @@ -302,8 +302,16 @@ private void StartOnClick(object sender, EventArgs e) continue; } - OutputBox.AppendText("."); - entry.Import(checkBoxDirectSave.Checked, ref changedUltimaClass); + try + { + OutputBox.AppendText("."); + entry.Import(checkBoxDirectSave.Checked, ref changedUltimaClass); + } + catch (Exception ex) + { + OutputBox.AppendText( + $"{Environment.NewLine}Error importing {entry.Name} (index {entry.Index}): {ex.Message}{Environment.NewLine}"); + } } OutputBox.AppendText($"Done{Environment.NewLine}"); diff --git a/UoFiddler.Plugin.MassImport/Imports/ImportEntry.cs b/UoFiddler.Plugin.MassImport/Imports/ImportEntry.cs index 146a06b1..ebe1841f 100644 --- a/UoFiddler.Plugin.MassImport/Imports/ImportEntry.cs +++ b/UoFiddler.Plugin.MassImport/Imports/ImportEntry.cs @@ -104,7 +104,7 @@ protected bool GetTileDataInfo(string fileName, ref string message, ref string[] string[] split = line.Split(';'); - if (split.Length < 36) + if (split.Length < 35) { continue; } diff --git a/UoFiddler.Plugin.MassImport/Imports/ImportEntryTileDataItem.cs b/UoFiddler.Plugin.MassImport/Imports/ImportEntryTileDataItem.cs index 2d7b7edf..2c3a3c6b 100644 --- a/UoFiddler.Plugin.MassImport/Imports/ImportEntryTileDataItem.cs +++ b/UoFiddler.Plugin.MassImport/Imports/ImportEntryTileDataItem.cs @@ -22,6 +22,10 @@ public class ImportEntryTileDataItem : ImportEntry public override string Name => "TileDataItem"; + // Minimum column counts: 44 for pre-HSA clients (1 ID + 11 fields + 32 flags), + // 75 for HSA clients (1 ID + 11 fields + 63 flags). + private const int _itemDataColumnsHsa = 75; + protected override void TestFile(ref string message) { if (!File.Contains(".csv")) @@ -32,6 +36,10 @@ protected override void TestFile(ref string message) else { Valid = GetTileDataInfo(File, ref message, ref _tiledata); + if (Valid && Ultima.Art.IsUOAHS() && _tiledata.Length < _itemDataColumnsHsa) + { + message += " (old-format CSV: missing extended HSA flags will default to 0)"; + } } } diff --git a/UoFiddler.Plugin.MassImport/Imports/ImportEntryTileDataLand.cs b/UoFiddler.Plugin.MassImport/Imports/ImportEntryTileDataLand.cs index 15050605..fff173fe 100644 --- a/UoFiddler.Plugin.MassImport/Imports/ImportEntryTileDataLand.cs +++ b/UoFiddler.Plugin.MassImport/Imports/ImportEntryTileDataLand.cs @@ -20,6 +20,10 @@ public class ImportEntryTileDataLand : ImportEntry public override string Name => "TileDataLand"; + // Minimum column counts: 35 for pre-HSA clients (1 ID + 2 fields + 32 flags), + // 66 for HSA clients (1 ID + 2 fields + 63 flags). + private const int _landDataColumnsHsa = 66; + protected override void TestFile(ref string message) { if (!File.Contains(".csv")) @@ -30,6 +34,10 @@ protected override void TestFile(ref string message) else { Valid = GetTileDataInfo(File, ref message, ref _tiledata); + if (Valid && Ultima.Art.IsUOAHS() && _tiledata.Length < _landDataColumnsHsa) + { + message += " (old-format CSV: missing extended HSA flags will default to 0)"; + } } } diff --git a/UoFiddler.Plugin.MultiEditor/Classes/MultiEditorComponentList.cs b/UoFiddler.Plugin.MultiEditor/Classes/MultiEditorComponentList.cs index 917e4b1b..d197324a 100644 --- a/UoFiddler.Plugin.MultiEditor/Classes/MultiEditorComponentList.cs +++ b/UoFiddler.Plugin.MultiEditor/Classes/MultiEditorComponentList.cs @@ -21,7 +21,8 @@ namespace UoFiddler.Plugin.MultiEditor.Classes { internal class MultiEditorComponentList { - private const int _undoListMaxSize = 10; + public const int DefaultUndoStackSize = 50; + private int _undoListMaxSize = DefaultUndoStackSize; private bool _modified; private static MultiEditorControl _parent; @@ -50,7 +51,7 @@ public MultiEditorComponentList(int width, int height, MultiEditorControl parent } } - UndoList = new UndoStruct[_undoListMaxSize]; + UndoList = new List(); _modified = true; RecalculateMinMax(); } @@ -84,7 +85,7 @@ public MultiEditorComponentList(MultiComponentList list, MultiEditorControl pare CalcSolver(); Tiles.Sort(); - UndoList = new UndoStruct[_undoListMaxSize]; + UndoList = new List(); _modified = true; RecalculateMinMax(); } @@ -93,7 +94,9 @@ public MultiEditorComponentList(MultiComponentList list, MultiEditorControl pare public List Tiles { get; private set; } - public UndoStruct[] UndoList { get; } + public List UndoList { get; private set; } + + public List RedoList { get; private set; } = new List(); public int Width { get; private set; } @@ -235,6 +238,11 @@ public void GetImage(Graphics gfx, int xOff, int yOff, int maxHeight, Point mous gfx.DrawImage(bmp, _drawDestRectangle, 0, 0, _drawDestRectangle.Width, _drawDestRectangle.Height, GraphicsUnit.Pixel, MultiTile.SelectedColor); } + else if (_parent.SelectedTiles.Count > 1 && _parent.SelectedTiles.Contains(tile)) + { + gfx.DrawImage(bmp, _drawDestRectangle, 0, 0, _drawDestRectangle.Width, + _drawDestRectangle.Height, GraphicsUnit.Pixel, MultiTile.MultiSelectedColor); + } else if (tile.Transparent) { gfx.DrawImage(bmp, _drawDestRectangle, 0, 0, _drawDestRectangle.Width, @@ -423,6 +431,45 @@ public void TileMove(MultiTile tile, int newX, int newY) RecalculateMinMax(tile); } + /// + /// Removes all tiles within the given multi-space rectangle at or above minZ in a single undo entry. + /// + public void TileRemoveRect(int x0, int y0, int x1, int y1, int minZ, int maxZ = int.MaxValue) + { + if (Width == 0 || Height == 0) + { + return; + } + + AddToUndoList("Remove Rect"); + + Tiles.RemoveAll(t => !t.IsVirtualFloor && t.X >= x0 && t.X <= x1 && t.Y >= y0 && t.Y <= y1 && t.Z >= minZ && t.Z <= maxZ); + + _modified = true; + RecalculateMinMax(); + } + + /// + /// Removes multiple tiles in a single undo entry + /// + public void TileRemoveBatch(IEnumerable tiles) + { + if (Width == 0 || Height == 0) + { + return; + } + + AddToUndoList("Remove Tiles"); + + foreach (MultiTile tile in tiles) + { + Tiles.Remove(tile); + } + + _modified = true; + RecalculateMinMax(); + } + /// /// Removes specific /// @@ -491,17 +538,178 @@ public void TileZSet(MultiTile tile, int setZ) RecalculateMinMax(tile); } - public void Undo(int index) + /// + /// Adjusts Z for a group of tiles in a single undo step. + /// + public void TileZMod(IEnumerable tiles, int modZ) { - if (UndoList[index].Tiles == null) + AddToUndoList("Group Modify Z"); + foreach (MultiTile tile in tiles) { - return; + tile.Z = Math.Clamp(tile.Z + modZ, -128, 127); + CalcSolver(tile.X, tile.Y); + } + + _modified = true; + Tiles.Sort(); + RecalculateMinMax(); + } + + /// + /// Sets Z for a group of tiles in a single undo step. + /// + public void TileZSet(IEnumerable tiles, int setZ) + { + AddToUndoList("Group Set Z"); + int clampedZ = Math.Clamp(setZ, -128, 127); + foreach (MultiTile tile in tiles) + { + tile.Z = clampedZ; + CalcSolver(tile.X, tile.Y); + } + + _modified = true; + Tiles.Sort(); + RecalculateMinMax(); + } + + /// + /// Fills a rectangular area with a tile at the given Z level. + /// + public void TileAddRect(int x0, int y0, int x1, int y1, int z, ushort id) + { + AddToUndoList("Rectangle Fill"); + for (int x = x0; x <= x1; x++) + { + for (int y = y0; y <= y1; y++) + { + if (x < 0 || x >= Width || y < 0 || y >= Height) + { + continue; + } + + Tiles.Add(new MultiTile(id, x, y, z, 1)); + CalcSolver(x, y); + } + } + + _modified = true; + Tiles.Sort(); + RecalculateMinMax(); + } + + /// + /// Places tiles along a Bresenham line at the given Z level. + /// + public void TileAddLine(int x0, int y0, int x1, int y1, int z, ushort id) + { + AddToUndoList("Line Draw"); + foreach (var (x, y) in BresenhamLine(x0, y0, x1, y1)) + { + if (x < 0 || x >= Width || y < 0 || y >= Height) + { + continue; + } + + Tiles.Add(new MultiTile(id, x, y, z, 1)); + CalcSolver(x, y); + } + + _modified = true; + Tiles.Sort(); + RecalculateMinMax(); + } + + public static IEnumerable<(int x, int y)> BresenhamLinePublic(int x0, int y0, int x1, int y1) + => BresenhamLine(x0, y0, x1, y1); + + private static IEnumerable<(int x, int y)> BresenhamLine(int x0, int y0, int x1, int y1) + { + int dx = Math.Abs(x1 - x0); + int sx = x0 < x1 ? 1 : -1; + int dy = -Math.Abs(y1 - y0); + int sy = y0 < y1 ? 1 : -1; + int err = dx + dy; + + while (true) + { + yield return (x0, y0); + if (x0 == x1 && y0 == y1) + { + break; + } + + int e2 = 2 * err; + if (e2 >= dy) + { + err += dy; + x0 += sx; + } + + if (e2 <= dx) + { + err += dx; + y0 += sy; + } + } + } + + /// + /// Places an NxN brush of tiles centered on (cx, cy) at the given Z level. + /// + public void TileAddBrush(int cx, int cy, int z, ushort id, int brushSize) + { + AddToUndoList("Draw Brush"); + int half = brushSize / 2; + for (int dx = -half; dx <= half; dx++) + { + for (int dy = -half; dy <= half; dy++) + { + int x = cx + dx; + int y = cy + dy; + if (x < 0 || x >= Width || y < 0 || y >= Height) + { + continue; + } + + Tiles.Add(new MultiTile(id, x, y, z, 1)); + CalcSolver(x, y); + } } - Width = UndoList[index].Width; - Height = UndoList[index].Height; + _modified = true; + Tiles.Sort(); + RecalculateMinMax(); + } + + /// + /// Adds a batch of tiles in a single undo step (used by copy/paste). + /// + public void TileAddBatch(List<(ushort id, int x, int y, int z)> tiles) + { + AddToUndoList("Paste"); + foreach (var (id, x, y, z) in tiles) + { + if (x < 0 || x >= Width || y < 0 || y >= Height) + { + continue; + } + + Tiles.Add(new MultiTile(id, x, y, z, 1)); + CalcSolver(x, y); + } + + _modified = true; + Tiles.Sort(); + RecalculateMinMax(); + } + + private void RestoreSnapshot(UndoStruct entry) + { + Width = entry.Width; + Height = entry.Height; Tiles = new List(); - foreach (MultiTile tile in UndoList[index].Tiles) + foreach (MultiTile tile in entry.Tiles) { Tiles.Add(tile.IsVirtualFloor ? new FloorTile(tile.X, tile.Y, tile.Z) @@ -512,13 +720,59 @@ public void Undo(int index) RecalculateMinMax(); } - public void UndoClear() + public void Undo(int index) { - for (int i = 0; i < _undoListMaxSize; ++i) + if (index < 0 || index >= UndoList.Count) { - UndoList[i].Action = null; - UndoList[i].Tiles = null; + return; } + + RestoreSnapshot(UndoList[index]); + RedoList.Clear(); + } + + /// Single-step undo (Ctrl+Z). Pushes current state to redo stack. + public bool UndoStep() + { + if (UndoList.Count == 0) + { + return false; + } + + RedoList.Insert(0, SnapshotCurrent(UndoList[0].Action)); + if (RedoList.Count > _undoListMaxSize) + { + RedoList.RemoveAt(RedoList.Count - 1); + } + + RestoreSnapshot(UndoList[0]); + UndoList.RemoveAt(0); + return true; + } + + /// Single-step redo (Ctrl+Y). Pushes current state back onto undo stack. + public bool RedoStep() + { + if (RedoList.Count == 0) + { + return false; + } + + UndoList.Insert(0, SnapshotCurrent(RedoList[0].Action)); + if (UndoList.Count > _undoListMaxSize) + { + UndoList.RemoveAt(UndoList.Count - 1); + } + + RestoreSnapshot(RedoList[0]); + RedoList.RemoveAt(0); + return true; + } + + public void UndoClear() + { + UndoList.Clear(); + RedoList.Clear(); } public void CalcWalkable() @@ -631,24 +885,77 @@ public List GetMultiTileLitAtCoordinate(int x, int y) return multiTiles; } - private void AddToUndoList(string action) + /// + /// Returns all tiles whose bitmaps overlap the given screen-space rectangle. + /// xOff/yOff are the current scrollbar values. + /// + public List GetTilesInScreenRect(Rectangle screenRect, int xOff, int yOff, int maxHeight, bool drawFloor) { - for (int i = _undoListMaxSize - 2; i >= 0; --i) + var result = new List(); + foreach (MultiTile tile in Tiles) { - UndoList[i + 1] = UndoList[i]; + if (tile.IsVirtualFloor) + { + continue; + } + + if (tile.Z > maxHeight) + { + continue; + } + + if (drawFloor && _parent.DrawFloorZ > tile.Z) + { + continue; + } + + Bitmap bmp = tile.GetBitmap(); + if (bmp == null) + { + continue; + } + + int px = tile.XMod - XMin - xOff; + int py = tile.YMod - YMin - yOff; + var tileBounds = new Rectangle(px, py, bmp.Width, bmp.Height); + if (tileBounds.IntersectsWith(screenRect)) + { + result.Add(tile); + } } - UndoList[0].Action = action; - UndoList[0].Tiles = new List(); - UndoList[0].Width = Width; - UndoList[0].Height = Height; + return result; + } + + private UndoStruct SnapshotCurrent(string action) + { + var entry = new UndoStruct + { + Action = action, + Tiles = new List(), + Width = Width, + Height = Height + }; foreach (MultiTile tile in Tiles) { - UndoList[0].Tiles.Add(tile.IsVirtualFloor - ? new FloorTile(tile.X, tile.Y, tile.Y) + entry.Tiles.Add(tile.IsVirtualFloor + ? new FloorTile(tile.X, tile.Y, tile.Z) : new MultiTile(tile.Id, tile.X, tile.Y, tile.Z, tile.Invisible)); } + + return entry; + } + + private void AddToUndoList(string action) + { + UndoList.Insert(0, SnapshotCurrent(action)); + if (UndoList.Count > _undoListMaxSize) + { + UndoList.RemoveAt(UndoList.Count - 1); + } + + RedoList.Clear(); } /// @@ -841,6 +1148,24 @@ public override Bitmap GetBitmap() public class MultiTile : IComparable { + private static readonly ColorMatrix _removeHighlightMatrix = new ColorMatrix(new float[][] + { + new float[] {1, 0, 0, 0, 0}, + new float[] {0, 0, 0, 0, 0}, + new float[] {0, 0, 0, 0, 0}, + new float[] {0, 0, 0, .7f, 0}, + new float[] {.4f, 0, 0, 0, 1} + }); + + private static readonly ColorMatrix _multiSelectedMatrix = new ColorMatrix(new float[][] + { + new float[] {0, 0, 1, 0, 0}, + new float[] {0, 1, 0, 0, 0}, + new float[] {1, 0, 0, 0, 0}, + new float[] {0, 0, 0, 1, 0}, + new float[] {0, .4f, .4f, 0, 1} + }); + private static readonly ColorMatrix _drawMatrix = new ColorMatrix(new float[][] { new float[] {0, 0, 0, 0, 0}, @@ -929,6 +1254,12 @@ static MultiTile() SelectedColor.SetColorMatrix(_selectedMatrix); } + if (MultiSelectedColor == null) + { + MultiSelectedColor = new ImageAttributes(); + MultiSelectedColor.SetColorMatrix(_multiSelectedMatrix); + } + if (DrawColor == null) { DrawColor = new ImageAttributes(); @@ -941,6 +1272,12 @@ static MultiTile() TransColor.SetColorMatrix(_transMatrix); } + if (RemoveHighlightColor == null) + { + RemoveHighlightColor = new ImageAttributes(); + RemoveHighlightColor.SetColorMatrix(_removeHighlightMatrix); + } + if (StandableColor == null) { StandableColor = new ImageAttributes(); @@ -948,8 +1285,12 @@ static MultiTile() } } + public static ImageAttributes RemoveHighlightColor { get; private set; } + public static ImageAttributes DrawColor { get; } + public static ImageAttributes MultiSelectedColor { get; } + public int Height => TileData.ItemTable[Id].Height; public static ImageAttributes HoverColor { get; } diff --git a/UoFiddler.Plugin.MultiEditor/Classes/TileRecentlyUsed.cs b/UoFiddler.Plugin.MultiEditor/Classes/TileRecentlyUsed.cs new file mode 100644 index 00000000..52a5ff46 --- /dev/null +++ b/UoFiddler.Plugin.MultiEditor/Classes/TileRecentlyUsed.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml.Linq; +using UoFiddler.Controls.Classes; + +namespace UoFiddler.Plugin.MultiEditor.Classes +{ + public static class TileRecentlyUsed + { + public const int MaxRecentTiles = 40; + + private static string GetFilePath() + => Path.Combine(Options.AppDataPath, "MultiEditorRecentTiles.xml"); + + public static List Load() + { + var result = new List(); + string path = GetFilePath(); + if (!File.Exists(path)) + { + return result; + } + + try + { + var doc = XDocument.Load(path); + foreach (var elem in doc.Root?.Elements("Tile") ?? Array.Empty()) + { + string idStr = (string)elem.Attribute("id"); + if (idStr != null && int.TryParse(idStr, System.Globalization.NumberStyles.HexNumber, null, out int id)) + { + result.Add(id); + } + } + } + catch + { + // Silently ignore corrupt file + } + + return result; + } + + public static void Save(List tiles) + { + var doc = new XDocument(new XElement("RecentTiles")); + foreach (int id in tiles) + { + doc.Root.Add(new XElement("Tile", new XAttribute("id", id.ToString("X")))); + } + + try + { + doc.Save(GetFilePath()); + } + catch + { + // Silently ignore write errors + } + } + } +} diff --git a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.Designer.cs b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.Designer.cs index ffe9777e..801fc618 100644 --- a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.Designer.cs +++ b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.Designer.cs @@ -70,8 +70,13 @@ private void InitializeComponent() BTN_Save = new System.Windows.Forms.Button(); splitContainer1 = new System.Windows.Forms.SplitContainer(); splitContainer3 = new System.Windows.Forms.SplitContainer(); - BTN_Trans = new System.Windows.Forms.CheckBox(); + BTN_RectFill = new System.Windows.Forms.CheckBox(); imageListTools = new System.Windows.Forms.ImageList(components); + BTN_LineDraw = new System.Windows.Forms.CheckBox(); + RB_Brush_S = new System.Windows.Forms.RadioButton(); + RB_Brush_M = new System.Windows.Forms.RadioButton(); + RB_Brush_L = new System.Windows.Forms.RadioButton(); + BTN_Trans = new System.Windows.Forms.CheckBox(); BTN_Pipette = new System.Windows.Forms.CheckBox(); BTN_Floor = new System.Windows.Forms.CheckBox(); BTN_Z = new System.Windows.Forms.CheckBox(); @@ -80,7 +85,7 @@ private void InitializeComponent() BTN_Select = new System.Windows.Forms.CheckBox(); numericUpDown_Floor = new System.Windows.Forms.NumericUpDown(); numericUpDown_Z = new System.Windows.Forms.NumericUpDown(); - collapsibleSplitter1 = new Controls.UserControls.CollapsibleSplitter(); + collapsibleSplitter1 = new UoFiddler.Controls.UserControls.CollapsibleSplitter(); Selectedpanel = new System.Windows.Forms.Panel(); groupBox3 = new System.Windows.Forms.GroupBox(); DynamiccheckBox = new System.Windows.Forms.CheckBox(); @@ -90,22 +95,13 @@ private void InitializeComponent() splitContainer2 = new System.Windows.Forms.SplitContainer(); MaxHeightTrackBar = new System.Windows.Forms.TrackBar(); splitter1 = new System.Windows.Forms.Splitter(); + pictureBoxMinimap = new System.Windows.Forms.PictureBox(); pictureBoxMulti = new System.Windows.Forms.PictureBox(); hScrollBar = new System.Windows.Forms.HScrollBar(); vScrollBar = new System.Windows.Forms.VScrollBar(); toolStrip1 = new System.Windows.Forms.ToolStrip(); toolStripDropDownButton1 = new System.Windows.Forms.ToolStripDropDownButton(); UndoItems = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem0 = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem1 = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem2 = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem3 = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem4 = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem5 = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem6 = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem7 = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem8 = new System.Windows.Forms.ToolStripMenuItem(); - UndoItem9 = new System.Windows.Forms.ToolStripMenuItem(); showWalkablesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); showDoubleSurfaceMenuItem = new System.Windows.Forms.ToolStripMenuItem(); removeAllTransToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -114,8 +110,10 @@ private void InitializeComponent() toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); SelectedTileLabel = new System.Windows.Forms.ToolStripLabel(); toolStripLabelCoord = new System.Windows.Forms.ToolStripLabel(); + toolStripBtnZoom = new System.Windows.Forms.ToolStripButton(); toolTip1 = new System.Windows.Forms.ToolTip(components); FloatingPreviewPanel = new System.Windows.Forms.Panel(); + brushSizeLabel = new System.Windows.Forms.Label(); TC_MultiEditorToolbox.SuspendLayout(); tileTab.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)splitContainer4).BeginInit(); @@ -151,6 +149,7 @@ private void InitializeComponent() splitContainer2.Panel2.SuspendLayout(); splitContainer2.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)MaxHeightTrackBar).BeginInit(); + ((System.ComponentModel.ISupportInitialize)pictureBoxMinimap).BeginInit(); ((System.ComponentModel.ISupportInitialize)pictureBoxMulti).BeginInit(); toolStrip1.SuspendLayout(); SuspendLayout(); @@ -166,7 +165,7 @@ private void InitializeComponent() TC_MultiEditorToolbox.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); TC_MultiEditorToolbox.Name = "TC_MultiEditorToolbox"; TC_MultiEditorToolbox.SelectedIndex = 0; - TC_MultiEditorToolbox.Size = new System.Drawing.Size(240, 314); + TC_MultiEditorToolbox.Size = new System.Drawing.Size(280, 284); TC_MultiEditorToolbox.TabIndex = 0; // // tileTab @@ -177,7 +176,7 @@ private void InitializeComponent() tileTab.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); tileTab.Name = "tileTab"; tileTab.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); - tileTab.Size = new System.Drawing.Size(232, 286); + tileTab.Size = new System.Drawing.Size(272, 256); tileTab.TabIndex = 0; tileTab.Text = "Tiles"; tileTab.UseVisualStyleBackColor = true; @@ -198,8 +197,8 @@ private void InitializeComponent() // splitContainer4.Panel2.Controls.Add(pictureBoxDrawTiles); splitContainer4.Panel2.Controls.Add(vScrollBarDrawTiles); - splitContainer4.Size = new System.Drawing.Size(224, 280); - splitContainer4.SplitterDistance = 126; + splitContainer4.Size = new System.Drawing.Size(264, 250); + splitContainer4.SplitterDistance = 112; splitContainer4.SplitterWidth = 5; splitContainer4.TabIndex = 0; // @@ -211,7 +210,7 @@ private void InitializeComponent() treeViewTilesXML.Location = new System.Drawing.Point(0, 0); treeViewTilesXML.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); treeViewTilesXML.Name = "treeViewTilesXML"; - treeViewTilesXML.Size = new System.Drawing.Size(224, 126); + treeViewTilesXML.Size = new System.Drawing.Size(264, 112); treeViewTilesXML.TabIndex = 0; treeViewTilesXML.AfterSelect += TreeViewTilesXML_OnAfterSelect; // @@ -228,7 +227,7 @@ private void InitializeComponent() pictureBoxDrawTiles.Location = new System.Drawing.Point(0, 0); pictureBoxDrawTiles.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); pictureBoxDrawTiles.Name = "pictureBoxDrawTiles"; - pictureBoxDrawTiles.Size = new System.Drawing.Size(207, 149); + pictureBoxDrawTiles.Size = new System.Drawing.Size(247, 133); pictureBoxDrawTiles.TabIndex = 3; pictureBoxDrawTiles.TabStop = false; pictureBoxDrawTiles.SizeChanged += PictureBoxDrawTiles_OnResize; @@ -240,9 +239,9 @@ private void InitializeComponent() // vScrollBarDrawTiles // vScrollBarDrawTiles.Dock = System.Windows.Forms.DockStyle.Right; - vScrollBarDrawTiles.Location = new System.Drawing.Point(207, 0); + vScrollBarDrawTiles.Location = new System.Drawing.Point(247, 0); vScrollBarDrawTiles.Name = "vScrollBarDrawTiles"; - vScrollBarDrawTiles.Size = new System.Drawing.Size(17, 149); + vScrollBarDrawTiles.Size = new System.Drawing.Size(17, 133); vScrollBarDrawTiles.TabIndex = 0; vScrollBarDrawTiles.Scroll += VScrollBarDrawTiles_Scroll; // @@ -254,7 +253,7 @@ private void InitializeComponent() designTab.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); designTab.Name = "designTab"; designTab.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); - designTab.Size = new System.Drawing.Size(232, 286); + designTab.Size = new System.Drawing.Size(272, 256); designTab.TabIndex = 1; designTab.Text = "Design"; designTab.UseVisualStyleBackColor = true; @@ -323,7 +322,7 @@ private void InitializeComponent() importTab.Location = new System.Drawing.Point(4, 24); importTab.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); importTab.Name = "importTab"; - importTab.Size = new System.Drawing.Size(232, 286); + importTab.Size = new System.Drawing.Size(272, 256); importTab.TabIndex = 2; importTab.Text = "Import"; importTab.UseVisualStyleBackColor = true; @@ -337,7 +336,7 @@ private void InitializeComponent() treeViewMultiList.Location = new System.Drawing.Point(0, 0); treeViewMultiList.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); treeViewMultiList.Name = "treeViewMultiList"; - treeViewMultiList.Size = new System.Drawing.Size(232, 286); + treeViewMultiList.Size = new System.Drawing.Size(272, 256); treeViewMultiList.TabIndex = 0; treeViewMultiList.NodeMouseHover += TreeViewMultiList_NodeMouseHover; treeViewMultiList.NodeMouseDoubleClick += TreeViewMultiList_NodeMouseDoubleClick; @@ -350,7 +349,7 @@ private void InitializeComponent() Save.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); Save.Name = "Save"; Save.Padding = new System.Windows.Forms.Padding(4, 3, 4, 3); - Save.Size = new System.Drawing.Size(232, 286); + Save.Size = new System.Drawing.Size(272, 256); Save.TabIndex = 3; Save.Text = "Save"; Save.UseVisualStyleBackColor = true; @@ -499,7 +498,7 @@ private void InitializeComponent() splitContainer1.Panel2.Controls.Add(splitContainer2); splitContainer1.Panel2.Controls.Add(toolStrip1); splitContainer1.Size = new System.Drawing.Size(800, 480); - splitContainer1.SplitterDistance = 240; + splitContainer1.SplitterDistance = 280; splitContainer1.SplitterWidth = 5; splitContainer1.TabIndex = 1; // @@ -515,6 +514,12 @@ private void InitializeComponent() // // splitContainer3.Panel1 // + splitContainer3.Panel1.Controls.Add(brushSizeLabel); + splitContainer3.Panel1.Controls.Add(BTN_RectFill); + splitContainer3.Panel1.Controls.Add(BTN_LineDraw); + splitContainer3.Panel1.Controls.Add(RB_Brush_S); + splitContainer3.Panel1.Controls.Add(RB_Brush_M); + splitContainer3.Panel1.Controls.Add(RB_Brush_L); splitContainer3.Panel1.Controls.Add(BTN_Trans); splitContainer3.Panel1.Controls.Add(BTN_Pipette); splitContainer3.Panel1.Controls.Add(BTN_Floor); @@ -530,26 +535,26 @@ private void InitializeComponent() splitContainer3.Panel2.Controls.Add(TC_MultiEditorToolbox); splitContainer3.Panel2.Controls.Add(collapsibleSplitter1); splitContainer3.Panel2.Controls.Add(Selectedpanel); - splitContainer3.Size = new System.Drawing.Size(240, 480); - splitContainer3.SplitterDistance = 60; + splitContainer3.Size = new System.Drawing.Size(280, 480); + splitContainer3.SplitterDistance = 90; splitContainer3.SplitterWidth = 2; splitContainer3.TabIndex = 1; // - // BTN_Trans - // - BTN_Trans.Appearance = System.Windows.Forms.Appearance.Button; - BTN_Trans.FlatStyle = System.Windows.Forms.FlatStyle.Popup; - BTN_Trans.ImageKey = "TransButton.bmp"; - BTN_Trans.ImageList = imageListTools; - BTN_Trans.Location = new System.Drawing.Point(102, 30); - BTN_Trans.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); - BTN_Trans.Name = "BTN_Trans"; - BTN_Trans.Size = new System.Drawing.Size(24, 24); - BTN_Trans.TabIndex = 15; - toolTip1.SetToolTip(BTN_Trans, "Switch Transparent"); - BTN_Trans.UseVisualStyleBackColor = true; - BTN_Trans.CheckStateChanged += BTN_Toolbox_CheckedChanged; - BTN_Trans.Click += BTN_Trans_Clicked; + // BTN_RectFill + // + BTN_RectFill.Appearance = System.Windows.Forms.Appearance.Button; + BTN_RectFill.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + BTN_RectFill.ImageKey = "RectFillButton.bmp"; + BTN_RectFill.ImageList = imageListTools; + BTN_RectFill.Location = new System.Drawing.Point(5, 57); + BTN_RectFill.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + BTN_RectFill.Name = "BTN_RectFill"; + BTN_RectFill.Size = new System.Drawing.Size(24, 24); + BTN_RectFill.TabIndex = 17; + toolTip1.SetToolTip(BTN_RectFill, "Rectangle Fill"); + BTN_RectFill.UseVisualStyleBackColor = true; + BTN_RectFill.CheckStateChanged += BTN_Toolbox_CheckedChanged; + BTN_RectFill.Click += BTN_RectFill_Click; // // imageListTools // @@ -570,6 +575,86 @@ private void InitializeComponent() imageListTools.Images.SetKeyName(11, "PipetteButton_Selected.bmp"); imageListTools.Images.SetKeyName(12, "TransButton_Selected.bmp"); imageListTools.Images.SetKeyName(13, "TransButton.bmp"); + imageListTools.Images.SetKeyName(14, "LineDrawButton.bmp"); + imageListTools.Images.SetKeyName(15, "LineDrawButton_Selected.bmp"); + imageListTools.Images.SetKeyName(16, "RectFillButton.bmp"); + imageListTools.Images.SetKeyName(17, "RectFillButton_Selected.bmp"); + // + // BTN_LineDraw + // + BTN_LineDraw.Appearance = System.Windows.Forms.Appearance.Button; + BTN_LineDraw.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + BTN_LineDraw.ImageKey = "LineDrawButton.bmp"; + BTN_LineDraw.ImageList = imageListTools; + BTN_LineDraw.Location = new System.Drawing.Point(36, 57); + BTN_LineDraw.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + BTN_LineDraw.Name = "BTN_LineDraw"; + BTN_LineDraw.Size = new System.Drawing.Size(24, 24); + BTN_LineDraw.TabIndex = 18; + toolTip1.SetToolTip(BTN_LineDraw, "Line Draw"); + BTN_LineDraw.UseVisualStyleBackColor = true; + BTN_LineDraw.CheckStateChanged += BTN_Toolbox_CheckedChanged; + BTN_LineDraw.Click += BTN_LineDraw_Click; + // + // RB_Brush_S + // + RB_Brush_S.Appearance = System.Windows.Forms.Appearance.Button; + RB_Brush_S.Checked = true; + RB_Brush_S.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + RB_Brush_S.Location = new System.Drawing.Point(137, 57); + RB_Brush_S.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + RB_Brush_S.Name = "RB_Brush_S"; + RB_Brush_S.Size = new System.Drawing.Size(26, 24); + RB_Brush_S.TabIndex = 19; + RB_Brush_S.TabStop = true; + RB_Brush_S.Text = "S"; + RB_Brush_S.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + toolTip1.SetToolTip(RB_Brush_S, "Small brush (1x1)"); + RB_Brush_S.UseVisualStyleBackColor = true; + // + // RB_Brush_M + // + RB_Brush_M.Appearance = System.Windows.Forms.Appearance.Button; + RB_Brush_M.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + RB_Brush_M.Location = new System.Drawing.Point(165, 57); + RB_Brush_M.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + RB_Brush_M.Name = "RB_Brush_M"; + RB_Brush_M.Size = new System.Drawing.Size(26, 24); + RB_Brush_M.TabIndex = 20; + RB_Brush_M.Text = "M"; + RB_Brush_M.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + toolTip1.SetToolTip(RB_Brush_M, "Medium brush (3x3)"); + RB_Brush_M.UseVisualStyleBackColor = true; + // + // RB_Brush_L + // + RB_Brush_L.Appearance = System.Windows.Forms.Appearance.Button; + RB_Brush_L.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + RB_Brush_L.Location = new System.Drawing.Point(193, 57); + RB_Brush_L.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + RB_Brush_L.Name = "RB_Brush_L"; + RB_Brush_L.Size = new System.Drawing.Size(26, 24); + RB_Brush_L.TabIndex = 21; + RB_Brush_L.Text = "L"; + RB_Brush_L.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + toolTip1.SetToolTip(RB_Brush_L, "Large brush (5x5)"); + RB_Brush_L.UseVisualStyleBackColor = true; + // + // BTN_Trans + // + BTN_Trans.Appearance = System.Windows.Forms.Appearance.Button; + BTN_Trans.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + BTN_Trans.ImageKey = "TransButton.bmp"; + BTN_Trans.ImageList = imageListTools; + BTN_Trans.Location = new System.Drawing.Point(102, 30); + BTN_Trans.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); + BTN_Trans.Name = "BTN_Trans"; + BTN_Trans.Size = new System.Drawing.Size(24, 24); + BTN_Trans.TabIndex = 15; + toolTip1.SetToolTip(BTN_Trans, "Switch Transparent"); + BTN_Trans.UseVisualStyleBackColor = true; + BTN_Trans.CheckStateChanged += BTN_Toolbox_CheckedChanged; + BTN_Trans.Click += BTN_Trans_Clicked; // // BTN_Pipette // @@ -701,7 +786,7 @@ private void InitializeComponent() collapsibleSplitter1.Location = new System.Drawing.Point(0, 96); collapsibleSplitter1.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); collapsibleSplitter1.Name = "collapsibleSplitter1"; - collapsibleSplitter1.Size = new System.Drawing.Size(240, 8); + collapsibleSplitter1.Size = new System.Drawing.Size(280, 8); collapsibleSplitter1.TabIndex = 5; collapsibleSplitter1.TabStop = false; toolTip1.SetToolTip(collapsibleSplitter1, "Selected Tile Panel"); @@ -715,7 +800,7 @@ private void InitializeComponent() Selectedpanel.Location = new System.Drawing.Point(0, 0); Selectedpanel.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); Selectedpanel.Name = "Selectedpanel"; - Selectedpanel.Size = new System.Drawing.Size(240, 96); + Selectedpanel.Size = new System.Drawing.Size(280, 96); Selectedpanel.TabIndex = 6; // // groupBox3 @@ -791,10 +876,11 @@ private void InitializeComponent() // splitContainer2.Panel2 // splitContainer2.Panel2.Controls.Add(splitter1); + splitContainer2.Panel2.Controls.Add(pictureBoxMinimap); splitContainer2.Panel2.Controls.Add(pictureBoxMulti); splitContainer2.Panel2.Controls.Add(hScrollBar); splitContainer2.Panel2.Controls.Add(vScrollBar); - splitContainer2.Size = new System.Drawing.Size(555, 455); + splitContainer2.Size = new System.Drawing.Size(515, 455); splitContainer2.SplitterDistance = 30; splitContainer2.SplitterWidth = 5; splitContainer2.TabIndex = 2; @@ -805,7 +891,7 @@ private void InitializeComponent() MaxHeightTrackBar.Location = new System.Drawing.Point(0, 0); MaxHeightTrackBar.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); MaxHeightTrackBar.Name = "MaxHeightTrackBar"; - MaxHeightTrackBar.Size = new System.Drawing.Size(555, 30); + MaxHeightTrackBar.Size = new System.Drawing.Size(515, 30); MaxHeightTrackBar.TabIndex = 0; toolTip1.SetToolTip(MaxHeightTrackBar, "Max Height Displayed"); MaxHeightTrackBar.ValueChanged += MaxHeightTrackBarOnValueChanged; @@ -819,6 +905,19 @@ private void InitializeComponent() splitter1.TabIndex = 3; splitter1.TabStop = false; // + // pictureBoxMinimap + // + pictureBoxMinimap.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right; + pictureBoxMinimap.BackColor = System.Drawing.Color.DimGray; + pictureBoxMinimap.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + pictureBoxMinimap.Location = new System.Drawing.Point(342, 280); + pictureBoxMinimap.Name = "pictureBoxMinimap"; + pictureBoxMinimap.Size = new System.Drawing.Size(155, 100); + pictureBoxMinimap.TabIndex = 10; + pictureBoxMinimap.TabStop = false; + toolTip1.SetToolTip(pictureBoxMinimap, "Minimap — click to pan"); + pictureBoxMinimap.MouseClick += PictureBoxMinimap_OnMouseClick; + // // pictureBoxMulti // pictureBoxMulti.BackColor = System.Drawing.Color.White; @@ -827,7 +926,7 @@ private void InitializeComponent() pictureBoxMulti.Location = new System.Drawing.Point(0, 0); pictureBoxMulti.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); pictureBoxMulti.Name = "pictureBoxMulti"; - pictureBoxMulti.Size = new System.Drawing.Size(538, 403); + pictureBoxMulti.Size = new System.Drawing.Size(498, 403); pictureBoxMulti.TabIndex = 0; pictureBoxMulti.TabStop = false; pictureBoxMulti.SizeChanged += PictureBoxMultiOnResize; @@ -841,14 +940,14 @@ private void InitializeComponent() hScrollBar.Dock = System.Windows.Forms.DockStyle.Bottom; hScrollBar.Location = new System.Drawing.Point(0, 403); hScrollBar.Name = "hScrollBar"; - hScrollBar.Size = new System.Drawing.Size(538, 17); + hScrollBar.Size = new System.Drawing.Size(498, 17); hScrollBar.TabIndex = 2; hScrollBar.ValueChanged += ScrollBarsValueChanged; // // vScrollBar // vScrollBar.Dock = System.Windows.Forms.DockStyle.Right; - vScrollBar.Location = new System.Drawing.Point(538, 0); + vScrollBar.Location = new System.Drawing.Point(498, 0); vScrollBar.Name = "vScrollBar"; vScrollBar.Size = new System.Drawing.Size(17, 420); vScrollBar.TabIndex = 1; @@ -858,11 +957,11 @@ private void InitializeComponent() // toolStrip1.Dock = System.Windows.Forms.DockStyle.Bottom; toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; - toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { toolStripDropDownButton1, toolStripSeparator2, DrawTileLabel, toolStripSeparator1, SelectedTileLabel, toolStripLabelCoord }); + toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { toolStripDropDownButton1, toolStripSeparator2, DrawTileLabel, toolStripSeparator1, SelectedTileLabel, toolStripLabelCoord, toolStripBtnZoom }); toolStrip1.Location = new System.Drawing.Point(0, 455); toolStrip1.Name = "toolStrip1"; toolStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.System; - toolStrip1.Size = new System.Drawing.Size(555, 25); + toolStrip1.Size = new System.Drawing.Size(515, 25); toolStrip1.TabIndex = 3; toolStrip1.Text = "toolStrip1"; // @@ -877,92 +976,11 @@ private void InitializeComponent() // // UndoItems // - UndoItems.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { UndoItem0, UndoItem1, UndoItem2, UndoItem3, UndoItem4, UndoItem5, UndoItem6, UndoItem7, UndoItem8, UndoItem9 }); UndoItems.Name = "UndoItems"; UndoItems.Size = new System.Drawing.Size(189, 22); UndoItems.Text = "Undo"; UndoItems.DropDownOpening += UndoList_BeforeOpening; // - // UndoItem0 - // - UndoItem0.Name = "UndoItem0"; - UndoItem0.Size = new System.Drawing.Size(89, 22); - UndoItem0.Tag = 0; - UndoItem0.Text = "---"; - UndoItem0.Click += Undo_onClick; - // - // UndoItem1 - // - UndoItem1.Name = "UndoItem1"; - UndoItem1.Size = new System.Drawing.Size(89, 22); - UndoItem1.Tag = 1; - UndoItem1.Text = "---"; - UndoItem1.Click += Undo_onClick; - // - // UndoItem2 - // - UndoItem2.Name = "UndoItem2"; - UndoItem2.Size = new System.Drawing.Size(89, 22); - UndoItem2.Tag = 2; - UndoItem2.Text = "---"; - UndoItem2.Click += Undo_onClick; - // - // UndoItem3 - // - UndoItem3.Name = "UndoItem3"; - UndoItem3.Size = new System.Drawing.Size(89, 22); - UndoItem3.Tag = 3; - UndoItem3.Text = "---"; - UndoItem3.Click += Undo_onClick; - // - // UndoItem4 - // - UndoItem4.Name = "UndoItem4"; - UndoItem4.Size = new System.Drawing.Size(89, 22); - UndoItem4.Tag = 4; - UndoItem4.Text = "---"; - UndoItem4.Click += Undo_onClick; - // - // UndoItem5 - // - UndoItem5.Name = "UndoItem5"; - UndoItem5.Size = new System.Drawing.Size(89, 22); - UndoItem5.Tag = 5; - UndoItem5.Text = "---"; - UndoItem5.Click += Undo_onClick; - // - // UndoItem6 - // - UndoItem6.Name = "UndoItem6"; - UndoItem6.Size = new System.Drawing.Size(89, 22); - UndoItem6.Tag = 6; - UndoItem6.Text = "---"; - UndoItem6.Click += Undo_onClick; - // - // UndoItem7 - // - UndoItem7.Name = "UndoItem7"; - UndoItem7.Size = new System.Drawing.Size(89, 22); - UndoItem7.Tag = 7; - UndoItem7.Text = "---"; - UndoItem7.Click += Undo_onClick; - // - // UndoItem8 - // - UndoItem8.Name = "UndoItem8"; - UndoItem8.Size = new System.Drawing.Size(89, 22); - UndoItem8.Tag = 8; - UndoItem8.Text = "---"; - UndoItem8.Click += Undo_onClick; - // - // UndoItem9 - // - UndoItem9.Name = "UndoItem9"; - UndoItem9.Size = new System.Drawing.Size(89, 22); - UndoItem9.Tag = 9; - UndoItem9.Text = "---"; - UndoItem9.Click += Undo_onClick; - // // showWalkablesToolStripMenuItem // showWalkablesToolStripMenuItem.CheckOnClick = true; @@ -1018,6 +1036,16 @@ private void InitializeComponent() toolStripLabelCoord.Text = "0,0,0"; toolStripLabelCoord.ToolTipText = "Coordinates"; // + // toolStripBtnZoom + // + toolStripBtnZoom.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; + toolStripBtnZoom.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + toolStripBtnZoom.Name = "toolStripBtnZoom"; + toolStripBtnZoom.Size = new System.Drawing.Size(39, 22); + toolStripBtnZoom.Text = "100%"; + toolStripBtnZoom.ToolTipText = "Zoom — click or Ctrl+0 to reset to 100%"; + toolStripBtnZoom.Click += ToolStripBtnZoom_Click; + // // FloatingPreviewPanel // FloatingPreviewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; @@ -1028,6 +1056,15 @@ private void InitializeComponent() FloatingPreviewPanel.Size = new System.Drawing.Size(233, 115); FloatingPreviewPanel.TabIndex = 4; // + // brushSizeLabel + // + brushSizeLabel.AutoSize = true; + brushSizeLabel.Location = new System.Drawing.Point(68, 62); + brushSizeLabel.Name = "brushSizeLabel"; + brushSizeLabel.Size = new System.Drawing.Size(62, 15); + brushSizeLabel.TabIndex = 22; + brushSizeLabel.Text = "Brush size:"; + // // MultiEditorControl // AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); @@ -1062,6 +1099,7 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit(); splitContainer1.ResumeLayout(false); splitContainer3.Panel1.ResumeLayout(false); + splitContainer3.Panel1.PerformLayout(); splitContainer3.Panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)splitContainer3).EndInit(); splitContainer3.ResumeLayout(false); @@ -1079,6 +1117,7 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)splitContainer2).EndInit(); splitContainer2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)MaxHeightTrackBar).EndInit(); + ((System.ComponentModel.ISupportInitialize)pictureBoxMinimap).EndInit(); ((System.ComponentModel.ISupportInitialize)pictureBoxMulti).EndInit(); toolStrip1.ResumeLayout(false); toolStrip1.PerformLayout(); @@ -1139,22 +1178,19 @@ private void InitializeComponent() private System.Windows.Forms.ToolStrip toolStrip1; private System.Windows.Forms.ToolStripDropDownButton toolStripDropDownButton1; private System.Windows.Forms.ToolStripLabel toolStripLabelCoord; + private System.Windows.Forms.ToolStripButton toolStripBtnZoom; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; private System.Windows.Forms.ToolTip toolTip1; private System.Windows.Forms.TreeView treeViewMultiList; private System.Windows.Forms.TreeView treeViewTilesXML; - private System.Windows.Forms.ToolStripMenuItem UndoItem0; - private System.Windows.Forms.ToolStripMenuItem UndoItem1; - private System.Windows.Forms.ToolStripMenuItem UndoItem2; - private System.Windows.Forms.ToolStripMenuItem UndoItem3; - private System.Windows.Forms.ToolStripMenuItem UndoItem4; - private System.Windows.Forms.ToolStripMenuItem UndoItem5; - private System.Windows.Forms.ToolStripMenuItem UndoItem6; - private System.Windows.Forms.ToolStripMenuItem UndoItem7; - private System.Windows.Forms.ToolStripMenuItem UndoItem8; - private System.Windows.Forms.ToolStripMenuItem UndoItem9; private System.Windows.Forms.ToolStripMenuItem UndoItems; + private System.Windows.Forms.CheckBox BTN_RectFill; + private System.Windows.Forms.CheckBox BTN_LineDraw; + private System.Windows.Forms.RadioButton RB_Brush_S; + private System.Windows.Forms.RadioButton RB_Brush_M; + private System.Windows.Forms.RadioButton RB_Brush_L; + private System.Windows.Forms.PictureBox pictureBoxMinimap; private System.Windows.Forms.VScrollBar vScrollBar; private System.Windows.Forms.VScrollBar vScrollBarDrawTiles; @@ -1163,5 +1199,6 @@ private void InitializeComponent() private System.Windows.Forms.Button BTN_Export_CSV; private System.Windows.Forms.Button BTN_Export_UOX3; private System.Windows.Forms.Button BTN_Export_XML; + private System.Windows.Forms.Label brushSizeLabel; } } diff --git a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs index 753022b0..1fee56b2 100644 --- a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs +++ b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using System.Drawing; using System.IO; +using System.Linq; using System.Windows.Forms; using System.Xml; using Ultima; @@ -37,6 +38,43 @@ public partial class MultiEditorControl : UserControl private MultiTile _hoverTile; private MultiTile _selectedTile; + // Multi-selection + private readonly HashSet _selectedTiles = new HashSet(); + private bool _isMarqueeDragging; + private Point _marqueeStart; + private Point _marqueeEnd; + + // Copy/Paste + private List<(ushort id, int dx, int dy, int dz)> _clipboard; + private bool _isPasteMode; + + // Zoom + private float _zoomFactor = 1.0f; + + // Minimap + private bool _minimapDirty = true; + private Bitmap _minimapTilesBmp; // cached tile-dot layer, regenerated only when tiles change + + // Recently used tiles + private readonly List _recentTiles = new List(); + private FlowLayoutPanel _recentPanel; + private readonly List _recentSlots = new List(); + + // Rectangle fill tool + private bool _isRectFillDragging; + private int _rectFillStartX, _rectFillStartY; + private int _rectFillEndX, _rectFillEndY; + + // Line draw tool + private bool _isLineDragging; + private int _lineStartX, _lineStartY; + private int _lineEndX, _lineEndY; + + // Bulk remove tool (multi-space coords, mirrors rect fill) + private bool _isRemoveDragging; + private int _removeStartX, _removeStartY; + private int _removeEndX, _removeEndY; + /// /// Current MouseLoc + Scrollbar values (for hover effect) /// @@ -64,7 +102,9 @@ public MultiEditorControl() BTN_Select.Checked = true; pictureBoxDrawTiles.MouseWheel += PictureBoxDrawTiles_OnMouseWheel; + pictureBoxMulti.MouseWheel += PictureBoxMulti_OnMouseWheel; pictureBoxMulti.ContextMenuStrip = null; + } /// @@ -86,7 +126,7 @@ public MultiTile HoverTile } /// - /// Current Selected Tile (set OnMouseUp) + /// Current Selected Tile (set OnMouseUp). Setting this also syncs the single-tile selection panel. /// public MultiTile SelectedTile { @@ -96,21 +136,30 @@ private set _selectedTile = value; if (value != null) { + Selectedpanel.Visible = true; SelectedTileLabel.Text = $"ID: 0x{value.Id:X} Z: {value.Z}"; numericUpDown_Selected_X.Value = value.X; numericUpDown_Selected_Y.Value = value.Y; numericUpDown_Selected_Z.Value = value.Z; DynamiccheckBox.Checked = value.Invisible; } - else + else if (_selectedTiles.Count == 0) { + Selectedpanel.Visible = false; SelectedTileLabel.Text = "ID:"; } + else + { + // Multiple tiles selected — show count in label, keep panel visible for Z operations + Selectedpanel.Visible = true; + SelectedTileLabel.Text = $"{_selectedTiles.Count} tiles selected"; + } } } public bool ShowWalkables => showWalkablesToolStripMenuItem.Checked; public bool ShowDoubleSurface => showDoubleSurfaceMenuItem.Checked; + public HashSet SelectedTiles => _selectedTiles; // Private Methods (35)  @@ -155,6 +204,8 @@ private void BTN_Draw_Click(object sender, EventArgs e) BTN_Z.Checked = false; BTN_Pipette.Checked = false; BTN_Trans.Checked = false; + BTN_RectFill.Checked = false; + BTN_LineDraw.Checked = false; pictureBoxMulti.Invalidate(); } @@ -271,6 +322,8 @@ private void BTN_Pipette_Click(object sender, EventArgs e) BTN_Z.Checked = false; BTN_Pipette.Checked = true; BTN_Trans.Checked = false; + BTN_RectFill.Checked = false; + BTN_LineDraw.Checked = false; pictureBoxMulti.Invalidate(); } @@ -286,6 +339,8 @@ private void BTN_Remove_Click(object sender, EventArgs e) BTN_Z.Checked = false; BTN_Pipette.Checked = false; BTN_Trans.Checked = false; + BTN_RectFill.Checked = false; + BTN_LineDraw.Checked = false; pictureBoxMulti.Invalidate(); } @@ -339,6 +394,8 @@ private void BTN_Select_Click(object sender, EventArgs e) BTN_Z.Checked = false; BTN_Pipette.Checked = false; BTN_Trans.Checked = false; + BTN_RectFill.Checked = false; + BTN_LineDraw.Checked = false; pictureBoxMulti.Invalidate(); } @@ -370,6 +427,12 @@ private void BTN_Toolbox_CheckedChanged(object sender, EventArgs e) case "BTN_Trans": thisBox.ImageKey = thisBox.Checked ? "TransButton_Selected.bmp" : "TransButton.bmp"; break; + case "BTN_RectFill": + thisBox.ImageKey = thisBox.Checked ? "RectFillButton_Selected.bmp" : "RectFillButton.bmp"; + break; + case "BTN_LineDraw": + thisBox.ImageKey = thisBox.Checked ? "LineDrawButton_Selected.bmp" : "LineDrawButton.bmp"; + break; } } @@ -384,6 +447,8 @@ private void BTN_Z_Click(object sender, EventArgs e) BTN_Z.Checked = true; BTN_Pipette.Checked = false; BTN_Trans.Checked = false; + BTN_RectFill.Checked = false; + BTN_LineDraw.Checked = false; pictureBoxMulti.Invalidate(); } @@ -396,10 +461,43 @@ private void BTN_Trans_Clicked(object sender, EventArgs e) BTN_Z.Checked = false; BTN_Pipette.Checked = false; BTN_Trans.Checked = true; + BTN_RectFill.Checked = false; + BTN_LineDraw.Checked = false; + + pictureBoxMulti.Invalidate(); + } + + private void BTN_RectFill_Click(object sender, EventArgs e) + { + BTN_Select.Checked = false; + BTN_Draw.Checked = false; + BTN_Remove.Checked = false; + BTN_Z.Checked = false; + BTN_Pipette.Checked = false; + BTN_Trans.Checked = false; + BTN_LineDraw.Checked = false; + BTN_RectFill.Checked = true; pictureBoxMulti.Invalidate(); } + private void BTN_LineDraw_Click(object sender, EventArgs e) + { + BTN_Select.Checked = false; + BTN_Draw.Checked = false; + BTN_Remove.Checked = false; + BTN_Z.Checked = false; + BTN_Pipette.Checked = false; + BTN_Trans.Checked = false; + BTN_RectFill.Checked = false; + BTN_LineDraw.Checked = true; + + pictureBoxMulti.Invalidate(); + } + + + private int BrushSize => RB_Brush_M.Checked ? 3 : RB_Brush_L.Checked ? 4 : 1; + /// /// Converts pictureBox coords to Multi coords /// @@ -414,6 +512,11 @@ private void ConvertCoords(Point point, out int x, out int y, out int z) x = HoverTile.X; y = HoverTile.Y; z = HoverTile.Z + HoverTile.Height; + // Cap placement Z to MaxHeightTrackBar when height filter is active + if (MaxHeightTrackBar.Value < MaxHeightTrackBar.Maximum) + { + z = Math.Min(z, MaxHeightTrackBar.Value); + } return; } } @@ -516,12 +619,29 @@ private void NumericUpDown_Selected_Y_Changed(object sender, EventArgs e) /// private void NumericUpDown_Selected_Z_Changed(object sender, EventArgs e) { - if (_compList == null || SelectedTile == null || (int)numericUpDown_Selected_Z.Value == SelectedTile.Z) + if (_compList == null) { return; } - _compList.TileZSet(SelectedTile, (int)numericUpDown_Selected_Z.Value); + int newZ = (int)numericUpDown_Selected_Z.Value; + + if (_selectedTiles.Count > 1) + { + // Apply absolute Z to the whole group + _compList.TileZSet(_selectedTiles, newZ); + MaxHeightTrackBar.Minimum = _compList.ZMin; + MaxHeightTrackBar.Maximum = _compList.ZMax; + pictureBoxMulti.Invalidate(); + return; + } + + if (SelectedTile == null || newZ == SelectedTile.Z) + { + return; + } + + _compList.TileZSet(SelectedTile, newZ); MaxHeightTrackBar.Minimum = _compList.ZMin; MaxHeightTrackBar.Maximum = _compList.ZMax; @@ -557,6 +677,15 @@ private void OnLoad(object sender, EventArgs e) XML_InitializeToolBox(); + if (!_loaded) + { + _recentTiles.Clear(); + _recentTiles.AddRange(TileRecentlyUsed.Load()); + InitializeRecentTab(); + } + + RefreshRecentPanel(); + string path = Options.AppDataPath; string fileName = Path.Combine(path, "Multilist.xml"); @@ -704,9 +833,7 @@ private void OnMultiChangeEvent(object sender, int id) /// private void PictureBoxMultiOnMouseMove(object sender, MouseEventArgs e) { - _mouseLoc = e.Location; - _mouseLoc.X += hScrollBar.Value; - _mouseLoc.Y += vScrollBar.Value; + _mouseLoc = ToScrolledSpace(e.Location); if (_moving) { @@ -718,6 +845,28 @@ private void PictureBoxMultiOnMouseMove(object sender, MouseEventArgs e) hScrollBar.Value = Math.Max(0, Math.Min(hScrollBar.Maximum, hScrollBar.Value + deltaX)); vScrollBar.Value = Math.Max(0, Math.Min(vScrollBar.Maximum, vScrollBar.Value + deltaY)); } + else if (_isMarqueeDragging) + { + _marqueeEnd = new Point(e.X + hScrollBar.Value, e.Y + vScrollBar.Value); + } + else if (_isRectFillDragging && _compList != null) + { + ConvertCoords(_mouseLoc, out int x, out int y, out int _); + _rectFillEndX = x; + _rectFillEndY = y; + } + else if (_isLineDragging && _compList != null) + { + ConvertCoords(_mouseLoc, out int x, out int y, out int _); + _lineEndX = x; + _lineEndY = y; + } + else if (_isRemoveDragging && _compList != null) + { + ConvertCoords(_mouseLoc, out int rx, out int ry, out int _); + _removeEndX = rx; + _removeEndY = ry; + } pictureBoxMulti.Invalidate(); } @@ -727,15 +876,50 @@ private void PictureBoxMultiOnMouseDown(object sender, MouseEventArgs e) if (e.Button == MouseButtons.Right) { _moving = true; - _movingLoc = e.Location; - Cursor = Cursors.Hand; } + else if (e.Button == MouseButtons.Left && BTN_Select.Checked && _compList != null) + { + bool ctrlHeld = (ModifierKeys & Keys.Control) != 0; + if (_hoverTile == null && !ctrlHeld) + { + // Start marquee drag over empty space + _isMarqueeDragging = true; + _marqueeStart = new Point(e.X + hScrollBar.Value, e.Y + vScrollBar.Value); + _marqueeEnd = _marqueeStart; + } + } + else if (e.Button == MouseButtons.Left && BTN_RectFill.Checked && _compList != null) + { + ConvertCoords(_mouseLoc, out int x, out int y, out int _); + _isRectFillDragging = true; + _rectFillStartX = x; + _rectFillStartY = y; + _rectFillEndX = x; + _rectFillEndY = y; + } + else if (e.Button == MouseButtons.Left && BTN_LineDraw.Checked && _compList != null) + { + ConvertCoords(_mouseLoc, out int x, out int y, out int _); + _isLineDragging = true; + _lineStartX = x; + _lineStartY = y; + _lineEndX = x; + _lineEndY = y; + } + else if (e.Button == MouseButtons.Left && BTN_Remove.Checked && _compList != null) + { + ConvertCoords(_mouseLoc, out int rx, out int ry, out int _); + _isRemoveDragging = true; + _removeStartX = rx; + _removeStartY = ry; + _removeEndX = rx; + _removeEndY = ry; + } else { _moving = false; - Cursor = Cursors.Default; } } @@ -751,6 +935,25 @@ private void PictureBoxMultiOnMouseUp(object sender, MouseEventArgs e) if (e.Button == MouseButtons.Right) { + if (_isMarqueeDragging) + { + _isMarqueeDragging = false; + pictureBoxMulti.Invalidate(); + } + + if (_isRemoveDragging) + { + _isRemoveDragging = false; + pictureBoxMulti.Invalidate(); + return; + } + + if (_isPasteMode) + { + _isPasteMode = false; + pictureBoxMulti.Invalidate(); + } + return; } @@ -759,6 +962,19 @@ private void PictureBoxMultiOnMouseUp(object sender, MouseEventArgs e) return; } + // Paste commit + if (_isPasteMode && e.Button == MouseButtons.Left && _clipboard != null) + { + ConvertCoords(_mouseLoc, out int px, out int py, out int pz); + var batch = _clipboard.Select(c => (c.id, px + c.dx, py + c.dy, pz + c.dz)).ToList(); + _compList.TileAddBatch(batch); + _isPasteMode = false; + MaxHeightTrackBar.Minimum = _compList.ZMin; + MaxHeightTrackBar.Maximum = _compList.ZMax; + pictureBoxMulti.Invalidate(); + return; + } + if (e.Button == MouseButtons.Middle) { _overlayList.Clear(); @@ -781,7 +997,73 @@ private void PictureBoxMultiOnMouseUp(object sender, MouseEventArgs e) } else if (BTN_Select.Checked) { - SelectedTile = _hoverTile; + bool ctrlHeld = (ModifierKeys & Keys.Control) != 0; + + if (_isMarqueeDragging) + { + _isMarqueeDragging = false; + int sx = Math.Min(_marqueeStart.X, _marqueeEnd.X) - hScrollBar.Value; + int sy = Math.Min(_marqueeStart.Y, _marqueeEnd.Y) - vScrollBar.Value; + int sw = Math.Abs(_marqueeEnd.X - _marqueeStart.X); + int sh = Math.Abs(_marqueeEnd.Y - _marqueeStart.Y); + + if (sw > 3 && sh > 3) + { + var rect = new Rectangle(sx, sy, sw, sh); + var tiles = _compList.GetTilesInScreenRect( + rect, hScrollBar.Value, vScrollBar.Value, + MaxHeightTrackBar.Value, BTN_Floor.Checked); + if (!ctrlHeld) + { + _selectedTiles.Clear(); + } + + foreach (var t in tiles) + { + _selectedTiles.Add(t); + } + + SelectedTile = _selectedTiles.Count == 1 ? _selectedTiles.First() : null; + } + else + { + // Tiny drag — treat as plain click + if (!ctrlHeld) + { + _selectedTiles.Clear(); + } + + if (_hoverTile != null) + { + _selectedTiles.Add(_hoverTile); + } + + SelectedTile = _hoverTile; + } + } + else if (ctrlHeld && _hoverTile != null) + { + if (_selectedTiles.Contains(_hoverTile)) + { + _selectedTiles.Remove(_hoverTile); + } + else + { + _selectedTiles.Add(_hoverTile); + } + + SelectedTile = _selectedTiles.Count == 1 ? _selectedTiles.First() : null; + } + else + { + _selectedTiles.Clear(); + if (_hoverTile != null) + { + _selectedTiles.Add(_hoverTile); + } + + SelectedTile = _hoverTile; + } } else if (BTN_Draw.Checked) { @@ -789,7 +1071,17 @@ private void PictureBoxMultiOnMouseUp(object sender, MouseEventArgs e) if (x >= 0 && x < _compList.Width && y >= 0 && y < _compList.Height) { - _compList.TileAdd(x, y, z, _drawTile.Id); + int brushSize = BrushSize; + if (brushSize <= 1) + { + _compList.TileAdd(x, y, z, _drawTile.Id); + } + else + { + _compList.TileAddBrush(x, y, z, _drawTile.Id, brushSize); + } + + RecordRecentTile(_drawTile.Id); MaxHeightTrackBar.Minimum = _compList.ZMin; MaxHeightTrackBar.Maximum = _compList.ZMax; if (MaxHeightTrackBar.Value < z) @@ -798,9 +1090,52 @@ private void PictureBoxMultiOnMouseUp(object sender, MouseEventArgs e) } } } + else if (BTN_RectFill.Checked && _isRectFillDragging) + { + _isRectFillDragging = false; + ConvertCoords(_mouseLoc, out int ex, out int ey, out int z); + int x0 = Math.Min(_rectFillStartX, ex); + int x1 = Math.Max(_rectFillStartX, ex); + int y0 = Math.Min(_rectFillStartY, ey); + int y1 = Math.Max(_rectFillStartY, ey); + _compList.TileAddRect(x0, y0, x1, y1, z, _drawTile.Id); + RecordRecentTile(_drawTile.Id); + MaxHeightTrackBar.Minimum = _compList.ZMin; + MaxHeightTrackBar.Maximum = _compList.ZMax; + if (MaxHeightTrackBar.Value < z) + { + MaxHeightTrackBar.Value = z; + } + } + else if (BTN_LineDraw.Checked && _isLineDragging) + { + _isLineDragging = false; + ConvertCoords(_mouseLoc, out int ex, out int ey, out int z); + (ex, ey) = GetLineEnd(ex, ey); + _compList.TileAddLine(_lineStartX, _lineStartY, ex, ey, z, _drawTile.Id); + RecordRecentTile(_drawTile.Id); + MaxHeightTrackBar.Minimum = _compList.ZMin; + MaxHeightTrackBar.Maximum = _compList.ZMax; + if (MaxHeightTrackBar.Value < z) + { + MaxHeightTrackBar.Value = z; + } + } else if (BTN_Remove.Checked) { - if (_hoverTile != null) + bool wasDrag = _isRemoveDragging && + (_removeEndX != _removeStartX || _removeEndY != _removeStartY); + _isRemoveDragging = false; + + if (wasDrag) + { + int x0 = Math.Min(_removeStartX, _removeEndX); + int x1 = Math.Max(_removeStartX, _removeEndX); + int y0 = Math.Min(_removeStartY, _removeEndY); + int y1 = Math.Max(_removeStartY, _removeEndY); + _compList.TileRemoveRect(x0, y0, x1, y1, DrawFloorZ, MaxHeightTrackBar.Value); + } + else if (_hoverTile != null) { _compList.TileRemove(_hoverTile); } @@ -839,9 +1174,15 @@ private void PictureBoxMultiOnMouseUp(object sender, MouseEventArgs e) } else if (BTN_Z.Checked) { - if (_hoverTile != null) + int z = (int)numericUpDown_Z.Value; + if (_selectedTiles.Count > 1) + { + _compList.TileZMod(_selectedTiles, z); + MaxHeightTrackBar.Minimum = _compList.ZMin; + MaxHeightTrackBar.Maximum = _compList.ZMax; + } + else if (_hoverTile != null) { - int z = (int)numericUpDown_Z.Value; _compList.TileZMod(_hoverTile, z); MaxHeightTrackBar.Minimum = _compList.ZMin; MaxHeightTrackBar.Maximum = _compList.ZMax; @@ -858,6 +1199,7 @@ private void PictureBoxMultiOnMouseUp(object sender, MouseEventArgs e) _drawTile.Set(_hoverTile.Id, 0); PictureBoxDrawTiles_Select(); DrawTileLabel.Text = $"Draw ID: 0x{_hoverTile.Id:X}"; + UpdateRecentSelection(); } } else if (BTN_Trans.Checked) @@ -877,6 +1219,7 @@ private void PictureBoxMultiOnMouseUp(object sender, MouseEventArgs e) _overlayList.Clear(); } + _minimapDirty = true; pictureBoxMulti.Invalidate(); } @@ -900,8 +1243,18 @@ private void PictureBoxMultiOnPaint(object sender, PaintEventArgs e) return; } + if (_zoomFactor != 1.0f) + { + float cx = pictureBoxMulti.Width / 2f; + float cy = pictureBoxMulti.Height / 2f; + e.Graphics.TranslateTransform(cx, cy); + e.Graphics.ScaleTransform(_zoomFactor, _zoomFactor); + e.Graphics.TranslateTransform(-cx, -cy); + } + _compList.GetImage(e.Graphics, hScrollBar.Value, vScrollBar.Value, MaxHeightTrackBar.Value, _mouseLoc, BTN_Floor.Checked); + if (ShowWalkables) { showWalkablesToolStripMenuItem.Text = $"Show Walkable tiles ({_compList.WalkableCount})"; @@ -919,37 +1272,112 @@ private void PictureBoxMultiOnPaint(object sender, PaintEventArgs e) Invoke(new ADelegate(SetToolStripText), $"{x},{y},{z}"); } - if (BTN_Draw.Checked) + // Draw marquee selection rectangle + if (_isMarqueeDragging) { - if (x < 0 || x >= _compList.Width || y < 0 || y >= _compList.Height) + int sx = Math.Min(_marqueeStart.X, _marqueeEnd.X) - hScrollBar.Value; + int sy = Math.Min(_marqueeStart.Y, _marqueeEnd.Y) - vScrollBar.Value; + int sw = Math.Abs(_marqueeEnd.X - _marqueeStart.X); + int sh = Math.Abs(_marqueeEnd.Y - _marqueeStart.Y); + using (var pen = new System.Drawing.Pen(Color.DodgerBlue, 1)) { - return; + pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; + e.Graphics.DrawRectangle(pen, sx, sy, sw, sh); } - Invoke(new ADelegate(SetToolStripText), $"{x},{y},{z}"); + using (var brush = new SolidBrush(Color.FromArgb(30, Color.DodgerBlue))) + { + e.Graphics.FillRectangle(brush, sx, sy, sw, sh); + } + } + + // Bulk remove drag preview — highlight existing tiles in the multi-space rect + if (_isRemoveDragging) + { + int rx0 = Math.Min(_removeStartX, _removeEndX); + int rx1 = Math.Max(_removeStartX, _removeEndX); + int ry0 = Math.Min(_removeStartY, _removeEndY); + int ry1 = Math.Max(_removeStartY, _removeEndY); + foreach (MultiTile ht in _compList.Tiles) + { + if (ht.IsVirtualFloor || ht.Z < DrawFloorZ || ht.Z > MaxHeightTrackBar.Value || ht.X < rx0 || ht.X > rx1 || ht.Y < ry0 || ht.Y > ry1) + { + continue; + } + + Bitmap htBmp = ht.GetBitmap(); + if (htBmp == null) + { + continue; + } - Bitmap bmp = _drawTile.GetBitmap(); + int hpx = ht.XMod - _compList.XMin - hScrollBar.Value; + int hpy = ht.YMod - _compList.YMin - vScrollBar.Value; + e.Graphics.DrawImage(htBmp, new Rectangle(hpx, hpy, htBmp.Width, htBmp.Height), + 0, 0, htBmp.Width, htBmp.Height, GraphicsUnit.Pixel, MultiTile.RemoveHighlightColor); + } + } - if (bmp == null) + // Paste ghost preview + if (_isPasteMode && _clipboard != null) + { + ConvertCoords(_mouseLoc, out int px, out int py, out int pz); + foreach (var (id, dx, dy, dz) in _clipboard) { - return; + var ghost = new MultiTile(id, px + dx, py + dy, pz + dz, 1); + Bitmap ghostBmp = ghost.GetBitmap(); + if (ghostBmp == null) + { + continue; + } + + int gpx = (ghost.X - ghost.Y) * 22 - ghostBmp.Width / 2 - _compList.XMin + MultiEditorComponentList.GapXMod - hScrollBar.Value; + int gpy = (ghost.X + ghost.Y) * 22 - ghost.Z * 4 - ghostBmp.Height - _compList.YMin + MultiEditorComponentList.GapYMod - vScrollBar.Value; + e.Graphics.DrawImage(ghostBmp, new Rectangle(gpx, gpy, ghostBmp.Width, ghostBmp.Height), + 0, 0, ghostBmp.Width, ghostBmp.Height, GraphicsUnit.Pixel, MultiTile.DrawColor); } + } - int px = (x - y) * 22; - int py = (x + y) * 22; + if (BTN_Draw.Checked) + { + if (x < 0 || x >= _compList.Width || y < 0 || y >= _compList.Height) + { + return; + } - px -= bmp.Width / 2; - py -= z * 4; - py -= bmp.Height; - px -= _compList.XMin; - py -= _compList.YMin; - py += MultiEditorComponentList.GapYMod; // Mod for a bit of gap - px += MultiEditorComponentList.GapXMod; - px -= hScrollBar.Value; - py -= vScrollBar.Value; + Invoke(new ADelegate(SetToolStripText), $"{x},{y},{z}"); - e.Graphics.DrawImage(bmp, new Rectangle(px, py, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, - GraphicsUnit.Pixel, MultiTile.DrawColor); + int brushSize = BrushSize; + int half = brushSize / 2; + for (int dx = -half; dx <= half; dx++) + { + for (int dy = -half; dy <= half; dy++) + { + DrawTilePreviewAt(e.Graphics, x + dx, y + dy, z); + } + } + } + else if (BTN_RectFill.Checked && _isRectFillDragging) + { + int x0 = Math.Min(_rectFillStartX, _rectFillEndX); + int x1 = Math.Max(_rectFillStartX, _rectFillEndX); + int y0 = Math.Min(_rectFillStartY, _rectFillEndY); + int y1 = Math.Max(_rectFillStartY, _rectFillEndY); + for (int rx = x0; rx <= x1; rx++) + { + for (int ry = y0; ry <= y1; ry++) + { + DrawTilePreviewAt(e.Graphics, rx, ry, z); + } + } + } + else if (BTN_LineDraw.Checked && _isLineDragging) + { + var (cex, cey) = GetLineEnd(_lineEndX, _lineEndY); + foreach (var (lx, ly) in MultiEditorComponentList.BresenhamLinePublic(_lineStartX, _lineStartY, cex, cey)) + { + DrawTilePreviewAt(e.Graphics, lx, ly, z); + } } else if (_overlayList.Count > 0) { @@ -968,6 +1396,55 @@ private void PictureBoxMultiOnPaint(object sender, PaintEventArgs e) overX += bmp.Width + 10; } } + + UpdateMinimap(); + } + + private void PictureBoxMulti_OnMouseWheel(object sender, MouseEventArgs e) + { + if ((ModifierKeys & Keys.Control) != 0) + { + float delta = e.Delta > 0 ? 0.1f : -0.1f; + SetZoom(_zoomFactor + delta); + if (e is HandledMouseEventArgs hme) + { + hme.Handled = true; + } + + return; + } + + // Normal scroll: pan vertically + int scrollDelta = e.Delta > 0 ? -22 : 22; + vScrollBar.Value = Math.Clamp(vScrollBar.Value + scrollDelta, 0, vScrollBar.Maximum); + } + + private Point ToScrolledSpace(Point screenPt) + { + float cx = pictureBoxMulti.Width / 2f; + float cy = pictureBoxMulti.Height / 2f; + float sx = (screenPt.X - cx) / _zoomFactor + cx + hScrollBar.Value; + float sy = (screenPt.Y - cy) / _zoomFactor + cy + vScrollBar.Value; + return new Point((int)sx, (int)sy); + } + + private void DrawTilePreviewAt(Graphics gfx, int tx, int ty, int z) + { + if (tx < 0 || tx >= _compList.Width || ty < 0 || ty >= _compList.Height) + { + return; + } + + Bitmap bmp = _drawTile.GetBitmap(); + if (bmp == null) + { + return; + } + + int px = (tx - ty) * 22 - bmp.Width / 2 - _compList.XMin + MultiEditorComponentList.GapXMod - hScrollBar.Value; + int py = (tx + ty) * 22 - z * 4 - bmp.Height - _compList.YMin + MultiEditorComponentList.GapYMod - vScrollBar.Value; + gfx.DrawImage(bmp, new Rectangle(px, py, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, + GraphicsUnit.Pixel, MultiTile.DrawColor); } /// @@ -1311,23 +1788,30 @@ private void UndoList_BeforeOpening(object sender, EventArgs e) return; } - foreach (ToolStripItem item in UndoItems.DropDownItems) + UndoItems.DropDownItems.Clear(); + for (int i = 0; i < _compList.UndoList.Count; i++) { - int index = (int)item.Tag; - item.Text = _compList.UndoList[index].Tiles != null - ? _compList.UndoList[index].Action - : "---"; + var item = new ToolStripMenuItem(_compList.UndoList[i].Action ?? "---") + { + Tag = i + }; + item.Click += Undo_onClick; + UndoItems.DropDownItems.Add(item); + } + + if (UndoItems.DropDownItems.Count == 0) + { + UndoItems.DropDownItems.Add(new ToolStripMenuItem("---") { Enabled = false }); } } private void UndoList_Clear() { _compList?.UndoClear(); - - foreach (ToolStripItem item in UndoItems.DropDownItems) - { - item.Text = "---"; - } + UndoItems.DropDownItems.Clear(); + _minimapTilesBmp?.Dispose(); + _minimapTilesBmp = null; + _minimapDirty = true; } private static void XML_AddChildren(TreeNode node, XmlElement mainNode) @@ -1397,6 +1881,7 @@ public void SelectDrawTile(ushort id) _drawTile.Set(id, 0); PictureBoxDrawTiles_Select(); DrawTileLabel.Text = $"Draw ID: 0x{id:X}"; + UpdateRecentSelection(); } private int GetIndex(int x, int y) @@ -1434,6 +1919,7 @@ private void PictureBoxDrawTiles_OnMouseClick(object sender, MouseEventArgs e) DrawTileLabel.Text = $"Draw ID: 0x{index:X}"; pictureBoxDrawTiles.Invalidate(); + UpdateRecentSelection(); } private void PictureBoxDrawTilesMouseMove(object sender, MouseEventArgs e) @@ -1599,6 +2085,163 @@ private void PictureBoxDrawTiles_Select() } } + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + if (_compList != null) + { + // Undo / Redo + if (keyData == (Keys.Control | Keys.Z)) + { + if (_compList.UndoStep()) + { + UpdateTrackBarAfterZChange(); + _selectedTiles.Clear(); + pictureBoxMulti.Invalidate(); + } + + return true; + } + + if (keyData == (Keys.Control | Keys.Y) || keyData == (Keys.Control | Keys.Shift | Keys.Z)) + { + if (_compList.RedoStep()) + { + UpdateTrackBarAfterZChange(); + _selectedTiles.Clear(); + pictureBoxMulti.Invalidate(); + } + + return true; + } + + // Z up/down for selection: [ = -1, ] = +1 + IEnumerable zTargets = _selectedTiles.Count > 0 + ? (IEnumerable)_selectedTiles + : (SelectedTile != null ? new[] { SelectedTile } : null); + + if (keyData == Keys.OemOpenBrackets && zTargets != null) + { + _compList.TileZMod(zTargets, -1); + UpdateTrackBarAfterZChange(); + pictureBoxMulti.Invalidate(); + return true; + } + + if (keyData == Keys.OemCloseBrackets && zTargets != null) + { + _compList.TileZMod(zTargets, 1); + UpdateTrackBarAfterZChange(); + pictureBoxMulti.Invalidate(); + return true; + } + + // Copy / Paste + if (keyData == (Keys.Control | Keys.C) && _selectedTiles.Count > 0) + { + int ox = _selectedTiles.Min(t => t.X); + int oy = _selectedTiles.Min(t => t.Y); + int oz = _selectedTiles.Min(t => t.Z); + _clipboard = _selectedTiles.Select(t => (t.Id, t.X - ox, t.Y - oy, t.Z - oz)).ToList(); + return true; + } + + if (keyData == (Keys.Control | Keys.V) && _clipboard != null) + { + _isPasteMode = true; + pictureBoxMulti.Invalidate(); + return true; + } + + if (keyData == Keys.Escape && _isPasteMode) + { + _isPasteMode = false; + pictureBoxMulti.Invalidate(); + return true; + } + + // Navigation: arrow keys pan, PgUp/PgDn step floor + const int PanStep = 22; + if (keyData == Keys.Left) { hScrollBar.Value = Math.Max(0, hScrollBar.Value - PanStep); return true; } + if (keyData == Keys.Right) { hScrollBar.Value = Math.Min(hScrollBar.Maximum, hScrollBar.Value + PanStep); return true; } + if (keyData == Keys.Up) { vScrollBar.Value = Math.Max(0, vScrollBar.Value - PanStep); return true; } + if (keyData == Keys.Down) { vScrollBar.Value = Math.Min(vScrollBar.Maximum, vScrollBar.Value + PanStep); return true; } + + if (keyData == Keys.PageUp) + { + numericUpDown_Floor.Value = Math.Min(numericUpDown_Floor.Maximum, numericUpDown_Floor.Value + 5); + return true; + } + + if (keyData == Keys.PageDown) + { + numericUpDown_Floor.Value = Math.Max(numericUpDown_Floor.Minimum, numericUpDown_Floor.Value - 5); + return true; + } + + // Zoom + if (keyData == Keys.Add || keyData == (Keys.Shift | Keys.Oemplus)) + { + SetZoom(_zoomFactor + 0.1f); + return true; + } + + if (keyData == Keys.Subtract || keyData == Keys.OemMinus) + { + SetZoom(_zoomFactor - 0.1f); + return true; + } + + if (keyData == (Keys.Control | Keys.D0) || keyData == (Keys.Control | Keys.NumPad0)) + { + SetZoom(1.0f); + return true; + } + } + + return base.ProcessCmdKey(ref msg, keyData); + } + + /// + /// Returns the line end constrained to the dominant axis when Shift is held. + /// + private (int ex, int ey) GetLineEnd(int rawEx, int rawEy) + { + if ((ModifierKeys & Keys.Shift) == 0) + { + return (rawEx, rawEy); + } + + int dx = Math.Abs(rawEx - _lineStartX); + int dy = Math.Abs(rawEy - _lineStartY); + return dx >= dy + ? (rawEx, _lineStartY) // horizontal axis + : (_lineStartX, rawEy); // vertical axis + } + + private void SetZoom(float factor) + { + _zoomFactor = Math.Clamp(factor, 0.25f, 4.0f); + toolStripBtnZoom.Text = $"{(int)Math.Round(_zoomFactor * 100)}%"; + pictureBoxMulti.Invalidate(); + } + + private void ToolStripBtnZoom_Click(object sender, EventArgs e) + { + SetZoom(1.0f); + } + + private void UpdateTrackBarAfterZChange() + { + MaxHeightTrackBar.Minimum = _compList.ZMin; + MaxHeightTrackBar.Maximum = _compList.ZMax; + if (MaxHeightTrackBar.Value < _compList.ZMax) + { + MaxHeightTrackBar.Value = _compList.ZMax; + } + + _minimapDirty = true; + } + private void BTN_DynamicCheckBox_Changed(object sender, EventArgs e) { if (_compList == null || SelectedTile == null) @@ -1658,5 +2301,192 @@ private void OnDummyContextMenuOpening(object sender, System.ComponentModel.Canc { e.Cancel = true; } + + private void InitializeRecentTab() + { + var recentTab = new TabPage { Text = "Recent" }; + + _recentPanel = new FlowLayoutPanel + { + Dock = DockStyle.Fill, + AutoScroll = true, + Padding = new Padding(2) + }; + + for (int i = 0; i < TileRecentlyUsed.MaxRecentTiles; i++) + { + var slot = new PictureBox + { + Size = new Size(44, 44), + BorderStyle = BorderStyle.FixedSingle, + SizeMode = PictureBoxSizeMode.Zoom, + Tag = -1, + BackColor = Color.Transparent + }; + slot.Click += RecentSlot_Click; + + _recentSlots.Add(slot); + _recentPanel.Controls.Add(slot); + } + + recentTab.Controls.Add(_recentPanel); + TC_MultiEditorToolbox.TabPages.Add(recentTab); + } + + private void RefreshRecentPanel() + { + for (int i = 0; i < _recentSlots.Count; i++) + { + var slot = _recentSlots[i]; + if (i < _recentTiles.Count) + { + slot.Tag = _recentTiles[i]; + slot.Image = Ultima.Art.GetStatic(_recentTiles[i]); + toolTip1.SetToolTip(slot, $"0x{_recentTiles[i]:X}"); + } + else + { + slot.Tag = -1; + slot.Image = null; + toolTip1.SetToolTip(slot, string.Empty); + } + } + + UpdateRecentSelection(); + } + + private void UpdateRecentSelection() + { + foreach (var slot in _recentSlots) + { + slot.BackColor = slot.Tag is int id && id == _drawTile.Id + ? Color.LightBlue + : Color.Transparent; + } + } + + private void RecentSlot_Click(object sender, EventArgs e) + { + if (sender is PictureBox pb && pb.Tag is int id && id >= 0) + { + _drawTile.Set((ushort)id, 0); + DrawTileLabel.Text = $"Draw ID: 0x{id:X}"; + PictureBoxDrawTiles_Select(); + pictureBoxDrawTiles.Invalidate(); + UpdateRecentSelection(); + } + } + + private void RecordRecentTile(int tileId) + { + if (tileId < 0) + { + return; + } + + _recentTiles.Remove(tileId); + _recentTiles.Insert(0, tileId); + if (_recentTiles.Count > TileRecentlyUsed.MaxRecentTiles) + { + _recentTiles.RemoveAt(_recentTiles.Count - 1); + } + + TileRecentlyUsed.Save(_recentTiles); + RefreshRecentPanel(); + } + + private void UpdateMinimap() + { + if (_compList == null || pictureBoxMinimap.Width <= 0 || pictureBoxMinimap.Height <= 0) + { + return; + } + + int multiW = _compList.XMax - _compList.XMin + MultiEditorComponentList.GapXMod * 2; + int multiH = _compList.YMaxOrg - _compList.YMin + MultiEditorComponentList.GapYMod * 3; + if (multiW <= 0 || multiH <= 0) + { + return; + } + + float scaleX = (float)pictureBoxMinimap.Width / multiW; + float scaleY = (float)pictureBoxMinimap.Height / multiH; + float scale = Math.Min(scaleX, scaleY); + if (scale <= 0) + { + return; + } + + // Regenerate tile-dot layer only when tiles changed + if (_minimapDirty || _minimapTilesBmp == null) + { + _minimapDirty = false; + _minimapTilesBmp?.Dispose(); + _minimapTilesBmp = new Bitmap(pictureBoxMinimap.Width, pictureBoxMinimap.Height); + using (var gfx = Graphics.FromImage(_minimapTilesBmp)) + { + gfx.Clear(Color.DimGray); + int dotSize = Math.Max(1, (int)(2 * scale)); + using (var brush = new SolidBrush(Color.LightGray)) + { + foreach (MultiTile tile in _compList.Tiles) + { + if (tile.IsVirtualFloor) + { + continue; + } + + int px = (int)((tile.XMod - _compList.XMin) * scale); + int py = (int)((tile.YMod - _compList.YMin) * scale); + gfx.FillRectangle(brush, px, py, dotSize, dotSize); + } + } + } + } + + // Composite: tile dots + fresh viewport rect every frame + var bmp = new Bitmap(pictureBoxMinimap.Width, pictureBoxMinimap.Height); + using (var gfx = Graphics.FromImage(bmp)) + { + gfx.DrawImageUnscaled(_minimapTilesBmp, 0, 0); + + float vx = hScrollBar.Value * scale; + float vy = vScrollBar.Value * scale; + float vw = pictureBoxMulti.Width * scale; + float vh = pictureBoxMulti.Height * scale; + gfx.DrawRectangle(Pens.Red, vx, vy, Math.Max(1, vw), Math.Max(1, vh)); + } + + pictureBoxMinimap.Image?.Dispose(); + pictureBoxMinimap.Image = bmp; + } + + private void PictureBoxMinimap_OnMouseClick(object sender, MouseEventArgs e) + { + if (_compList == null) + { + return; + } + + int multiW = _compList.XMax - _compList.XMin + MultiEditorComponentList.GapXMod * 2; + int multiH = _compList.YMaxOrg - _compList.YMin + MultiEditorComponentList.GapYMod * 3; + if (multiW <= 0 || multiH <= 0) + { + return; + } + + float scaleX = (float)pictureBoxMinimap.Width / multiW; + float scaleY = (float)pictureBoxMinimap.Height / multiH; + float scale = Math.Min(scaleX, scaleY); + if (scale <= 0) + { + return; + } + + int newHScroll = Math.Clamp((int)(e.X / scale) - pictureBoxMulti.Width / 2, 0, hScrollBar.Maximum); + int newVScroll = Math.Clamp((int)(e.Y / scale) - pictureBoxMulti.Height / 2, 0, vScrollBar.Maximum); + hScrollBar.Value = newHScroll; + vScrollBar.Value = newVScroll; + } } } \ No newline at end of file diff --git a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.resx b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.resx index cf491008..b8143ae0 100644 --- a/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.resx +++ b/UoFiddler.Plugin.MultiEditor/UserControls/MultiEditorControl.resx @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/UoFiddler/UoFiddler.csproj b/UoFiddler/UoFiddler.csproj index 4daa299c..1cb8529a 100644 --- a/UoFiddler/UoFiddler.csproj +++ b/UoFiddler/UoFiddler.csproj @@ -9,9 +9,9 @@ UoFiddler UoFiddler Copyright © 2026 - 4.17.9 - 4.17.9 - 4.17.9 + 4.18.0 + 4.18.0 + 4.18.0 true