diff --git a/OpenRA.Editor/Form1.Designer.cs b/OpenRA.Editor/Form1.Designer.cs
index 82f7f76bbe..854561d7d7 100755
--- a/OpenRA.Editor/Form1.Designer.cs
+++ b/OpenRA.Editor/Form1.Designer.cs
@@ -82,6 +82,9 @@ namespace OpenRA.Editor
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripStatusLabelFiller = new System.Windows.Forms.ToolStripStatusLabel();
this.toolStripStatusLabelMousePosition = new System.Windows.Forms.ToolStripStatusLabel();
+ this.copySelectionToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator();
+ this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
@@ -417,8 +420,11 @@ namespace OpenRA.Editor
this.resizeToolStripMenuItem,
this.showActorNamesToolStripMenuItem,
this.showGridToolStripMenuItem,
+ this.toolStripSeparator5,
this.fixOpenAreasToolStripMenuItem,
- this.setupDefaultPlayersMenuItem});
+ this.setupDefaultPlayersMenuItem,
+ this.toolStripSeparator4,
+ this.copySelectionToolStripMenuItem});
this.mapToolStripMenuItem.Name = "mapToolStripMenuItem";
this.mapToolStripMenuItem.Size = new System.Drawing.Size(43, 23);
this.mapToolStripMenuItem.Text = "&Map";
@@ -507,6 +513,23 @@ namespace OpenRA.Editor
this.toolStripStatusLabelMousePosition.Size = new System.Drawing.Size(22, 17);
this.toolStripStatusLabelMousePosition.Text = "0,0";
//
+ // copySelectionToolStripMenuItem
+ //
+ this.copySelectionToolStripMenuItem.Name = "copySelectionToolStripMenuItem";
+ this.copySelectionToolStripMenuItem.Size = new System.Drawing.Size(185, 22);
+ this.copySelectionToolStripMenuItem.Text = "Copy Selection";
+ this.copySelectionToolStripMenuItem.Click += new System.EventHandler(this.copySelectionToolStripMenuItem_Click);
+ //
+ // toolStripSeparator4
+ //
+ this.toolStripSeparator4.Name = "toolStripSeparator4";
+ this.toolStripSeparator4.Size = new System.Drawing.Size(182, 6);
+ //
+ // toolStripSeparator5
+ //
+ this.toolStripSeparator5.Name = "toolStripSeparator5";
+ this.toolStripSeparator5.Size = new System.Drawing.Size(182, 6);
+ //
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -520,9 +543,9 @@ namespace OpenRA.Editor
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "OpenRA Editor";
- this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OnFormClosing);
this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
+ this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyUp);
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.ResumeLayout(false);
@@ -592,6 +615,9 @@ namespace OpenRA.Editor
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.FlowLayoutPanel actorPalette;
private System.Windows.Forms.ComboBox actorOwnerChooser;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator5;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator4;
+ private System.Windows.Forms.ToolStripMenuItem copySelectionToolStripMenuItem;
}
}
diff --git a/OpenRA.Editor/Form1.cs b/OpenRA.Editor/Form1.cs
index 53351cb450..4eda4f950e 100755
--- a/OpenRA.Editor/Form1.cs
+++ b/OpenRA.Editor/Form1.cs
@@ -545,5 +545,10 @@ namespace OpenRA.Editor
var player = actorOwnerChooser.SelectedItem as PlayerReference;
surface1.NewActorOwner = player.Name;
}
+
+ private void copySelectionToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ surface1.CopySelection();
+ }
}
}
diff --git a/OpenRA.Editor/Form1.resx b/OpenRA.Editor/Form1.resx
index e21860adab..9757275de8 100755
--- a/OpenRA.Editor/Form1.resx
+++ b/OpenRA.Editor/Form1.resx
@@ -120,13 +120,45 @@
17, 17
-
- 76, 17
-
198, 17
+
+
+ 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
@@ -260,41 +292,6 @@
z2ki+Wo1CWklROkMCiT8wEm0kXEsCTmrAiTbDtcEpTVdZOS1oDfWk5xZ6RPeQZeUR8zxK0Qe1BO65xjr
t0YotXhjAEAeQ7It8ZSESUjkznIq2bYsTGYW29JZxIs2nFEdLOSdfwFwpvLxRKIY2AAAAABJRU5ErkJg
gg==
-
-
-
-
- iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
- JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAACCklE
- QVQ4T6WT30tTUQDHz39QD0UQSpAPIkgPyR60AiUiyoGBL4qZjOyt0tZP9tBDk1AsXIhj93ILdd27DPPH
- 3VwrUrdK2ioJHAgVOdoPaQsarBg43L6ec+akuRsEPnw5D4fP5/vlXg4BQHaSf8LjjwdqaTA2cg+y1Ith
- qxmi5Tas/SYWk+QRoPgmtNsLcPq7GYX8+XoTqaUL+KR2cAmDxeBgqeBv2NhWzwUFOBk4g5/zRxB3V8Es
- 38AtbzuIw/0RLMrMeyhTs2CzGdRtaOTn1dajvLkAR9VKLNvLcHmoExddzSDKzAfkcjkkEtEiOLxoQpdB
- z+Er7ScQUg/DL5TD2bsfl5oPoKWnCZ3jehDZGeAC1hwL3uXNs55Jep7Gis/AJWxyTeVe1FXvhq5qH6oP
- 7nlw/NoxGByNIKPT77CezSEeD6Pn+jlEIiGk6X8N+F9zyfLYIZzUVUCwT0J36jy9yX83KjDq7zSADE8t
- cGB7kpksFt76YDzbgMWVFLzBX0WCTcku8mjiTSm8lkUslcHnH2kK/+aw6k+UCJiESE+9XCApz2Gzu5Gk
- sEVy4r6got82vRV5blVbIDyZ21rAZrPmL7w5P5s1KxQWXRFtgU15lV8ge2AbdXPY8pAuEIsXWJ6FtAVW
- +SWSmXWssuZ4vnl+s5nNFl1hMLjP8U1bMGR/wS/+N9tf7o6eMpNtADko6xybtEXLAAAAAElFTkSuQmCC
-
-
-
-
- iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6
- JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAACXBIWXMAAAsMAAALDAE/QCLIAAADLklE
- QVQ4T3WS60/ScRjFf39CL3rR1ovurduWbbU2t7ZqdlkXt7Lrym6O1VoXcdYqQ54wKlGxABE1CzWF0nIm
- lZcoTbyUNJFIzDJSJK+E0qy8wInvz+i2erazfd+cz3m+zw4nTS+FLOeZNim3Vp6UU5sqvf5MSZqnyjhV
- pfKUvEx54kqp8rCkWHVQVKSJPHtbs+tUgSYiOicVAMfEqfR1dVFCGSqrX94cHQeN/aXhbyD3Zz91uf3U
- 9tFHTQ4fzVtH9BOQVdKcW2F6/eKkWA1zcxu6vUAQMmCzk/3AErLtDyFrrY035z16T3PXin8B5LfqZE6P
- HyZzKw5FX+Yh4XtjwZKZGV3lNPIkhhojplON3Uc3S9/Q7LDfADKtKYklMsgTkwV7joixKHQr2Nq2fSET
- 5uQwqtsyjcot45R510ozV8f/2iAhsyolCNh9WIyFoRGYHbIGfYN+SVd7Nznzk8ll0FLzKxdZO3xkaOjG
- GYUxcIIfRxSlPU4N/rn1fS8JJVlU1WCT3npggVLfAIWuHjJtNRIyjIhTPEKM7D6OSop4RcXpwZ2Wl11l
- gHanmze/c36ioc8jyRlFjSzljxl2daI9Pwuv1Cnw9PRjZeQ1cCcSS68Fza6+IXL2fCG7w0ssmc3o2IR8
- gbc1PQU9NUp48sNRcUyAkPBL4AIlUbLk3gEvS6YXrW6p0dx9UZ5n4gHjzBmYAAPPYwRwazeiMXYWqjcs
- wLSVInAHRYWq0TEf9Q+NUEsg+fr9t2nF1U71leyqn+u3vPuIl2298HZ2wnxkO5q2LYOtxoKpK86D23tW
- r+7zfCVzywAVGT/QVV2LvNDo0Eo0j3mAtbUTiRnFOJ94Axp9LfIKK5Ctq0RDmw9TQuPAsW7bHYNUYLCQ
- JL2GRAqjtMDYwV+8wzUAWeY9eIfHYW0fxNodxyGWZeOSPBvzl27C5OXnwG0T5irmr79wgdWTNYyVJFL8
- kAeo8wyBA/rx2jGErBIH0nXPsWmPEHcM9YgURGPS0jMTZfiXGKDfM4Y0fVOgA/UgRQWECTpExaqxUyDF
- wuUbJjb4H0AQfxtrDqiweLMUc8LEmLEqnv9zUMzM9B1/cM83lepxTAAAAABJRU5ErkJggg==
diff --git a/OpenRA.Editor/Surface.cs b/OpenRA.Editor/Surface.cs
index 9185036e87..65079e5041 100755
--- a/OpenRA.Editor/Surface.cs
+++ b/OpenRA.Editor/Surface.cs
@@ -38,6 +38,12 @@ namespace OpenRA.Editor
public bool ShowActorNames;
public bool ShowGrid;
+ public bool IsPaste { get { return TileSelection != null && ResourceSelection != null; } }
+ public TileReference[,] TileSelection;
+ public TileReference[,] ResourceSelection;
+ public CPos SelectionStart;
+ public CPos SelectionEnd;
+
public string NewActorOwner;
public event Action AfterChange = () => { };
@@ -59,7 +65,7 @@ namespace OpenRA.Editor
Tool = null;
}
- public void SetTool(ITool tool) { Tool = tool; }
+ public void SetTool(ITool tool) { Tool = tool; ClearSelection(); }
public void BindActorTemplates(IEnumerable templates)
{
@@ -83,6 +89,8 @@ namespace OpenRA.Editor
UpdateStyles();
}
+ static readonly Pen SelectionPen = new Pen(Color.Blue);
+ static readonly Pen PastePen = new Pen(Color.Green);
static readonly Pen CordonPen = new Pen(Color.Red);
int2 MousePos;
@@ -182,12 +190,20 @@ namespace OpenRA.Editor
}
AfterChange();
+ ClearSelection();
}
void Draw()
{
- if (Tool != null) Tool.Apply(this);
- AfterChange();
+ if (Tool != null)
+ {
+ Tool.Apply(this);
+ AfterChange();
+ }
+ else if (IsPaste)
+ PasteSelection();
+ else
+ SelectionEnd = GetBrushLocation();
}
protected override void OnMouseDown(MouseEventArgs e)
@@ -199,7 +215,11 @@ namespace OpenRA.Editor
if (!IsPanning)
{
if (e.Button == MouseButtons.Right) Erase();
- if (e.Button == MouseButtons.Left) Draw();
+ if (e.Button == MouseButtons.Left)
+ {
+ Draw();
+ if (!IsPaste) SelectionStart = GetBrushLocation();
+ }
}
Invalidate();
@@ -367,6 +387,25 @@ namespace OpenRA.Editor
Map.Bounds.Width * TileSet.TileSize * Zoom,
Map.Bounds.Height * TileSet.TileSize * Zoom);
+ e.Graphics.DrawRectangle(SelectionPen,
+ (SelectionStart.X * TileSet.TileSize * Zoom) + Offset.X,
+ (SelectionStart.Y * TileSet.TileSize * Zoom) + Offset.Y,
+ (SelectionEnd - SelectionStart).X * TileSet.TileSize * Zoom,
+ (SelectionEnd - SelectionStart).Y * TileSet.TileSize * Zoom);
+
+ if (IsPaste)
+ {
+ var loc = GetBrushLocation();
+ var width = Math.Abs((SelectionStart - SelectionEnd).X);
+ var height = Math.Abs((SelectionStart - SelectionEnd).Y);
+
+ e.Graphics.DrawRectangle(PastePen,
+ (loc.X * TileSet.TileSize * Zoom) + Offset.X,
+ (loc.Y * TileSet.TileSize * Zoom) + Offset.Y,
+ width * (TileSet.TileSize * Zoom),
+ height * (TileSet.TileSize * Zoom));
+ }
+
foreach (var ar in Map.Actors.Value)
{
if (ActorTemplates.ContainsKey(ar.Value.Type))
@@ -395,6 +434,67 @@ namespace OpenRA.Editor
DrawActorBorder(e.Graphics, x.Value.Location(), ActorTemplates[x.Value.Type]);
}
}
+
+ public void CopySelection()
+ {
+ // Grab tiles and resources within selection (doesn't do actors)
+ var start = SelectionStart;
+ var end = SelectionEnd;
+
+ if (start == end) return;
+
+ int width = Math.Abs((start - end).X);
+ int height = Math.Abs((start - end).Y);
+
+ TileSelection = new TileReference[width, height];
+ ResourceSelection = new TileReference[width, height];
+
+ for (int x = 0; x < width; x++)
+ {
+ for (int y = 0; y < height; y++)
+ {
+ //todo: crash prevention
+ TileSelection[x, y] = Map.MapTiles.Value[start.X + x, start.Y + y];
+ ResourceSelection[x, y] = Map.MapResources.Value[start.X + x, start.Y + y];
+ }
+ }
+ }
+
+ void PasteSelection()
+ {
+ var loc = GetBrushLocation();
+ var width = Math.Abs((SelectionStart - SelectionEnd).X);
+ var height = Math.Abs((SelectionStart - SelectionEnd).Y);
+
+ for (int x = 0; x < width; x++)
+ {
+ for (int y = 0; y < height; y++)
+ {
+ var mapX = loc.X + x;
+ var mapY = loc.Y + y;
+
+ //todo: crash prevention for outside of bounds
+ Map.MapTiles.Value[mapX, mapY] = TileSelection[x, y];
+ Map.MapResources.Value[mapX, mapY] = ResourceSelection[x, y];
+
+ var ch = new int2(mapX / ChunkSize, mapY / ChunkSize);
+ if (Chunks.ContainsKey(ch))
+ {
+ Chunks[ch].Dispose();
+ Chunks.Remove(ch);
+ }
+ }
+ }
+ AfterChange();
+ }
+
+ void ClearSelection()
+ {
+ SelectionStart = CPos.Zero;
+ SelectionEnd = CPos.Zero;
+ TileSelection = null;
+ ResourceSelection = null;
+ }
}
static class ActorReferenceExts