CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

OverlaysTool.cs (11223B)


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