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