OverlaysTool.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // The Command & Conquer Map Editor and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // The Command & Conquer Map Editor and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. using MobiusEditor.Controls;
  15. using MobiusEditor.Event;
  16. using MobiusEditor.Interface;
  17. using MobiusEditor.Model;
  18. using MobiusEditor.Utility;
  19. using MobiusEditor.Widgets;
  20. using System;
  21. using System.Drawing;
  22. using System.Linq;
  23. using System.Windows.Forms;
  24. namespace MobiusEditor.Tools
  25. {
  26. public class OverlaysTool : ViewTool
  27. {
  28. private readonly TypeComboBox overlayTypeComboBox;
  29. private readonly MapPanel overlayTypeMapPanel;
  30. private Map previewMap;
  31. protected override Map RenderMap => previewMap;
  32. private bool placementMode;
  33. private OverlayType selectedOverlayType;
  34. private OverlayType SelectedOverlayType
  35. {
  36. get => selectedOverlayType;
  37. set
  38. {
  39. if (selectedOverlayType != value)
  40. {
  41. if (placementMode && (selectedOverlayType != null))
  42. {
  43. mapPanel.Invalidate(map, navigationWidget.MouseCell);
  44. }
  45. selectedOverlayType = value;
  46. overlayTypeComboBox.SelectedValue = selectedOverlayType;
  47. RefreshMapPanel();
  48. }
  49. }
  50. }
  51. public OverlaysTool(MapPanel mapPanel, MapLayerFlag layers, ToolStripStatusLabel statusLbl, TypeComboBox overlayTypeComboBox, MapPanel overlayTypeMapPanel, IGamePlugin plugin, UndoRedoList<UndoRedoEventArgs> url)
  52. : base(mapPanel, layers, statusLbl, plugin, url)
  53. {
  54. previewMap = map;
  55. this.mapPanel.MouseDown += MapPanel_MouseDown;
  56. this.mapPanel.MouseMove += MapPanel_MouseMove;
  57. (this.mapPanel as Control).KeyDown += OverlaysTool_KeyDown;
  58. (this.mapPanel as Control).KeyUp += OverlaysTool_KeyUp;
  59. this.overlayTypeComboBox = overlayTypeComboBox;
  60. this.overlayTypeComboBox.SelectedIndexChanged += OverlayTypeComboBox_SelectedIndexChanged;
  61. this.overlayTypeMapPanel = overlayTypeMapPanel;
  62. this.overlayTypeMapPanel.BackColor = Color.White;
  63. this.overlayTypeMapPanel.MaxZoom = 1;
  64. navigationWidget.MouseCellChanged += MouseoverWidget_MouseCellChanged;
  65. SelectedOverlayType = this.overlayTypeComboBox.Types.First() as OverlayType;
  66. UpdateStatus();
  67. }
  68. private void OverlayTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
  69. {
  70. SelectedOverlayType = overlayTypeComboBox.SelectedValue as OverlayType;
  71. }
  72. private void OverlaysTool_KeyDown(object sender, KeyEventArgs e)
  73. {
  74. if (e.KeyCode == Keys.ShiftKey)
  75. {
  76. EnterPlacementMode();
  77. }
  78. }
  79. private void OverlaysTool_KeyUp(object sender, KeyEventArgs e)
  80. {
  81. if (e.KeyCode == Keys.ShiftKey)
  82. {
  83. ExitPlacementMode();
  84. }
  85. }
  86. private void MapPanel_MouseDown(object sender, MouseEventArgs e)
  87. {
  88. if (placementMode)
  89. {
  90. if (e.Button == MouseButtons.Left)
  91. {
  92. AddOverlay(navigationWidget.MouseCell);
  93. }
  94. else if (e.Button == MouseButtons.Right)
  95. {
  96. RemoveOverlay(navigationWidget.MouseCell);
  97. }
  98. }
  99. else if ((e.Button == MouseButtons.Left) || (e.Button == MouseButtons.Right))
  100. {
  101. PickOverlay(navigationWidget.MouseCell);
  102. }
  103. }
  104. private void MapPanel_MouseMove(object sender, MouseEventArgs e)
  105. {
  106. if (!placementMode && (Control.ModifierKeys == Keys.Shift))
  107. {
  108. EnterPlacementMode();
  109. }
  110. else if (placementMode && (Control.ModifierKeys == Keys.None))
  111. {
  112. ExitPlacementMode();
  113. }
  114. }
  115. private void MouseoverWidget_MouseCellChanged(object sender, MouseCellChangedEventArgs e)
  116. {
  117. if (placementMode)
  118. {
  119. if (SelectedOverlayType != null)
  120. {
  121. mapPanel.Invalidate(map, new Rectangle(e.OldCell, new Size(1, 1)));
  122. mapPanel.Invalidate(map, new Rectangle(e.NewCell, new Size(1, 1)));
  123. }
  124. }
  125. }
  126. private void AddOverlay(Point location)
  127. {
  128. if ((location.Y == 0) || (location.Y == (map.Metrics.Height - 1)))
  129. {
  130. return;
  131. }
  132. if (map.Overlay[location] == null)
  133. {
  134. if (SelectedOverlayType != null)
  135. {
  136. var overlay = new Overlay
  137. {
  138. Type = SelectedOverlayType,
  139. Icon = 0
  140. };
  141. map.Overlay[location] = overlay;
  142. mapPanel.Invalidate(map, location);
  143. void undoAction(UndoRedoEventArgs e)
  144. {
  145. e.MapPanel.Invalidate(e.Map, location);
  146. e.Map.Overlay[location] = null;
  147. }
  148. void redoAction(UndoRedoEventArgs e)
  149. {
  150. e.Map.Overlay[location] = overlay;
  151. e.MapPanel.Invalidate(e.Map, location);
  152. }
  153. url.Track(undoAction, redoAction);
  154. plugin.Dirty = true;
  155. }
  156. }
  157. }
  158. private void RemoveOverlay(Point location)
  159. {
  160. if ((map.Overlay[location] is Overlay overlay) && overlay.Type.IsPlaceable)
  161. {
  162. map.Overlay[location] = null;
  163. mapPanel.Invalidate(map, location);
  164. void undoAction(UndoRedoEventArgs e)
  165. {
  166. e.Map.Overlay[location] = overlay;
  167. e.MapPanel.Invalidate(e.Map, location);
  168. }
  169. void redoAction(UndoRedoEventArgs e)
  170. {
  171. e.MapPanel.Invalidate(e.Map, location);
  172. e.Map.Overlay[location] = null;
  173. }
  174. url.Track(undoAction, redoAction);
  175. plugin.Dirty = true;
  176. }
  177. }
  178. private void EnterPlacementMode()
  179. {
  180. if (placementMode)
  181. {
  182. return;
  183. }
  184. placementMode = true;
  185. navigationWidget.MouseoverSize = Size.Empty;
  186. if (SelectedOverlayType != null)
  187. {
  188. mapPanel.Invalidate(map, navigationWidget.MouseCell);
  189. }
  190. UpdateStatus();
  191. }
  192. private void ExitPlacementMode()
  193. {
  194. if (!placementMode)
  195. {
  196. return;
  197. }
  198. placementMode = false;
  199. navigationWidget.MouseoverSize = new Size(1, 1);
  200. if (SelectedOverlayType != null)
  201. {
  202. mapPanel.Invalidate(map, navigationWidget.MouseCell);
  203. }
  204. UpdateStatus();
  205. }
  206. private void PickOverlay(Point location)
  207. {
  208. if (map.Metrics.GetCell(location, out int cell))
  209. {
  210. var overlay = map.Overlay[cell];
  211. if ((overlay != null) && !overlay.Type.IsWall)
  212. {
  213. SelectedOverlayType = overlay.Type;
  214. }
  215. }
  216. }
  217. private void RefreshMapPanel()
  218. {
  219. overlayTypeMapPanel.MapImage = SelectedOverlayType?.Thumbnail;
  220. }
  221. private void UpdateStatus()
  222. {
  223. if (placementMode)
  224. {
  225. statusLbl.Text = "Left-Click to place overlay, Right-Click to remove overlay";
  226. }
  227. else
  228. {
  229. statusLbl.Text = "Shift to enter placement mode, Left-Click or Right-Click to pick overlay";
  230. }
  231. }
  232. protected override void PreRenderMap()
  233. {
  234. base.PreRenderMap();
  235. previewMap = map.Clone();
  236. if (placementMode)
  237. {
  238. var location = navigationWidget.MouseCell;
  239. if (SelectedOverlayType != null)
  240. {
  241. if (previewMap.Metrics.GetCell(location, out int cell))
  242. {
  243. if (previewMap.Overlay[cell] == null)
  244. {
  245. previewMap.Overlay[cell] = new Overlay
  246. {
  247. Type = SelectedOverlayType,
  248. Icon = 0,
  249. Tint = Color.FromArgb(128, Color.White)
  250. };
  251. }
  252. }
  253. }
  254. }
  255. }
  256. protected override void PostRenderMap(Graphics graphics)
  257. {
  258. base.PostRenderMap(graphics);
  259. var overlayPen = new Pen(Color.Green, 4.0f);
  260. foreach (var (cell, overlay) in previewMap.Overlay.Where(x => x.Value.Type.IsPlaceable))
  261. {
  262. previewMap.Metrics.GetLocation(cell, out Point topLeft);
  263. var bounds = new Rectangle(new Point(topLeft.X * Globals.TileWidth, topLeft.Y * Globals.TileHeight), Globals.TileSize);
  264. graphics.DrawRectangle(overlayPen, bounds);
  265. }
  266. }
  267. #region IDisposable Support
  268. private bool disposedValue = false;
  269. protected override void Dispose(bool disposing)
  270. {
  271. if (!disposedValue)
  272. {
  273. if (disposing)
  274. {
  275. overlayTypeComboBox.SelectedIndexChanged -= OverlayTypeComboBox_SelectedIndexChanged;
  276. mapPanel.MouseDown -= MapPanel_MouseDown;
  277. mapPanel.MouseMove -= MapPanel_MouseMove;
  278. (mapPanel as Control).KeyDown -= OverlaysTool_KeyDown;
  279. (mapPanel as Control).KeyUp -= OverlaysTool_KeyUp;
  280. navigationWidget.MouseCellChanged -= MouseoverWidget_MouseCellChanged;
  281. }
  282. disposedValue = true;
  283. }
  284. base.Dispose(disposing);
  285. }
  286. #endregion
  287. }
  288. }