diff --git a/SpriteMapEditor/DirectBitmap.cs b/SpriteMapEditor/DirectBitmap.cs new file mode 100644 index 0000000..1141713 --- /dev/null +++ b/SpriteMapEditor/DirectBitmap.cs @@ -0,0 +1,78 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SpriteMapEditor +{ + [Serializable] + public class DirectBitmap : IDisposable + { + public Bitmap Bitmap { get; private set; } + public Int32[] Bits { get; private set; } + public bool Disposed { get; private set; } + public int Height { get; private set; } + public int Width { get; private set; } + + protected GCHandle BitsHandle { get; private set; } + + public DirectBitmap(int width, int height) + { + Width = width; + Height = height; + Bits = new Int32[width * height]; + BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned); + Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject()); + } + + public DirectBitmap(DirectBitmap original) + { + Width = original.Width; + Height = original.Height; + Bits = (int[])original.Bits.Clone(); + BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned); + Bitmap = new Bitmap(Width, Height, Width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject()); + } + + public void CopyBitmap(DirectBitmap source) + { + if(Width == source.Width && Height == source.Height) + { + Bits = (int[])source.Bits.Clone(); + BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned); + Bitmap = new Bitmap(Width, Height, Width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject()); + } + } + + public void SetPixel(int x, int y, Color colour) + { + int index = x + (y * Width); + int col = colour.ToArgb(); + + Bits[index] = col; + } + + public Color GetPixel(int x, int y) + { + int index = x + (y * Width); + int col = Bits[index]; + Color result = Color.FromArgb(col); + + return result; + } + + public void Dispose() + { + if (Disposed) return; + Disposed = true; + Bitmap.Dispose(); + BitsHandle.Free(); + } + } +} diff --git a/SpriteMapEditor/Form1.Designer.cs b/SpriteMapEditor/Form1.Designer.cs index fecbacb..d924ac3 100644 --- a/SpriteMapEditor/Form1.Designer.cs +++ b/SpriteMapEditor/Form1.Designer.cs @@ -28,19 +28,16 @@ /// private void InitializeComponent() { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); + this.components = new System.ComponentModel.Container(); this.spriteList = new System.Windows.Forms.ListBox(); this.addSpriteButton = new System.Windows.Forms.Button(); this.removeSpriteButton = new System.Windows.Forms.Button(); - this.loadSpriteSheetButton = new System.Windows.Forms.Button(); - this.loadMapButton = new System.Windows.Forms.Button(); - this.saveMapButton = new System.Windows.Forms.Button(); - this.filePanel = new System.Windows.Forms.Panel(); this.spriteListPanel = new System.Windows.Forms.Panel(); this.moveDownButton = new System.Windows.Forms.Button(); this.moveUpButton = new System.Windows.Forms.Button(); this.spritesLabel = new System.Windows.Forms.Label(); this.spritePanel = new System.Windows.Forms.Panel(); + this.editingOriginCheckBox = new System.Windows.Forms.CheckBox(); this.originYPosBox = new System.Windows.Forms.NumericUpDown(); this.originXPosBox = new System.Windows.Forms.NumericUpDown(); this.originYPosLabel = new System.Windows.Forms.Label(); @@ -53,19 +50,29 @@ this.widthLabel = new System.Windows.Forms.Label(); this.yPosLabel = new System.Windows.Forms.Label(); this.xPosLabel = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); + this.spriteNameLabel = new System.Windows.Forms.Label(); this.spriteSettingsLabel = new System.Windows.Forms.Label(); this.spriteNameBox = new System.Windows.Forms.TextBox(); this.loadSpriteSheetDialog = new System.Windows.Forms.OpenFileDialog(); this.loadMapDialog = new System.Windows.Forms.OpenFileDialog(); this.saveMapDialog = new System.Windows.Forms.SaveFileDialog(); - this.fillButton = new System.Windows.Forms.Button(); this.spriteViewerPanel = new System.Windows.Forms.Panel(); - this.spriteSheetViewer = new SpriteMapEditor.PictureBoxWithInterpolationMode(); this.zoomInButton = new System.Windows.Forms.Button(); this.zoomOutButton = new System.Windows.Forms.Button(); this.zoomLabel = new System.Windows.Forms.Label(); - this.filePanel.SuspendLayout(); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.loadSpriteSheetToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.loadSpriteMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.saveSpriteMapToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.saveSpriteMapAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.highlightCheckBox = new System.Windows.Forms.CheckBox(); + this.outlineTimer = new System.Windows.Forms.Timer(this.components); + this.spriteSheetViewer = new SpriteMapEditor.PictureBoxWithInterpolationMode(); + this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.undoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.redoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.spriteListPanel.SuspendLayout(); this.spritePanel.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.originYPosBox)).BeginInit(); @@ -75,6 +82,7 @@ ((System.ComponentModel.ISupportInitialize)(this.spriteYPosBox)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.spriteXPosBox)).BeginInit(); this.spriteViewerPanel.SuspendLayout(); + this.menuStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.spriteSheetViewer)).BeginInit(); this.SuspendLayout(); // @@ -84,6 +92,7 @@ this.spriteList.FormattingEnabled = true; this.spriteList.Location = new System.Drawing.Point(3, 32); this.spriteList.Name = "spriteList"; + this.spriteList.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended; this.spriteList.Size = new System.Drawing.Size(183, 199); this.spriteList.TabIndex = 0; this.spriteList.SelectedValueChanged += new System.EventHandler(this.spriteList_SelectedValueChanged); @@ -108,46 +117,6 @@ this.removeSpriteButton.UseVisualStyleBackColor = true; this.removeSpriteButton.Click += new System.EventHandler(this.removeSpriteButton_Click); // - // loadSpriteSheetButton - // - this.loadSpriteSheetButton.Location = new System.Drawing.Point(3, 3); - this.loadSpriteSheetButton.Name = "loadSpriteSheetButton"; - this.loadSpriteSheetButton.Size = new System.Drawing.Size(185, 23); - this.loadSpriteSheetButton.TabIndex = 4; - this.loadSpriteSheetButton.Text = "Load Sprite Sheet..."; - this.loadSpriteSheetButton.UseVisualStyleBackColor = true; - this.loadSpriteSheetButton.Click += new System.EventHandler(this.loadSpriteSheetButton_Click); - // - // loadMapButton - // - this.loadMapButton.Location = new System.Drawing.Point(3, 32); - this.loadMapButton.Name = "loadMapButton"; - this.loadMapButton.Size = new System.Drawing.Size(92, 23); - this.loadMapButton.TabIndex = 5; - this.loadMapButton.Text = "Load Map..."; - this.loadMapButton.UseVisualStyleBackColor = true; - this.loadMapButton.Click += new System.EventHandler(this.loadMapButton_Click); - // - // saveMapButton - // - this.saveMapButton.Location = new System.Drawing.Point(96, 32); - this.saveMapButton.Name = "saveMapButton"; - this.saveMapButton.Size = new System.Drawing.Size(92, 23); - this.saveMapButton.TabIndex = 6; - this.saveMapButton.Text = "Save Map As..."; - this.saveMapButton.UseVisualStyleBackColor = true; - this.saveMapButton.Click += new System.EventHandler(this.saveMapButton_Click); - // - // filePanel - // - this.filePanel.Controls.Add(this.loadSpriteSheetButton); - this.filePanel.Controls.Add(this.saveMapButton); - this.filePanel.Controls.Add(this.loadMapButton); - this.filePanel.Location = new System.Drawing.Point(2, 2); - this.filePanel.Name = "filePanel"; - this.filePanel.Size = new System.Drawing.Size(190, 62); - this.filePanel.TabIndex = 7; - // // spriteListPanel // this.spriteListPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -160,9 +129,9 @@ this.spriteListPanel.Controls.Add(this.spriteList); this.spriteListPanel.Controls.Add(this.addSpriteButton); this.spriteListPanel.Controls.Add(this.removeSpriteButton); - this.spriteListPanel.Location = new System.Drawing.Point(2, 63); + this.spriteListPanel.Location = new System.Drawing.Point(2, 27); this.spriteListPanel.Name = "spriteListPanel"; - this.spriteListPanel.Size = new System.Drawing.Size(190, 254); + this.spriteListPanel.Size = new System.Drawing.Size(190, 258); this.spriteListPanel.TabIndex = 8; // // moveDownButton @@ -198,6 +167,7 @@ // spritePanel // this.spritePanel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.spritePanel.Controls.Add(this.editingOriginCheckBox); this.spritePanel.Controls.Add(this.originYPosBox); this.spritePanel.Controls.Add(this.originXPosBox); this.spritePanel.Controls.Add(this.originYPosLabel); @@ -210,23 +180,39 @@ this.spritePanel.Controls.Add(this.widthLabel); this.spritePanel.Controls.Add(this.yPosLabel); this.spritePanel.Controls.Add(this.xPosLabel); - this.spritePanel.Controls.Add(this.label2); + this.spritePanel.Controls.Add(this.spriteNameLabel); this.spritePanel.Controls.Add(this.spriteSettingsLabel); this.spritePanel.Controls.Add(this.spriteNameBox); - this.spritePanel.Location = new System.Drawing.Point(2, 323); + this.spritePanel.Location = new System.Drawing.Point(2, 291); this.spritePanel.Name = "spritePanel"; - this.spritePanel.Size = new System.Drawing.Size(190, 140); + this.spritePanel.Size = new System.Drawing.Size(190, 172); this.spritePanel.TabIndex = 9; // + // editingOriginCheckBox + // + this.editingOriginCheckBox.AutoSize = true; + this.editingOriginCheckBox.Location = new System.Drawing.Point(9, 108); + this.editingOriginCheckBox.Name = "editingOriginCheckBox"; + this.editingOriginCheckBox.Size = new System.Drawing.Size(107, 17); + this.editingOriginCheckBox.TabIndex = 23; + this.editingOriginCheckBox.Text = "Edit Origin Point?"; + this.editingOriginCheckBox.UseVisualStyleBackColor = true; + this.editingOriginCheckBox.CheckedChanged += new System.EventHandler(this.editingOriginCheckBox_CheckedChanged); + // // originYPosBox // this.originYPosBox.Enabled = false; - this.originYPosBox.Location = new System.Drawing.Point(143, 108); + this.originYPosBox.Location = new System.Drawing.Point(143, 131); this.originYPosBox.Maximum = new decimal(new int[] { 2147483647, 0, 0, 0}); + this.originYPosBox.Minimum = new decimal(new int[] { + 2147483647, + 0, + 0, + -2147483648}); this.originYPosBox.Name = "originYPosBox"; this.originYPosBox.Size = new System.Drawing.Size(45, 20); this.originYPosBox.TabIndex = 22; @@ -235,12 +221,17 @@ // originXPosBox // this.originXPosBox.Enabled = false; - this.originXPosBox.Location = new System.Drawing.Point(51, 108); + this.originXPosBox.Location = new System.Drawing.Point(51, 131); this.originXPosBox.Maximum = new decimal(new int[] { 2147483647, 0, 0, 0}); + this.originXPosBox.Minimum = new decimal(new int[] { + 2147483647, + 0, + 0, + -2147483648}); this.originXPosBox.Name = "originXPosBox"; this.originXPosBox.Size = new System.Drawing.Size(45, 20); this.originXPosBox.TabIndex = 21; @@ -250,7 +241,7 @@ // this.originYPosLabel.AutoSize = true; this.originYPosLabel.Enabled = false; - this.originYPosLabel.Location = new System.Drawing.Point(98, 111); + this.originYPosLabel.Location = new System.Drawing.Point(98, 134); this.originYPosLabel.Name = "originYPosLabel"; this.originYPosLabel.Size = new System.Drawing.Size(44, 13); this.originYPosLabel.TabIndex = 20; @@ -260,7 +251,7 @@ // this.originXPosLabel.AutoSize = true; this.originXPosLabel.Enabled = false; - this.originXPosLabel.Location = new System.Drawing.Point(6, 111); + this.originXPosLabel.Location = new System.Drawing.Point(6, 134); this.originXPosLabel.Name = "originXPosLabel"; this.originXPosLabel.Size = new System.Drawing.Size(44, 13); this.originXPosLabel.TabIndex = 19; @@ -354,14 +345,14 @@ this.xPosLabel.TabIndex = 8; this.xPosLabel.Text = "X Pos."; // - // label2 + // spriteNameLabel // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(6, 30); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(38, 13); - this.label2.TabIndex = 6; - this.label2.Text = "Name:"; + this.spriteNameLabel.AutoSize = true; + this.spriteNameLabel.Location = new System.Drawing.Point(6, 30); + this.spriteNameLabel.Name = "spriteNameLabel"; + this.spriteNameLabel.Size = new System.Drawing.Size(38, 13); + this.spriteNameLabel.TabIndex = 6; + this.spriteNameLabel.Text = "Name:"; // // spriteSettingsLabel // @@ -379,7 +370,8 @@ this.spriteNameBox.Name = "spriteNameBox"; this.spriteNameBox.Size = new System.Drawing.Size(144, 20); this.spriteNameBox.TabIndex = 0; - this.spriteNameBox.TextChanged += new System.EventHandler(this.spriteNameBox_TextChanged); + this.spriteNameBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.spriteNameBox_KeyPress); + this.spriteNameBox.Leave += new System.EventHandler(this.spriteNameBox_Leave); // // loadSpriteSheetDialog // @@ -397,31 +389,128 @@ this.saveMapDialog.DefaultExt = "smap"; this.saveMapDialog.Filter = "QUROGame SpriteMap|*.smap"; // - // fillButton - // - this.fillButton.Location = new System.Drawing.Point(454, 5); - this.fillButton.Name = "fillButton"; - this.fillButton.Size = new System.Drawing.Size(86, 23); - this.fillButton.TabIndex = 12; - this.fillButton.Text = "Highight"; - this.fillButton.UseVisualStyleBackColor = true; - this.fillButton.Click += new System.EventHandler(this.highlightButton_Click); - // // spriteViewerPanel // this.spriteViewerPanel.AutoScroll = true; this.spriteViewerPanel.BackColor = System.Drawing.SystemColors.ControlDark; this.spriteViewerPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; this.spriteViewerPanel.Controls.Add(this.spriteSheetViewer); - this.spriteViewerPanel.Location = new System.Drawing.Point(199, 34); + this.spriteViewerPanel.Location = new System.Drawing.Point(198, 59); this.spriteViewerPanel.Name = "spriteViewerPanel"; - this.spriteViewerPanel.Size = new System.Drawing.Size(488, 429); + this.spriteViewerPanel.Size = new System.Drawing.Size(488, 404); this.spriteViewerPanel.TabIndex = 14; this.spriteViewerPanel.Scroll += new System.Windows.Forms.ScrollEventHandler(this.spriteViewerPanel_Scroll); // + // zoomInButton + // + this.zoomInButton.Location = new System.Drawing.Point(659, 30); + this.zoomInButton.Name = "zoomInButton"; + this.zoomInButton.Size = new System.Drawing.Size(27, 23); + this.zoomInButton.TabIndex = 5; + this.zoomInButton.Text = "+"; + this.zoomInButton.UseVisualStyleBackColor = true; + this.zoomInButton.Click += new System.EventHandler(this.zoomInButton_Click); + // + // zoomOutButton + // + this.zoomOutButton.Location = new System.Drawing.Point(566, 30); + this.zoomOutButton.Name = "zoomOutButton"; + this.zoomOutButton.Size = new System.Drawing.Size(28, 23); + this.zoomOutButton.TabIndex = 6; + this.zoomOutButton.Text = "-"; + this.zoomOutButton.UseVisualStyleBackColor = true; + this.zoomOutButton.Click += new System.EventHandler(this.zoomOutButton_Click); + // + // zoomLabel + // + this.zoomLabel.AutoSize = true; + this.zoomLabel.Location = new System.Drawing.Point(600, 35); + this.zoomLabel.Name = "zoomLabel"; + this.zoomLabel.Size = new System.Drawing.Size(53, 13); + this.zoomLabel.TabIndex = 15; + this.zoomLabel.Text = "Zoom: 3X"; + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem, + this.editToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(691, 24); + this.menuStrip1.TabIndex = 16; + this.menuStrip1.Text = "menuStrip1"; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.loadSpriteSheetToolStripMenuItem, + this.loadSpriteMapToolStripMenuItem, + this.toolStripMenuItem1, + this.saveSpriteMapToolStripMenuItem, + this.saveSpriteMapAsToolStripMenuItem}); + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "File"; + // + // loadSpriteSheetToolStripMenuItem + // + this.loadSpriteSheetToolStripMenuItem.Name = "loadSpriteSheetToolStripMenuItem"; + this.loadSpriteSheetToolStripMenuItem.Size = new System.Drawing.Size(183, 22); + this.loadSpriteSheetToolStripMenuItem.Text = "Load Sprite Sheet..."; + this.loadSpriteSheetToolStripMenuItem.Click += new System.EventHandler(this.loadSpriteSheetToolStripMenuItem_Click); + // + // loadSpriteMapToolStripMenuItem + // + this.loadSpriteMapToolStripMenuItem.Enabled = false; + this.loadSpriteMapToolStripMenuItem.Name = "loadSpriteMapToolStripMenuItem"; + this.loadSpriteMapToolStripMenuItem.Size = new System.Drawing.Size(183, 22); + this.loadSpriteMapToolStripMenuItem.Text = "Load Sprite Map..."; + this.loadSpriteMapToolStripMenuItem.Click += new System.EventHandler(this.loadMapToolStripMenuItem_Click); + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(180, 6); + // + // saveSpriteMapToolStripMenuItem + // + this.saveSpriteMapToolStripMenuItem.Enabled = false; + this.saveSpriteMapToolStripMenuItem.Name = "saveSpriteMapToolStripMenuItem"; + this.saveSpriteMapToolStripMenuItem.Size = new System.Drawing.Size(183, 22); + this.saveSpriteMapToolStripMenuItem.Text = "Save Sprite Map"; + this.saveSpriteMapToolStripMenuItem.Click += new System.EventHandler(this.saveSpriteMapToolStripMenuItem_Click); + // + // saveSpriteMapAsToolStripMenuItem + // + this.saveSpriteMapAsToolStripMenuItem.Enabled = false; + this.saveSpriteMapAsToolStripMenuItem.Name = "saveSpriteMapAsToolStripMenuItem"; + this.saveSpriteMapAsToolStripMenuItem.Size = new System.Drawing.Size(183, 22); + this.saveSpriteMapAsToolStripMenuItem.Text = "Save Sprite Map As..."; + this.saveSpriteMapAsToolStripMenuItem.Click += new System.EventHandler(this.saveMapAsToolStripMenuItem_Click); + // + // highlightCheckBox + // + this.highlightCheckBox.AutoSize = true; + this.highlightCheckBox.Checked = true; + this.highlightCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.highlightCheckBox.Location = new System.Drawing.Point(446, 34); + this.highlightCheckBox.Name = "highlightCheckBox"; + this.highlightCheckBox.Size = new System.Drawing.Size(114, 17); + this.highlightCheckBox.TabIndex = 17; + this.highlightCheckBox.Text = "Highlight Selection"; + this.highlightCheckBox.UseVisualStyleBackColor = true; + this.highlightCheckBox.CheckedChanged += new System.EventHandler(this.highlightCheckBox_CheckedChanged); + // + // outlineTimer + // + this.outlineTimer.Enabled = true; + this.outlineTimer.Interval = 66; + this.outlineTimer.Tick += new System.EventHandler(this.outlineTimer_Tick); + // // spriteSheetViewer // - this.spriteSheetViewer.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("spriteSheetViewer.BackgroundImage"))); + this.spriteSheetViewer.BackgroundImage = global::SpriteMapEditor.Properties.Resources.transparentUI; this.spriteSheetViewer.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; this.spriteSheetViewer.Location = new System.Drawing.Point(0, 0); this.spriteSheetViewer.Margin = new System.Windows.Forms.Padding(0); @@ -436,34 +525,28 @@ this.spriteSheetViewer.MouseMove += new System.Windows.Forms.MouseEventHandler(this.spriteSheetViewer_MouseMove); this.spriteSheetViewer.MouseUp += new System.Windows.Forms.MouseEventHandler(this.spriteSheetViewer_MouseUp); // - // zoomInButton + // editToolStripMenuItem // - this.zoomInButton.Location = new System.Drawing.Point(652, 5); - this.zoomInButton.Name = "zoomInButton"; - this.zoomInButton.Size = new System.Drawing.Size(27, 23); - this.zoomInButton.TabIndex = 5; - this.zoomInButton.Text = "+"; - this.zoomInButton.UseVisualStyleBackColor = true; - this.zoomInButton.Click += new System.EventHandler(this.zoomInButton_Click); + this.editToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.undoToolStripMenuItem, + this.redoToolStripMenuItem}); + this.editToolStripMenuItem.Name = "editToolStripMenuItem"; + this.editToolStripMenuItem.Size = new System.Drawing.Size(39, 20); + this.editToolStripMenuItem.Text = "Edit"; // - // zoomOutButton + // undoToolStripMenuItem // - this.zoomOutButton.Location = new System.Drawing.Point(559, 5); - this.zoomOutButton.Name = "zoomOutButton"; - this.zoomOutButton.Size = new System.Drawing.Size(28, 23); - this.zoomOutButton.TabIndex = 6; - this.zoomOutButton.Text = "-"; - this.zoomOutButton.UseVisualStyleBackColor = true; - this.zoomOutButton.Click += new System.EventHandler(this.zoomOutButton_Click); + this.undoToolStripMenuItem.Name = "undoToolStripMenuItem"; + this.undoToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.undoToolStripMenuItem.Text = "Undo"; + this.undoToolStripMenuItem.Click += new System.EventHandler(this.undoToolStripMenuItem_Click); // - // zoomLabel + // redoToolStripMenuItem // - this.zoomLabel.AutoSize = true; - this.zoomLabel.Location = new System.Drawing.Point(593, 10); - this.zoomLabel.Name = "zoomLabel"; - this.zoomLabel.Size = new System.Drawing.Size(53, 13); - this.zoomLabel.TabIndex = 15; - this.zoomLabel.Text = "Zoom: 3X"; + this.redoToolStripMenuItem.Name = "redoToolStripMenuItem"; + this.redoToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.redoToolStripMenuItem.Text = "Redo"; + this.redoToolStripMenuItem.Click += new System.EventHandler(this.redoToolStripMenuItem_Click); // // Form1 // @@ -471,17 +554,19 @@ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.SystemColors.Control; this.ClientSize = new System.Drawing.Size(691, 465); + this.Controls.Add(this.highlightCheckBox); this.Controls.Add(this.zoomLabel); this.Controls.Add(this.zoomInButton); this.Controls.Add(this.spriteViewerPanel); this.Controls.Add(this.zoomOutButton); - this.Controls.Add(this.fillButton); this.Controls.Add(this.spritePanel); this.Controls.Add(this.spriteListPanel); - this.Controls.Add(this.filePanel); + this.Controls.Add(this.menuStrip1); + this.KeyPreview = true; this.Name = "Form1"; this.Text = "QUROGames Sprite Map Editor"; - this.filePanel.ResumeLayout(false); + this.Click += new System.EventHandler(this.Form1_Click); + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown); this.spriteListPanel.ResumeLayout(false); this.spriteListPanel.PerformLayout(); this.spritePanel.ResumeLayout(false); @@ -493,6 +578,8 @@ ((System.ComponentModel.ISupportInitialize)(this.spriteYPosBox)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.spriteXPosBox)).EndInit(); this.spriteViewerPanel.ResumeLayout(false); + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.spriteSheetViewer)).EndInit(); this.ResumeLayout(false); this.PerformLayout(); @@ -504,16 +591,12 @@ private System.Windows.Forms.ListBox spriteList; private System.Windows.Forms.Button addSpriteButton; private System.Windows.Forms.Button removeSpriteButton; - private System.Windows.Forms.Button loadSpriteSheetButton; - private System.Windows.Forms.Button loadMapButton; - private System.Windows.Forms.Button saveMapButton; - private System.Windows.Forms.Panel filePanel; private System.Windows.Forms.Panel spriteListPanel; private System.Windows.Forms.Label spritesLabel; private System.Windows.Forms.Panel spritePanel; private System.Windows.Forms.Label spriteSettingsLabel; private System.Windows.Forms.TextBox spriteNameBox; - private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label spriteNameLabel; private System.Windows.Forms.Label xPosLabel; private System.Windows.Forms.Label heightLabel; private System.Windows.Forms.Label widthLabel; @@ -521,7 +604,6 @@ private System.Windows.Forms.OpenFileDialog loadSpriteSheetDialog; private System.Windows.Forms.OpenFileDialog loadMapDialog; private System.Windows.Forms.SaveFileDialog saveMapDialog; - private System.Windows.Forms.Button fillButton; private PictureBoxWithInterpolationMode spriteSheetViewer; private System.Windows.Forms.Panel spriteViewerPanel; private System.Windows.Forms.Button zoomInButton; @@ -537,6 +619,19 @@ private System.Windows.Forms.Label originXPosLabel; private System.Windows.Forms.Button moveDownButton; private System.Windows.Forms.Button moveUpButton; + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem loadSpriteSheetToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem loadSpriteMapToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem saveSpriteMapToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem saveSpriteMapAsToolStripMenuItem; + private System.Windows.Forms.CheckBox editingOriginCheckBox; + private System.Windows.Forms.CheckBox highlightCheckBox; + private System.Windows.Forms.Timer outlineTimer; + private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem undoToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem redoToolStripMenuItem; } } diff --git a/SpriteMapEditor/Form1.cs b/SpriteMapEditor/Form1.cs index e2bf466..7ab3f4b 100644 --- a/SpriteMapEditor/Form1.cs +++ b/SpriteMapEditor/Form1.cs @@ -19,18 +19,45 @@ namespace SpriteMapEditor { public partial class Form1 : Form { + private SpriteMapModifications.History undoHistory; + private BindingList sprites; + private List selectedSprites; private bool highlight = false; - private SpriteMapRegion currentSprite; private int zoomLevel = 3; private bool loadingSprite = false; private bool movingWithMouse = false; - private bool rearrangingSprites = false; + private bool editingOrigin = false; + + const string TITLE = "QUROGames Sprite Map Editor"; + private string currentSpriteMapFileLocation; + private string CurrentSpriteMapFileLocation + { + get { return currentSpriteMapFileLocation; } + set + { + currentSpriteMapFileLocation = value; + Text = TITLE + " - " + Path.GetFileName(currentSpriteMapFileLocation); + } + } + + Image originPointer_black; + Image originPointer_white; + + Image spriteSheet; + + Pen blackPen; + Pen whitePen; + + DirectBitmap baseMask; + DirectBitmap highlightMask; private Point newPosition; private Point oldPosition; + private int totalDragX; + private int totalDragY; private int drawingRectangleOffset { @@ -48,74 +75,104 @@ namespace SpriteMapEditor InitializeComponent(); FormBorderStyle = FormBorderStyle.FixedSingle; + undoHistory = new SpriteMapModifications.History(); + spriteSheetViewer.Width = 1; spriteSheetViewer.Height = 1; sprites = new BindingList { new SpriteMapRegion() }; - - currentSprite = sprites[0]; + selectedSprites = new List(); spriteList.DataSource = sprites; spriteList.DisplayMember = "Name"; spriteList.ValueMember = "Bounds"; + originPointer_black = Properties.Resources.originPointer_black; + originPointer_white = Properties.Resources.originPointer_white; + + blackPen = new Pen(Color.Black); + whitePen = new Pen(Color.White); + whitePen.DashPattern = new float[] { 4, 4 }; + + highlight = highlightCheckBox.Checked; + LoadSpriteEditorValues(); } - private void loadSpriteSheetButton_Click(object sender, EventArgs e) + private void loadSpriteSheetToolStripMenuItem_Click(object sender, EventArgs e) { if(loadSpriteSheetDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { - spriteSheetViewer.Image = Image.FromFile(loadSpriteSheetDialog.FileName); + spriteSheet = Image.FromFile(loadSpriteSheetDialog.FileName); + spriteSheetViewer.Image = spriteSheet; } + + EnableLoadAndSaveAsSpriteMap(); + InitializeMask(); + } + + private void EnableLoadAndSaveAsSpriteMap() + { + loadSpriteMapToolStripMenuItem.Enabled = true; + saveSpriteMapAsToolStripMenuItem.Enabled = true; } private void spriteSheetViewer_Paint(object sender, PaintEventArgs e) { - if (spriteSheetViewer.Image != null) + if (spriteSheet != null) { - spriteSheetViewer.Width = spriteSheetViewer.Image.Width * zoomLevel; - spriteSheetViewer.Height = spriteSheetViewer.Image.Height * zoomLevel; + spriteSheetViewer.Width = spriteSheet.Width * zoomLevel; + spriteSheetViewer.Height = spriteSheet.Height * zoomLevel; if (highlight) - SurroundWithTranslucentRects(GetDrawingRect(currentSprite.Bounds, false), Color.Gray, e.Graphics); - DrawHighContrastOutline(GetDrawingRect(currentSprite.Bounds), e.Graphics); - /* - * Origin display code, uncomment when ready to implement - * - using (Brush magentaBrush = new SolidBrush(Color.Magenta)) { - e.Graphics.FillRectangle(magentaBrush, GetOriginDrawingRect(currentSprite)); + Rectangle highlightBounds = new Rectangle(0,0, highlightMask.Width * zoomLevel, highlightMask.Height * zoomLevel); + e.Graphics.DrawImage(highlightMask.Bitmap, highlightBounds); + } + + foreach (SpriteMapRegion currentSprite in selectedSprites) + { + DrawHighContrastOutline(GetDrawingRect(currentSprite.Bounds), e.Graphics); + DrawOriginPoint(currentSprite, e.Graphics); } - */ } - base.OnPaint(e); } private void LoadSpriteEditorValues() { loadingSprite = true; - spriteNameBox.Text = currentSprite.Name; - spriteXPosBox.Value = currentSprite.Bounds.X; - spriteYPosBox.Value = currentSprite.Bounds.Y; - spriteWidthBox.Value = currentSprite.Bounds.Width; - spriteHeightBox.Value = currentSprite.Bounds.Height; - originXPosBox.Value = (int)currentSprite.Origin.X; - originYPosBox.Value = (int)currentSprite.Origin.Y; + if (spriteList.SelectedIndices.Count > 1) + { + spriteNameBox.Text = ""; + spriteXPosBox.Text = ""; + spriteYPosBox.Text = ""; + spriteWidthBox.Text = ""; + spriteHeightBox.Text = ""; + originXPosBox.Text = ""; + originYPosBox.Text = ""; + + } + else if(spriteList.SelectedIndices.Count > 0) + { + SpriteMapRegion currentSprite = selectedSprites[0]; + spriteNameBox.Text = currentSprite.Name; + spriteXPosBox.Value = currentSprite.Bounds.X; + spriteXPosBox.Text = currentSprite.Bounds.X.ToString(); + spriteYPosBox.Value = currentSprite.Bounds.Y; + spriteYPosBox.Text = currentSprite.Bounds.Y.ToString(); + spriteWidthBox.Value = currentSprite.Bounds.Width; + spriteWidthBox.Text = currentSprite.Bounds.Width.ToString(); + spriteHeightBox.Value = currentSprite.Bounds.Height; + spriteHeightBox.Text = currentSprite.Bounds.Height.ToString(); + originXPosBox.Value = (int)currentSprite.Origin.X; + originXPosBox.Text = ((int)currentSprite.Origin.X).ToString(); + originYPosBox.Value = (int)currentSprite.Origin.Y; + originYPosBox.Text = ((int)currentSprite.Origin.Y).ToString(); + } loadingSprite = false; } - private void UpdateSpriteBounds() - { - currentSprite.Bounds = new Microsoft.Xna.Framework.Rectangle((int)spriteXPosBox.Value, (int)spriteYPosBox.Value, (int)spriteWidthBox.Value, (int)spriteHeightBox.Value); - } - - private void UpdateSpriteOrigin() - { - currentSprite.Origin = new Microsoft.Xna.Framework.Vector2((int)originXPosBox.Value, (int)originYPosBox.Value); - } - private Rectangle GetDrawingRect(Microsoft.Xna.Framework.Rectangle baseRect, bool outline = true) { var drawingRect = new Rectangle(baseRect.X, baseRect.Y, baseRect.Width, baseRect.Height); @@ -126,75 +183,91 @@ namespace SpriteMapEditor drawingRect.Width *= zoomLevel; drawingRect.Height *= zoomLevel; - if (outline) - { - drawingRect.X--; - drawingRect.Y--; - drawingRect.Width++; - drawingRect.Height++; - } + drawingRect.Width--; + drawingRect.Height--; return drawingRect; } - private Rectangle GetOriginDrawingRect(SpriteMapRegion sprite) + private Point GetOriginDrawingPoint(SpriteMapRegion sprite) { - var drawingRect = new Rectangle(sprite.Bounds.X, sprite.Bounds.Y, 2, 2); - drawingRect.X = drawingRect.X * zoomLevel - (zoomLevel - 1); - drawingRect.Y = drawingRect.Y * zoomLevel - (zoomLevel - 1); - drawingRect.X += drawingRectangleOffset; - drawingRect.Y += drawingRectangleOffset; - drawingRect.X += (int)sprite.Origin.X * zoomLevel; - drawingRect.Y += (int)sprite.Origin.Y * zoomLevel; - return drawingRect; + var drawingPoint = new Point(sprite.Bounds.X, sprite.Bounds.Y); + drawingPoint.X = drawingPoint.X * zoomLevel - (zoomLevel - 1); + drawingPoint.Y = drawingPoint.Y * zoomLevel - (zoomLevel - 1); + drawingPoint.X += drawingRectangleOffset; + drawingPoint.Y += drawingRectangleOffset; + drawingPoint.X += (int)sprite.Origin.X * zoomLevel; + drawingPoint.Y += (int)sprite.Origin.Y * zoomLevel; + return drawingPoint; } - private void SurroundWithTranslucentRects(Rectangle rect, Color color, Graphics graphics) + private void DrawOriginPoint(SpriteMapRegion sprite, Graphics graphics) { - Rectangle topBorder = new Rectangle(0, 0, spriteSheetViewer.Width, rect.Y); - Rectangle leftBorder = new Rectangle(0, rect.Y, rect.X, rect.Height); - Rectangle rightBorder = new Rectangle(rect.X + rect.Width, rect.Y, spriteSheetViewer.Width - rect.X + rect.Width, rect.Height); - Rectangle bottomBorder = new Rectangle(0, rect.Y + rect.Height, spriteSheetViewer.Width, spriteSheetViewer.Height - rect.Y + rect.Height); - FillTranslucentRects(new Rectangle[] { topBorder, leftBorder, rightBorder, bottomBorder }, color, graphics); - } - - private void FillTranslucentRect(Rectangle rect, Color color, Graphics graphics) - { - using (Brush whiteBrush = new SolidBrush(Color.FromArgb(128, color))) + if (editingOrigin) { - graphics.FillRectangle(whiteBrush, rect); + var spriteSheetBitmap = (Bitmap)spriteSheet; + var colorAtOrigin = spriteSheetBitmap.GetPixel((int)(sprite.Bounds.X + sprite.Origin.X), + (int)(sprite.Bounds.Y + sprite.Origin.Y)); + + var highContrastPointer = originPointer_black; + if (colorAtOrigin.GetBrightness() < 0.5f) + { + highContrastPointer = originPointer_white; + } + + var drawPoint = GetOriginDrawingPoint(sprite); + drawPoint.X -= 5; + drawPoint.Y -= 5; + + graphics.DrawImage(highContrastPointer, drawPoint); } } - private void FillTranslucentRects(Rectangle[] rects, Color color, Graphics graphics) + private void UpdateHighlightMask() { - using (Brush whiteBrush = new SolidBrush(Color.FromArgb(128, color))) + if (highlight) { - graphics.FillRectangles(whiteBrush, rects); + InitializeMask(); + foreach (SpriteMapRegion currentSprite in selectedSprites) + { + for (int currentY = 0; currentY < currentSprite.Bounds.Height; currentY++) + { + for (int currentX = 0; currentX < currentSprite.Bounds.Width; currentX++) + { + highlightMask.SetPixel(currentX + currentSprite.Bounds.X, currentY + currentSprite.Bounds.Y, Color.Transparent); + } + } + } + } + } + + private void InitializeMask() + { + if (baseMask == null) + { + Color maskColor = Color.FromArgb(128, 32, 32, 32); + + highlightMask = new DirectBitmap(spriteSheet.Width, spriteSheet.Height); + for (int currentY = 0; currentY < highlightMask.Height; currentY++) + { + for (int currentX = 0; currentX < highlightMask.Width; currentX++) + { + highlightMask.SetPixel(currentX, currentY, maskColor); + } + } + baseMask = new DirectBitmap(highlightMask); + } + else + { + highlightMask.Dispose(); + highlightMask = new DirectBitmap(baseMask); } } private void DrawHighContrastOutline(Rectangle rect, Graphics graphics) { - using (Pen blackPen = new Pen(Color.Black)) - { - graphics.DrawRectangle(blackPen, rect); - } - using (Pen whitePen = new Pen(Color.White)) - { - whitePen.DashPattern = new float[] { 4, 4 }; - graphics.DrawRectangle(whitePen, rect); - } - } - - private void highlightButton_Click(object sender, EventArgs e) - { - highlight = !highlight; - if (highlight) - fillButton.Text = "No Highlight"; - else - fillButton.Text = "Highlight"; - spriteSheetViewer.Refresh(); + graphics.DrawRectangle(blackPen, rect); + graphics.DrawRectangle(whitePen, rect); } private void zoomInButton_Click(object sender, EventArgs e) @@ -223,7 +296,10 @@ namespace SpriteMapEditor { if (loadingSprite) return; - UpdateSpriteBounds(); + var modification = new SpriteMapModifications.ModifyBounds(selectedSprites, x: (int)spriteXPosBox.Value); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); + UpdateHighlightMask(); spriteSheetViewer.Refresh(); } @@ -231,7 +307,10 @@ namespace SpriteMapEditor { if (loadingSprite) return; - UpdateSpriteBounds(); + var modification = new SpriteMapModifications.ModifyBounds(selectedSprites, y: (int)spriteYPosBox.Value); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); + UpdateHighlightMask(); spriteSheetViewer.Refresh(); } @@ -239,7 +318,10 @@ namespace SpriteMapEditor { if (loadingSprite) return; - UpdateSpriteBounds(); + var modification = new SpriteMapModifications.ModifyBounds(selectedSprites, width: (int)spriteWidthBox.Value); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); + UpdateHighlightMask(); spriteSheetViewer.Refresh(); } @@ -247,40 +329,96 @@ namespace SpriteMapEditor { if (loadingSprite) return; - UpdateSpriteBounds(); + var modification = new SpriteMapModifications.ModifyBounds(selectedSprites, height: (int)spriteHeightBox.Value); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); + UpdateHighlightMask(); spriteSheetViewer.Refresh(); } - private void spriteNameBox_TextChanged(object sender, EventArgs e) - { - if (loadingSprite) - return; - currentSprite.Name = spriteNameBox.Text; - sprites.ResetBindings(); - } - private void addSpriteButton_Click(object sender, EventArgs e) { - sprites.Add(new SpriteMapRegion(currentSprite.Name, currentSprite.Bounds)); + var modification = new SpriteMapModifications.AddSprite(sprites, selectedSprites[0]); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); } private void removeSpriteButton_Click(object sender, EventArgs e) { - if (spriteList.SelectedIndex > -1 && spriteList.SelectedIndex < sprites.Count) - sprites.RemoveAt(spriteList.SelectedIndex); + int indexToRemove = spriteList.SelectedIndex; + if (indexToRemove == sprites.Count - 1) + { + spriteList.SelectedIndices.Clear(); + spriteList.SelectedIndex = indexToRemove - 1; + } + + if (indexToRemove > -1 && indexToRemove < sprites.Count) + { + var modification = new SpriteMapModifications.RemoveSprite(sprites, indexToRemove); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); + } } private void spriteList_SelectedValueChanged(object sender, EventArgs e) { if (spriteList.SelectedIndex > -1 && spriteList.SelectedIndex < sprites.Count) { - currentSprite = sprites[spriteList.SelectedIndex]; + UpdateSelectedSpriteList(); LoadSpriteEditorValues(); + UpdateHighlightMask(); spriteSheetViewer.Refresh(); } } - private void saveMapButton_Click(object sender, EventArgs e) + private void SingleSpriteFunctions_SetEnabled(bool status) + { + moveDownButton.Enabled = status; + moveUpButton.Enabled = status; + spriteNameLabel.Enabled = status; + spriteNameBox.Enabled = status; + removeSpriteButton.Enabled = status; + addSpriteButton.Enabled = status; + } + + private void UpdateSelectedSpriteList() + { + selectedSprites.Clear(); + foreach(int currentIndex in spriteList.SelectedIndices) + { + selectedSprites.Add(sprites[currentIndex]); + } + if (selectedSprites.Count > 1) + SingleSpriteFunctions_SetEnabled(false); + else + SingleSpriteFunctions_SetEnabled(true); + } + + private Rectangle GetSelectedGroupRectangle() + { + Microsoft.Xna.Framework.Rectangle leftMost = selectedSprites[0].Bounds; + Microsoft.Xna.Framework.Rectangle topMost = selectedSprites[0].Bounds; + Microsoft.Xna.Framework.Rectangle rightMost = selectedSprites[0].Bounds; + Microsoft.Xna.Framework.Rectangle bottomMost = selectedSprites[0].Bounds; + + foreach (SpriteMapRegion currentSprite in selectedSprites) + { + if (currentSprite.Bounds.X < leftMost.X) + leftMost = currentSprite.Bounds; + if (currentSprite.Bounds.Y < topMost.Y) + topMost = currentSprite.Bounds; + if (currentSprite.Bounds.X + currentSprite.Bounds.Width > rightMost.X + rightMost.Width) + rightMost = currentSprite.Bounds; + if (currentSprite.Bounds.Y + currentSprite.Bounds.Height > bottomMost.Y + bottomMost.Width) + bottomMost = currentSprite.Bounds; + } + + return new Rectangle(leftMost.X, topMost.Y, + rightMost.X + rightMost.Width - leftMost.X, + bottomMost.Y + bottomMost.Height - topMost.Y); + } + + private void saveMapAsToolStripMenuItem_Click(object sender, EventArgs e) { var exportDict = new Dictionary(); foreach (SpriteMapRegion sprite in sprites) @@ -299,19 +437,51 @@ namespace SpriteMapEditor if (saveMapDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { - using (XmlWriter writer = XmlWriter.Create(saveMapDialog.FileName)) + CurrentSpriteMapFileLocation = saveMapDialog.FileName; + + using (XmlWriter writer = XmlWriter.Create(CurrentSpriteMapFileLocation)) + { + IntermediateSerializer.Serialize(writer, exportDict, null); + } + } + + saveSpriteMapToolStripMenuItem.Enabled = true; + } + + private void saveSpriteMapToolStripMenuItem_Click(object sender, EventArgs e) + { + if (CurrentSpriteMapFileLocation != null) + { + var exportDict = new Dictionary(); + foreach (SpriteMapRegion sprite in sprites) + { + if (exportDict.ContainsKey(sprite.Name)) + { + string errorMessage = "Duplicate names found! Please ensure all sprites have unique names."; + string caption = "Save Aborted"; + MessageBoxButtons saveError = MessageBoxButtons.OK; + + MessageBox.Show(errorMessage, caption, saveError); + return; + } + exportDict.Add(sprite.Name, sprite); + } + + using (XmlWriter writer = XmlWriter.Create(CurrentSpriteMapFileLocation)) { IntermediateSerializer.Serialize(writer, exportDict, null); } } } - private void loadMapButton_Click(object sender, EventArgs e) + private void loadMapToolStripMenuItem_Click(object sender, EventArgs e) { if(loadMapDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) { + CurrentSpriteMapFileLocation = loadMapDialog.FileName; + Dictionary loadedSpriteMap; - using (XmlReader xmlRead = XmlReader.Create(loadMapDialog.FileName)) + using (XmlReader xmlRead = XmlReader.Create(CurrentSpriteMapFileLocation)) { loadedSpriteMap = IntermediateSerializer.Deserialize>(xmlRead, null); } @@ -323,55 +493,104 @@ namespace SpriteMapEditor } spriteList.DataSource = sprites; + + saveSpriteMapToolStripMenuItem.Enabled = true; } } private void spriteSheetViewer_MouseMove(object sender, MouseEventArgs e) { - if(spriteSheetViewer.Image == null) + if(spriteSheet == null) return; Point mousePosition = new Point(e.X, e.Y); - if (GetDrawingRect(currentSprite.Bounds).Contains(mousePosition)) - { - Cursor = Cursors.SizeAll; - if (movingWithMouse) - { - newPosition = mousePosition; - newPosition.X /= zoomLevel; - newPosition.Y /= zoomLevel; - int differenceX = newPosition.X - oldPosition.X; - int differenceY = newPosition.Y - oldPosition.Y; - Console.WriteLine(differenceX + ", " + differenceY); - var newBounds = currentSprite.Bounds; - newBounds.X += differenceX; - newBounds.Y += differenceY; + bool hovering = false; - currentSprite.Bounds = newBounds; - oldPosition = newPosition; - spriteSheetViewer.Refresh(); - LoadSpriteEditorValues(); + foreach (SpriteMapRegion currentSprite in selectedSprites) + { + if (GetDrawingRect(currentSprite.Bounds).Contains(mousePosition)) + { + hovering = true; + Cursor = Cursors.SizeAll; + if (movingWithMouse) + { + newPosition = mousePosition; + newPosition.X /= zoomLevel; + newPosition.Y /= zoomLevel; + int differenceX = newPosition.X - oldPosition.X; + int differenceY = newPosition.Y - oldPosition.Y; + + var groupRect = GetSelectedGroupRectangle(); + if (groupRect.X + differenceX < 0 || + groupRect.X + groupRect.Width + differenceX > spriteSheet.Width) + differenceX = 0; + if (groupRect.Y + differenceY < 0 || + groupRect.Y + groupRect.Height + differenceY > spriteSheet.Height) + differenceY = 0; + + totalDragX += differenceX; + totalDragY += differenceY; + + foreach (SpriteMapRegion spriteToMove in selectedSprites) + { + var newBounds = spriteToMove.Bounds; + newBounds.X += differenceX; + newBounds.Y += differenceY; + + newBounds = ClampRectangleToSheet(newBounds); + + spriteToMove.Bounds = newBounds; + } + oldPosition = newPosition; + UpdateHighlightMask(); + spriteSheetViewer.Refresh(); + LoadSpriteEditorValues(); + break; + } } } - else + if(!hovering) Cursor = Cursors.Default; } + private Microsoft.Xna.Framework.Rectangle ClampRectangleToSheet(Microsoft.Xna.Framework.Rectangle rect) + { + var clampedRect = rect; + + //clamp X value + if (clampedRect.X < 0) + clampedRect.X = 0; + else if (clampedRect.X + clampedRect.Width > spriteSheet.Width) + clampedRect.X = spriteSheet.Width - clampedRect.Width; + //clamp Y value + if (clampedRect.Y < 0) + clampedRect.Y = 0; + else if (clampedRect.Y + clampedRect.Height > spriteSheet.Height) + clampedRect.Y = spriteSheet.Height - clampedRect.Height; + + return clampedRect; + } + private void spriteSheetViewer_MouseDown(object sender, MouseEventArgs e) { - if (spriteSheetViewer.Image == null) + if (spriteSheet == null) return; Point mousePosition = new Point(e.X, e.Y); - if (GetDrawingRect(currentSprite.Bounds).Contains(mousePosition)) + foreach (SpriteMapRegion currentSprite in selectedSprites) { - movingWithMouse = true; - newPosition = mousePosition; - newPosition.X /= zoomLevel; - newPosition.Y /= zoomLevel; - oldPosition = newPosition; + if (GetDrawingRect(currentSprite.Bounds).Contains(mousePosition)) + { + movingWithMouse = true; + totalDragX = 0; + totalDragY = 0; + newPosition = mousePosition; + newPosition.X /= zoomLevel; + newPosition.Y /= zoomLevel; + oldPosition = newPosition; + } } } @@ -384,13 +603,23 @@ namespace SpriteMapEditor private void spriteSheetViewer_MouseUp(object sender, MouseEventArgs e) { movingWithMouse = false; + if(totalDragX != 0 || totalDragY != 0) + { + var modification = new SpriteMapModifications.MoveBounds(selectedSprites, totalDragX, totalDragY); + var selection = SpriteMapModifications.ModHelper.GetSelectionList(spriteList); + modification.SetPreChangeSelection(selection); + modification.SetPostChangeSelection(selection); + undoHistory.Add(modification); + } } private void originXPosBox_ValueChanged(object sender, EventArgs e) { if (loadingSprite) return; - UpdateSpriteOrigin(); + var modification = new SpriteMapModifications.ModifyOrigin(selectedSprites, x: (int)originXPosBox.Value); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); spriteSheetViewer.Refresh(); } @@ -398,7 +627,9 @@ namespace SpriteMapEditor { if (loadingSprite) return; - UpdateSpriteOrigin(); + var modification = new SpriteMapModifications.ModifyOrigin(selectedSprites, y: (int)originYPosBox.Value); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); spriteSheetViewer.Refresh(); } @@ -406,10 +637,12 @@ namespace SpriteMapEditor { if(spriteList.SelectedIndex < sprites.Count - 1) { - var spriteBelow = sprites[spriteList.SelectedIndex + 1]; - sprites[spriteList.SelectedIndex + 1] = currentSprite; - sprites[spriteList.SelectedIndex] = spriteBelow; - spriteList.SelectedIndex++; + var modification = new SpriteMapModifications.MoveSpriteListEntry(sprites, spriteList.SelectedIndex, 1); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); + int newPosition = spriteList.SelectedIndex + 1; + spriteList.SelectedIndices.Clear(); + spriteList.SelectedIndex = newPosition; } } @@ -417,11 +650,113 @@ namespace SpriteMapEditor { if(spriteList.SelectedIndex > 0) { - var spriteAbove = sprites[spriteList.SelectedIndex - 1]; - sprites[spriteList.SelectedIndex - 1] = currentSprite; - sprites[spriteList.SelectedIndex] = spriteAbove; - spriteList.SelectedIndex--; + var modification = new SpriteMapModifications.MoveSpriteListEntry(sprites, spriteList.SelectedIndex, -1); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); + int newPosition = spriteList.SelectedIndex - 1; + spriteList.SelectedIndices.Clear(); + spriteList.SelectedIndex = newPosition; } } + + private void editingOriginCheckBox_CheckedChanged(object sender, EventArgs e) + { + editingOrigin = editingOriginCheckBox.Checked; + + if (editingOrigin) + { + originXPosLabel.Enabled = true; + originXPosBox.Enabled = true; + originYPosLabel.Enabled = true; + originYPosBox.Enabled = true; + } + else + { + originXPosLabel.Enabled = false; + originXPosBox.Enabled = false; + originYPosLabel.Enabled = false; + originYPosBox.Enabled = false; + } + + spriteViewerPanel.Refresh(); + } + + private void highlightCheckBox_CheckedChanged(object sender, EventArgs e) + { + highlight = highlightCheckBox.Checked; + if (highlight) + { + UpdateHighlightMask(); + } + spriteSheetViewer.Refresh(); + } + + private void outlineTimer_Tick(object sender, EventArgs e) + { + if (whitePen.DashOffset < 7) + whitePen.DashOffset++; + else + whitePen.DashOffset = 0; + spriteSheetViewer.Refresh(); + } + + private void UpdateSpriteName() + { + var modification = new SpriteMapModifications.RenameSprite(selectedSprites[0], spriteNameBox.Text); + SpriteMapModifications.ModHelper.DoModificationWithSelectionTracking(modification, spriteList); + undoHistory.Add(modification); + sprites.ResetBindings(); + } + + private void spriteNameBox_Leave(object sender, EventArgs e) + { + if (selectedSprites[0].Name != spriteNameBox.Text) + { + UpdateSpriteName(); + } + } + + private void spriteNameBox_KeyPress(object sender, KeyPressEventArgs e) + { + if (e.KeyChar == (char)Keys.Return && selectedSprites[0].Name != spriteNameBox.Text) + { + UpdateSpriteName(); + } + } + + private void Form1_Click(object sender, EventArgs e) + { + if (selectedSprites[0].Name != spriteNameBox.Text) + { + UpdateSpriteName(); + } + } + + private void Form1_KeyDown(object sender, KeyEventArgs e) + { + if (e.Modifiers == Keys.Control) + { + if (e.KeyCode == Keys.Z) + { + //Console.WriteLine("Undo Keypress"); + undoHistory.Undo(spriteList); + } + else if (e.KeyCode == Keys.Y) + { + //Console.WriteLine("Redo Keypress"); + undoHistory.Redo(spriteList); + } + } + } + + private void undoToolStripMenuItem_Click(object sender, EventArgs e) + { + undoHistory.Undo(spriteList); + } + + private void redoToolStripMenuItem_Click(object sender, EventArgs e) + { + undoHistory.Redo(spriteList); + } } } diff --git a/SpriteMapEditor/Form1.resx b/SpriteMapEditor/Form1.resx index 622b2df..f2da520 100644 --- a/SpriteMapEditor/Form1.resx +++ b/SpriteMapEditor/Form1.resx @@ -126,56 +126,10 @@ 325, 17 - - - - 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 - - + + 461, 17 + + + 576, 17 + \ No newline at end of file diff --git a/SpriteMapEditor/Properties/Resources.Designer.cs b/SpriteMapEditor/Properties/Resources.Designer.cs index 5d6ac28..366c787 100644 --- a/SpriteMapEditor/Properties/Resources.Designer.cs +++ b/SpriteMapEditor/Properties/Resources.Designer.cs @@ -60,6 +60,26 @@ namespace SpriteMapEditor.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap originPointer_black { + get { + object obj = ResourceManager.GetObject("originPointer_black", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap originPointer_white { + get { + object obj = ResourceManager.GetObject("originPointer_white", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/SpriteMapEditor/Properties/Resources.resx b/SpriteMapEditor/Properties/Resources.resx index 2b94a9d..d7626de 100644 --- a/SpriteMapEditor/Properties/Resources.resx +++ b/SpriteMapEditor/Properties/Resources.resx @@ -118,7 +118,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + ..\Resources\originPointer_black.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\originPointer_white.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + - ..\transparentui.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\transparentUI.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a \ No newline at end of file diff --git a/SpriteMapEditor/Resources/originPointer_black.png b/SpriteMapEditor/Resources/originPointer_black.png new file mode 100644 index 0000000..bc98207 Binary files /dev/null and b/SpriteMapEditor/Resources/originPointer_black.png differ diff --git a/SpriteMapEditor/Resources/originPointer_white.png b/SpriteMapEditor/Resources/originPointer_white.png new file mode 100644 index 0000000..25a472d Binary files /dev/null and b/SpriteMapEditor/Resources/originPointer_white.png differ diff --git a/SpriteMapEditor/SpriteMapEditor.csproj b/SpriteMapEditor/SpriteMapEditor.csproj index fdb995a..e607c7a 100644 --- a/SpriteMapEditor/SpriteMapEditor.csproj +++ b/SpriteMapEditor/SpriteMapEditor.csproj @@ -51,17 +51,28 @@ + Form Form1.cs + + + + + Component + + + + + Form1.cs @@ -88,17 +99,20 @@ - - - - - - {4581e0c8-b14a-454d-9a7b-52d37535e7e9} QURO + + + + + + + + + \ No newline at end of file diff --git a/SpriteMapEditor/SpriteMapModifications/AddSprite.cs b/SpriteMapEditor/SpriteMapModifications/AddSprite.cs new file mode 100644 index 0000000..84b5552 --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/AddSprite.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.ComponentModel; +using QURO; +using System.Windows.Forms; + +namespace SpriteMapEditor.SpriteMapModifications +{ + class AddSprite : ISpriteMapModification + { + private readonly BindingList allSprites; + + private readonly SpriteMapRegion selectedSprite; + + private List preChangeSelection; + private List postChangeSelection; + + public AddSprite(BindingList spriteList, SpriteMapRegion selected = null) + { + allSprites = spriteList; + + selectedSprite = selected; + } + + public void Do() + { + if (selectedSprite != null) + allSprites.Add(new SpriteMapRegion(selectedSprite.Name, selectedSprite.Bounds, selectedSprite.Origin)); + else + allSprites.Add(new SpriteMapRegion()); + } + + public void Undo() + { + allSprites.RemoveAt(allSprites.Count - 1); + } + + public List GetPreChangeSelection() + { + return preChangeSelection; + } + public void SetPreChangeSelection(List currentSelection) + { + preChangeSelection = currentSelection; + } + public List GetPostChangeSelection() + { + return postChangeSelection; + } + public void SetPostChangeSelection(List currentSelection) + { + postChangeSelection = currentSelection; + } + + + public override string ToString() + { + return "Add Sprite"; + } + } +} diff --git a/SpriteMapEditor/SpriteMapModifications/History.cs b/SpriteMapEditor/SpriteMapModifications/History.cs new file mode 100644 index 0000000..4afe256 --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/History.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace SpriteMapEditor.SpriteMapModifications +{ + class History + { + private List changes; + private int position; + + public bool CanUndo + { + get { return position >= 0 && changes.Count > 0; } + } + + public bool CanRedo + { + get { return position < changes.Count - 1; } + } + + public History() + { + changes = new List(); + } + + public void Add(ISpriteMapModification change) + { + if (position < changes.Count - 1) + { + changes.RemoveRange(position + 1, changes.Count - 1 - position); + } + changes.Add(change); + position = changes.Count - 1; + //Console.WriteLine("Available Undo Steps: " + changes.Count + "; Current Undo Position: " + position); + } + + public void Undo() + { + if (CanUndo) + { + changes[position].Undo(); + position--; + } + } + + public void Undo(ListBox listBox) + { + if (CanUndo) + { + ModHelper.UndoAndRestoreSelection(changes[position], listBox); + position--; + } + } + + public void Redo() + { + if (CanRedo) + { + changes[position + 1].Do(); + position++; + } + } + + public void Redo(ListBox listBox) + { + if (CanRedo) + { + ModHelper.RedoAndRestoreSelection(changes[position + 1], listBox); + position++; + } + } + + public string NextUndoString() + { + if (!CanUndo) + return "Undo..."; + else + return "Undo " + changes[position]; + } + + public string NextRedoString() + { + if (!CanRedo) + return "Redo..."; + else + return "Redo " + changes[position + 1]; + } + } +} diff --git a/SpriteMapEditor/SpriteMapModifications/ISpriteModification.cs b/SpriteMapEditor/SpriteMapModifications/ISpriteModification.cs new file mode 100644 index 0000000..ed0e9d6 --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/ISpriteModification.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SpriteMapEditor.SpriteMapModifications +{ + public interface ISpriteMapModification + { + void Do(); + void Undo(); + List GetPreChangeSelection(); + void SetPreChangeSelection(List currentSelection); + List GetPostChangeSelection(); + void SetPostChangeSelection(List currentSelection); + } +} diff --git a/SpriteMapEditor/SpriteMapModifications/ModHelper.cs b/SpriteMapEditor/SpriteMapModifications/ModHelper.cs new file mode 100644 index 0000000..7f9f26c --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/ModHelper.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.ComponentModel; +using QURO; + +namespace SpriteMapEditor.SpriteMapModifications +{ + public static class ModHelper + { + public static void DoModificationWithSelectionTracking(SpriteMapModifications.ISpriteMapModification mod, ListBox listBox) + { + mod.SetPreChangeSelection(GetSelectionList(listBox)); + mod.Do(); + mod.SetPostChangeSelection(GetSelectionList(listBox)); + } + + public static void UndoAndRestoreSelection(SpriteMapModifications.ISpriteMapModification mod, ListBox listBox) + { + mod.Undo(); + SelectFromList(listBox, mod.GetPreChangeSelection()); + } + + public static void RedoAndRestoreSelection(SpriteMapModifications.ISpriteMapModification mod, ListBox listBox) + { + mod.Do(); + SelectFromList(listBox, mod.GetPostChangeSelection()); + } + + public static List GetSelectionList(ListBox listBox) + { + List result = new List(); + foreach(int currentIndex in listBox.SelectedIndices) + { + result.Add(currentIndex); + } + return result; + } + + public static void SelectFromList(ListBox listBox, List newSelection) + { + listBox.SelectedIndices.Clear(); + var source = (BindingList)listBox.DataSource; + foreach (int currentIndex in newSelection) + { + if(currentIndex < source.Count) + listBox.SelectedIndex = currentIndex; + } + } + } +} diff --git a/SpriteMapEditor/SpriteMapModifications/ModifyBounds.cs b/SpriteMapEditor/SpriteMapModifications/ModifyBounds.cs new file mode 100644 index 0000000..7e76231 --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/ModifyBounds.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using QURO; +using Microsoft.Xna.Framework; +using System.Windows.Forms; + +namespace SpriteMapEditor.SpriteMapModifications +{ + class ModifyBounds : ISpriteMapModification + { + private readonly List sprites; + + private readonly int newXPosition; + private readonly int newYPosition; + private readonly int newWidth; + private readonly int newHeight; + + private readonly List oldBounds; + + private List preChangeSelection; + private List postChangeSelection; + + public ModifyBounds(List spritesToModify, int x = -1, int y = -1, int width = -1, int height = -1) + { + sprites = spritesToModify.ToList(); + newXPosition = x; + newYPosition = y; + newWidth = width; + newHeight = height; + + oldBounds = new List(); + + for(int index = 0; index < sprites.Count; index++) + { + oldBounds.Add(sprites[index].Bounds); + } + } + + public void Do() + { + for (int index = 0; index < sprites.Count; index++) + { + Rectangle newBounds = sprites[index].Bounds; + + if (newXPosition > -1) + newBounds.X = newXPosition; + if (newYPosition > -1) + newBounds.Y = newYPosition; + if (newWidth > -1) + newBounds.Width = newWidth; + if (newHeight > -1) + newBounds.Height = newHeight; + + sprites[index].Bounds = newBounds; + } + } + + public void Undo() + { + for (int index = 0; index < sprites.Count; index++) + { + sprites[index].Bounds = oldBounds[index]; + } + } + + public List GetPreChangeSelection() + { + return preChangeSelection; + } + public void SetPreChangeSelection(List currentSelection) + { + preChangeSelection = currentSelection; + } + public List GetPostChangeSelection() + { + return postChangeSelection; + } + public void SetPostChangeSelection(List currentSelection) + { + postChangeSelection = currentSelection; + } + + public override string ToString() + { + return "Modify Sprite Bounds"; + } + } +} diff --git a/SpriteMapEditor/SpriteMapModifications/ModifyOrigin.cs b/SpriteMapEditor/SpriteMapModifications/ModifyOrigin.cs new file mode 100644 index 0000000..64a3d40 --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/ModifyOrigin.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using QURO; +using Microsoft.Xna.Framework; + +namespace SpriteMapEditor.SpriteMapModifications +{ + class ModifyOrigin : ISpriteMapModification + { + private readonly List sprites; + + private readonly int newOriginX; + private readonly int newOriginY; + + private readonly List oldOrigins; + + private List preChangeSelection; + private List postChangeSelection; + + public ModifyOrigin(List spritesToEditOrigin, int x = -1, int y = -1) + { + sprites = spritesToEditOrigin.ToList(); + newOriginX = x; + newOriginY = y; + + oldOrigins = new List(); + for(int index = 0; index < sprites.Count; index++) + { + oldOrigins.Add(sprites[index].Origin); + } + } + + public void Do() + { + for (int index = 0; index < sprites.Count; index++) + { + var newOrigin = sprites[index].Origin; + + if (newOriginX > -1) + newOrigin.X = newOriginX; + if (newOriginY > -1) + newOrigin.Y = newOriginY; + + sprites[index].Origin = newOrigin; + } + } + + public void Undo() + { + for (int index = 0; index < sprites.Count; index++) + { + sprites[index].Origin = oldOrigins[index]; + } + } + + public List GetPreChangeSelection() + { + return preChangeSelection; + } + public void SetPreChangeSelection(List currentSelection) + { + preChangeSelection = currentSelection; + } + public List GetPostChangeSelection() + { + return postChangeSelection; + } + public void SetPostChangeSelection(List currentSelection) + { + postChangeSelection = currentSelection; + } + + public override string ToString() + { + return "Modify Sprite Origin"; + } + } +} diff --git a/SpriteMapEditor/SpriteMapModifications/MoveBounds.cs b/SpriteMapEditor/SpriteMapModifications/MoveBounds.cs new file mode 100644 index 0000000..9138f2f --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/MoveBounds.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using QURO; + +namespace SpriteMapEditor.SpriteMapModifications +{ + class MoveBounds : ISpriteMapModification + { + private readonly List sprites; + + private readonly int xDiff; + private readonly int yDiff; + + private List preChangeSelection; + private List postChangeSelection; + + public MoveBounds(List spritesToMove, int xDifference, int yDifference) + { + sprites = spritesToMove.ToList(); + xDiff = xDifference; + yDiff = yDifference; + } + + public void Do() + { + foreach (SpriteMapRegion sprite in sprites) + { + var newBounds = sprite.Bounds; + newBounds.X += xDiff; + newBounds.Y += yDiff; + sprite.Bounds = newBounds; + } + } + public void Undo() + { + foreach (SpriteMapRegion sprite in sprites) + { + var newBounds = sprite.Bounds; + newBounds.X -= xDiff; + newBounds.Y -= yDiff; + sprite.Bounds = newBounds; + } + } + + public List GetPreChangeSelection() + { + return preChangeSelection; + } + public void SetPreChangeSelection(List currentSelection) + { + preChangeSelection = currentSelection; + } + public List GetPostChangeSelection() + { + return postChangeSelection; + } + public void SetPostChangeSelection(List currentSelection) + { + postChangeSelection = currentSelection; + } + + public override string ToString() + { + return "Move Sprite Bounds"; + } + } +} diff --git a/SpriteMapEditor/SpriteMapModifications/MoveSpriteListEntry.cs b/SpriteMapEditor/SpriteMapModifications/MoveSpriteListEntry.cs new file mode 100644 index 0000000..c5beaab --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/MoveSpriteListEntry.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using QURO; +using System.ComponentModel; + +namespace SpriteMapEditor.SpriteMapModifications +{ + class MoveSpriteListEntry : ISpriteMapModification + { + private readonly BindingList allSprites; + + private readonly int selectedIndex; + private readonly int dir; + + private List preChangeSelection; + private List postChangeSelection; + + public MoveSpriteListEntry(BindingList spriteList, int selection, int direction) + { + allSprites = spriteList; + selectedIndex = selection; + dir = Math.Sign(direction); + } + + public void Do() + { + var movingSprite = allSprites[selectedIndex]; + allSprites[selectedIndex] = allSprites[selectedIndex + dir]; + allSprites[selectedIndex + dir] = movingSprite; + } + + public void Undo() + { + var movingSprite = allSprites[selectedIndex + dir]; + allSprites[selectedIndex + dir] = allSprites[selectedIndex]; + allSprites[selectedIndex] = movingSprite; + } + + public List GetPreChangeSelection() + { + return preChangeSelection; + } + public void SetPreChangeSelection(List currentSelection) + { + preChangeSelection = currentSelection; + } + public List GetPostChangeSelection() + { + return postChangeSelection; + } + public void SetPostChangeSelection(List currentSelection) + { + postChangeSelection = currentSelection; + } + + public override string ToString() + { + return "Move Sprite List Entry"; + } + } +} diff --git a/SpriteMapEditor/SpriteMapModifications/RemoveSprite.cs b/SpriteMapEditor/SpriteMapModifications/RemoveSprite.cs new file mode 100644 index 0000000..458bae6 --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/RemoveSprite.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using QURO; +using System.ComponentModel; + +namespace SpriteMapEditor.SpriteMapModifications +{ + class RemoveSprite : ISpriteMapModification + { + private readonly BindingList allSprites; + + private readonly int index; + + private readonly SpriteMapRegion removedSprite; + + private List preChangeSelection; + private List postChangeSelection; + + public RemoveSprite(BindingList spriteList, int indexToRemove) + { + allSprites = spriteList; + index = indexToRemove; + removedSprite = allSprites[index]; + } + + public void Do() + { + allSprites.RemoveAt(index); + } + + public void Undo() + { + allSprites.Insert(index, removedSprite); + } + + public List GetPreChangeSelection() + { + return preChangeSelection; + } + public void SetPreChangeSelection(List currentSelection) + { + preChangeSelection = currentSelection; + } + public List GetPostChangeSelection() + { + return postChangeSelection; + } + public void SetPostChangeSelection(List currentSelection) + { + postChangeSelection = currentSelection; + } + + public override string ToString() + { + return "Remove Sprite"; + } + } +} diff --git a/SpriteMapEditor/SpriteMapModifications/RenameSprite.cs b/SpriteMapEditor/SpriteMapModifications/RenameSprite.cs new file mode 100644 index 0000000..c729eb8 --- /dev/null +++ b/SpriteMapEditor/SpriteMapModifications/RenameSprite.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using QURO; + +namespace SpriteMapEditor.SpriteMapModifications +{ + class RenameSprite : ISpriteMapModification + { + private readonly SpriteMapRegion sprite; + + private readonly string newName; + private readonly string oldName; + + private List preChangeSelection; + private List postChangeSelection; + + public RenameSprite(SpriteMapRegion spriteToRename, string name) + { + sprite = spriteToRename; + newName = name; + oldName = sprite.Name; + } + + public void Do() + { + sprite.Name = newName; + } + + public void Undo() + { + sprite.Name = oldName; + } + + public List GetPreChangeSelection() + { + return preChangeSelection; + } + public void SetPreChangeSelection(List currentSelection) + { + preChangeSelection = currentSelection; + } + public List GetPostChangeSelection() + { + return postChangeSelection; + } + public void SetPostChangeSelection(List currentSelection) + { + postChangeSelection = currentSelection; + } + + public override string ToString() + { + return "Rename Sprite"; + } + } +} diff --git a/SpriteMapEditor/transparentUI.png b/SpriteMapEditor/transparentUI.png deleted file mode 100644 index eb68dbf..0000000 Binary files a/SpriteMapEditor/transparentUI.png and /dev/null differ