SmudgeTool.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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 SmudgeTool : ViewTool
  27. {
  28. private readonly TypeComboBox smudgeTypeComboBox;
  29. private readonly MapPanel smudgeTypeMapPanel;
  30. private Map previewMap;
  31. protected override Map RenderMap => previewMap;
  32. private bool placementMode;
  33. private SmudgeType selectedSmudgeType;
  34. private SmudgeType SelectedSmudgeType
  35. {
  36. get => selectedSmudgeType;
  37. set
  38. {
  39. if (selectedSmudgeType != value)
  40. {
  41. if (placementMode && (selectedSmudgeType != null))
  42. {
  43. mapPanel.Invalidate(map, navigationWidget.MouseCell);
  44. }
  45. selectedSmudgeType = value;
  46. smudgeTypeComboBox.SelectedValue = selectedSmudgeType;
  47. if (placementMode && (selectedSmudgeType != null))
  48. {
  49. mapPanel.Invalidate(map, navigationWidget.MouseCell);
  50. }
  51. RefreshMapPanel();
  52. }
  53. }
  54. }
  55. public SmudgeTool(MapPanel mapPanel, MapLayerFlag layers, ToolStripStatusLabel statusLbl, TypeComboBox smudgeTypeComboBox, MapPanel smudgeTypeMapPanel, IGamePlugin plugin, UndoRedoList<UndoRedoEventArgs> url)
  56. : base(mapPanel, layers, statusLbl, plugin, url)
  57. {
  58. previewMap = map;
  59. this.mapPanel.MouseDown += MapPanel_MouseDown;
  60. this.mapPanel.MouseMove += MapPanel_MouseMove;
  61. (this.mapPanel as Control).KeyDown += SmudgeTool_KeyDown;
  62. (this.mapPanel as Control).KeyUp += SmudgeTool_KeyUp;
  63. this.smudgeTypeComboBox = smudgeTypeComboBox;
  64. this.smudgeTypeComboBox.SelectedIndexChanged += SmudgeTypeComboBox_SelectedIndexChanged;
  65. this.smudgeTypeMapPanel = smudgeTypeMapPanel;
  66. this.smudgeTypeMapPanel.BackColor = Color.White;
  67. this.smudgeTypeMapPanel.MaxZoom = 1;
  68. navigationWidget.MouseCellChanged += MouseoverWidget_MouseCellChanged;
  69. SelectedSmudgeType = smudgeTypeComboBox.Types.First() as SmudgeType;
  70. UpdateStatus();
  71. }
  72. private void SmudgeTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
  73. {
  74. SelectedSmudgeType = smudgeTypeComboBox.SelectedValue as SmudgeType;
  75. }
  76. private void SmudgeTool_KeyDown(object sender, KeyEventArgs e)
  77. {
  78. if (e.KeyCode == Keys.ShiftKey)
  79. {
  80. EnterPlacementMode();
  81. }
  82. }
  83. private void SmudgeTool_KeyUp(object sender, KeyEventArgs e)
  84. {
  85. if (e.KeyCode == Keys.ShiftKey)
  86. {
  87. ExitPlacementMode();
  88. }
  89. }
  90. private void MapPanel_MouseDown(object sender, MouseEventArgs e)
  91. {
  92. if (placementMode)
  93. {
  94. if (e.Button == MouseButtons.Left)
  95. {
  96. AddSmudge(navigationWidget.MouseCell);
  97. }
  98. else if (e.Button == MouseButtons.Right)
  99. {
  100. RemoveSmudge(navigationWidget.MouseCell);
  101. }
  102. }
  103. else if ((e.Button == MouseButtons.Left) || (e.Button == MouseButtons.Right))
  104. {
  105. PickSmudge(navigationWidget.MouseCell);
  106. }
  107. }
  108. private void MapPanel_MouseMove(object sender, MouseEventArgs e)
  109. {
  110. if (!placementMode && (Control.ModifierKeys == Keys.Shift))
  111. {
  112. EnterPlacementMode();
  113. }
  114. else if (placementMode && (Control.ModifierKeys == Keys.None))
  115. {
  116. ExitPlacementMode();
  117. }
  118. }
  119. private void MouseoverWidget_MouseCellChanged(object sender, MouseCellChangedEventArgs e)
  120. {
  121. if (placementMode)
  122. {
  123. if (SelectedSmudgeType != null)
  124. {
  125. mapPanel.Invalidate(map, e.OldCell);
  126. mapPanel.Invalidate(map, e.NewCell);
  127. }
  128. }
  129. }
  130. private void AddSmudge(Point location)
  131. {
  132. if (map.Smudge[location] == null)
  133. {
  134. if (SelectedSmudgeType != null)
  135. {
  136. var smudge = new Smudge
  137. {
  138. Type = SelectedSmudgeType,
  139. Icon = 0,
  140. Data = 0
  141. };
  142. map.Smudge[location] = smudge;
  143. mapPanel.Invalidate(map, location);
  144. void undoAction(UndoRedoEventArgs e)
  145. {
  146. e.MapPanel.Invalidate(e.Map, location);
  147. e.Map.Smudge[location] = null;
  148. }
  149. void redoAction(UndoRedoEventArgs e)
  150. {
  151. e.Map.Smudge[location] = smudge;
  152. e.MapPanel.Invalidate(e.Map, location);
  153. }
  154. url.Track(undoAction, redoAction);
  155. plugin.Dirty = true;
  156. }
  157. }
  158. }
  159. private void RemoveSmudge(Point location)
  160. {
  161. if ((map.Smudge[location] is Smudge smudge) && ((smudge.Type.Flag & SmudgeTypeFlag.Bib) == SmudgeTypeFlag.None))
  162. {
  163. map.Smudge[location] = null;
  164. mapPanel.Invalidate(map, location);
  165. void undoAction(UndoRedoEventArgs e)
  166. {
  167. e.Map.Smudge[location] = smudge;
  168. e.MapPanel.Invalidate(e.Map, location);
  169. }
  170. void redoAction(UndoRedoEventArgs e)
  171. {
  172. e.MapPanel.Invalidate(e.Map, location);
  173. e.Map.Smudge[location] = null;
  174. }
  175. url.Track(undoAction, redoAction);
  176. plugin.Dirty = true;
  177. }
  178. }
  179. private void EnterPlacementMode()
  180. {
  181. if (placementMode)
  182. {
  183. return;
  184. }
  185. placementMode = true;
  186. navigationWidget.MouseoverSize = Size.Empty;
  187. if (SelectedSmudgeType != null)
  188. {
  189. mapPanel.Invalidate(map, navigationWidget.MouseCell);
  190. }
  191. UpdateStatus();
  192. }
  193. private void ExitPlacementMode()
  194. {
  195. if (!placementMode)
  196. {
  197. return;
  198. }
  199. placementMode = false;
  200. navigationWidget.MouseoverSize = new Size(1, 1);
  201. if (SelectedSmudgeType != null)
  202. {
  203. mapPanel.Invalidate(map, navigationWidget.MouseCell);
  204. }
  205. UpdateStatus();
  206. }
  207. private void PickSmudge(Point location)
  208. {
  209. if (map.Metrics.GetCell(location, out int cell))
  210. {
  211. var smudge = map.Smudge[cell];
  212. if (smudge != null)
  213. {
  214. SelectedSmudgeType = smudge.Type;
  215. }
  216. }
  217. }
  218. private void RefreshMapPanel()
  219. {
  220. smudgeTypeMapPanel.MapImage = SelectedSmudgeType?.Thumbnail;
  221. }
  222. private void UpdateStatus()
  223. {
  224. if (placementMode)
  225. {
  226. statusLbl.Text = "Left-Click to place smudge, Right-Click to remove smudge";
  227. }
  228. else
  229. {
  230. statusLbl.Text = "Shift to enter placement mode, Left-Click or Right-Click to pick smudge";
  231. }
  232. }
  233. protected override void PreRenderMap()
  234. {
  235. base.PreRenderMap();
  236. previewMap = map.Clone();
  237. if (placementMode)
  238. {
  239. var location = navigationWidget.MouseCell;
  240. if (SelectedSmudgeType != null)
  241. {
  242. if (previewMap.Metrics.GetCell(location, out int cell))
  243. {
  244. if (previewMap.Smudge[cell] == null)
  245. {
  246. previewMap.Smudge[cell] = new Smudge { Type = SelectedSmudgeType, Data = 0, Tint = Color.FromArgb(128, Color.White) };
  247. }
  248. }
  249. }
  250. }
  251. }
  252. protected override void PostRenderMap(Graphics graphics)
  253. {
  254. base.PostRenderMap(graphics);
  255. var smudgePen = new Pen(Color.Green, 4.0f);
  256. foreach (var (cell, smudge) in previewMap.Smudge.Where(x => (x.Value.Type.Flag & SmudgeTypeFlag.Bib) == SmudgeTypeFlag.None))
  257. {
  258. previewMap.Metrics.GetLocation(cell, out Point topLeft);
  259. var bounds = new Rectangle(new Point(topLeft.X * Globals.TileWidth, topLeft.Y * Globals.TileHeight), Globals.TileSize);
  260. graphics.DrawRectangle(smudgePen, bounds);
  261. }
  262. }
  263. #region IDisposable Support
  264. private bool disposedValue = false;
  265. protected override void Dispose(bool disposing)
  266. {
  267. if (!disposedValue)
  268. {
  269. if (disposing)
  270. {
  271. smudgeTypeComboBox.SelectedIndexChanged -= SmudgeTypeComboBox_SelectedIndexChanged;
  272. mapPanel.MouseDown -= MapPanel_MouseDown;
  273. mapPanel.MouseMove -= MapPanel_MouseMove;
  274. (mapPanel as Control).KeyDown -= SmudgeTool_KeyDown;
  275. (mapPanel as Control).KeyUp -= SmudgeTool_KeyUp;
  276. navigationWidget.MouseCellChanged -= MouseoverWidget_MouseCellChanged;
  277. }
  278. disposedValue = true;
  279. }
  280. base.Dispose(disposing);
  281. }
  282. #endregion
  283. }
  284. }