PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/OpenRA.Editor/Form1.cs

https://github.com/alzeih/OpenRA
C# | 526 lines | 408 code | 100 blank | 18 comment | 55 complexity | 049a5dd4ded1f97f29d02a48f22410da MD5 | raw file
Possible License(s): GPL-3.0
  1. #region Copyright & License Information
  2. /*
  3. * Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
  4. * This file is part of OpenRA, which is free software. It is made
  5. * available to you under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation. For more information,
  7. * see COPYING.
  8. */
  9. #endregion
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Drawing;
  13. using System.IO;
  14. using System.Linq;
  15. using System.Windows.Forms;
  16. using OpenRA.FileFormats;
  17. using OpenRA.Graphics;
  18. using OpenRA.Traits;
  19. namespace OpenRA.Editor
  20. {
  21. public partial class Form1 : Form
  22. {
  23. public Form1(string[] args)
  24. {
  25. InitializeComponent();
  26. AppDomain.CurrentDomain.AssemblyResolve += FileSystem.ResolveAssembly;
  27. currentMod = args.FirstOrDefault() ?? "ra";
  28. toolStripComboBox1.Items.AddRange(Mod.AllMods.Keys.ToArray());
  29. toolStripComboBox1.SelectedIndexChanged += (_, e) =>
  30. {
  31. tilePalette.SuspendLayout();
  32. actorPalette.SuspendLayout();
  33. resourcePalette.SuspendLayout();
  34. tilePalette.Controls.Clear();
  35. actorPalette.Controls.Clear();
  36. resourcePalette.Controls.Clear();
  37. tilePalette.ResumeLayout();
  38. actorPalette.ResumeLayout();
  39. resourcePalette.ResumeLayout();
  40. surface1.Bind(null, null, null);
  41. pmMiniMap.Image = null;
  42. currentMod = toolStripComboBox1.SelectedItem as string;
  43. Text = "OpenRA Editor (mod:{0})".F(currentMod);
  44. Game.modData = new ModData(currentMod);
  45. FileSystem.LoadFromManifest(Game.modData.Manifest);
  46. Rules.LoadRules(Game.modData.Manifest, new Map());
  47. loadedMapName = null;
  48. };
  49. toolStripComboBox1.SelectedItem = currentMod;
  50. surface1.AfterChange += OnMapChanged;
  51. surface1.MousePositionChanged += s => toolStripStatusLabelMousePosition.Text = s;
  52. surface1.ActorDoubleClicked += ActorDoubleClicked;
  53. if (args.Length >= 2)
  54. LoadMap(args[1]);
  55. }
  56. void OnMapChanged()
  57. {
  58. MakeDirty();
  59. pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
  60. }
  61. void ActorDoubleClicked(KeyValuePair<string,ActorReference> kv)
  62. {
  63. using( var apd = new ActorPropertiesDialog() )
  64. {
  65. var name = kv.Key;
  66. apd.AddRow("(Name)", apd.MakeEditorControl(typeof(string), () => name, v => name = (string)v));
  67. apd.AddRow("(Type)", apd.MakeEditorControl(typeof(string), () => kv.Value.Type, v => kv.Value.Type = (string)v));
  68. var objSaved = kv.Value.Save();
  69. // TODO: make this work properly
  70. foreach( var init in Rules.Info[kv.Value.Type].GetInitKeys() )
  71. apd.AddRow(init.First,
  72. apd.MakeEditorControl(init.Second,
  73. () => objSaved.NodesDict.ContainsKey( init.First ) ? objSaved.NodesDict[init.First].Value : null,
  74. _ => {}));
  75. apd.ShowDialog();
  76. // TODO: writeback
  77. }
  78. }
  79. void MakeDirty() { dirty = true; }
  80. string loadedMapName;
  81. string currentMod = "ra";
  82. TileSet tileset;
  83. bool dirty = false;
  84. void LoadMap(string mapname)
  85. {
  86. tilePalette.Controls.Clear();
  87. actorPalette.Controls.Clear();
  88. resourcePalette.Controls.Clear();
  89. loadedMapName = mapname;
  90. // load the map
  91. var map = new Map(mapname);
  92. // upgrade maps that have no player definitions. editor doesnt care,
  93. // but this breaks the game pretty badly.
  94. if (map.Players.Count == 0)
  95. map.MakeDefaultPlayers();
  96. PrepareMapResources(Game.modData.Manifest, map);
  97. dirty = false;
  98. }
  99. void NewMap(Map map)
  100. {
  101. tilePalette.Controls.Clear();
  102. actorPalette.Controls.Clear();
  103. resourcePalette.Controls.Clear();
  104. loadedMapName = null;
  105. PrepareMapResources(Game.modData.Manifest, map);
  106. MakeDirty();
  107. }
  108. // this code is insanely stupid, and mostly my fault -- chrisf
  109. void PrepareMapResources(Manifest manifest, Map map)
  110. {
  111. Rules.LoadRules(manifest, map);
  112. tileset = Rules.TileSets[map.Tileset];
  113. tileset.LoadTiles();
  114. var palette = new Palette(FileSystem.Open(tileset.Palette), true);
  115. surface1.Bind(map, tileset, palette);
  116. // construct the palette of tiles
  117. var palettes = new[] { tilePalette, actorPalette, resourcePalette };
  118. foreach (var p in palettes) { p.Visible = false; p.SuspendLayout(); }
  119. foreach (var t in tileset.Templates)
  120. {
  121. try
  122. {
  123. var bitmap = tileset.RenderTemplate((ushort)t.Key, palette);
  124. var ibox = new PictureBox
  125. {
  126. Image = bitmap,
  127. Width = bitmap.Width / 2,
  128. Height = bitmap.Height / 2,
  129. SizeMode = PictureBoxSizeMode.StretchImage
  130. };
  131. var brushTemplate = new BrushTemplate { Bitmap = bitmap, N = t.Key };
  132. ibox.Click += (_, e) => surface1.SetTool(new BrushTool(brushTemplate));
  133. var template = t.Value;
  134. tilePalette.Controls.Add(ibox);
  135. tt.SetToolTip(ibox,
  136. "{1}:{0} ({2}x{3})".F(
  137. template.Image,
  138. template.Id,
  139. template.Size.X,
  140. template.Size.Y));
  141. }
  142. catch { }
  143. }
  144. var actorTemplates = new List<ActorTemplate>();
  145. foreach (var a in Rules.Info.Keys)
  146. {
  147. try
  148. {
  149. var info = Rules.Info[a];
  150. if (!info.Traits.Contains<RenderSimpleInfo>()) continue;
  151. var etf = info.Traits.GetOrDefault<EditorTilesetFilterInfo>();
  152. if (etf != null && etf.ExcludeTilesets != null
  153. && etf.ExcludeTilesets.Contains(tileset.Id)) continue;
  154. if (etf != null && etf.RequireTilesets != null
  155. && !etf.RequireTilesets.Contains(tileset.Id)) continue;
  156. var template = RenderUtils.RenderActor(info, tileset, palette);
  157. var ibox = new PictureBox
  158. {
  159. Image = template.Bitmap,
  160. Width = 32,
  161. Height = 32,
  162. SizeMode = PictureBoxSizeMode.Zoom,
  163. BorderStyle = BorderStyle.FixedSingle
  164. };
  165. ibox.Click += (_, e) => surface1.SetTool(new ActorTool(template));
  166. actorPalette.Controls.Add(ibox);
  167. tt.SetToolTip(ibox,
  168. "{0}".F(
  169. info.Name));
  170. actorTemplates.Add(template);
  171. }
  172. catch { }
  173. }
  174. surface1.BindActorTemplates(actorTemplates);
  175. var resourceTemplates = new List<ResourceTemplate>();
  176. foreach (var a in Rules.Info["world"].Traits.WithInterface<ResourceTypeInfo>())
  177. {
  178. try
  179. {
  180. var template = RenderUtils.RenderResourceType(a, tileset.Extensions, palette);
  181. var ibox = new PictureBox
  182. {
  183. Image = template.Bitmap,
  184. Width = 32,
  185. Height = 32,
  186. SizeMode = PictureBoxSizeMode.Zoom,
  187. BorderStyle = BorderStyle.FixedSingle
  188. };
  189. ibox.Click += (_, e) => surface1.SetTool(new ResourceTool(template));
  190. resourcePalette.Controls.Add(ibox);
  191. tt.SetToolTip(ibox,
  192. "{0}:{1}cr".F(
  193. template.Info.Name,
  194. template.Info.ValuePerUnit));
  195. resourceTemplates.Add(template);
  196. }
  197. catch { }
  198. }
  199. surface1.BindResourceTemplates(resourceTemplates);
  200. foreach (var p in palettes)
  201. {
  202. p.Visible = true;
  203. p.ResumeLayout();
  204. }
  205. pmMiniMap.Image = Minimap.AddStaticResources(surface1.Map, Minimap.TerrainBitmap(surface1.Map, true));
  206. propertiesToolStripMenuItem.Enabled = true;
  207. resizeToolStripMenuItem.Enabled = true;
  208. saveToolStripMenuItem.Enabled = true;
  209. saveAsToolStripMenuItem.Enabled = true;
  210. mnuMinimapToPNG.Enabled = true; // todo: what is this VB naming bullshit doing here?
  211. PopulateActorOwnerChooser();
  212. }
  213. void PopulateActorOwnerChooser()
  214. {
  215. actorOwnerChooser.Items.Clear();
  216. actorOwnerChooser.Items.AddRange(surface1.Map.Players.Values.ToArray());
  217. actorOwnerChooser.SelectedIndex = 0;
  218. surface1.NewActorOwner = (actorOwnerChooser.SelectedItem as PlayerReference).Name;
  219. }
  220. void ResizeClicked(object sender, EventArgs e)
  221. {
  222. using (var rd = new ResizeDialog())
  223. {
  224. rd.width.Value = surface1.Map.MapSize.X;
  225. rd.height.Value = surface1.Map.MapSize.Y;
  226. rd.cordonLeft.Value = surface1.Map.Bounds.Left;
  227. rd.cordonTop.Value = surface1.Map.Bounds.Top;
  228. rd.cordonRight.Value = surface1.Map.Bounds.Right;
  229. rd.cordonBottom.Value = surface1.Map.Bounds.Bottom;
  230. if (DialogResult.OK != rd.ShowDialog())
  231. return;
  232. surface1.Map.ResizeCordon((int)rd.cordonLeft.Value,
  233. (int)rd.cordonTop.Value,
  234. (int)rd.cordonRight.Value,
  235. (int)rd.cordonBottom.Value);
  236. if ((int)rd.width.Value != surface1.Map.MapSize.X || (int)rd.height.Value != surface1.Map.MapSize.Y)
  237. {
  238. surface1.Map.Resize((int)rd.width.Value, (int)rd.height.Value);
  239. surface1.Bind(surface1.Map, surface1.TileSet, surface1.Palette); // rebind it to invalidate all caches
  240. }
  241. surface1.Invalidate();
  242. }
  243. }
  244. void SaveClicked(object sender, EventArgs e)
  245. {
  246. if (loadedMapName == null)
  247. SaveAsClicked(sender, e);
  248. else
  249. {
  250. surface1.Map.Save(loadedMapName);
  251. dirty = false;
  252. }
  253. }
  254. void SaveAsClicked(object sender, EventArgs e)
  255. {
  256. using (var nms = new MapSelect(currentMod))
  257. {
  258. nms.txtNew.ReadOnly = false;
  259. nms.btnOk.Text = "Save";
  260. nms.txtNew.Text = "unnamed";
  261. nms.txtPathOut.ReadOnly = false;
  262. if (DialogResult.OK == nms.ShowDialog())
  263. {
  264. if (nms.txtNew.Text == "")
  265. nms.txtNew.Text = "unnamed";
  266. // TODO: Allow the user to choose map format (directory vs oramap)
  267. loadedMapName = Path.Combine(nms.MapFolderPath, nms.txtNew.Text + ".oramap");
  268. SaveClicked(sender, e);
  269. }
  270. }
  271. }
  272. void OpenClicked(object sender, EventArgs e)
  273. {
  274. using (var nms = new MapSelect(currentMod))
  275. {
  276. nms.txtNew.ReadOnly = true;
  277. nms.txtPathOut.ReadOnly = true;
  278. nms.btnOk.Text = "Open";
  279. if (DialogResult.OK == nms.ShowDialog())
  280. LoadMap(nms.txtNew.Tag as string);
  281. }
  282. }
  283. void NewClicked(object sender, EventArgs e)
  284. {
  285. using (var nmd = new NewMapDialog())
  286. {
  287. nmd.theater.Items.Clear();
  288. nmd.theater.Items.AddRange(Rules.TileSets.Select(a => a.Value.Id).ToArray());
  289. nmd.theater.SelectedIndex = 0;
  290. if (DialogResult.OK == nmd.ShowDialog())
  291. {
  292. var map = Map.FromTileset(nmd.theater.SelectedItem as string);
  293. map.Resize((int)nmd.width.Value, (int)nmd.height.Value);
  294. map.ResizeCordon((int)nmd.cordonLeft.Value, (int)nmd.cordonTop.Value,
  295. (int)nmd.cordonRight.Value, (int)nmd.cordonBottom.Value);
  296. map.MakeDefaultPlayers();
  297. NewMap(map);
  298. }
  299. }
  300. }
  301. void PropertiesClicked(object sender, EventArgs e)
  302. {
  303. using (var pd = new PropertiesDialog())
  304. {
  305. pd.title.Text = surface1.Map.Title;
  306. pd.desc.Text = surface1.Map.Description;
  307. pd.author.Text = surface1.Map.Author;
  308. pd.selectable.Checked = surface1.Map.Selectable;
  309. pd.useAsShellmap.Checked = surface1.Map.UseAsShellmap;
  310. if (DialogResult.OK != pd.ShowDialog())
  311. return;
  312. surface1.Map.Title = pd.title.Text;
  313. surface1.Map.Description = pd.desc.Text;
  314. surface1.Map.Author = pd.author.Text;
  315. surface1.Map.Selectable = pd.selectable.Checked;
  316. surface1.Map.UseAsShellmap = pd.useAsShellmap.Checked;
  317. }
  318. }
  319. void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = true; }
  320. void Form1_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Space) surface1.IsPanning = false; }
  321. void CloseClicked(object sender, EventArgs e)
  322. {
  323. Close();
  324. }
  325. void ImportLegacyMapClicked(object sender, EventArgs e)
  326. {
  327. using (var ofd = new OpenFileDialog { RestoreDirectory = true,
  328. Filter = "Legacy maps (*.ini;*.mpr)|*.ini;*.mpr" })
  329. if (DialogResult.OK == ofd.ShowDialog())
  330. {
  331. /* massive hack: we should be able to call NewMap() with the imported Map object,
  332. * but something's not right internally in it, unless loaded via the real maploader */
  333. var savePath = Path.Combine(Path.GetTempPath(), "OpenRA.Import");
  334. Directory.CreateDirectory(savePath);
  335. var errors = new List<string>();
  336. var map = LegacyMapImporter.Import(ofd.FileName, a => errors.Add(a));
  337. if (errors.Count > 0)
  338. using (var eld = new ErrorListDialog(errors))
  339. eld.ShowDialog();
  340. map.MakeDefaultPlayers();
  341. map.Save(savePath);
  342. LoadMap(savePath);
  343. loadedMapName = null; /* editor needs to think this hasnt been saved */
  344. Directory.Delete(savePath, true);
  345. MakeDirty();
  346. }
  347. }
  348. void OnFormClosing(object sender, FormClosingEventArgs e)
  349. {
  350. if (!dirty) return;
  351. switch (MessageBox.Show("The map has been modified since it was last saved. " + "\r\n" + "Save changes now?",
  352. "Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation))
  353. {
  354. case DialogResult.Yes: SaveClicked(null, EventArgs.Empty); break;
  355. case DialogResult.No: break;
  356. case DialogResult.Cancel: e.Cancel = true; break;
  357. }
  358. }
  359. void ExportMinimap(object sender, EventArgs e)
  360. {
  361. using( var sfd = new SaveFileDialog() {
  362. InitialDirectory = Path.Combine(Environment.CurrentDirectory, "maps"),
  363. DefaultExt = "*.png",
  364. Filter = "PNG Image (*.png)|*.png",
  365. Title = "Export Minimap to PNG",
  366. FileName = Path.ChangeExtension(loadedMapName, ".png"),
  367. RestoreDirectory = true } )
  368. if (DialogResult.OK == sfd.ShowDialog())
  369. pmMiniMap.Image.Save(sfd.FileName);
  370. }
  371. void ShowActorNamesClicked(object sender, EventArgs e)
  372. {
  373. showActorNamesToolStripMenuItem.Checked ^= true;
  374. surface1.ShowActorNames = showActorNamesToolStripMenuItem.Checked;
  375. }
  376. void ShowGridClicked(object sender, EventArgs e)
  377. {
  378. showGridToolStripMenuItem.Checked ^= true;
  379. surface1.ShowGrid = showGridToolStripMenuItem.Checked;
  380. surface1.Chunks.Clear();
  381. }
  382. void FixOpenAreas(object sender, EventArgs e)
  383. {
  384. dirty = true;
  385. var r = new Random();
  386. for (var j = surface1.Map.Bounds.Top; j < surface1.Map.Bounds.Bottom; j++)
  387. for (var i = surface1.Map.Bounds.Left; i < surface1.Map.Bounds.Right; i++)
  388. {
  389. var tr = surface1.Map.MapTiles.Value[i, j];
  390. if (tr.type == 0xff || tr.type == 0xffff || tr.type == 1 || tr.type == 2)
  391. tr.index = (byte)r.Next(0,
  392. Rules.TileSets[surface1.Map.Tileset].Templates[tr.type].Data.TileBitmapBytes.Count);
  393. surface1.Map.MapTiles.Value[i, j] = tr;
  394. }
  395. surface1.Chunks.Clear();
  396. surface1.Invalidate();
  397. }
  398. void SetupDefaultPlayers(object sender, EventArgs e)
  399. {
  400. dirty = true;
  401. surface1.Map.MakeDefaultPlayers();
  402. surface1.Chunks.Clear();
  403. surface1.Invalidate();
  404. PopulateActorOwnerChooser();
  405. }
  406. void DrawPlayerListItem(object sender, DrawItemEventArgs e)
  407. {
  408. // color block
  409. var player = e.Index >= 0 ? (PlayerReference)(sender as ComboBox).Items[e.Index] : null;
  410. e.DrawBackground();
  411. e.DrawFocusRectangle();
  412. if (player == null)
  413. return;
  414. var color = player.ColorRamp.GetColor(0);
  415. using( var brush = new SolidBrush(color) )
  416. e.Graphics.FillRectangle( brush, e.Bounds.Left + 2, e.Bounds.Top + 2, e.Bounds.Height + 6, e.Bounds.Height - 4 );
  417. using( var foreBrush = new SolidBrush(e.ForeColor) )
  418. e.Graphics.DrawString( player.Name, e.Font, foreBrush, e.Bounds.Left + e.Bounds.Height + 12, e.Bounds.Top );
  419. }
  420. void OnSelectedPlayerChanged(object sender, EventArgs e)
  421. {
  422. var player = actorOwnerChooser.SelectedItem as PlayerReference;
  423. surface1.NewActorOwner = player.Name;
  424. }
  425. }
  426. }